Discovery
What: find every supported agent on the machine, instantly, without launching anything. Checks env overrides,PATH, the login-shell PATH
(GUI apps often miss it), and known install directories. Agents that are
supported but missing come back with an install hint.
probe
or probe_auth asks the agent.
Gates: none. Call runtime.prewarm() at startup to scan early.
Not found? MissingAgent.searched lists every directory that was checked,
so an app can show it and offer a file picker. A user with an unusual install
sets ANYAGENT_<AGENT>_BIN (see Agents).
An installer that edits the user’s PATH is invisible to an app that is
already running: say “installed? restart the app”, not “not found”.
Some agents have a richer, separately installed runtime (Antigravity’s ACP
server). When only the base CLI is found, agent.upgrade names what to
install for more capabilities.
Probe and auth
What: ask the agent itself what it can do. Opens a throwaway session (about 1 s) and returns version, real login state, capabilities, config options, and slash commands.probe_auth is the cheaper call when you only
need the login state.
AgentDetails. The same struct is available later as
session.info().details.
Gates: none. probe_with(&agent, options) probes with your dir, env,
args and config home; in a workspace’s dir it returns that workspace’s
commands, and each command’s source tells a skill (Skill { path, scope })
from a built-in. On claude a probe skips the user’s configured hooks
and MCP servers (servers the app declares still load), so the user’s
MCP-provided prompts are not in commands. On codex a probe opens no
thread, so nothing of the user’s starts at all.
anyagent never reads or holds credentials and never drives a login flow. It
tells you the exact command or env var to show the user. Keep several
logins of one agent apart with SessionOptions::config_home(dir).
Sessions
What: one live conversation with one agent process.open spawns the
agent, handshakes, and returns two halves: Session (commands, cheap to
clone) and Events (the stream, one consumer).
open returns. session.info() has the resume token,
capabilities, and config options.
Gates: none. Fails typed: AuthRequired { login } when logged out,
HandshakeTimeout after 30 s, ResumeFailed when the agent has no
conversation for the token.
Drain Events continuously. It buffers 1024 events; a consumer that falls a
full buffer behind is treated as gone and the session closes. close() ends
the process; dropping Events does the same.
Prompting
What: send text, slash commands, and file attachments. What happens depends on session state, and the returnedDelivery tells you which.
Confirms:
TurnStarted { origin: Prompt(id) } for started and queued
prompts.
Gates: Steer decides steer vs queue. Images decides whether an
attachment goes inline or degrades to a path in the prompt text.
Drop a queued prompt before it starts with session.dequeue(prompt_id).
Slash commands from details.commands are sent as plain text:
session.prompt("/review"). An unknown slash prompt is just text.
Permissions and questions
What: the agent’s “may I run this?” and “which one?” moments, forwarded as typed requests with the choices the agent actually offers. Answer exactly once.Answer::Deny { message }; to take a
request back without choosing, Answer::Cancel. What each agent does with
them: answers by agent.
Confirms: RequestClosed. It also arrives when a cancelled turn
withdraws the request, so clear your UI on that event, not on your own
answer. While a request is open, session.status() is NeedsInput.
Gates: Permissions and Questions. An agent without Permissions
runs tools without asking.
For unattended runs, open with
SessionOptions::permission_mode(PermissionMode::AutoApprove): anyagent
allows each request once without forwarding it. PermissionMode::AcceptEdits
does the same only for file edits (Edit, Delete, Move); every other
request is forwarded. In every mode, the request right after a
PlanProposed (the plan’s approval) is forwarded.
Cancel
What: stop the running turn. The session and its context survive.RequestClosed for any request the turn had open, then
TurnEnded { stop: Cancelled }.
Gates: none.
Configuration
What: models, effort, mode, sandbox, switched without a restart. Agents advertise their settings asConfigOptions with typed choices, so a picker
renders what the agent offers instead of a hardcoded list.
Confirms:
SessionUpdated, carrying the new configuration and the
rebuilt config_options. Wait for it rather than for configure to return.
Gates: the option must be in details.config_options, else
InvalidConfiguration.
Status
What: the one value a thread list needs.Idle, Working, or
NeedsInput, pushed on every change and readable on demand.
StatusChanged is emitted only on change. A turn ending with
another prompt queued stays Working, never flashing Idle.
Gates: none.
One-shot generation
What: prompt in, string out, no session to manage. For thread titles, commit messages, branch names, PR bodies.SessionOptions::output_schema(schema) the
string is the turn’s final message, JSON matching the schema (claude, codex;
OutputSchema gates it).
Confirms: the returned String.
Gates: Permissions, or a wire that can launch without tools. Requires
a new session: resume and fork_from options are rejected. A tool event or
a question needing a choice cancels generation. Put context inline;
attachments cannot be opened without tools.
Resume
What: continue a conversation from a new process. Every session mints an opaqueresume_token; store it with your transcript.
open returns; the agent has its context back. No old events
are replayed, so keep your own transcript.
Gates: Resume, else ResumeFailed. The token is agent-owned: store it
as-is, never parse it. The session id is not a resume token.
Fork
What: a new session starting from an old one’s history. The original is untouched, which is what “try this a different way” needs.open returns a new session with its own resume token.
Gates: Fork.
Rollback
What: rewind this session in place by whole turns.
Confirms: the call returns once the agent answers;
SessionUpdated
carries the new snapshot. A refusal is InvalidRequest with the agent’s reason.
Gates: above, plus an idle session and no other rollback pending
(SessionBusy otherwise).
Compact
What: ask the agent to summarize its own context, freeing room in the window without losing the thread.ContextCompacted, then a lower ContextUsage. Compaction
runs as an agent-originated turn: prompts sent meanwhile queue behind it. An
agent that finds nothing to summarize says so as a Diagnostic.
Gates: Compact (claude, codex, opencode, pi) and an idle session.
Subagents
What: agents that spawn agents render as a tree, not interleaved noise.parent_tool_id on the child’s events. A child can never end
the parent’s turn; anyagent consumes the child’s turn bookkeeping.
tool.subagent names its role and model and carries its latest progress line
and token count (claude all four, codex tokens only).
Gates: Subagents.
Context and plan usage
What: the two gauges apps show. They measure different things.ContextUsage and PlanUsage. Plan usage also needs a
subscription login (AuthKind::Subscription).
MCP servers
What: hand the agent your app’s MCP servers for this session.ToolUpdated with
ToolKind::Mcp { server, tool }. Over ACP the agent must name them in the
call’s _meta (antigravity’s server, kiro and qwen do); hermes calls stay
Other.
Gates: the agent’s supported transports. An unsupported transport fails
open typed rather than dropping the server.
Wire recording
What: a bug report that contains the actual bug. Tees every raw protocol frame, both directions, to a JSONL file.Testing without a subprocess
What: run your app over a scripted agent. The engine, turn rules, and event shapes are real; only the agent is fake.Cargo.toml
mock. Script flags (steer, deterministic,
buffer, …) model the wire shapes the engine has to cope with.