Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 58 additions & 26 deletions PROTOCOL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Agent Chorus Protocol v0.14.0
# Agent Chorus Protocol v0.16.0

## Purpose
Define a lightweight, local-first standard for reading and coordinating cross-agent session evidence across Codex, Gemini, Claude, Cursor, and Hermes.
Define a lightweight, local-first standard for reading and coordinating cross-agent session evidence across Codex, Gemini, Claude, Cursor (both cursor-agent CLI transcripts and Cursor IDE chat store), and Hermes.

## Tenets
1. Local-first: read local session logs only by default.
Expand All @@ -20,22 +20,28 @@ Define a lightweight, local-first standard for reading and coordinating cross-ag
### Dual-implementation commands (Node + Rust parity required)

```bash
chorus read --agent <codex|gemini|claude|cursor|hermes> [--id=<substring>] [--cwd=<path>] [--chats-dir=<path>] [--last=<N>] [--json] [--metadata-only] [--audit-redactions]
chorus read --agent <codex|gemini|claude|cursor|hermes> [--id=<substring>] [--cwd=<path>] [--chats-dir=<path>] [--last=<N>] [--include-user] [--tool-calls] [--history=<on-demand|none|eager>] [--format=<json|markdown>] [--json] [--metadata-only] [--audit-redactions]
chorus compare --source <agent[:session-substring]>... [--cwd=<path>] [--last=<N>] [--json]
chorus report --handoff <path-to-handoff.json> [--cwd=<path>] [--json]
chorus list --agent <codex|gemini|claude|cursor|hermes> [--cwd=<path>] [--limit=<N>] [--json]
chorus search <query> --agent <codex|gemini|claude|cursor|hermes> [--cwd=<path>] [--limit=<N>] [--json]
chorus diff --agent <codex|gemini|claude|cursor|hermes> --from <id> --to <id> [--cwd=<path>] [--last=<N>] [--json]
chorus summary --agent <codex|gemini|claude|cursor|hermes> [--cwd=<path>] [--format=<json|markdown>] [--json]
chorus timeline [--agent <agent>]... [--cwd=<path>] [--limit=<N>] [--format=<json|markdown>] [--json]
chorus relevance --list | --test <path> | --suggest [--cwd=<path>] [--json]
chorus send --from <agent> --to <agent> --message <text> [--cwd=<path>]
chorus messages --agent <agent> [--cwd=<path>] [--clear] [--json]
chorus agent-context <init|seal|build|sync-main|install-hooks|rollback|check-freshness|verify> [--ci] [--base=<ref>] [--json]
chorus checkpoint --from <agent> [--cwd=<path>] [--message=<text>] [--json]
chorus agent-context <init|seal|build|sync-main|install-hooks|rollback|check-freshness|verify|diff> [--ci] [--base=<ref>] [--enforce-separate-commits] [--json]
chorus teardown [--cwd=<path>] [--dry-run] [--global] [--json]
```

### Node-only administrative commands
### Setup and doctor (dual-parity since v0.13.0)

The following commands are provided by the Node CLI only. They are not part of the dual-parity contract and are not implemented in the Rust CLI:
`setup` and `doctor` were Node-only in v0.7. As of v0.13.0 they have
full Node+Rust parity (byte-identical JSON for the same inputs) and are
part of the dual-implementation contract enforced by
`scripts/conformance.sh`:

