Skip to content

Latest commit

 

History

History
133 lines (98 loc) · 4.2 KB

File metadata and controls

133 lines (98 loc) · 4.2 KB

AGENTS.md — acp-cli Development Brief

Read this before writing any code.


Project Overview

acp-cli is a headless CLI client for the Agent Client Protocol (ACP). It spawns coding agents (Claude, Codex, Gemini, etc.) as child processes and communicates over structured JSON-RPC via stdio pipes.


Repository Structure

acp-cli/
├── Cargo.toml
├── src/
│   ├── main.rs            # CLI entry point
│   ├── lib.rs             # Library re-exports
│   ├── config.rs          # Config loading + merging
│   ├── error.rs           # Error types (thiserror)
│   ├── agent/registry.rs  # Agent name → command mapping
│   ├── bridge/            # AcpBridge (spawn_blocking + LocalSet)
│   ├── cli/               # Commands: init, prompt, exec, sessions
│   ├── client/            # BridgedAcpClient + permission resolution
│   ├── output/            # Renderers: text, json, quiet
│   ├── queue/             # Queue owner/client, IPC, lease
│   └── session/           # Session scoping, persistence, history
├── skills/acp-cli/        # AI skill card
├── README.md
├── llms.txt               # LLM-consumable API reference
├── CLAUDE.md              # Claude Code project instructions
├── CHANGELOG.md
└── LICENSE

Key Design Decisions

  • !Send bridge pattern — ACP SDK uses Rc/spawn_local; bridge runs in spawn_blocking + LocalSet, communicates via mpsc channels
  • Queue system — first process becomes queue owner (holds agent connection), subsequent processes connect as clients via Unix socket
  • Session scoping — key is SHA-256(agent + "\0" + git_root + "\0" + name), ensuring isolation per project/agent/name
  • Auth token chain — env var → config file → ~/.claude.json → macOS Keychain (never guess, always explicit)
  • Permission modes — three modes (approve-all, approve-reads, deny-all) applied at BridgedAcpClient level
  • Agent registry — hardcoded defaults + config overrides + raw command fallback

Coding Standards

  • cargo fmt before every commit
  • cargo clippy -- -D warnings — zero warnings policy
  • Errors: use thiserror via AcpCliError; never unwrap() in library code
  • Async: tokio runtime; async-trait for trait objects
  • Serialization: serde with #[serde(default)] for backward-compatible config fields
  • Tests: #[tokio::test] for async tests

Common Commands

# Development
cargo fmt
cargo clippy -- -D warnings
cargo check

# Testing (macOS needs libiconv)
LIBRARY_PATH="/opt/homebrew/opt/libiconv/lib" cargo test

# Run locally
LIBRARY_PATH="/opt/homebrew/opt/libiconv/lib" cargo run -- claude "hello"

Adding a New Agent

  1. Add entry to default_registry() in src/agent/registry.rs
  2. Update agent table in README.md and llms.txt
  3. No code changes needed — registry maps name → command + args

Adding a New CLI Command

  1. Add variant to Commands enum in src/cli/mod.rs
  2. Add match arm in src/main.rs run() function
  3. Implement in src/cli/<command>.rs
  4. Update Commands section in README.md, llms.txt

What NOT to Do

  • Do not use unwrap() or expect() in library code (only in main.rs after error handling)
  • Do not add agent-specific logic outside agent/registry.rs and bridge/mod.rs
  • Do not store secrets in config without the user's explicit consent (init asks)
  • Do not break the AcpBridge public API — it's used as a library by motosan-workflow-core
  • Do not use git add -A — always add specific files

Before Committing

cargo fmt
cargo clippy -- -D warnings
LIBRARY_PATH="/opt/homebrew/opt/libiconv/lib" cargo check

Releasing

# 1. Update CHANGELOG.md (move Unreleased → version)
# 2. Bump version in Cargo.toml
# 3. Update version in: llms.txt, AGENTS.md
# 4. Commit + tag + push
git commit -m "chore: release v0.2.0"
git tag -a v0.2.0 -m "v0.2.0 — summary"
git push origin main v0.2.0

Tag push triggers publish.yml → crates.io.