# Agent CLI

> Control Zuse chats and sessions from scripts with structured JSON output.

Canonical URL: https://docs.zuse.sh/serve/agent-cli



The agent CLI controls Zuse from a terminal or automation process. It can discover computers, projects, and models; create and inspect chats and sessions; send messages; change modes; interrupt or resume work; and attach files, images, or issue context.

Install the published executable globally for the examples below:

<Command>
  npm install --global @zusehq/serve
</Command>

Run `npx @zusehq/serve` instead of `zuse` if you prefer an installless invocation.

## Discover the surface [#discover-the-surface]

Start with read-only discovery:

```bash
zuse commands
zuse computer list
zuse project list
zuse model list
```

`zuse commands` returns the supported command manifest. List projects and models before creating work so automation uses IDs and choices returned by the connected server.

## Cloud computers and previews [#cloud-computers-and-previews]

Cloud runtimes include `zuse` and discover their local credentials automatically.
You do not need to log in or pass a token from an agent running inside a workspace.

```bash
zuse workspace projects
zuse workspace providers
zuse workspace list
zuse workspace create --project <cloud-project-id> --sandbox-provider <id> \
  --provider <agent-id> --model <model-id> --prompt-file ./task.md \
  --idempotency-key <unique-operation-id>
zuse workspace status <workspace-id>
zuse session list --cloud-workspace <workspace-id>
zuse session create --cloud-workspace <workspace-id> --chat <chat-id> \
  --provider <agent-id> --prompt "Review the current changes."
```

`workspace create` provisions a separate cloud computer. `chat create` creates a
chat/worktree on the selected computer; `session create` adds a conversation tab.
Cloud project IDs come from `workspace projects`; local project IDs come from
`project list`. `--sandbox-provider` chooses compute; `--provider` chooses the agent.
When there is exactly one cloud project or compute provider, it is inferred.
The base branch defaults to the cloud project's default branch. Creation returns
workspace, chat, and initial session IDs; poll `workspace status` until ready
before controlling its sessions.

Use `workspace rename <workspace-id> --title <name>` to rename its sidebar chat.
Lifecycle commands are `workspace pause|resume|restart|archive|unarchive|delete`.
Pass a workspace ID or use the current cloud workspace. Deletion requires
`--confirm`. Reuse `--idempotency-key` when retrying creation or lifecycle actions.

Start a website or static-file HTTP server, then expose its port:

```bash
zuse preview list
zuse preview set --port 8123
zuse preview delete --port 8123
```

`preview set` returns the provider's HTTPS URL. Anyone holding the URL can access
that port. It does not start the HTTP server. Pass `--cloud-workspace <id>` to
select another computer. `preview delete --all` removes all preview routes;
failed or unsupported revocation returns an error. Pausing a computer does not
revoke its URLs. `preview list` lists listening servers, not published URLs.

The CLI retains structured JSON output. `zuse help` and command `--help` work
without a running server. Cross-workspace delegation uses the current runtime's
rotating credential and is limited to orchestration operations in its personal
account. Organization runtimes reject account-level delegation rather than
impersonating a member; their local chat/session commands still work.

## JSON contract [#json-contract]

Every agent command writes exactly one JSON object to standard output. Success uses:

```json
{"schemaVersion":1,"ok":true,"data":{}}
```

A failure writes a structured error and exits non-zero:

```json
{"schemaVersion":1,"ok":false,"error":{"code":"project_required","message":"--project is required when the project cannot be inferred uniquely.","details":{"candidates":[]}}}
```

Exit code `2` means invalid input, `3` means authentication or connection authorization failed, and other failures exit `1`. Automation must check both the process exit code and the `ok` field. Receiving parseable JSON does not mean a mutation succeeded.

## Chats and sessions [#chats-and-sessions]

A chat is a sidebar item tied to a project and workspace. A session is one provider conversation tab inside a chat.

```bash
zuse chat list --project <project-id>
zuse chat get --project <project-id> --chat <chat-id>
zuse session list --project <project-id> --chat <chat-id>
zuse session get --project <project-id> --session <session-id>
zuse session read --project <project-id> --session <session-id> --limit 20
```

Create an isolated workspace and start its first session:

```bash
zuse chat create \
  --project <project-id> \
  --workspace fresh \
  --title "Implement parser" \
  --provider codex \
  --model <model-id> \
  --prompt "Implement the parser and run focused tests." \
  --idempotency-key <unique-operation-id>
```

Use `--workspace main` for the main checkout or pass an existing worktree ID. Create another provider conversation in the same chat with:

```bash
zuse session create \
  --project <project-id> \
  --chat <chat-id> \
  --provider codex \
  --model <model-id> \
  --prompt "Review the current diff without editing files." \
  --idempotency-key <unique-session-id>
```

`thread create` aliases `chat create`. Other `thread` actions alias the corresponding session action. Prefer the explicit `chat` and `session` names in new automation because they preserve the application topology.

