docs: added documentation for the new headless mode and acp-server

2026-07-27 20:02:13 -06:00
parent 542789ce1d
commit 7a1b77892a
3 changed files with 188 additions and 1 deletions
+1 -1
@@ -120,5 +120,5 @@ can also pass the `--disable-log-colors` flag as well.
# Miscellaneous Variables # Miscellaneous Variables
| Environment Variable | Description | Default Value | | Environment Variable | Description | Default Value |
|----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| |----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
| `AUTO_CONFIRM` | Bypass all `guard_*` checks in the bash prompt helpers; useful for agent composition and routing. Can also be enabled for a single invocation by passing `--dangerously-skip-permissions` (Coyote sets `AUTO_CONFIRM=true` for the process and all spawned tools/agents). | | | `AUTO_CONFIRM` | Bypass all `guard_*` checks in the bash prompt helpers; useful for agent composition and routing. Set automatically when passing `--dangerously-skip-permissions`, `--headless`, or `--acp-server` (Coyote sets `AUTO_CONFIRM=true` for the process and all spawned tools/agents). See [Unattended Mode](Unattended-Mode). | |
| `LLM_TOOL_DATA_FILE` | Set automatically by Coyote on Windows. Points to a temporary file containing the JSON tool call data. <br>Tool scripts (`run-tool.sh`, `run-agent.sh`, etc.) read from this file instead of command-line args <br>to avoid JSON escaping issues when data passes through `cmd.exe` → bash. **Not intended to be set by users.** | | | `LLM_TOOL_DATA_FILE` | Set automatically by Coyote on Windows. Points to a temporary file containing the JSON tool call data. <br>Tool scripts (`run-tool.sh`, `run-agent.sh`, etc.) read from this file instead of command-line args <br>to avoid JSON escaping issues when data passes through `cmd.exe` → bash. **Not intended to be set by users.** | |
+184
@@ -0,0 +1,184 @@
Coyote supports two unattended operation modes for scripting and programmatic use:
- **`--headless`** suppresses all interactive prompts and runs as a non-interactive CLI process.
- **`--acp-server`** exposes a full agent server over stdio using JSON-RPC 2.0, suitable for host-side orchestration.
It implies `--headless`.
---
# `--headless`
The `--headless` flag runs Coyote in fully unattended mode. It is designed for use in scripts, CI pipelines, and
sandboxed environments where no user is present to respond to prompts.
When `--headless` is active:
- All interactive prompts (confirmations, selections, free-text inputs) return structured JSON instead of blocking.
- `AUTO_CONFIRM=true` is set for the process and all spawned tools.
- REPL mode is not supported; a prompt must be provided via `-f <file>` or as an inline argument.
```shell
coyote --headless -f prompt.txt
coyote --headless "Summarize this project for me"
```
User-interaction tool calls (e.g. `user__confirm`, `user__select`) return a structured JSON object instead of prompting.
The response shape matches the tool's normal output, so agents handle it transparently.
---
# ACP Agent Server (`--acp-server`)
`--acp-server` starts Coyote as an ACP agent server over stdio. It is designed for host applications that need to drive
Coyote programmatically — the host sends JSON-RPC requests over stdin and reads JSON-RPC responses from stdout.
Every byte on stdout is a valid JSON-RPC 2.0 frame. Diagnostic logs go to stderr (or to the log file if `COYOTE_LOG_FILE`
is configured). The flag implies `--headless`.
```shell
coyote --acp-server
```
All normal context flags work alongside `--acp-server` and are applied before the server starts listening:
```shell
coyote --acp-server --role diagnose
coyote --acp-server --agent sisyphus
coyote --acp-server --rag my-index --no-memory
coyote --acp-server --model gpt-4o
```
The server then inherits the fully-configured context — the client manages sessions via `session/new` / `session/load`
as normal.
## Protocol
Each request and response is a single JSON object on one line, terminated by `\n`. Send requests line-by-line; the
server processes them sequentially and writes a response (or nothing, for notifications) before reading the next line.
**Request:**
```json
{"jsonrpc": "2.0", "id": 1, "method": "method/name", "params": {...}}
```
**Success response:**
```json
{"jsonrpc": "2.0", "id": 1, "result": {...}}
```
**Error response:**
```json
{"jsonrpc": "2.0", "id": 1, "error": {"code": -32601, "message": "Method not found: ..."}}
```
## Methods
| Method | Params | Result | Notes |
|------------------|-------------------------|---------------------------------------------|-------------------------------------------------------------------------------------|
| `initialize` | none | `{name, version, protocolVersion}` | Returns server identity. Call this first. |
| `session/new` | none | `{sessionId: "default"}` | Starts a new temporary session. Only one session per process. |
| `session/load` | `{sessionId: "<name>"}` | `{sessionId: "<name>"}` | Loads a previously saved session by name (as shown in `coyote --list-sessions`). |
| `session/prompt` | `{text: "<prompt>"}` | `{output, stopReason}` | Runs one conversation turn. Requires an active session. |
| `session/cancel` | none (notification) | `{}` if an `id` was given, else no response | Sets the abort flag for the next call. See [Known Limitations](#known-limitations). |
## Outbound Notifications
The server may emit notifications (messages without an `id`) between a request and its response.
| Notification | Params | When |
|------------------------------|-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
| `session/request_permission` | `{action, question, options}` | Emitted when a tool triggers a user-interaction call (e.g. `user__confirm`, `user__select`). Sent before the turn's final response. |
## Error Codes
| Code | Meaning |
|----------|--------------------------------------------------------------------|
| `-32700` | Parse error — request line was not valid JSON |
| `-32601` | Method not found |
| `-32602` | Invalid params — a required field is missing |
| `-32600` | Invalid request — e.g. `session/prompt` before `session/new` |
| `-32000` | Application error — e.g. no active session, session already active |
## Smoke Testing
Build the binary first (`cargo build`), then use a heredoc to send multiple requests:
**Structural test (no LLM required):**
```shell
./target/debug/coyote --acp-server << 'EOF'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}
{"jsonrpc":"2.0","id":2,"method":"unknown/method","params":{}}
EOF
```
Expected: initialize succeeds, then `-32601` method-not-found.
**Parse error recovery:**
```shell
./target/debug/coyote --acp-server << 'EOF'
not valid json
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}
EOF
```
Expected: `-32700` for the bad line, then a valid initialize response. The server continues processing after a parse
error.
**Full session (requires a configured model):**
```shell
coyote --acp-server << 'EOF'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}
{"jsonrpc":"2.0","id":2,"method":"session/new","params":{}}
{"jsonrpc":"2.0","id":3,"method":"session/prompt","params":{"text":"Reply with the single word: pong"}}
EOF
```
**Multi-turn context:**
```shell
coyote --acp-server << 'EOF'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}
{"jsonrpc":"2.0","id":2,"method":"session/new","params":{}}
{"jsonrpc":"2.0","id":3,"method":"session/prompt","params":{"text":"Count to 3 and stop."}}
{"jsonrpc":"2.0","id":4,"method":"session/prompt","params":{"text":"What was the last number you said?"}}
EOF
```
id=4 should answer "3", confirming session history threads across turns.
**Load a saved session:**
```shell
coyote --acp-server << 'EOF'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}
{"jsonrpc":"2.0","id":2,"method":"session/load","params":{"sessionId":"my-saved-session"}}
{"jsonrpc":"2.0","id":3,"method":"session/prompt","params":{"text":"Summarize what we've discussed."}}
EOF
```
## Known Limitations
**`session/cancel` cannot interrupt a running `session/prompt`.** The server processes requests sequentially. While a
`session/prompt` turn is executing, the server is not reading stdin. `session/cancel` sets an abort flag that takes
effect on the *next* invocation.
**`session/request_permission` notifications are post-turn.** They are emitted immediately before the turn's final
response, not mid-stream. A real-time permission bridge would require a concurrent server design.
---
# Sbx-Kit Headless Profile
The embedded sbx kit ships a `headless` profile for running Coyote in unattended mode inside a sandbox. Set
`COYOTE_PROMPT_FILE` to the path of a prompt file before launching:
```shell
export COYOTE_PROMPT_FILE=/path/to/prompt.txt
sbx run coyote --profile headless
```
The headless profile passes `--headless -f "${COYOTE_PROMPT_FILE}"` to Coyote and sets `COYOTE_LOG_LEVEL=WARN` to
reduce noise on stderr. For ACP use inside a sandbox, override the entrypoint directly via `sbx run --entrypoint`.
+3
@@ -11,6 +11,9 @@
- [Shell Integrations](Shell-Integrations) - [Shell Integrations](Shell-Integrations)
- [Bash Prompt Helpers](Bash-Prompt-Helpers) - [Bash Prompt Helpers](Bash-Prompt-Helpers)
- [Sessions](Sessions) - [Sessions](Sessions)
- [Unattended Mode](Unattended-Mode)
- [--headless](Unattended-Mode#--headless)
- [ACP Agent Server](Unattended-Mode#acp-agent-server---acp-server)
## Model Providers ## Model Providers
- [Clients](Clients) - [Clients](Clients)