# AO CLI 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: ```bash cd backend go build -o ./bin/ao ./cmd/ao ./bin/ao agent ls ``` ## Current commands Every product command resolves to a daemon HTTP route. Run `ao --help` for the authoritative flag shape. ### Daemon control | 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 ` | 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`. | ### Product commands | Command | Daemon route | | ----------------------------------- | ---------------------------------------------- | | `ao project add` | `POST /api/v1/projects` | | `ao project ls` | `GET /api/v1/projects` | | `ao project get ` | `GET /api/v1/projects/{id}` | | `ao project set-config ` | `PUT /api/v1/projects/{id}/config` | | `ao project rm ` | `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 ` | `GET /api/v1/sessions/{id}` | | `ao session kill ` | `POST /api/v1/sessions/{id}/kill` | | `ao session restore ` | `POST /api/v1/sessions/{id}/restore` | | `ao session rename ` | `PATCH /api/v1/sessions/{id}` | | `ao session cleanup` | `POST /api/v1/sessions/cleanup` | | `ao session claim-pr ` | `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 ` | `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. 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 ` 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`, `fill`, `type`, `press`, `hover`, `scroll`, `select`, `check`, `uncheck`, `get`, `highlight`, `unhighlight`, `tabs`, `tab new`, `tab select`, `tab close`, `wait`, `screenshot`, `network start/status/list/stop/clear`, `console`, and `errors`. 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`. ## Configuration 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`. ## Manual smoke test ```bash 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" ``` ## Adding new commands 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.