```bash
chorus setup [--cwd=<path>] [--dry-run] [--force] [--agent-context] [--json]
Expand All @@ -59,12 +65,20 @@ Rules:
14. `messages` reads (and optionally clears with `--clear`) the message queue for an agent.
15. `teardown` removes managed blocks from provider files, deletes `.agent-chorus/` directory, removes `.agent-chorus/` from `.gitignore`, and removes hook sentinels. `--dry-run` previews without changes. `--global` also removes `~/.cache/agent-chorus/`. The Claude Code plugin is NOT removed by teardown.
16. `setup` creates `.agent-chorus/` scaffolding, injects managed blocks into CLAUDE.md/AGENTS.md/GEMINI.md, appends `.agent-chorus/` to `.gitignore`, and auto-installs the Claude Code skill plugin if the `claude` CLI is present. `--agent-context` runs `init` + `install-hooks`. Safe to re-run; idempotent unless `--force` is given.
17. `doctor` checks: version, session directory availability, setup completeness, provider instruction wiring, session discoverability, context pack state, Claude Code plugin installation, and update status.
17. `doctor` checks: version, session directory availability, setup completeness, provider instruction wiring, session discoverability (codex / claude / gemini / cursor-cli / cursor-app / hermes), context pack state, git hook state, env-override health, snippet / managed-block freshness, Claude Code plugin installation, and update status.
18. **`read --history` (v0.16.0)**: takes one of `on-demand` (default), `none`, or `eager`. `on-demand` returns only the latest session for the cwd — chorus does NOT auto-pull prior sessions; consumers call `chorus list / timeline / search` explicitly when they need historical context. `none` is equivalent to `--metadata-only`. `eager` is reserved for a future multi-session merge; it currently behaves identically to `on-demand` AND pushes a warning into `warnings[]` so consumers cannot silently rely on it. Any other value MUST exit non-zero with `Invalid --history value: <value>. Allowed: on-demand | none | eager.` on both runtimes.
19. **`read` cwd-fallback contract (v0.16.0)**: when `--cwd <PATH>` was passed but no session matched and the adapter fell back to the latest session, the JSON output MUST set `cwd_mismatch: true` AND the fallback warning string MUST be mirrored to stderr prefixed with `chorus: `. `cwd_mismatch` is only present when the fallback fires — it MUST NOT be emitted as `false`. Schema: `schemas/read-output.schema.json`.
20. **`--tool-calls` uniform NOT_AVAILABLE warning (v0.16.0)**: for agents whose transcript format does not carry tool-call structure (currently `gemini` and `hermes`), passing `--tool-calls` MUST run without error, MUST still set `included_tool_calls: true` (the flag was honored), and MUST push this exact warning into `warnings[]`: `--tool-calls has no effect for <agent> sessions: this agent's transcript format does not carry tool calls.` The phrasing is byte-identical between Node and Rust dispatch.
21. **`--history` and `cwd_mismatch` are dual-runtime contract (v0.16.0)**: both fields and their semantics are gated by `scripts/conformance.sh`. Any change to the allowed `--history` values, the eager warning string, the cwd-fallback warning string, or the `cwd_mismatch` boolean emission rule requires updating both runtimes, both schemas (where relevant), and golden fixtures in the same PR.
22. **Unknown-flag rejection (F11, v0.16.0)**: both runtimes MUST fail closed on unknown flags. Per-command allowlists live in `cli/src/main.rs` (clap) and `scripts/read_session.cjs:ALLOWED_FLAGS`. Unknown flags MUST exit non-zero with an error that names the offending flag and subcommand.
23. **Search invariant (v0.16.0)**: for every adapter, `read(text) ⊆ search(tokens-from-text)` MUST hold. If `chorus read --agent <X>` returns content for a session, `chorus search --agent <X>` with tokens from that content MUST return that session. Enforced in `scripts/conformance.sh` for claude, codex, gemini, cursor (both CLI and IDE app surfaces), and hermes.
24. **Cursor IDE app surface (v0.16.0)**: chorus reads Cursor sessions from BOTH `~/.cursor/projects/<project>/agent-transcripts/<session>/*.jsonl` (CLI surface) AND `~/.cursor/chats/<hash>/<uuid>/store.db` (SQLite, IDE app surface). `chorus list --agent cursor` and `chorus search --agent cursor` entries carry a cursor-only `source: "cli" | "app"` string field; other agents' list/search entries MUST NOT emit this field. The Node CLI requires Node >= 22.5 for the IDE app surface (via `node:sqlite`); on older Node, the IDE surface is gracefully omitted rather than failing.

## JSON Output Contract (`chorus read --json`)

```json
{
"chorus_output_version": 1,
"agent": "codex",
"source": "/absolute/path/to/session-file",
"content": "last assistant/model turn or fallback text",
Expand All @@ -73,19 +87,33 @@ Rules:
"timestamp": "2026-02-08T15:30:00Z",
"message_count": 10,
"messages_returned": 1,
"included_roles": ["assistant"],
"included_tool_calls": false,
"cwd_mismatch": true,
"warnings": [
"Warning: no Codex session matched cwd /path; falling back to latest session."
]
}
```

Schema is defined in `schemas/read-output.schema.json`.
`chorus list --json` and `chorus search --json` outputs are defined by `schemas/list-output.schema.json`.

**v0.16.0 conditional fields on `read --json`:**

| Field | Type | Emitted when |
|---|---|---|
| `included_roles` | `string[]` | `--include-user` was passed (otherwise omitted; assistant-only is the default). |
| `included_tool_calls` | `boolean` | `--tool-calls` was passed. Set to `true` even for agents whose transcript format carries no tool calls (`gemini`, `hermes`) — the flag was honored even if the data isn't structurally available; a uniform warning is added to `warnings[]` in that case. |
| `cwd_mismatch` | `boolean` (always `true` when present) | `--cwd <PATH>` was passed but no session matched and the adapter fell back to the latest session. NOT emitted as `false`; absence means "no fallback occurred". The matching warning is also mirrored to stderr prefixed with `chorus: `. |
| `redactions` | `object[]` | `--audit-redactions` was passed. Each entry is `{pattern, count}`. |

`chorus list --json` and `chorus search --json` outputs are defined by `schemas/list-output.schema.json`. Entries for `--agent cursor` carry an extra string field `source: "cli" | "app"` (cursor-only; absent for other agents) distinguishing the cursor-agent CLI transcript surface from the Cursor IDE `store.db` surface.

