Skip to content

feat: add agent-device acp, a deterministic stdio ACP agent#1132

Open
XeonBloomfield wants to merge 5 commits into
callstack:mainfrom
XeonBloomfield:feat/acp-agent
Open

feat: add agent-device acp, a deterministic stdio ACP agent#1132
XeonBloomfield wants to merge 5 commits into
callstack:mainfrom
XeonBloomfield:feat/acp-agent

Conversation

@XeonBloomfield

Copy link
Copy Markdown

Summary

Adds agent-device acp: an Agent Client Protocol v1 agent over stdio, so ACP clients such as Zed can drive devices from their agent panel. Before: ACP editors could only reach agent-device indirectly, through whatever LLM agent they run and its MCP config. After: agent-device acp is a first-class agent surface — each prompt line is one agent-device command in CLI syntax, executed through the same AgentDeviceClient path as MCP tools, streamed back as ACP tool calls with daemon progress updates and inline screenshot images.

Design choices:

  • Deterministic agent, no LLM: natural-language prompts are refused with guidance; the reasoning stays in the ACP client's own model. Keeps the zero-runtime-dependency policy — the protocol layer is hand-rolled in src/acp/, reusing the MCP server's newline-delimited JSON-RPC transport, payload queue, and error formatting (the shared pieces are now exported from src/mcp/ instead of duplicated).
  • Prompt lines are tokenized with the replay-script tokenizer and parsed by the real CLI parser, so ACP prompts, replay scripts, and the CLI share one dialect. Target flags (--platform, --device, --udid, --session, --state-dir) are sticky within an ACP session.
  • session/cancel is intercepted ahead of the serialized inbound queue so it takes effect between command lines of a running prompt. The command already in flight runs to completion — there is no abort seam in the daemon client; documented as a v1 limitation.
  • session/new advertises all MCP-exposed commands via available_commands_update (response-before-notification ordering is pinned by test).

Docs: new ACP section in agent-setup.md with the Zed agent_servers config, README pointer, CHANGELOG entry, CONTEXT.md command-surface vocabulary update.

23 files touched (13 new: src/acp/ + tests). Scope stayed within the planned command-surface addition; the only changes outside it are exports of previously-private MCP transport/formatting helpers and the replay tokenizer.

Validation

Full unit bundle green (3296 tests / 366 files, including 27 new ACP tests covering the router contract, prompt parsing, sticky flags, cancellation, refusal, screenshot image attachment, and out-of-band cancel interception). check:quick, check:layering, fallow audit (0 dead code / 0 duplication after deduplicating against src/mcp/), and test:smoke all pass — including a new smoke-acp.test.ts that spawns the real stdio process and drives initialize → session/new → prompt refusal → clean shutdown. Live device evidence: through the packaged build (dist/src/internal/bin.js acp), an ACP session ran devices against a real daemon with an isolated state dir and streamed back actual inventory (iPhone 17 Pro simulator + host macOS target) as a completed tool_call_update; the daemon and state dir were cleaned up afterwards. Zed itself was not exercised — the wire contract was verified against the official ACP v1 JSON schema; a follow-up interactive Zed session is the remaining real-client check.

🤖 Generated with Claude Code

@thymikee

thymikee commented Jul 6, 2026

Copy link
Copy Markdown
Member

Review finding: available_commands_update advertises agent-device commands as ACP available commands, but the prompt parser only accepts bare CLI lines. ACP slash-command usage sends the command as prompt text with a leading slash (for example /devices or /snapshot -i); on this branch those resolve as unknown commands because parsePromptCommandLine only strips optional agent-device before calling the CLI parser. Please either accept a leading / command prefix and add tests for /devices / /snapshot -i, or stop advertising available_commands_update until slash-form invocation is supported.

Comment thread website/docs/docs/agent-setup.md Outdated
```
open com.example.app --platform ios
snapshot -i
/snapshot -i

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this line within the guide can be reverted as the previous behavior still works!

@thymikee

thymikee commented Jul 6, 2026

Copy link
Copy Markdown
Member

Ready for human review.

I rechecked #1132 at head 5b802f60 after the ACP follow-up commits. The prior blocker is addressed: advertised ACP commands now accept slash-form prompt lines (/devices, /snapshot -i) and tests cover that path in src/acp/__tests__/prompt-lines.test.ts. session/new now rejects relative cwd and malformed/missing mcpServers, with router coverage for invalid params. The docs were updated to explain ACP as a first-class deterministic interface while keeping examples CLI-shaped.

Checks: 15 successful; only expected skipped Bundle Size and deploy-preview jobs. Remaining residual risk is real-client Zed validation, but the stdio/protocol behavior now matches the ACP usage shape reviewed earlier.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Jul 6, 2026
XeonBloomfield and others added 5 commits July 6, 2026 19:38
Add an Agent Client Protocol (ACP) v1 agent mode so ACP clients such as
Zed can drive devices from the agent panel. agent-device has no LLM, so
the agent is deterministic: each prompt line is one agent-device command
in CLI syntax, executed through the same AgentDeviceClient path as MCP
tools.

- Hand-rolled protocol layer in src/acp/ mirroring src/mcp/ (zero new
  runtime dependencies), reusing the MCP newline-delimited JSON-RPC
  stdio transport, payload queue, and error formatting.
- Prompt lines are tokenized with the replay-script tokenizer and parsed
  with the real CLI parser; target flags (--platform, --device, --udid,
  --session, --state-dir) are sticky within an ACP session.
- Command executions stream as tool_call/tool_call_update notifications
  with daemon progress forwarding; screenshots attach as inline images;
  errors keep the code/hint/supportedOn contract.
- session/cancel is intercepted ahead of the serialized queue so it
  takes effect between command lines of a running prompt; the command
  already in flight runs to completion (documented v1 limitation).
- Natural-language prompts are refused with guidance instead of guessed
  at; available commands are advertised per session after session/new.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants