Skip to content

Unattended Mode

Alex Clarke edited this page Jul 28, 2026 · 1 revision

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.
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.

coyote --acp-server

All normal context flags work alongside --acp-server and are applied before the server starts listening:

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:

{"jsonrpc": "2.0", "id": 1, "method": "method/name", "params": {...}}

Success response:

{"jsonrpc": "2.0", "id": 1, "result": {...}}

Error response:

{"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.

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):

./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:

./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):

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:

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:

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:

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.

Clone this wiki locally