agents-can-communicate 0.1.16 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -133
- package/bin/acc-hook.mjs +2 -0
- package/docs/CAPABILITIES.md +105 -85
- package/node_modules/@agents-can-communicate/adapter-claude-code/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/skills/acc/SKILL.md +80 -154
- package/node_modules/@agents-can-communicate/adapter-claude-code/src/adapter.mjs +3 -1
- package/node_modules/@agents-can-communicate/adapter-codex/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-codex/plugin/skills/acc/SKILL.md +80 -154
- package/node_modules/@agents-can-communicate/adapter-codex/src/adapter.mjs +3 -1
- package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/skills/acc/SKILL.md +80 -154
- package/node_modules/@agents-can-communicate/adapter-gemini-cli/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-gemini-cli/src/adapter.mjs +3 -1
- package/node_modules/@agents-can-communicate/adapter-grok/package.json +13 -0
- package/node_modules/@agents-can-communicate/adapter-grok/plugin/hooks/hooks.json +61 -0
- package/node_modules/@agents-can-communicate/adapter-grok/plugin/skills/acc/SKILL.md +154 -0
- package/node_modules/@agents-can-communicate/adapter-grok/src/adapter.mjs +61 -0
- package/node_modules/@agents-can-communicate/adapter-grok/src/hooks.mjs +127 -0
- package/node_modules/@agents-can-communicate/adapter-grok/src/install.mjs +101 -0
- package/node_modules/@agents-can-communicate/adapter-kimi/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-kimi/plugin/skills/acc/SKILL.md +80 -154
- package/node_modules/@agents-can-communicate/adapter-kimi/src/adapter.mjs +3 -1
- package/node_modules/@agents-can-communicate/adapter-sdk/package.json +1 -1
- package/node_modules/@agents-can-communicate/adapter-sdk/src/context-projector.mjs +125 -189
- package/node_modules/@agents-can-communicate/adapter-sdk/src/index.mjs +1 -1
- package/node_modules/@agents-can-communicate/cli/package.json +1 -1
- package/node_modules/@agents-can-communicate/cli/src/args.mjs +3 -0
- package/node_modules/@agents-can-communicate/cli/src/help.mjs +4 -2
- package/node_modules/@agents-can-communicate/cli/src/install-command.mjs +3 -1
- package/node_modules/@agents-can-communicate/cli/src/main.mjs +23 -2
- package/node_modules/@agents-can-communicate/cli/src/session-owner.mjs +1 -1
- package/node_modules/@agents-can-communicate/core/package.json +1 -1
- package/node_modules/@agents-can-communicate/core/src/inbox.mjs +134 -0
- package/node_modules/@agents-can-communicate/core/src/index.mjs +1 -0
- package/node_modules/@agents-can-communicate/core/src/message-signals.mjs +41 -0
- package/node_modules/@agents-can-communicate/core/src/ports.mjs +1 -1
- package/node_modules/@agents-can-communicate/core/src/service.mjs +3 -0
- package/node_modules/@agents-can-communicate/core/src/sessions.mjs +48 -0
- package/node_modules/@agents-can-communicate/core/src/sync.mjs +36 -0
- package/node_modules/@agents-can-communicate/hook-runner/package.json +1 -1
- package/node_modules/@agents-can-communicate/hook-runner/src/runner.mjs +77 -33
- package/node_modules/@agents-can-communicate/installer/package.json +1 -1
- package/node_modules/@agents-can-communicate/mcp-server/package.json +1 -1
- package/node_modules/@agents-can-communicate/mcp-server/src/server.mjs +29 -21
- package/node_modules/@agents-can-communicate/mcp-server/src/tools.mjs +25 -1
- package/node_modules/@agents-can-communicate/protocol/package.json +1 -1
- package/node_modules/@agents-can-communicate/storage-filesystem/package.json +1 -1
- package/node_modules/@agents-can-communicate/storage-filesystem/src/store.mjs +23 -7
- package/node_modules/@agents-can-communicate/storage-filesystem/src/writer-mutex.mjs +18 -2
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -4,171 +4,101 @@
|
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://nodejs.org)
|
|
6
6
|
|
|
7
|
-
**Give
|
|
8
|
-
|
|
7
|
+
**Give the agent sessions you already opened a shared room — and stop being the wire
|
|
8
|
+
between them.**
|
|
9
9
|
|
|
10
|
-
ACC is a local-first coordination layer for
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
ACC is a local-first coordination layer for independent AI coding sessions on one repo.
|
|
11
|
+
They see who else is here, claim the files they touch, message each other directly, and
|
|
12
|
+
hand work across — while each keeps its own client, checkout, permissions, and human. It
|
|
13
|
+
runs entirely on your machine, on Node's standard library with **zero runtime
|
|
14
|
+
dependencies**, and your transcripts never leave the client.
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
## The wall is you
|
|
17
|
+
|
|
18
|
+
One session refactors and is about to remove a field called `item.drive`. Another, in a
|
|
19
|
+
file you're not looking at, still reads it. Neither terminal knows the other exists — so
|
|
20
|
+
either you carry the warning across by hand, or it ships broken.
|
|
21
|
+
|
|
22
|
+
**Without ACC**, every warning, question, and handoff between sessions stops at you and
|
|
23
|
+
starts again from you. **With ACC**, the sessions carry them to each other: the second
|
|
24
|
+
agent sees the claim, gets the measured impact as a message, and the change lands in one
|
|
25
|
+
piece. You go back to directing.
|
|
16
26
|
|
|
17
27
|
```mermaid
|
|
18
28
|
flowchart TB
|
|
19
|
-
Y["You
|
|
20
|
-
A["
|
|
21
|
-
B["
|
|
22
|
-
C["
|
|
23
|
-
R["ACC shared room<br/>presence ·
|
|
24
|
-
O["Coordinated work<br/>with shared context"]
|
|
25
|
-
|
|
29
|
+
Y["You — set direction"]
|
|
30
|
+
A["session A"]
|
|
31
|
+
B["session B"]
|
|
32
|
+
C["session C"]
|
|
33
|
+
R["ACC shared room<br/>presence · claims · messages · handoffs"]
|
|
26
34
|
Y --> A
|
|
27
35
|
Y --> B
|
|
28
36
|
Y --> C
|
|
29
37
|
A <--> R
|
|
30
38
|
B <--> R
|
|
31
39
|
C <--> R
|
|
32
|
-
R --> O
|
|
33
40
|
```
|
|
34
41
|
|
|
35
|
-
## You opened more agents. You became the coordinator.
|
|
36
|
-
|
|
37
|
-
One session implements. Another writes tests. A third reviews. At first, more agents means
|
|
38
|
-
more work gets done.
|
|
39
|
-
|
|
40
|
-
Then you start copying context between windows. You warn two agents away from the same
|
|
41
|
-
file. You relay a question, return with the answer, and try to remember which terminal was
|
|
42
|
-
waiting for what. The agents are capable; they need a room they can share.
|
|
43
|
-
|
|
44
|
-
ACC gives them that room. Each session stays in its original client, checkout, and trust
|
|
45
|
-
boundary. You still decide when it starts and stops. ACC only supplies the coordination
|
|
46
|
-
that was previously passing through you.
|
|
47
|
-
|
|
48
|
-
## A handoff the agents carry themselves
|
|
49
|
-
|
|
50
|
-
One agent finishes building a feature and sees that its final tests still need work. It
|
|
51
|
-
asks the testing agent to take over, including a short summary of what is ready and what
|
|
52
|
-
remains.
|
|
53
|
-
|
|
54
|
-
```mermaid
|
|
55
|
-
flowchart LR
|
|
56
|
-
A["Feature agent<br/>finishes its part"] --> B["Requests tests<br/>from the testing agent"]
|
|
57
|
-
B --> C["ACC keeps the handoff<br/>ready for that agent"]
|
|
58
|
-
C --> D["Testing agent<br/>completes the work"]
|
|
59
|
-
D --> E["Result returns<br/>to the feature agent"]
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
The request stays with the testing agent across terminal restarts. When that agent returns,
|
|
63
|
-
it receives the handoff, completes the tests, and sends the result back. You choose the
|
|
64
|
-
direction and review the outcome; the agents carry the context between them.
|
|
65
|
-
|
|
66
42
|
## Install
|
|
67
43
|
|
|
68
|
-
|
|
69
|
-
run:
|
|
44
|
+
Two commands, once per macOS or Linux machine where your clients run:
|
|
70
45
|
|
|
71
46
|
```bash
|
|
72
47
|
npm install -g agents-can-communicate
|
|
73
48
|
acc install
|
|
74
49
|
```
|
|
75
50
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
Open or restart your agent client inside a project. Each new session joins that project's
|
|
84
|
-
room automatically. Open another session in the same project and the two can coordinate;
|
|
85
|
-
run `acc status` from the project directory whenever you want to see the room yourself.
|
|
51
|
+
`acc install` wires ACC into the clients you have — Codex, Claude Code, Gemini CLI, Grok,
|
|
52
|
+
Kimi Code — and names everything it changed. **Restart the client afterwards** (hooks load
|
|
53
|
+
at startup); Codex also needs you to trust the plugin. Then just open a session in a
|
|
54
|
+
project and it joins that project's room by itself; open a second and they coordinate.
|
|
55
|
+
`acc doctor` shows what's active, `acc update --apply` keeps it current, `acc uninstall`
|
|
56
|
+
removes only what ACC wrote.
|
|
86
57
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
platform, as described in [configuration](docs/CONFIGURATION.md). Project files stay
|
|
91
|
-
unchanged. Git worktrees from one repository share a room, and plain folders receive the
|
|
92
|
-
same coordination experience.
|
|
58
|
+
Coordination data lives in the platform app-data directory (`~/Library/Application
|
|
59
|
+
Support/acc`, `~/.local/share/acc`; override with `ACC_DATA_HOME`), never in your repo.
|
|
60
|
+
Every worktree of a repo shares one room; a plain folder works the same.
|
|
93
61
|
|
|
94
|
-
|
|
95
|
-
the client integrations together. `acc doctor` points to that action when their versions
|
|
96
|
-
drift.
|
|
62
|
+
## What the room holds
|
|
97
63
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
**
|
|
104
|
-
focus, and the files they have claimed.
|
|
105
|
-
|
|
106
|
-
**Parallel work becomes deliberate.** Agents claim shared files before editing. Supported
|
|
107
|
-
client edits respect those claims and identify the participant already working there.
|
|
108
|
-
|
|
109
|
-
**Questions and work find their way back.** Requests, decisions, and handoffs stay with
|
|
110
|
-
the intended agent across session restarts, and results return to the agent that asked.
|
|
111
|
-
|
|
112
|
-
**Human authority stays clear.** Peer messages arrive with attribution and remain peer
|
|
113
|
-
context. Your instructions and approved policy continue to set the boundaries.
|
|
114
|
-
|
|
115
|
-
**Solo work stays quiet.** A single session receives the familiar client experience.
|
|
116
|
-
Shared context appears when another participant or pending handoff makes it useful.
|
|
117
|
-
|
|
118
|
-
## Fits the workflow you already have
|
|
119
|
-
|
|
120
|
-
Your agent client remains the place where sessions start, permissions are granted, and
|
|
121
|
-
work happens. ACC joins at natural moments, shares the relevant context, and returns
|
|
122
|
-
control to the client. Forward progress stays the priority during any coordination delay.
|
|
123
|
-
|
|
124
|
-
ACC currently connects directly to Codex, Claude Code, Gemini CLI, and Kimi Code. Other
|
|
125
|
-
clients that support MCP can join the same room, see its activity, and exchange work when
|
|
126
|
-
they sync.
|
|
127
|
-
|
|
128
|
-
When a client exposes supported file edits, ACC can protect a claimed file before another
|
|
129
|
-
agent changes it. Shell commands and separate local applications rely on visible claims
|
|
130
|
-
instead. `acc status` explains the protection available in the current room.
|
|
131
|
-
|
|
132
|
-
Current support focuses on multiple sessions working in one project on one machine, on
|
|
133
|
-
macOS or Linux. Each client retains its session lifecycle and full conversation history.
|
|
134
|
-
The [capability evidence](docs/CAPABILITIES.md) records exactly what each integration has
|
|
135
|
-
demonstrated in a real client.
|
|
64
|
+
| | |
|
|
65
|
+
|---|---|
|
|
66
|
+
| **presence** | who's live, their client and branch, and what each intends — one `acc status`. |
|
|
67
|
+
| **claims** | the files each session is touching; on guardable clients a clashing edit is refused and the owner named. |
|
|
68
|
+
| **messages** | questions, decisions, notes — attributed, delivered on the recipient's next turn, and data they weigh rather than orders. |
|
|
69
|
+
| **requests & handoffs** | work addressed to a participant, so it waits across restarts and carries the answer back. |
|
|
136
70
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
71
|
+
A targeted `acc inbox` survives context compaction, and `acc reply` answers and
|
|
72
|
+
acknowledges in one operation. A session alone in a repo pays nothing — no banner, no
|
|
73
|
+
protocol, nothing left behind.
|
|
140
74
|
|
|
141
75
|
## Everyday controls
|
|
142
76
|
|
|
143
|
-
The installed guidance teaches agents
|
|
144
|
-
|
|
77
|
+
The installed guidance teaches your agents to claim, ask, request, and hand off on their
|
|
78
|
+
own. These give you a direct view when you want one:
|
|
145
79
|
|
|
146
|
-
| Command |
|
|
80
|
+
| Command | For |
|
|
147
81
|
|---|---|
|
|
148
|
-
| `acc status` |
|
|
149
|
-
| `acc
|
|
150
|
-
| `acc
|
|
151
|
-
| `acc
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
## Keep exploring
|
|
156
|
-
|
|
157
|
-
- **Start using ACC:** [getting started](docs/GETTING_STARTED.md) ·
|
|
158
|
-
[configuration](docs/CONFIGURATION.md) · [troubleshooting](docs/TROUBLESHOOTING.md)
|
|
159
|
-
- **Understand the promise:** [why ACC](docs/WHY_ACC.md) · [concepts](docs/CONCEPTS.md) ·
|
|
160
|
-
[capabilities](docs/CAPABILITIES.md) · [security](docs/SECURITY_MODEL.md)
|
|
161
|
-
- **Build on ACC:** [MCP](docs/MCP.md) · [writing an adapter](docs/ADAPTER_AUTHORING.md) ·
|
|
162
|
-
[protocol](docs/PROTOCOL.md)
|
|
82
|
+
| `acc status` | who's here, what they claim, and the room's protection level |
|
|
83
|
+
| `acc inbox` | recover an addressed message without a workspace dump |
|
|
84
|
+
| `acc reply` | answer and acknowledge in one operation |
|
|
85
|
+
| `acc doctor` | confirm which client integrations are active and current |
|
|
86
|
+
| `acc update --apply` | install the latest release and refresh integrations |
|
|
87
|
+
| `acc uninstall` | remove ACC's integrations — settings you changed stay yours |
|
|
163
88
|
|
|
164
|
-
|
|
165
|
-
[research in a plain directory](examples/non-git-research.md). Contributions start with
|
|
166
|
-
[Repository Guidelines](AGENTS.md).
|
|
89
|
+
## Documentation
|
|
167
90
|
|
|
168
|
-
|
|
91
|
+
Start at the **[documentation map](docs/index.md)** — it lays out a path for whatever
|
|
92
|
+
brought you here: [why ACC](docs/WHY_ACC.md) and [concepts](docs/CONCEPTS.md) to evaluate
|
|
93
|
+
it, [getting started](docs/GETTING_STARTED.md) to run it, the [CLI](docs/CLI.md) /
|
|
94
|
+
[protocol](docs/PROTOCOL.md) / [capabilities](docs/CAPABILITIES.md) reference, and
|
|
95
|
+
[adapter authoring](docs/ADAPTER_AUTHORING.md) to extend it. New to the vocabulary? The
|
|
96
|
+
[glossary](docs/GLOSSARY.md) defines every term in one line.
|
|
169
97
|
|
|
170
|
-
|
|
98
|
+
See it run: [three workstreams](examples/three-workstreams.md) · [research in a plain
|
|
99
|
+
folder](examples/non-git-research.md). Contributing starts with [AGENTS.md](AGENTS.md).
|
|
171
100
|
|
|
172
|
-
##
|
|
101
|
+
## Requirements & license
|
|
173
102
|
|
|
174
|
-
|
|
103
|
+
Node 24+, macOS or Linux, Git optional. MIT — use it, fork it, keep it
|
|
104
|
+
([LICENSE](LICENSE)).
|
package/bin/acc-hook.mjs
CHANGED
|
@@ -13,12 +13,14 @@ import { runHook } from "@agents-can-communicate/hook-runner";
|
|
|
13
13
|
import { createClaudeCodeAdapter } from "@agents-can-communicate/adapter-claude-code";
|
|
14
14
|
import { createCodexAdapter } from "@agents-can-communicate/adapter-codex";
|
|
15
15
|
import { createGeminiCliAdapter } from "@agents-can-communicate/adapter-gemini-cli";
|
|
16
|
+
import { createGrokAdapter } from "@agents-can-communicate/adapter-grok";
|
|
16
17
|
import { createKimiAdapter } from "@agents-can-communicate/adapter-kimi";
|
|
17
18
|
|
|
18
19
|
const adapters = {
|
|
19
20
|
claude_code: createClaudeCodeAdapter(),
|
|
20
21
|
codex: createCodexAdapter(),
|
|
21
22
|
gemini_cli: createGeminiCliAdapter(),
|
|
23
|
+
grok: createGrokAdapter(),
|
|
22
24
|
kimi: createKimiAdapter(),
|
|
23
25
|
};
|
|
24
26
|
|
package/docs/CAPABILITIES.md
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
# Capabilities
|
|
2
2
|
|
|
3
|
-
Capability honesty is part of the product
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Capability honesty is part of the product: ACC coordinates sessions it does not own, so a
|
|
4
|
+
workspace can promise only what every session in it actually exposes — one weaker
|
|
5
|
+
participant lowers the reported protection level instead of inheriting a stronger label
|
|
6
|
+
from its peers.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
been tested, and at least one finding here is filesystem- and path-shaped, so the table
|
|
14
|
-
should be re-run before claiming another platform.
|
|
8
|
+
Every row below is **measured**, not asserted: a `yes` has a fixture captured from a real
|
|
9
|
+
session of that client version; a `no` means the behavior was not observed, not that it is
|
|
10
|
+
impossible. Certified 2026-08-16 on macOS 15 (darwin 25.5.0, arm64) only — at least one
|
|
11
|
+
finding here is filesystem- and path-shaped, so re-run the table before trusting it on
|
|
12
|
+
another platform.
|
|
15
13
|
|
|
16
14
|
## Clients
|
|
17
15
|
|
|
@@ -20,33 +18,34 @@ should be re-run before claiming another platform.
|
|
|
20
18
|
| `codex` | `codex-cli` | 0.147.0 |
|
|
21
19
|
| `claude_code` | Claude Code | 2.1.233 |
|
|
22
20
|
| `gemini_cli` | Gemini CLI | 0.37.0 and 0.55.1 |
|
|
21
|
+
| `grok` | Grok | 1.0.13 |
|
|
23
22
|
| `kimi` | Kimi Code | 0.36.1 |
|
|
24
23
|
|
|
25
24
|
## Matrix
|
|
26
25
|
|
|
27
|
-
| Capability | codex | claude_code | gemini_cli | kimi |
|
|
28
|
-
|
|
29
|
-
| `lifecycle.sessionStart` | yes | yes | yes | yes |
|
|
30
|
-
| `lifecycle.sessionResume` | no | no | no | no |
|
|
31
|
-
| `lifecycle.sessionEnd` | yes | yes | yes | no |
|
|
32
|
-
| `lifecycle.heartbeat` | no | no | no | yes |
|
|
33
|
-
| `lifecycle.childSessions` | no | no | no | no |
|
|
34
|
-
| `context.startupInjection` | no | no | no | no |
|
|
35
|
-
| `context.beforeTurnInjection` | yes | yes | yes | yes |
|
|
36
|
-
| `context.safePointInjection` | no | no | no | no |
|
|
37
|
-
| `guards.beforeRead` | no | no | no | no |
|
|
38
|
-
| `guards.beforeWrite` | yes | yes | yes | yes |
|
|
39
|
-
| `guards.beforeShell` | yes | yes | yes | yes |
|
|
40
|
-
| `delivery.polling` | yes | yes | yes | yes |
|
|
41
|
-
| `delivery.activeNotification` | no | no | no | no |
|
|
42
|
-
| `delivery.wakeDormantSession` | no | no | no | no |
|
|
43
|
-
| `execution.launch` | no | no | no | no |
|
|
44
|
-
| `execution.resume` | no | no | no | no |
|
|
45
|
-
| `execution.terminate` | no | no | no | no |
|
|
26
|
+
| Capability | codex | claude_code | gemini_cli | grok | kimi |
|
|
27
|
+
|---|---|---|---|---|---|
|
|
28
|
+
| `lifecycle.sessionStart` | yes | yes | yes | yes | yes |
|
|
29
|
+
| `lifecycle.sessionResume` | no | no | no | no | no |
|
|
30
|
+
| `lifecycle.sessionEnd` | yes | yes | yes | yes | no |
|
|
31
|
+
| `lifecycle.heartbeat` | no | no | no | no | yes |
|
|
32
|
+
| `lifecycle.childSessions` | no | no | no | no | no |
|
|
33
|
+
| `context.startupInjection` | no | no | no | no | no |
|
|
34
|
+
| `context.beforeTurnInjection` | yes | yes | yes | no | yes |
|
|
35
|
+
| `context.safePointInjection` | no | no | no | no | no |
|
|
36
|
+
| `guards.beforeRead` | no | no | no | no | no |
|
|
37
|
+
| `guards.beforeWrite` | yes | yes | yes | no | yes |
|
|
38
|
+
| `guards.beforeShell` | yes | yes | yes | no | yes |
|
|
39
|
+
| `delivery.polling` | yes | yes | yes | yes | yes |
|
|
40
|
+
| `delivery.activeNotification` | no | no | no | no | no |
|
|
41
|
+
| `delivery.wakeDormantSession` | no | no | no | no | no |
|
|
42
|
+
| `execution.launch` | no | no | no | no | no |
|
|
43
|
+
| `execution.resume` | no | no | no | no | no |
|
|
44
|
+
| `execution.terminate` | no | no | no | no | no |
|
|
46
45
|
|
|
47
46
|
## Resolving a client's pid is not universal either
|
|
48
47
|
|
|
49
|
-
Not a capability above
|
|
48
|
+
Not a capability above — no adapter method backs it, so it has no row in the matrix — but
|
|
50
49
|
it is presence's other signal for telling a dead process from an idle one, and it does not
|
|
51
50
|
reach every client.
|
|
52
51
|
|
|
@@ -60,15 +59,16 @@ interpreter's name rather than the script's.
|
|
|
60
59
|
|---|---|---|---|
|
|
61
60
|
| `codex` | `codex` | `codex`, a native binary | yes |
|
|
62
61
|
| `claude_code` | `claude` | `claude`, a native binary | yes |
|
|
63
|
-
| `gemini_cli` | `gemini` | `node`
|
|
64
|
-
| `
|
|
62
|
+
| `gemini_cli` | `gemini` | `node` — `gemini.js` starts `#!/usr/bin/env node` | **no** |
|
|
63
|
+
| `grok` | `grok` | `grok`, a native Mach-O at `~/.grok/bin/grok` | yes |
|
|
64
|
+
| `kimi` | `kimi` | not installed on the machine this table was measured on; Kimi Code ships via npm as a Node.js CLI (`@moonshot-ai/kimi-code`), the same shape as Gemini CLI | **almost certainly no — not measured** |
|
|
65
65
|
|
|
66
66
|
A Gemini session records `pid: null` for its whole life, and Kimi's is very likely the
|
|
67
67
|
same, unconfirmed. `null` is the correct "nobody knows" answer and is handled identically
|
|
68
|
-
wherever it is read
|
|
69
|
-
a confirmed-dead pid retires a session immediately and exactly, and today that is `codex
|
|
70
|
-
|
|
71
|
-
session has for whenever a pid is unavailable
|
|
68
|
+
wherever it is read — not a correctness bug. It does change what presence delivers, though:
|
|
69
|
+
a confirmed-dead pid retires a session immediately and exactly, and today that is `codex`,
|
|
70
|
+
`claude_code`, and `grok`. `gemini_cli` and `kimi` fall back to the same age-based floor every
|
|
71
|
+
session has for whenever a pid is unavailable — thirty minutes of silence — so their
|
|
72
72
|
sessions still leave, just later and on a timer instead of on the fact. See
|
|
73
73
|
[ARCHITECTURE.md](ARCHITECTURE.md#presence) for the full floor.
|
|
74
74
|
|
|
@@ -89,8 +89,8 @@ toolset contained no `apply_patch`.
|
|
|
89
89
|
`replace` appear under `auto_edit`; `run_shell_command` under `yolo`.
|
|
90
90
|
|
|
91
91
|
**`guards.beforeShell` is resource-aware where the write is unambiguous.** ACC reads the
|
|
92
|
-
command for its write positions only
|
|
93
|
-
job is to put bytes somewhere
|
|
92
|
+
command for its write positions only — a redirection, an operand of a command whose whole
|
|
93
|
+
job is to put bytes somewhere — and declares those paths as targets. Reading positions are
|
|
94
94
|
left alone: `cat file` and `grep file` name a path and write nothing, and treating them as
|
|
95
95
|
writes would have sessions blocking each other for looking.
|
|
96
96
|
|
|
@@ -101,8 +101,9 @@ is: a session told to prefer the shell for file changes walked through every cla
|
|
|
101
101
|
workspace.
|
|
102
102
|
|
|
103
103
|
Where the guard cannot help, the turn context does: it names the claims other sessions
|
|
104
|
-
hold and says which way this session stands with them. Two facts decide the wording
|
|
105
|
-
|
|
104
|
+
hold and says which way this session stands with them. Two facts decide the wording — what
|
|
105
|
+
the claim's owner asked for (`guarded` or `advisory`; see [Glossary](GLOSSARY.md)), and
|
|
106
|
+
whether ACC can stop this session at all:
|
|
106
107
|
|
|
107
108
|
| Claim | This session | Note |
|
|
108
109
|
|---|---|---|
|
|
@@ -110,51 +111,59 @@ what the claim's owner asked for, and whether ACC can stop this session at all:
|
|
|
110
111
|
| guarded | cannot be guarded | `not enforced for this session; do not edit it` |
|
|
111
112
|
| advisory | either | `advisory; nothing will stop you, the owner is asking` |
|
|
112
113
|
|
|
113
|
-
Unenforceable is not the same as unknown
|
|
114
|
+
Unenforceable is not the same as unknown — and neither is it the same as unclaimed.
|
|
114
115
|
|
|
115
116
|
**`lifecycle.sessionEnd` on `kimi` is false and it matters.** Each `kimi -p` run leaves an
|
|
116
|
-
attached session that never closes itself
|
|
117
|
+
attached session that never closes itself — it just stops taking turns. Presence retires it
|
|
117
118
|
instead, most likely without ever resolving a pid (see above), which means the session
|
|
118
|
-
reads `offline`
|
|
119
|
+
reads `offline` — and disappears from the default `acc status` view — only after thirty
|
|
119
120
|
minutes of silence, not on its declared 60s heartbeat cadence. Interactive sessions
|
|
120
121
|
heartbeat and do not have this problem.
|
|
121
122
|
|
|
122
|
-
**`lifecycle.heartbeat` is Kimi's alone.** It fires on a timer
|
|
123
|
-
and 180006 ms of uptime
|
|
124
|
-
|
|
123
|
+
**`lifecycle.heartbeat` is Kimi's alone.** It fires on a timer — observed at 60002, 120004
|
|
124
|
+
and 180006 ms of uptime — so an idle Kimi session keeps its presence honest. The other
|
|
125
|
+
clients reach a hook only when the user takes a turn, so their idle sessions go stale while
|
|
125
126
|
alive. This is why it is a capability of its own rather than a flavour of
|
|
126
127
|
`delivery.polling`.
|
|
127
128
|
|
|
129
|
+
**`context.beforeTurnInjection` on `grok` is false.** Grok 1.0.13 discards
|
|
130
|
+
UserPromptSubmit stdout and `additionalContext`. The hook still runs (presence
|
|
131
|
+
and polling), but the model is not shown that text. Agents on this client read
|
|
132
|
+
`acc status` / `acc inbox` from the skill.
|
|
133
|
+
|
|
134
|
+
**`guards.beforeWrite` / `beforeShell` on `grok` are false.** PreToolUse fires, and
|
|
135
|
+
the matcher names `write`, `search_replace`, and `run_terminal_command`. A deny
|
|
136
|
+
has not yet been captured blocking a real call, so the capability stays false.
|
|
137
|
+
|
|
128
138
|
## Response contracts, which do not port
|
|
129
139
|
|
|
130
140
|
The single most portable-looking mistake an adapter can make. Measured by running each
|
|
131
141
|
candidate against a real session of each client and checking whether the tool actually
|
|
132
|
-
ran.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
|
138
|
-
|
|
139
|
-
|
|
|
140
|
-
| `{"
|
|
141
|
-
| `{"
|
|
142
|
-
|
|
|
143
|
-
| exit code 1 | - | - | ignored | ignored |
|
|
142
|
+
ran. A dash means the candidate was never run against that client, not that it fails —
|
|
143
|
+
only the shape each shipped adapter actually uses was measured on every client.
|
|
144
|
+
|
|
145
|
+
| Reply to a guard hook | codex | claude_code | gemini_cli | grok | kimi |
|
|
146
|
+
|---|---|---|---|---|---|
|
|
147
|
+
| exit code 2 | denies | - | denies | - | denies |
|
|
148
|
+
| `{"hookSpecificOutput":{…,"permissionDecision":"deny"}}` | - | denies | **ignored** | documented | denies |
|
|
149
|
+
| `{"decision":"deny","reason":…}` | - | - | - | documented | - |
|
|
150
|
+
| `{"decision":"block","reason":…}` | - | - | denies | - | **ignored** |
|
|
151
|
+
| `{"permission":"deny"}` | - | - | ignored | - | ignored |
|
|
152
|
+
| exit code 1 | - | - | ignored | - | ignored |
|
|
144
153
|
|
|
145
154
|
Codex has no structured reply at all: it denies by exiting 2 with the reason on stderr.
|
|
146
155
|
Gemini ignores the shape that Claude Code and Kimi Code both honour, and Kimi ignores the
|
|
147
|
-
shape Gemini needs. Each ignored case fails silently
|
|
156
|
+
shape Gemini needs. Each ignored case fails silently — the write goes through and the
|
|
148
157
|
client reports nothing.
|
|
149
158
|
|
|
150
159
|
Context injection does not follow the deny contract even within one client:
|
|
151
160
|
|
|
152
|
-
| Injection | codex | claude_code | gemini_cli | kimi |
|
|
153
|
-
|
|
154
|
-
| `hookSpecificOutput.additionalContext` | - | works | works | works, but **not unwrapped** |
|
|
155
|
-
| plain text on stdout | works | - | dropped | works |
|
|
161
|
+
| Injection | codex | claude_code | gemini_cli | grok | kimi |
|
|
162
|
+
|---|---|---|---|---|---|
|
|
163
|
+
| `hookSpecificOutput.additionalContext` | - | works | works | **discarded** on UserPromptSubmit | works, but **not unwrapped** |
|
|
164
|
+
| plain text on stdout | works | - | dropped | **discarded** on UserPromptSubmit | works |
|
|
156
165
|
|
|
157
|
-
Codex delivers a hook's stdout as a `developer` role message, verbatim
|
|
166
|
+
Codex delivers a hook's stdout as a `developer` role message, verbatim — the most direct
|
|
158
167
|
of the four channels, and a reason for care rather than comfort: at that role a model
|
|
159
168
|
reads text as instruction, so peer-authored text has to stay framed as data.
|
|
160
169
|
|
|
@@ -163,37 +172,48 @@ Kimi Code shows the model whatever a hook printed, wrapped in
|
|
|
163
172
|
conversation. Gemini unwraps the envelope and appends `<hook_context>…</hook_context>` to
|
|
164
173
|
the user turn, and drops a bare string entirely.
|
|
165
174
|
|
|
175
|
+
These two tables are the measurement; they say nothing about how an adapter produces the
|
|
176
|
+
right shape without knowing which client it is talking to. That contract —
|
|
177
|
+
`denyOutcome()` / `injectOutcome()` — is documented in
|
|
178
|
+
[ADAPTER_AUTHORING.md](ADAPTER_AUTHORING.md#response-contracts-do-not-port).
|
|
179
|
+
|
|
166
180
|
## Installation is not uniform either
|
|
167
181
|
|
|
168
|
-
| | codex | claude_code | gemini_cli | kimi |
|
|
169
|
-
|
|
170
|
-
| Where hooks live | marketplace plugin | plugin | `settings.json` | `config.toml` |
|
|
171
|
-
| Project-level config | no | no | yes | **no** |
|
|
172
|
-
| Hook `timeout` unit | - | - | milliseconds | **seconds** (max 600) |
|
|
173
|
-
| Command path | absolute required | `${CLAUDE_PLUGIN_ROOT}` | absolute required | absolute required |
|
|
174
|
-
| Extra step by the user | hook trust | - | - | - |
|
|
182
|
+
| | codex | claude_code | gemini_cli | grok | kimi |
|
|
183
|
+
|---|---|---|---|---|---|
|
|
184
|
+
| Where hooks live | marketplace plugin | plugin | `settings.json` | `~/.grok/hooks/acc.json` | `config.toml` |
|
|
185
|
+
| Project-level config | no | no | yes | yes (`<project>/.grok/hooks`, unused) | **no** |
|
|
186
|
+
| Hook `timeout` unit | - | - | milliseconds | **seconds** | **seconds** (max 600) |
|
|
187
|
+
| Command path | absolute required | `${CLAUDE_PLUGIN_ROOT}` | absolute required | absolute required | absolute required |
|
|
188
|
+
| Extra step by the user | hook trust | - | - | - | - |
|
|
175
189
|
|
|
176
190
|
Kimi Code is the only one with no project-level config, so ACC edits the user's global
|
|
177
|
-
`config.toml`
|
|
191
|
+
`config.toml` — as a delimited block it owns, because ACC ships without dependencies and a
|
|
178
192
|
hand-written TOML round-tripper would take the user's comments and formatting with it.
|
|
179
193
|
|
|
180
194
|
Codex needs four things before a hook runs, not one: the plugin directory, a parseable
|
|
181
195
|
marketplace, both `[marketplaces.…]` and `[plugins."…"]` registered in its config, and the
|
|
182
|
-
plugin copied into `plugins/cache/<marketplace>/<plugin>/<version>/`. ACC does all four
|
|
196
|
+
plugin copied into `plugins/cache/<marketplace>/<plugin>/<version>/`. ACC does all four —
|
|
183
197
|
that last copy is exactly and only what `codex plugin add` does, measured by diffing the
|
|
184
198
|
home around it. Hook trust remains a manual step, which is the client's security model.
|
|
185
199
|
|
|
186
200
|
## What a participant declares about itself
|
|
187
201
|
|
|
188
202
|
Every session records `enforcement` (`guarded` | `advisory`) and `lifecycle`
|
|
189
|
-
(`managed` | `manual`), taken from the adapter's proven capabilities
|
|
190
|
-
harness name
|
|
191
|
-
the CLI reads as advisory and manual.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
MCP
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
203
|
+
(`managed` | `manual`), taken from the adapter's proven capabilities in this matrix rather
|
|
204
|
+
than from the harness's name — both default to the weaker reading, so a generic MCP client
|
|
205
|
+
or a human at the CLI reads as advisory and manual. What that downgrade means for a
|
|
206
|
+
workspace, and why one MCP participant in the room is enough to drop everyone else's
|
|
207
|
+
protection, is explained canonically in
|
|
208
|
+
[MCP.md](MCP.md#native-adapter-vs-mcp-client).
|
|
209
|
+
|
|
210
|
+
**"Stoppable" is not "unevadable".** Even in a guarded workspace, a session that writes
|
|
211
|
+
through a language runtime rather than a recognised shell form gets past — see
|
|
212
|
+
`guards.beforeShell` above. The claim still says who is working where; enforcement is the
|
|
213
|
+
floor, not the ceiling.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
See also: [README](index.md) for navigation, [Glossary](GLOSSARY.md) for terms,
|
|
218
|
+
[Adapter authoring](ADAPTER_AUTHORING.md) for the deny/inject implementation contract, and
|
|
219
|
+
[MCP](MCP.md) for the participation tier and the native-vs-MCP explanation.
|