## Change models and providers [#change-models-and-providers]

Changing a model does not change the provider:

```bash
zuse session model --project <project-id> --session <session-id> --model <model-id>
```

Provider switching is a distinct operation and requires a model from the new provider:

```bash
zuse session provider --project <project-id> --session <session-id> --provider claude --model <model-id>
```

Provider switching is accepted only before the session has its first user message. A mid-conversation provider change would discard provider-native context, so create a fork with the new provider when you need to hand an active conversation to another provider.

## Fork from any message [#fork-from-any-message]

Use a message ID returned by `session read`. Fork into another tab in the source chat:

```bash
zuse session fork \
  --project <project-id> \
  --session <source-session-id> \
  --message <message-id> \
  --destination tab \
  --title "Alternative approach"
```

Or create another chat and fresh isolated workspace, optionally selecting a different provider and model:

```bash
zuse session fork \
  --project <project-id> \
  --session <source-session-id> \
  --message <message-id> \
  --destination chat \
  --provider codex \
  --model <model-id>
```

New-chat forks create a fresh worktree by default, matching the graphical chat. Use `--workspace main` for the main checkout or `--workspace <worktree-id>` for an existing worktree. If fork creation fails after allocating a fresh worktree, the CLI attempts to remove that unused worktree. If the fork is at the source transcript's tail and the provider supports native continuation, the result reports `forkMode: "resume"`. Other forks report `forkMode: "copy"` and import the visible transcript through the selected message. The source may be any session in the selected project; it does not need to be the currently active chat.

## Send, interrupt, and resume [#send-interrupt-and-resume]

```bash
zuse session send --project <project-id> --session <session-id> --message "Run the failing test again."
zuse session interrupt --project <project-id> --session <session-id>
zuse session resume --project <project-id> --session <session-id>
```

Sending can also change the permission or runtime mode before delivering the message. Use `session mode` when no message is needed:

```bash
zuse session mode \
  --project <project-id> \
  --session <session-id> \
  --permission plan \
  --runtime approval-required
```

Permission values are `default`, `plan`, and `accept-edits`. Runtime values are `approval-required`, `auto` (native automatic review), and `full-access`. Legacy values `auto-accept-edits` and `auto-accept-edits-and-bash` remain accepted for compatibility. A mode change does not grant authority for unrelated external or destructive actions.

## Attach context [#attach-context]

Creation and send commands accept repeatable context options:

```bash
zuse session send \
  --project <project-id> \
  --session <session-id> \
  --message "Use these references." \
  --attach ./screenshots/error.png \
  --file src/parser.ts \
  --file test/parser.test.ts
```

`--attach` uploads supported image files. `--file` accepts a project-relative file or directory and rejects paths outside the selected project.

### Transcript and plan handoffs [#transcript-and-plan-handoffs]

Retrieve transcript Markdown, optionally ending at a specific message:

```bash
zuse session transcript --project <project-id> --session <source-session-id>
zuse session transcript --project <project-id> --session <source-session-id> --through-message <message-id>
```

Retrieve the most recent proposed plan:

```bash
zuse session plan --project <project-id> --session <planning-session-id>
```

To hand either artifact to another agent, attach it directly to any chat-create, session-create, session-send, or queue-add/update command:

```bash
zuse session send \
  --project <project-id> \
  --session <target-session-id> \
  --message "Continue from these handoff materials." \
  --transcript <source-session-id> \
  --plan <planning-session-id>
```

Zuse exports each artifact to a Markdown file under the target workspace's gitignored `.context/files/` directory and sends it through the normal file-reference pipeline. Repeat `--transcript` or `--plan` to combine handoffs. `--through-message` applies to exported transcript attachments.

## Plans and interactive questions [#plans-and-interactive-questions]

Respond to a pending plan-review tool call:

```bash
zuse session plan-respond \
  --project <project-id> \
  --session <session-id> \
  --tool-call <tool-call-id> \
  --outcome approved
```

Outcomes are `approved`, `cancelled`, and `abandoned`. Add `--feedback <text>` when the outcome needs explanation.

Answer a pending agent question using the question and option indexes returned by the session event:

```bash
zuse session answer \
  --project <project-id> \
  --session <session-id> \
  --item <item-id> \
  --answers-json '[{"questionIndex":0,"selected":[1]}]'
```

Each answer may include `other` text. The command resolves the same pending interaction shown by the graphical chat.

## Durable message queue [#durable-message-queue]

Use the session queue while an agent is running or when follow-up order matters:

```bash
zuse session queue-list --project <project-id> --session <session-id>
zuse session queue-add --project <project-id> --session <session-id> --message "Run integration tests."
zuse session queue-update --project <project-id> --session <session-id> --queue <queue-id> --message "Run focused integration tests."
zuse session queue-delete --project <project-id> --session <session-id> --queue <queue-id>
zuse session queue-reorder --project <project-id> --session <session-id> --queue <first-id> --queue <second-id>
zuse session queue-run-next --project <project-id> --session <session-id> --queue <queue-id>
zuse session queue-flush --project <project-id> --session <session-id>
zuse session queue-resume --project <project-id> --session <session-id>
```

