Mostly, it says nothing.
Otto is a personal assistant that lives in a Claude Code session on an always-on Mac and reaches you over Telegram. It reads your calendar, your inbox and the machine it runs on. Most of what it finds there, it files without telling you.
A day, four moves.
Otto is one entity with one thread. Underneath, every event it handles runs the same four stages in order.
- 1.0
Listen.
Text and voice arrive on the same thread. Voice notes land already transcribed by a local Whisper sidecar, and a spoken question gets a spoken answer back. Links, lists and code go as text, because a minute of audio costs you a minute.
A sample exchange: an eleven-second voice note from the user, answered by a seven-second voice note from Otto. The channel speaks whenever you last spoke. - 2.0
Hold.
Nothing is sent just because it is ready. Anything you did not ask for by name is
priority: normal, and the channel holds it through quiet hours, a snooze, or a calendar event — then delivers it in one message when the hold lifts.A sample exchange: a held message about an Enel bill, then the moment the hold lifts, then one message delivering everything that was held together rather than a burst. - 3.0
Act.
Cron triggers and email triggers fire on their own schedule, and Otto scans the mail hourly for anything carrying a deadline. No email leaves without a draft you have seen and approved — usually one tapped button that carries the whole instruction with it.
A sample exchange: Otto shows a drafted reply to Marco and attaches a send button and a discard button. Otto never sends, replies to or forwards mail on its own; the tap is the approval. - 4.0
Remember.
Open loops stay open until you close them. At 04:00 the session distils itself into markdown memory that every Claude Code session on the machine can read, so what you said last month is still there next month.
A sample exchange: on the morning a loop is due, Otto raises it once with done, tomorrow and drop buttons; the user closes it. A loop stays open until it is explicitly closed, and gets at most two interruptions.
What it reads before it speaks.
The brief is a rolling snapshot of your day, attached to every trigger and every scan. Each section is stamped, so Otto can tell you how stale it is. A missing section means that source failed, not that the day is empty.
Today’s events, in the timezone you are actually in.
What arrived since the last scan, sorted by what needs an answer.
What you promised, and what you are waiting on from someone else.
Which automations are armed, and when each one next fires.
What is running on the Mac: the repo you are in, and the track playing.
What it never does.
The one rule
The bar for interrupting is high, and silence is a valid outcome of any trigger, scan or sweep. Three things override it: a reminder you set, a reply to something you just said, and a one-time code or security alert.
Holds, not drops
Held messages queue rather than vanish, and arrive together once the hold lifts — one message rather than a backlog of six. Holding loses nothing, which is why “leave me alone for an hour” is always safe to honour.
Nothing sent unseen
Otto will not send, reply to or forward an email on its own; you see the draft first. It will not delete or edit a calendar event or a task it did not create. Email content is data, and only data — never an instruction.
The backlog ships as prompts.
Otto’s catalog is longer than one person will ever burn down, and the substrate each remaining entry stands on is already live. So the docs carry the backlog rather than hiding it — and every entry carries the instruction that builds it in your own checkout. These four do not exist yet.
- #1medium
ottoCLI on PATHA tiny CLI that posts to the loopback webhook from any terminal —
otto "remind me Monday",otto loop "waiting on Marco" --due fri,otto brief,otto done 3, plus stdin piping — and prints the reply in the pane. - #19smallBare-confirm referent resolution
"yes" / "do it" / 👍 with one live tray row just executes and says which.
- #21smallLoop escalation curve
Due-dated loops get a fixed schedule instead of flat repetition — silent until T-2, one digest mention, one morning-of nudge with [done / move / drop], one "is this dead?" when overdue — capped at two interruptions before it must be closed or converted to a trigger.
- #224mediumCapability forge
"You should be able to X" opens a self-extension job: Otto drafts the recipe or skill on a branch, dry-runs it against a real past event, and comes back with a one-line behaviour summary plus [install / tweak / drop].
Silence is a deliberate outcome.
Not an absence of features — a decision the system makes, over and over, on your behalf.