Everything omni exposes, what each provider does underneath, and the endpoint this site serves the dial from.
Zero runtime dependencies. You bring the CLIs, and omni only offers the ones that are both installed and signed in.
The front door. The only object you need to import, besides the events.
Inference.claude, Inference.openai and Inference.google are the three account handles. They are resolved lazily, so touching one never imports the other two.
One live chat per session id. A second attempt raises SessionBusy; a lock whose owner has died is reclaimed, so a crash never wedges a session shut.
Every setter above is recorded when you call it and applied at the next turn boundary. Calling one again overwrites the last value. That is also how a new session is started: call load_or_create_session again.
send never blocks and is safe from any thread, including from inside an event handler, so the loop is yours to choose.
One dataclass for everything. Class attributes are the types, instance fields are the payload, and which fields are filled depends on the type.
Event.ERROR carries a kind: auth, limit, unavailable or crash for the model and its CLI, plus stderr for CLI chatter, omni when the engine itself failed, and handler when one of your callbacks raised.
Everything on_event sees plus omni's own bookkeeping: every launch, model change, provider switch, new session, message in, tool call, error and stop. All of it the same type, so it is parsable without a second schema — and it is already on disk in the session file.
omni drives each CLI's own login rather than making you use the CLI: it starts the flow, hands you the URL and types the code back if one is wanted. Codex runs its own browser callback, so there finish_auth waits rather than types. If a CLI does something unexpected, whatever it printed comes back verbatim along with the command to run yourself.
Answers are remembered for a minute, because every probe means running a CLI. A no is only trusted for ten seconds, so a network blip cannot quietly drop a provider off your dial.
used is a fraction, so 0.16 is 16%. Every provider is asked in a way that costs no tokens.
One long-lived claude -p handles every turn over stdin. Seeding is a file write into ~/.claude/projects/<slug>/<uuid>.jsonl, where the slug is the working directory with every non-alphanumeric character turned into a dash — resolved through symlinks first, because on macOS /var is one. Resume is scoped to that directory, so a session pins its cwd. Model and effort change over the control channel and omni only believes it once the CLI acknowledges.
The app server, not exec. It always runs against a CODEX_HOME under ~/.omni/jails/ holding a symlink to your real auth.json — linked, not copied, so a token refresh is not lost — and a near-empty config. Skills live outside that folder, so disable_subagents() switches them off one at a time over the protocol. A mid-turn message becomes a turn/steer, falling back to a new turn if the old one finished first.
The most restricted, and the one with the sharpest edges. Cold start is around ten seconds per launch. An unrecognised conversation id makes agy silently start a new one, so omni checks the id it gets back and re-seeds from the top if it is not the one it asked for. --print takes a value and will swallow the next flag if it is not passed last. Any failed turn kills the process outright.
This site serves the dial. omni asks for the one matching the providers it has and keeps the answer under ~/.omni/cache for an hour.
Point omni somewhere else with OMNI_REGISTRY. If the registry cannot be reached, omni prefers a dial it fetched before — even a stale one — over the copy packaged with the release, and backs off for five minutes rather than retrying on every call.
There is no database behind this. The models live in models-gdpval.json in a public repo, and the site reads that file over raw.githubusercontent at request time. Edit it, commit, and every install picks the change up within the hour — no release, no redeploy, and git keeps the history a database would have thrown away.