Errors with `--json` are defined by `schemas/error.schema.json`.
`chorus search --json` results include a `match_snippet` field showing a ~120-character context window around the first match.

`chorus report --json` outputs the coordinator report object defined by `schemas/report.schema.json`.
`chorus report --handoff` consumes packets defined by `schemas/handoff.schema.json`.
`chorus report --handoff` consumes packets defined by `schemas/handoff.schema.json`; the full handoff shape is also surfaced inline in `chorus report --help` as of v0.16.0.
`chorus messages --json` outputs an array of message objects defined by `schemas/message.schema.json`.

## Agent-to-Agent Messaging
Expand Down Expand Up @@ -117,27 +145,31 @@ Implementations must redact likely secrets from returned content before printing
- `CHORUS_CODEX_SESSIONS_DIR`
- `CHORUS_GEMINI_TMP_DIR`
- `CHORUS_CLAUDE_PROJECTS_DIR`
- `CHORUS_CURSOR_DATA_DIR` (cursor-agent projects root; default `~/.cursor/projects`)
- `CHORUS_CURSOR_DATA_DIR` (cursor-agent CLI projects root; default `~/.cursor/projects`)
- `CHORUS_CURSOR_APP_DATA_DIR` (Cursor IDE chat-store root; default `~/.cursor/chats`; v0.16.0)
- `CHORUS_HERMES_DATA_DIR` (provisional Hermes sessions root; default `~/.hermes/sessions`)
- `CHORUS_SKIP_UPDATE_CHECK`

Every `CHORUS_*` variable has a backward-compatible `BRIDGE_*` alias (e.g. `BRIDGE_CURSOR_APP_DATA_DIR`); when both are set, `CHORUS_*` wins. `chorus doctor` emits `env_override_dangling: warn` when any of these point at a non-existent directory.

## Doctor Contract
`chorus doctor --json` may include:

```json
{
"update": {
"available": true,
"current": "0.7.0",
"latest": "0.7.1",
"checked_at": "2026-02-15T..."
},
"context_pack_state": {
"valid": true,
"last_modified": "..."
}
}
```
`chorus doctor --json` returns `{ cwd, overall, checks: [...] }` where
each `check` is `{ id, status, detail }`. As of v0.16.0, `status` is one
of four values:

| Severity | Meaning | Elevates `overall`? |
|---|---|---|
| `pass` | Check passed. | no |
| `info` | Informational state — typically "this feature is intentionally not configured" (e.g. Hermes not installed; cwd is not a git repo). | **no** |
| `warn` | Soft failure — misconfigured but install still works. | yes → `overall: warn` |
| `fail` | Hard failure — install is broken or an adapter errored. | yes → `overall: fail` |

`overall` is computed as `fail` if any check is `fail`, else `warn` if any check is `warn`, else `pass`. `info` does NOT elevate `overall`.

The exit code is `0` when `overall ∈ {pass, warn}` and non-zero when `overall == fail`. Tooling that wants to catch all non-perfect states should compare `overall != "pass"`.

The check IDs (v0.16.0) include: `version`, `codex_sessions_dir`, `claude_projects_dir`, `gemini_tmp_dir`, `setup_intents`, `snippet_<agent>`, `integration_<agent>`, `sessions_codex`, `sessions_claude`, `sessions_gemini`, `sessions_cursor_cli` (replaces `sessions_cursor`), `sessions_cursor_app` (new), `sessions_hermes` (now downgrades to `info` when data dir absent), `env_override_dangling` (new), `snippet_<agent>_stale` (new — pre-v0.16.0 history-contract snippet), `integration_<agent>_stale` (new — pre-v0.16.0 history-contract managed block), `context_pack_state`, `context_pack_guidance`, `context_pack_hooks_path` (now reports `info` when cwd is not a git repo), `context_pack_pre_push` (same — `info` outside a git repo), `update_status`, and `claude_plugin`. See `docs/CLI_REFERENCE.md` for the full catalogue with per-check severity rules.

## Conformance
Any release must pass `scripts/conformance.sh`, which runs both implementations against shared fixtures and verifies equivalent JSON output for `read`, `compare`, `report`, `list`, `search`, `diff`, `relevance`, `send`, `messages`, and `teardown`.
Any release must pass `scripts/conformance.sh`, which runs both implementations against shared fixtures and verifies equivalent JSON output for `read`, `compare`, `report`, `list`, `search`, `diff`, `summary`, `timeline`, `relevance`, `send`, `messages`, `checkpoint`, `setup`, `doctor`, and `teardown`. v0.16.0 added a `search-read-parity` gate that enforces `read(text) ⊆ search(tokens-from-text)` for every adapter (claude, codex, gemini, cursor-cli, cursor-app, hermes).
Loading
Loading