diff --git a/README.md b/README.md index 3f24509..8211f7a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ Give your AI agent a real terminal it can drive, and get back reviewable snapsho [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](./LICENSE) ![Node](https://img.shields.io/node/v/agent-tty) +[Quickstart](#quickstart) · [Why](#why-not-just-tmux-expect-asciinema-or-playwright) · [How it works](#how-it-works) · [Commands](#command-surface) · [Contributing](#contributing) + ![agent-tty: drive a terminal session and watch it live in the dashboard](./assets/hero.gif) Tools like `tmux` or `screen` help _you_ manage your own terminal windows. `agent-tty` is for handing a real, long-lived terminal to an AI coding agent, so it can run commands, drive interactive apps like `nvim` or `htop`, and read the screen back. Because every session is recorded, you never have to take the agent's word for what happened: you (or another agent) get a plain-text snapshot, a real screenshot, or a video of the actual screen, and can replay it to check the work. It works just as well for plain shell automation and CI smoke tests with no agent involved. @@ -48,13 +50,13 @@ npm install -g agent-tty export AGENT_TTY_HOME="$(mktemp -d)" agent-tty doctor --json # check your environment -# Open a session, do something, wait for it, look at the result. -SID=$(agent-tty create --json -- /bin/bash | jq -r '.result.sessionId') -agent-tty run "$SID" 'printf "hello from agent-tty\n"' --json -agent-tty wait "$SID" --text 'hello from agent-tty' --json -agent-tty snapshot "$SID" --format text --json -agent-tty screenshot "$SID" --json -agent-tty destroy "$SID" --json +# The canonical loop: +SID=$(agent-tty create --json -- /bin/bash | jq -r '.result.sessionId') # 1. open a session +agent-tty run "$SID" 'printf "hello from agent-tty\n"' --json # 2. type into it +agent-tty wait "$SID" --text 'hello from agent-tty' --json # 3. wait for the screen +agent-tty snapshot "$SID" --format text --json # 4. read it back +agent-tty screenshot "$SID" --json # 5. capture proof +agent-tty destroy "$SID" --json # 6. clean up ``` Driving an interactive TUI is the same loop, with key chords and a wait for the screen to settle: @@ -111,9 +113,17 @@ A colleague then used `agent-tty` to build an experimental TUI for Coder agents ## Command surface -Every user-facing command takes `--json` and returns a stable, machine-readable envelope. The commands cover the session lifecycle (`create`, `list`, `inspect`, `destroy`, `gc`), input and control (`run`, `type`, `paste`, `send-keys`, `batch`, `resize`, `signal`, `mark`), observation and capture (`wait`, `snapshot`, `screenshot`, `record export`), the live `dashboard`, and environment checks (`version`, `doctor`, `skills`). +Every user-facing command takes `--json` and returns a stable, machine-readable envelope, and exits with a stable code (`0` success, `2` usage error, `3` session not found, …) so scripts can branch without parsing output. + +| Group | Commands | +| ----------------------- | ------------------------------------------------------------------------ | +| Session lifecycle | `create`, `list`, `inspect`, `destroy`, `gc` | +| Input and control | `run`, `type`, `paste`, `send-keys`, `batch`, `resize`, `signal`, `mark` | +| Observation and capture | `wait`, `snapshot`, `screenshot`, `record export` | +| Live view | `dashboard` | +| Environment | `version`, `doctor`, `skills` | -See [`docs/USAGE.md`](./docs/USAGE.md) for the full flag reference and [`docs/TROUBLESHOOTING.md`](./docs/TROUBLESHOOTING.md) for renderer and environment issues. +The CLI documents itself: `agent-tty --help` lists every command, and `agent-tty --help` shows its flags. The full reference, including the exit-code table, is in [`docs/USAGE.md`](./docs/USAGE.md); renderer and environment issues are in [`docs/TROUBLESHOOTING.md`](./docs/TROUBLESHOOTING.md). ## Agent skills diff --git a/docs/USAGE.md b/docs/USAGE.md index 4cdaa82..c73ae00 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -104,6 +104,8 @@ Useful flags: - `--exit`: wait for the process to exit. - `--timeout `: maximum wait time in milliseconds, with `0` meaning infinite. +On timeout, a standalone `wait` still exits `0` and reports `matched: false` / `timedOut: true` in the JSON result — check the envelope, not the exit code. Inside `batch`, a timed-out `wait` step is a step failure (`WAIT_TIMEOUT`, exit code `11` under fail-fast). + ### Screen Hash `snapshot` results (both `--format structured` and `--format text`) and a **matched** `wait` result carry an optional `screenHash`: a lowercase 64-character hex SHA-256 of the visible screen text. Compare it across two calls to tell whether the visible screen actually changed — equal hashes mean identical visible content, even if the event-log sequence advanced on a no-op repaint. @@ -229,6 +231,27 @@ agent-tty create --env PROMPT_EOL_MARK='%B%S%#%s%b' -- /bin/zsh A lone `'%'` does **not** restore the marker (zsh treats it as a prompt escape that expands to nothing); use `'%B%S%#%s%b'` for the styled default or `'%%'` for a plain percent. The default is applied at spawn time and is not stored in the manifest, so it does not appear in `inspect`, `list`, or `create --json` output. If your `~/.zshrc` assigns `PROMPT_EOL_MARK` it runs after the environment is imported and wins, so the marker can reappear — remove that line or set the value you want via `--env`. +## Exit Codes + +Every command exits with a stable code, so scripts can branch without parsing output. The `--json` error envelope carries the precise `error.code` (for example `WAIT_TIMEOUT`); the exit code is a coarser, stable summary of it. + +| Exit code | Meaning | +| --------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `0` | Success. | +| `1` | Internal or unclassified error. | +| `2` | Usage error: unknown command or flag, or an invalid argument (session ID, dimensions, keys, duration, signal, input). | +| `3` | Session not found. | +| `4` | Session is not running or already destroyed. | +| `5` | Session host timed out. | +| `6` | Session host unreachable. | +| `7` | Export failed. | +| `8` | Storage read/write or manifest validation error. | +| `9` | Protocol or RPC error. | +| `10` | Replay failed. | +| `11` | A `wait` step inside a fail-fast `batch` timed out (standalone `wait` exits `0` with `timedOut: true` in the result — see [`wait`](#wait)). | + +A fail-fast `batch` exits with the failed step's code (for example `11` for a wait timeout); `--keep-going` exits `1` if any step failed. + ## Anti-Patterns - Do not reach for `tmux`, `screen`, or ad hoc PTY wrappers first when `agent-tty` can provide an isolated, inspectable session. diff --git a/src/cli/exitCodes.ts b/src/cli/exitCodes.ts index eb0e742..de68c7f 100644 --- a/src/cli/exitCodes.ts +++ b/src/cli/exitCodes.ts @@ -1,5 +1,6 @@ import { ERROR_CODES } from '../protocol/errors.js'; +// Public contract: documented in docs/USAGE.md ("Exit Codes"). Keep in sync. const EXIT_CODE_BY_ERROR_CODE: Readonly> = Object.freeze( { [ERROR_CODES.INVALID_SESSION_ID]: 2,