Queue add and update accept the same `--attach`, `--file`, `--transcript`, and `--plan` context options as a direct send. Use `--draft` to add an item that is not ready and `--no-flush` to prevent immediate idle auto-flush.

## Rename, archive, and delete [#rename-archive-and-delete]

Chat and session lifecycle actions mirror their graphical equivalents:

```bash
zuse chat rename --project <project-id> --chat <chat-id> --title "New title"
zuse chat archive --project <project-id> --chat <chat-id>
zuse chat unarchive --project <project-id> --chat <chat-id>
zuse session rename --project <project-id> --session <session-id> --title "Review"
zuse session archive --project <project-id> --session <session-id>
zuse session unarchive --project <project-id> --session <session-id>
```

Move an unstarted chat to the main checkout or another existing worktree with `chat workspace --workspace main|<worktree-id>`. Started chats remain locked to their workspace.

Deletion is irreversible through the CLI and therefore requires explicit confirmation:

```bash
zuse chat delete --project <project-id> --chat <chat-id> --confirm
zuse session delete --project <project-id> --session <session-id> --confirm
```

## JSON input and stdin [#json-input-and-stdin]

Pass a complete option object directly or from a file:

```bash
zuse session send --input-json '{"project":"<project-id>","session":"<session-id>","message":"Continue with the approved plan."}'
zuse chat create --input-json @request.json
```

Array values become repeated options, which is useful for `file` and `attach`. Read a long prompt from stdin with `--prompt-file -`:

```bash
printf '%s' "$(<prompt.md)" | zuse chat create --project <project-id> --prompt-file - --idempotency-key <unique-operation-id>
```

Use an idempotency key for creation commands whenever a transport failure might cause a retry. Keep it stable for the same intended creation and generate a new key for genuinely new work.

## Select a project and computer [#select-a-project-and-computer]

`--project` accepts a project ID, exact name, or path. Zuse infers it only when the current directory belongs to exactly one registered project; otherwise the error response includes candidates.

The CLI targets the local Zuse RPC server by default. The installed desktop publishes its selected port and a dedicated credential to an owner-readable `cli-access.json` file in the Zuse user-data directory, which the CLI discovers automatically. When run from a repository using `bun dev`, the development desktop instead publishes an owner-readable, gitignored `.zuse/dev-instances/<instance>/cli-access.json` descriptor. Branch-local discovery supports concurrent development instances whose ports shifted away from `8788`. The CLI never prints either credential.

Explicit `--ws-url`/`--token` options and `ZUSE_WS_URL`/`ZUSE_TOKEN` override development discovery. Outside a development checkout, the conventional installed-desktop endpoint remains the fallback.

To target another connected computer, first list computers, then provide its connection endpoint:

```bash
zuse computer list
zuse session list \
  --computer <computer-id> \
  --ws-url <wss-url> \
  --token <access-token> \
  --project <project-id>
```

`ZUSE_WS_URL`, `ZUSE_TOKEN`, `ZUSE_PORT`, `ZUSE_USER_DATA`, `ZUSE_CLI_ACCESS_FILE`, `ZUSE_USER_DATA_DIR`, `ZUSE_DEV_INSTANCE`, and `ZUSE_DEV_CLI_ACCESS_FILE` are available for controlled automation environments. Do not print tokens, embed them in prompts, or commit them to the repository. Prefer environment-based secret injection where shell-history exposure matters.

## Reliable automation sequence [#reliable-automation-sequence]

1. Run `computer list`, `project list`, and `model list`.
2. Resolve returned IDs instead of relying on display text.
3. Create the chat or session with a stable idempotency key.
4. Require exit code `0` and `ok: true` before storing returned IDs.
5. Fetch the created chat or session to verify its persisted state when the workflow is consequential.
6. Use `session read` for progress and `session send` for follow-up instructions.

For deciding when work needs an isolated workspace rather than a shared session tab, continue with [Agent orchestration](/composer/orchestration.md).

## Connected plugins [#connected-plugins]

Inside a Zuse agent session, the CLI automatically uses that session's connected plugins and permissions:

```sh
zuse plugins list
zuse plugins search --query "linear issue"
zuse plugins schema --address <returned-address>
zuse plugins call --address <returned-address> --arguments-json '{"id":"TEAM-123"}'
```

Search directly by service and task; listing plugins first is optional. Use the returned schema to construct the call arguments (the example above is illustrative). Calls follow session approval and plan-mode rules. Connect or reauthenticate services in **Settings → Integrations**. An ordinary terminal outside an agent session has no plugin session credential; use the agent's plugin tools there instead.
