The ao CLI is a thin Go/Cobra client for the local Agent Orchestrator daemon.
It starts, discovers, inspects, and stops the daemon through the loopback HTTP
surface and the running.json handshake. It must not open SQLite directly or
call runtime, workspace, tracker, or agent adapters in-process.
When using the CLI directly from a shell, make sure the daemon is running first
with ao start or by opening the desktop app. Product commands such as
ao agent ls and ao spawn call the loopback daemon and will fail with a
"daemon is not running" error if no running.json points at a live process. From
a source checkout, build and run the local binary explicitly, for example:
cd backend
go build -o ./bin/ao ./cmd/ao
./bin/ao agent lsEvery product command resolves to a daemon HTTP route. Run ao <command> --help for the authoritative flag shape.
| Command | Purpose |
|---|---|
ao start |
Start the daemon in the background and wait for /readyz. |
ao stop |
Gracefully stop the daemon via loopback POST /shutdown after verifying daemon identity. |
ao status / --json |
Report daemon state from running.json, process liveness, /healthz, and /readyz. |
ao doctor / --json |
Check config, data directory, DB-file presence, daemon state, git, and (on Darwin/Linux) tmux; on Windows conpty is built in. |
ao completion <shell> |
Generate completions for bash, zsh, fish, or powershell. |
ao version / ao --version |
Print build metadata. |
ao daemon |
Hidden internal daemon entrypoint used by ao start. |
| Command | Daemon route |
|---|---|
ao project add |
POST /api/v1/projects |
ao project ls |
GET /api/v1/projects |
ao project get <id> |
GET /api/v1/projects/{id} |
ao project set-config <id> |
PUT /api/v1/projects/{id}/config |
ao project rm <id> |
DELETE /api/v1/projects/{id} |
ao agent ls |
GET /api/v1/agents |
ao agent ls --refresh |
POST /api/v1/agents/refresh |
ao spawn |
POST /api/v1/sessions |
ao session ls |
GET /api/v1/sessions |
ao session get <id> |
GET /api/v1/sessions/{id} |
ao session kill <id> |
POST /api/v1/sessions/{id}/kill |
ao session restore <id> |
POST /api/v1/sessions/{id}/restore |
ao session switch-agent <id> <target-harness> |
POST /api/v1/sessions/{id}/switch-agent |
ao session agent-switch ls <session-id> |
GET /api/v1/sessions/{id}/agent-switches |
ao session handoff submit |
POST /api/v1/sessions/{id}/agent-switches/{switchId}/handoff |
ao session rename <id> <name> |
PATCH /api/v1/sessions/{id} |
ao session cleanup |
POST /api/v1/sessions/cleanup |
ao session claim-pr <id> <pr-ref> |
POST /api/v1/sessions/{id}/pr/claim |
ao orchestrator ls |
GET /api/v1/orchestrators |
ao send |
POST /api/v1/sessions/{id}/send |
ao preview [url] |
POST /api/v1/sessions/{id}/preview |
ao preview start/status/stop |
POST/GET/DELETE /api/v1/sessions/{id}/preview/server |
ao browser ... |
GET /api/v1/browser/status, POST /api/v1/browser/commands |
ao hooks <agent> <event> |
POST /api/v1/sessions/{id}/activity (hidden) |
ao agent ls prints the daemon-supported agent catalog with local install/auth
readiness. Use --refresh to rerun the bounded local probes and --json to
print the raw inventory response.
ao spawn resolves project context in this order: explicit --project,
AO_PROJECT_ID, AO_SESSION_ID (by fetching the current session from the
daemon), then the current working directory matched against registered project
paths. If AO_SESSION_ID is set but the session cannot be fetched, pass
--project explicitly.
Agent switching is initially available only for worker sessions whose source and target harnesses are Claude Code or Codex. The main command accepts optional handoff guidance and an idempotency key:
ao session switch-agent ao-7 codex \
--note "Continue the failing integration test" \
--idempotency-key switch-ao-7-to-codex
ao session agent-switch ls ao-7 --jsonswitch-agent and agent-switch ls both support --json.
The agent-switch command also has the agent-switches alias, and ls has the
list alias.
ao session handoff submit is the internal source-agent path for optional
semantic enrichment, not a required human step in a normal switch. It requires
the switch ID, exact source launch generation, and a regular file containing
one JSON object no larger than 64 KiB. --session defaults to
AO_SESSION_ID:
AO_SESSION_ID=ao-7 ao session handoff submit \
--switch switch-123 \
--source-generation generation-456 \
--file /tmp/ao-handoff.json \
--jsonSwitching preserves the AO worker session and worktree. It does not translate, clip, or rewrite provider transcript files; providers continue to own their native history and compaction.
If --agent / --harness is omitted, ao spawn uses the resolved project's
worker.agent config. Before spawning, the CLI refreshes the advisory agent
catalog and fails early when the selected agent is unsupported, not installed,
or unauthorized. It warns-but-continues when auth remains unknown because daemon
spawn remains the authoritative runtime validation point. Use
--skip-agent-check to bypass only this CLI-side preflight.
ao preview resolves its session from the AO_SESSION_ID environment variable
(it is meant to run inside a session), not a flag. With no argument it
autodetects an index.html in the session workspace; with a URL argument it
opens that URL verbatim (file://, http, https).
ao preview start [configuration] loads .ao/launch.json from the session
workspace, starts that exact command under a session-owned supervisor, selects
or records its loopback port, waits for readiness, and opens application
targets in the Browser panel. status reports bounded recent logs and stop
terminates the managed process tree. Multiple configurations must be selected
by name; AO does not assign confidence scores to arbitrary localhost servers.
This is an optional, reusable project configuration, not a prerequisite for
preview. Agents must not create it automatically. Static HTML and Markdown use
the direct file preview and must not cause package-manager scaffolding,
dependency installation, or a development server to be introduced.
When a browser-displayable file is the requested artifact, agents should call
ao preview <workspace-path> immediately after creating or materially updating
the primary output. Markdown, HTML, PDF, SVG, and common images can be served
directly. Supporting assets must not replace an active application preview.
ao browser also resolves its target from AO_SESSION_ID, but controls the
session-owned live Electron browser rather than only setting its preview URL.
The target-isolated command set includes status, open, snapshot, click,
dblclick, focus, fill, type, press, hover, scroll,
scrollintoview, drag, select, check, uncheck, get, highlight,
unhighlight, tabs, tab new, tab select, tab close, frame, dialog,
wait, screenshot, network start/status/list/stop/clear, console, and
errors. The native engine is bound internally; there is no second command or
connection setup. Logical tab IDs remain stable for the session, and allowed popups
become AO browser tabs rather than separate OS-browser windows. The AO desktop
app must be open because Electron owns the WebContentsView.
References from a snapshot are invalidated after navigation or DOM replacement;
they are also invalidated when changing tabs. Take another snapshot when a
command reports STALE_REFERENCE.
Browser waits cover load completion, text or selector appearance and
disappearance, URL matching, fixed delays, and a configurable DOM-stability
window for HMR-driven verification.
Browser tabs in the same worker share a memory-only Electron profile. Different
workers receive distinct partitions, so cookies, authentication, local storage,
and session storage do not leak between their browser runtimes.
Network capture is disabled by default and must be started explicitly. It is
scoped to the active tab at start time, expires after 60 seconds by default
(maximum 300), retains at most 200 in-memory entries, and is cleared with the
tab/session. Captured data is metadata-only: request and response bodies are
never read, sensitive headers are omitted, and URL credentials, fragments, and
query values are redacted.
go run . in backend/ remains a compatibility wrapper around the daemon.
PR actions are available through ao pr merge and
ao pr resolve-comments. Review actions are available through ao review ls,
ao review trigger (also execute and restart), ao review cancel (also
stop), and ao review submit.
The CLI and daemon share the same environment-driven config:
| Var | Default | Purpose |
|---|---|---|
AO_PORT |
3001 |
Loopback daemon port. |
AO_RUN_FILE |
~/.ao/running.json |
PID/port handshake. |
AO_DATA_DIR |
~/.ao/data |
SQLite data directory. |
AO_REQUEST_TIMEOUT |
60s |
REST request timeout. |
AO_SHUTDOWN_TIMEOUT |
10s |
Graceful shutdown cap. |
AO_KEEP_DAEMON |
unset (off) | Keep the desktop app's daemon running after the window closes; stop only via ao stop. (fork) |
The daemon always binds 127.0.0.1.
cd backend
go build -o /tmp/ao ./cmd/ao
tmp=$(mktemp -d)
export AO_RUN_FILE="$tmp/running.json"
export AO_DATA_DIR="$tmp/data"
export AO_PORT=3037
/tmp/ao status --json
/tmp/ao doctor
/tmp/ao start
/tmp/ao status --json
/tmp/ao stop
/tmp/ao status --json
rm -rf "$tmp"Add a product command only when a daemon HTTP route owns the corresponding
mutation/read; the CLI must call that route rather than reimplementing daemon
behavior. Commands not yet exposed but with backend routes in place include
ao events ... (over the CDC/SSE endpoint) and CLI parity for PR/review
actions.
Do not port old in-process TypeScript CLI behavior that mixed command handling with storage and runtime implementation details.