agents-can-communicate 0.3.0 → 0.4.0

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.
Files changed (157) hide show
  1. package/README.md +112 -91
  2. package/SECURITY.md +8 -5
  3. package/bin/acc-bootstrap.mjs +5 -54
  4. package/bin/acc-claude-channel.mjs +8 -175
  5. package/bin/acc-hook.mjs +4 -133
  6. package/bin/acc-mcp.mjs +4 -59
  7. package/bin/acc-update-worker.mjs +8 -0
  8. package/bin/acc.mjs +5 -39
  9. package/bin/entrypoints/acc-bootstrap.mjs +47 -0
  10. package/bin/entrypoints/acc-claude-channel.mjs +149 -0
  11. package/bin/entrypoints/acc-hook.mjs +58 -0
  12. package/bin/entrypoints/acc-mcp.mjs +70 -0
  13. package/bin/entrypoints/acc.mjs +51 -0
  14. package/bin/entrypoints/claude-channel-stdio.mjs +29 -0
  15. package/bin/entrypoints/hook-output.mjs +73 -0
  16. package/docs/ADAPTER_AUTHORING.md +62 -24
  17. package/docs/ARCHITECTURE.md +79 -20
  18. package/docs/CAPABILITIES.md +52 -30
  19. package/docs/CLI.md +164 -35
  20. package/docs/CONCEPTS.md +97 -93
  21. package/docs/CONFIGURATION.md +66 -45
  22. package/docs/DESIGN_DECISIONS.md +24 -15
  23. package/docs/GETTING_STARTED.md +124 -118
  24. package/docs/GLOSSARY.md +12 -6
  25. package/docs/HOW_IT_WORKS.md +136 -229
  26. package/docs/MCP.md +98 -31
  27. package/docs/PROTOCOL.md +76 -14
  28. package/docs/RELEASING.md +128 -86
  29. package/docs/SECURITY_MODEL.md +52 -15
  30. package/docs/TROUBLESHOOTING.md +88 -18
  31. package/docs/UPGRADING.md +119 -0
  32. package/docs/WHY_ACC.md +19 -16
  33. package/docs/index.md +40 -24
  34. package/node_modules/@agents-can-communicate/adapter-claude-code/package.json +1 -1
  35. package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/skills/acc/SKILL.md +112 -9
  36. package/node_modules/@agents-can-communicate/adapter-claude-code/src/install.mjs +6 -6
  37. package/node_modules/@agents-can-communicate/adapter-claude-code/src/native-delivery.mjs +2 -1
  38. package/node_modules/@agents-can-communicate/adapter-codex/certification.json +38 -13
  39. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/certification-provenance.json +220 -0
  40. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.152.1-local-daemon-current-binding-product-evidence.json +1549 -0
  41. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.152.1-local-daemon-current-binding-product.json +27 -0
  42. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.152.1-local-daemon-product-evidence.json +1549 -0
  43. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.152.1-local-daemon-product.json +27 -0
  44. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.152.1-local-daemon-transport-evidence.json +259 -0
  45. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.152.1-local-daemon-transport.json +21 -0
  46. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.153.4-local-daemon-current-binding-product-evidence.json +1549 -0
  47. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.153.4-local-daemon-current-binding-product.json +27 -0
  48. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.153.4-local-daemon-product-evidence.json +1549 -0
  49. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.153.4-local-daemon-product.json +27 -0
  50. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.153.4-local-daemon-transport-evidence.json +259 -0
  51. package/node_modules/@agents-can-communicate/adapter-codex/fixtures/delivery/codex-cli-0.153.4-local-daemon-transport.json +21 -0
  52. package/node_modules/@agents-can-communicate/adapter-codex/package.json +14 -2
  53. package/node_modules/@agents-can-communicate/adapter-codex/plugin/skills/acc/SKILL.md +111 -8
  54. package/node_modules/@agents-can-communicate/adapter-codex/src/adapter.mjs +26 -44
  55. package/node_modules/@agents-can-communicate/adapter-codex/src/app-server-client.mjs +70 -17
  56. package/node_modules/@agents-can-communicate/adapter-codex/src/config-block.mjs +231 -0
  57. package/node_modules/@agents-can-communicate/adapter-codex/src/hooks.mjs +1 -1
  58. package/node_modules/@agents-can-communicate/adapter-codex/src/install.mjs +71 -63
  59. package/node_modules/@agents-can-communicate/adapter-codex/src/native-delivery.mjs +107 -103
  60. package/node_modules/@agents-can-communicate/adapter-codex/src/native-endpoint.mjs +96 -0
  61. package/node_modules/@agents-can-communicate/adapter-codex/src/ws-json-rpc.mjs +3 -2
  62. package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/gemini-extension.json +1 -1
  63. package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/skills/acc/SKILL.md +111 -8
  64. package/node_modules/@agents-can-communicate/adapter-gemini-cli/package.json +1 -1
  65. package/node_modules/@agents-can-communicate/adapter-gemini-cli/src/install.mjs +2 -2
  66. package/node_modules/@agents-can-communicate/adapter-grok/package.json +1 -1
  67. package/node_modules/@agents-can-communicate/adapter-grok/plugin/skills/acc/SKILL.md +111 -8
  68. package/node_modules/@agents-can-communicate/adapter-grok/src/install.mjs +2 -2
  69. package/node_modules/@agents-can-communicate/adapter-kimi/package.json +1 -1
  70. package/node_modules/@agents-can-communicate/adapter-kimi/plugin/skills/acc/SKILL.md +111 -8
  71. package/node_modules/@agents-can-communicate/adapter-kimi/src/hooks.mjs +1 -1
  72. package/node_modules/@agents-can-communicate/adapter-kimi/src/install.mjs +2 -2
  73. package/node_modules/@agents-can-communicate/adapter-sdk/package.json +1 -1
  74. package/node_modules/@agents-can-communicate/adapter-sdk/src/capabilities.mjs +5 -0
  75. package/node_modules/@agents-can-communicate/adapter-sdk/src/context-projector.mjs +26 -4
  76. package/node_modules/@agents-can-communicate/adapter-sdk/src/decision-text.mjs +19 -0
  77. package/node_modules/@agents-can-communicate/adapter-sdk/src/hook-shim.mjs +5 -3
  78. package/node_modules/@agents-can-communicate/adapter-sdk/src/index.mjs +1 -0
  79. package/node_modules/@agents-can-communicate/adapter-sdk/src/native-delivery.mjs +9 -2
  80. package/node_modules/@agents-can-communicate/adapter-sdk/src/native-vocabulary.mjs +2 -6
  81. package/node_modules/@agents-can-communicate/adapter-sdk/src/session-binding.mjs +29 -9
  82. package/node_modules/@agents-can-communicate/adapter-sdk/src/toml-block.mjs +8 -6
  83. package/node_modules/@agents-can-communicate/cli/package.json +4 -2
  84. package/node_modules/@agents-can-communicate/cli/src/args.mjs +49 -22
  85. package/node_modules/@agents-can-communicate/cli/src/doctor-command.mjs +11 -4
  86. package/node_modules/@agents-can-communicate/cli/src/git-probe.mjs +9 -3
  87. package/node_modules/@agents-can-communicate/cli/src/help.mjs +109 -14
  88. package/node_modules/@agents-can-communicate/cli/src/install-command.mjs +66 -18
  89. package/node_modules/@agents-can-communicate/cli/src/main.mjs +35 -12
  90. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/activation.mjs +110 -0
  91. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/command.mjs +63 -0
  92. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/download.mjs +71 -0
  93. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/entry.mjs +110 -0
  94. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/generation.mjs +167 -0
  95. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/install.mjs +73 -0
  96. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/launchers.mjs +60 -0
  97. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/leases.mjs +60 -0
  98. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/location.mjs +55 -0
  99. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/mutex.mjs +145 -0
  100. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/policy.mjs +4 -0
  101. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/refresh.mjs +40 -0
  102. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/schedule.mjs +21 -0
  103. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/state.mjs +122 -0
  104. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/worker.mjs +65 -0
  105. package/node_modules/@agents-can-communicate/cli/src/session-owner.mjs +33 -108
  106. package/node_modules/@agents-can-communicate/cli/src/update-command.mjs +25 -7
  107. package/node_modules/@agents-can-communicate/core/package.json +1 -1
  108. package/node_modules/@agents-can-communicate/core/src/attention.mjs +3 -0
  109. package/node_modules/@agents-can-communicate/core/src/claims.mjs +13 -8
  110. package/node_modules/@agents-can-communicate/core/src/conversations.mjs +48 -24
  111. package/node_modules/@agents-can-communicate/core/src/decision-changes.mjs +36 -0
  112. package/node_modules/@agents-can-communicate/core/src/decision-state.mjs +42 -0
  113. package/node_modules/@agents-can-communicate/core/src/delivery-bindings.mjs +11 -4
  114. package/node_modules/@agents-can-communicate/core/src/inbox.mjs +48 -17
  115. package/node_modules/@agents-can-communicate/core/src/intents.mjs +35 -15
  116. package/node_modules/@agents-can-communicate/core/src/materialisation.mjs +7 -5
  117. package/node_modules/@agents-can-communicate/core/src/message-pages.mjs +75 -0
  118. package/node_modules/@agents-can-communicate/core/src/next-turn-delivery.mjs +31 -0
  119. package/node_modules/@agents-can-communicate/core/src/session-opening.mjs +128 -0
  120. package/node_modules/@agents-can-communicate/core/src/sessions.mjs +58 -132
  121. package/node_modules/@agents-can-communicate/core/src/sync.mjs +31 -2
  122. package/node_modules/@agents-can-communicate/delivery-router/package.json +1 -1
  123. package/node_modules/@agents-can-communicate/delivery-router/src/refresh-binding.mjs +38 -0
  124. package/node_modules/@agents-can-communicate/delivery-router/src/router.mjs +86 -10
  125. package/node_modules/@agents-can-communicate/hook-runner/package.json +1 -1
  126. package/node_modules/@agents-can-communicate/hook-runner/src/client-version.mjs +1 -0
  127. package/node_modules/@agents-can-communicate/hook-runner/src/native-binding.mjs +6 -4
  128. package/node_modules/@agents-can-communicate/hook-runner/src/native-retirement.mjs +48 -0
  129. package/node_modules/@agents-can-communicate/hook-runner/src/process-table.mjs +1 -1
  130. package/node_modules/@agents-can-communicate/hook-runner/src/runner.mjs +175 -67
  131. package/node_modules/@agents-can-communicate/hook-runner/src/session-lifecycle.mjs +13 -0
  132. package/node_modules/@agents-can-communicate/installer/package.json +4 -2
  133. package/node_modules/@agents-can-communicate/installer/src/apply.mjs +17 -2
  134. package/node_modules/@agents-can-communicate/installer/src/bootstrap-runtime.mjs +11 -5
  135. package/node_modules/@agents-can-communicate/installer/src/detect.mjs +1 -1
  136. package/node_modules/@agents-can-communicate/installer/src/index.mjs +1 -0
  137. package/node_modules/@agents-can-communicate/installer/src/live-policy.mjs +21 -0
  138. package/node_modules/@agents-can-communicate/installer/src/native-activation.mjs +20 -6
  139. package/node_modules/@agents-can-communicate/installer/src/ownership.mjs +10 -4
  140. package/node_modules/@agents-can-communicate/installer/src/plan.mjs +3 -3
  141. package/node_modules/@agents-can-communicate/mcp-server/package.json +1 -1
  142. package/node_modules/@agents-can-communicate/mcp-server/src/protocol.mjs +85 -0
  143. package/node_modules/@agents-can-communicate/mcp-server/src/resources.mjs +3 -2
  144. package/node_modules/@agents-can-communicate/mcp-server/src/server.mjs +59 -57
  145. package/node_modules/@agents-can-communicate/mcp-server/src/tools.mjs +47 -33
  146. package/node_modules/@agents-can-communicate/protocol/package.json +1 -1
  147. package/node_modules/@agents-can-communicate/protocol/src/conversations.mjs +3 -0
  148. package/node_modules/@agents-can-communicate/protocol/src/decision-changes.mjs +15 -0
  149. package/node_modules/@agents-can-communicate/protocol/src/index.mjs +3 -1
  150. package/node_modules/@agents-can-communicate/protocol/src/schema.mjs +14 -5
  151. package/node_modules/@agents-can-communicate/storage-filesystem/package.json +1 -1
  152. package/node_modules/@agents-can-communicate/storage-filesystem/src/atomic-json.mjs +5 -1
  153. package/node_modules/@agents-can-communicate/storage-filesystem/src/deadline.mjs +7 -0
  154. package/node_modules/@agents-can-communicate/storage-filesystem/src/index.mjs +2 -0
  155. package/node_modules/@agents-can-communicate/storage-filesystem/src/session-read.mjs +25 -0
  156. package/node_modules/@agents-can-communicate/storage-filesystem/src/store.mjs +28 -25
  157. package/package.json +2 -1
package/README.md CHANGED
@@ -1,122 +1,143 @@
1
1
  # agents-can-communicate
2
2
 
3
+ **Open your agents. Let them coordinate.**
4
+
5
+ Give Codex the backend. Ask Claude Code to build the interface. Keep working as usual.
6
+
7
+ ACC makes supported sessions in the same project aware of each other and gives them
8
+ instructions for coordinating. Agents discover their peers, share what they're working
9
+ on, and decide when to ask questions, agree on changes, or avoid overlapping edits.
10
+
11
+ Think of the coordination you expect from subagents, extended across the independent
12
+ sessions you open yourself — with different clients and models. You keep giving them
13
+ ordinary tasks; they handle the conversations around their work.
14
+
15
+ Active hooks supply each agent's own CLI arguments in coordination context; the installed
16
+ skill tells the agent to use them. This path was observed in Claude Code 2.1.263 and
17
+ Codex 0.153.4. Hooks must be enabled and trusted by the client. Without hook context, owner
18
+ operations require an explicit pair or session-bound ACC MCP tools. See [CLI ownership](docs/CLI.md#coordinate-from-a-session).
19
+
20
+ [Try it](#try-it) · [Supported clients](#when-messages-arrive) · [Documentation](docs/index.md)
21
+
3
22
  [![CI](https://github.com/automatis-tools/agents-can-communicate/actions/workflows/ci.yml/badge.svg)](https://github.com/automatis-tools/agents-can-communicate/actions/workflows/ci.yml)
4
23
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
24
  [![Node](https://img.shields.io/badge/node-%E2%89%A524-brightgreen.svg)](https://nodejs.org)
6
25
 
7
- ACC connects independently opened AI sessions so they can discover, ask, answer, acknowledge, and hand off without becoming one managed agent team.
26
+ ## You describe the work. They work out the details.
8
27
 
9
- It is a local-first communication layer for sessions you already run. Each session keeps
10
- its own client, model, checkout, permissions, context, and human direction. ACC supplies a
11
- shared room with presence, intent, narrow file claims, durable conversation threads, and
12
- truthful per-recipient receipts. It does not launch, steer, supervise, or terminate agents.
28
+ Open two sessions in your project and give each its task:
13
29
 
14
- The project uses Node's standard library with **zero runtime dependencies**. Coordination
15
- state stays in platform app data outside the repository, and ACC never collects raw
16
- transcripts.
30
+ | Session | Your prompt |
31
+ |---|---|
32
+ | Codex | Build the backend for account registration. |
33
+ | Claude Code | Build the registration screen. |
17
34
 
18
- ## Stop relaying between windows
35
+ ACC's integration tells the agents that peers are present and teaches them how to find
36
+ out what those peers are doing. As they work, they can notice the dependency and coordinate
37
+ on their own. An illustrative exchange:
19
38
 
20
- One session finds that removing `item.drive` will break another area. A second session is
21
- working there, but neither client knows the other exists. Without ACC, the warning stops at
22
- you: copy it to the other window, copy the answer back, and repeat for every question.
39
+ ```text
40
+ Claude → Codex I'm building the registration screen. What will your endpoint accept?
41
+ Codex → Claude Email and password. I'll return the new user and handle validation.
42
+ Claude → Codex I'll use that shape and keep my changes in the UI files.
43
+ ```
23
44
 
24
- With ACC, the first session sends an attributed question. The second retrieves it, replies
25
- in the same thread, and thereby acknowledges the original. The first retrieves the answer.
26
- The message is durable throughout; neither model gains authority over the other.
45
+ The agents identify who to talk to and what to agree on. Your prompts stay focused on
46
+ the feature you want to build.
27
47
 
28
- ```mermaid
29
- flowchart LR
30
- A["session A — independently opened"] <--> R["ACC room<br/>presence · messages · receipts · claims"]
31
- B["session B — independently opened"] <--> R
32
- U["You — direction and authority"] --> A
33
- U --> B
34
- ```
48
+ The same setup supports a review and handoff. Ask one session to implement a change and
49
+ request review of an identified revision: a commit when Git is available, or named files
50
+ and version otherwise. Ask the other to return blocking defects or approval. The author
51
+ can address the verdict before finishing, or leave a durable handoff so a later session
52
+ can recover what is complete and what remains. See the
53
+ [review request](docs/CLI.md#messages-and-requests) and [handoff](docs/CLI.md#handoff)
54
+ commands behind that flow.
35
55
 
36
- The product's canonical activation event is simple: a second independently opened session
37
- completes a useful acknowledged interaction without the human copying peer message content.
56
+ Each session keeps its own conversation and instructions. Response timing depends on the
57
+ receiving client: see [when messages arrive](#when-messages-arrive).
38
58
 
39
- ## Install
59
+ ## Try it
40
60
 
41
- On macOS or Linux with Node 24 or newer:
61
+ You'll need **macOS or Linux, Node.js 24 or newer**, and two AI sessions in the same
62
+ project. They can use different clients or the same one.
42
63
 
43
64
  ```bash
44
65
  npm install -g agents-can-communicate
45
66
  acc install
46
67
  ```
47
68
 
48
- Restart the clients whose hooks were installed; Codex also requires trusting the plugin.
49
- Then open two sessions in the same repository or plain directory as usual. They remain
50
- independent and join the same ACC workspace. Use `acc doctor` to see exact versions,
51
- installation health, and delivery downgrades.
69
+ The installer connects the clients it finds. Open a new terminal and restart your AI
70
+ clients to load the integration. If you use Codex, accept its plugin trust prompt.
71
+ ACC then keeps its runtime and skills updated in the background, waiting for active clients
72
+ to exit before switching versions. [Update controls](docs/UPGRADING.md#automatic-updates-after-installation)
73
+ include manual update, opt-out, and version pinning.
52
74
 
53
- Runtime state lives in `~/Library/Application Support/acc` on macOS or the XDG data
54
- directory on Linux. `ACC_DATA_HOME` can override it, but ACC refuses a location inside a
55
- workspace. Git is optional; worktrees of one repository share awareness.
75
+ Open two sessions in your project and give them ordinary tasks, as in the example above.
76
+ On supported clients, ACC introduces peer awareness through the client's own integration;
77
+ its installed instructions guide the agents to coordinate when their work overlaps.
56
78
 
57
- ## The communication loop
79
+ Look for coordination in the agents' own activity: discovering a peer, checking who is
80
+ changing a file, or asking about a shared dependency. Each agent decides what is relevant
81
+ to its task; the integration provides awareness, not a guarantee that a model will
82
+ coordinate on every task. [Client support](#when-messages-arrive) determines how
83
+ automatically peers and messages reach it.
58
84
 
59
- ```bash
60
- # Session A publishes awareness and reserves only what it will edit.
61
- acc work --summary "changing the item schema" --mode edit --hint 'file:src/item.mjs'
62
- acc claim --resource 'file:src/item.mjs' --reason "changing the item schema"
85
+ If the other session doesn't appear, run `acc doctor` from your project directory.
86
+ [Get help with setup](docs/TROUBLESHOOTING.md).
87
+
88
+ ## When messages arrive
63
89
 
64
- # Session A asks a participant named by `acc status`.
65
- acc message --to models --type question --subject "item.drive" \
66
- --body "Can your code stop reading item.drive before I remove it?"
90
+ ACC connects sessions **on the same machine** and saves messages locally, so a waiting
91
+ session can pick them up later. Delivery depends on the client:
67
92
 
68
- # Session B reads and answers the exact message.
69
- acc inbox --message message_x
70
- acc reply --message message_x --body "Yes. Commit abc123 removes the final read."
93
+ | Client | How the agent receives a message |
94
+ |---|---|
95
+ | Codex CLI, Claude Code, Gemini CLI, Kimi Code | At the next normal turn on verified versions and platforms; otherwise by checking its ACC inbox. |
96
+ | Grok or another client connected through [MCP](docs/MCP.md) | By checking its ACC inbox. |
71
97
 
72
- # Either session records a handoff while context is still available.
73
- acc finish --goal "remove item.drive" --status complete \
74
- --completed "schema and reader updated" --remaining "none"
98
+ **Codex and Claude Code can also reply while idle.** These optional modes are
99
+ experimental, off by default, and can spend model tokens. On Apple Silicon Macs,
100
+ Codex 0.152.1 or newer requires an already-running LocalDaemon and an exact session
101
+ check; ACC preserves your ordinary launch command. Claude Code 2.1.258 or newer
102
+ requires zsh and its development-channel warning at startup. Messages arriving
103
+ mid-turn wait for it to finish.
104
+
105
+ Each direction follows the receiving client's policy and current reachability.
106
+ A Codex thread retained by LocalDaemon can receive opted-in messages after its
107
+ terminal exits. Turn ACC delivery off to prevent new native offers; already accepted
108
+ queue entries remain with the client.
109
+
110
+ [Full compatibility details](docs/CAPABILITIES.md).
111
+
112
+ ## Keep the workflow you like
113
+
114
+ - **Your usual tools.** Start clients with their normal commands. You choose each
115
+ agent's task, model, and permissions.
116
+ - **Separate checkouts, one project.** Git worktrees share an ACC workspace.
117
+ Plain project folders work too; Git is optional.
118
+ - **Agree before editing.** Agents can reserve files and identify overlapping work.
119
+ CLI reservations default to advisory. `--enforcement guarded` requests enforcement,
120
+ which still requires certified guards from every live participant.
121
+ [How reservations work](docs/CONCEPTS.md#intent-is-awareness-a-claim-commits).
122
+ - **Local coordination.** Messages live in app data outside your project. ACC doesn't
123
+ collect or share raw transcripts. Your clients use their usual model providers.
124
+
125
+ One npm package. No account or separate coordination service to set up.
126
+
127
+ To remove the integrations:
128
+
129
+ ```bash
130
+ acc uninstall
75
131
  ```
76
132
 
77
- Messages commit before any delivery attempt. `queued`, `offered`, `retrieved`, and
78
- `acknowledged` describe different observable facts: an offer is not a read, retrieval is
79
- not proof of model attention, and a reply resolves communication rather than proving a
80
- requested task finished.
81
-
82
- Durable inbox recovery is the baseline for every client. Certified next-turn injection
83
- reduces the polling for the exact captured client version and platform. Native live push is
84
- opt-in, experimental, and off until you choose it: **Claude Code 2.1.258 and Codex 0.152.1
85
- on macOS arm64 have passing live-push captures** and deliver an addressed message into a
86
- running session through the vendor's own transport, falling back to the durable inbox on any
87
- failure. Every other client, and any client below the captured minimum, stays next-turn or
88
- inbox only. The retained failed captures are shipped beside the passing ones as honest
89
- evidence.
90
-
91
- | Client | Native delivery |
92
- |---|---|
93
- | Claude Code 2.1.258 (darwin-arm64) | experimental Channel: idle offer, queue-after-turn, native reply, off until opt-in |
94
- | Codex 0.152.1 (darwin-arm64) | experimental App Server queue: idle/after-turn, reply via `acc reply`, off until opt-in |
95
- | Gemini CLI, Kimi Code | next-turn or inbox only; no captured transparent transport |
96
- | Grok | awaiting a compatibility capture; inbox only |
133
+ ACC preserves configuration changes you've made since installation.
97
134
 
98
- ## What ACC owns
135
+ ## Go further
99
136
 
100
- | ACC owns | ACC does not own |
101
- |---|---|
102
- | participant and session presence | process or model lifecycle |
103
- | current intent and resource claims | prompts, permissions, or token budgets |
104
- | messages, threads, replies, acknowledgements | work queues or execution state |
105
- | delivery evidence and visible fallback | raw transcripts or shared model memory |
106
-
107
- A peer message is untrusted input, never system authority. A guarded claim can stop only
108
- the write paths a client actually exposes; `acc status` reports `advisory` when that cannot
109
- be guaranteed.
110
-
111
- ## Documentation
112
-
113
- Start with [Getting started](docs/GETTING_STARTED.md), then read
114
- [How ACC works](docs/HOW_IT_WORKS.md) for the end-to-end engineering tour or use the
115
- [documentation map](docs/index.md). The exact surfaces are in the [CLI](docs/CLI.md),
116
- [MCP](docs/MCP.md), [Protocol](docs/PROTOCOL.md), and
117
- [Capabilities](docs/CAPABILITIES.md) references. Adapter evidence lives beside each
118
- adapter in its `COMPATIBILITY.md` and `certification.json`.
119
-
120
- Contributing starts with the repository's
121
- [AGENTS.md](https://github.com/automatis-tools/agents-can-communicate/blob/main/AGENTS.md).
122
- Node 24+, Git optional, MIT licensed.
137
+ [Getting started](docs/GETTING_STARTED.md) · [CLI reference](docs/CLI.md) ·
138
+ [Connect an MCP client](docs/MCP.md) · [How ACC works](docs/HOW_IT_WORKS.md) ·
139
+ [Security](docs/SECURITY_MODEL.md)
140
+
141
+ Want to contribute or add a client?
142
+ Start with [AGENTS.md](https://github.com/automatis-tools/agents-can-communicate/blob/main/AGENTS.md)
143
+ and the [adapter guide](docs/ADAPTER_AUTHORING.md).
package/SECURITY.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Security policy
2
2
 
3
- ## Reporting
3
+ This page is for reporting a vulnerability. For system boundaries and threat reasoning,
4
+ read the [security model](docs/SECURITY_MODEL.md).
5
+
6
+ ## Report privately
4
7
 
5
8
  Report privately via [GitHub security advisories](https://github.com/automatis-tools/agents-can-communicate/security/advisories/new).
6
9
 
@@ -9,23 +12,23 @@ Please do not open a public issue first.
9
12
  Include: what you ran, what happened, what you expected, and the client and
10
13
  version. A reproduction against a throwaway `ACC_DATA_HOME` is ideal.
11
14
 
12
- ## Scope
15
+ ## Check the scope
13
16
 
14
17
  | In scope | Out of scope |
15
18
  |---|---|
16
19
  | Peer text escaping its quoted block | An attacker who already has write access to your data home |
17
20
  | Any path escaping the managed root | A model choosing to obey persuasive peer text |
18
21
  | Uninstall deleting files ACC did not write | Vulnerabilities in Codex, Claude Code, Gemini, Grok, or Kimi themselves |
19
- | ACC writing into a repository | Denial of service by a trusted peer |
22
+ | Unexpected ACC runtime/state or installer artifacts in a repository (excluding user-requested `acc.workspace.json`) | Denial of service by a trusted peer |
20
23
  | Session impersonation across MCP | |
21
24
 
22
25
  Reasoning behind each: [docs/SECURITY_MODEL.md](docs/SECURITY_MODEL.md).
23
26
 
24
- ## Supported versions
27
+ ## Target a supported version
25
28
 
26
29
  Pre-1.0: the latest release only.
27
30
 
28
- ## What we will do
31
+ ## Expect this response
29
32
 
30
33
  Acknowledge, reproduce, and tell you whether it is in scope. If it is, the fix
31
34
  ships with a test in `tests/security/` so it cannot come back quietly.
@@ -1,56 +1,7 @@
1
1
  #!/usr/bin/env node
2
- // Internal entry point behind an ACC-owned shell shim: is this exact vendor
3
- // executable eligible for native delivery right now? Exit 0 means yes and the
4
- // shim exports its owned policy before `exec`; any other exit - including a
5
- // crash, a missing adapter, or a damaged install - means the shim launches the
6
- // vendor command untouched. Nothing is ever written to stdout, and stderr stays
7
- // empty unless ACC_BOOTSTRAP_DEBUG=1 asks for one safe line.
8
- import { checkNativeBootstrap } from "@agents-can-communicate/installer";
2
+ import { fileURLToPath } from "node:url";
3
+ import { invokedDirectly, runEntry } from "@agents-can-communicate/cli/managed-entry";
9
4
 
10
- import { createClaudeCodeAdapter } from "@agents-can-communicate/adapter-claude-code";
11
- import { createCodexAdapter } from "@agents-can-communicate/adapter-codex";
12
- import { createGeminiCliAdapter } from "@agents-can-communicate/adapter-gemini-cli";
13
- import { createGrokAdapter } from "@agents-can-communicate/adapter-grok";
14
- import { createKimiAdapter } from "@agents-can-communicate/adapter-kimi";
15
-
16
- const FLAGS = new Map([["--adapter", "adapter"], ["--real-executable", "realExecutable"],
17
- ["--data-home", "dataHome"]]);
18
-
19
- function debug(line) {
20
- if (process.env.ACC_BOOTSTRAP_DEBUG === "1") process.stderr.write(`acc-bootstrap: ${line}\n`);
21
- }
22
-
23
- function parse(args) {
24
- const options = {};
25
- for (let index = 0; index < args.length; index += 2) {
26
- const key = FLAGS.get(args[index]);
27
- const value = args[index + 1];
28
- if (key === undefined || typeof value !== "string" || value === "" || key in options) return null;
29
- options[key] = value;
30
- }
31
- return FLAGS.values().every(key => key in options) ? options : null;
32
- }
33
-
34
- try {
35
- const options = parse(process.argv.slice(2));
36
- if (options === null) {
37
- debug("usage: --adapter <id> --real-executable <path> --data-home <path>");
38
- process.exit(2);
39
- }
40
- const registry = {
41
- claude_code: createClaudeCodeAdapter, codex: createCodexAdapter,
42
- gemini_cli: createGeminiCliAdapter, grok: createGrokAdapter, kimi: createKimiAdapter,
43
- };
44
- const adapter = registry[options.adapter]?.();
45
- if (adapter === undefined) {
46
- debug(`${options.adapter}: unknown adapter`);
47
- process.exit(1);
48
- }
49
- const result = await checkNativeBootstrap({ adapter, realExecutable: options.realExecutable,
50
- platform: `${process.platform}-${process.arch}`, dataHome: options.dataHome, timeoutMs: 750 });
51
- debug(`${options.adapter}: ${result.supported ? "supported" : result.reasonCode}`);
52
- process.exit(result.supported ? 0 : 1);
53
- } catch (error) {
54
- debug(`failed: ${String(error?.code ?? error?.name ?? "error")}`);
55
- process.exit(1);
56
- }
5
+ if (invokedDirectly(import.meta.url)) await runEntry({
6
+ kind: "acc-bootstrap", packageRoot: fileURLToPath(new URL("..", import.meta.url)),
7
+ });
@@ -1,177 +1,10 @@
1
1
  #!/usr/bin/env node
2
- // The ACC Channel binary Claude Code spawns as a stdio MCP child. It composes
3
- // the same workspace discovery, session binding, core service, and local
4
- // data-home rules as acc-hook, opens a session-scoped endpoint for the delivery
5
- // router, and turns the model's explicit acc_reply / acc_ack into real ACC
6
- // records. It never collects a transcript or runs a model, and it fails open:
7
- // any composition error leaves Claude a plain MCP server that simply offers no
8
- // tools rather than crashing the session.
9
- import { randomBytes } from "node:crypto";
10
- import { realpathSync } from "node:fs";
11
- import path from "node:path";
12
2
  import { fileURLToPath } from "node:url";
13
-
14
- import { createClaudeCodeAdapter } from "@agents-can-communicate/adapter-claude-code";
15
- import { listSessionBindings } from "@agents-can-communicate/adapter-sdk";
16
- import { createCoordinationService } from "@agents-can-communicate/core";
17
- import { resolveClientPid } from "@agents-can-communicate/hook-runner/client-pid";
18
- import { readProcessTable } from "@agents-can-communicate/hook-runner/process-table";
19
- import { createId } from "@agents-can-communicate/protocol";
20
- import { openFilesystemStore } from "@agents-can-communicate/storage-filesystem";
21
- import { createGitProbe, discoverWorkspace, platformDataHome, runtimePaths }
22
- from "@agents-can-communicate/cli";
23
-
24
- import { createAccChannel, createInertChannel, endpointDir, routeAck, routeReply }
25
- from "@agents-can-communicate/adapter-claude-code/channel";
26
-
27
- const clock = { now: () => new Date().toISOString() };
28
- const ids = { next: kind => createId(kind, randomBytes) };
29
-
30
- /**
31
- * The ACC session this Claude process opened - decided by which client process
32
- * this Channel is running under, never by how many sessions happen to be
33
- * visible.
34
- *
35
- * There used to be a fallback here: if exactly one session was live, it was
36
- * taken to be this one. On a single-session machine that looked safe, and with
37
- * two sessions it silently handed one client the other's identity. The Channel
38
- * starts while its own SessionStart hook is still writing its binding, so the
39
- * only binding a second client can see at that moment is the *first* client's -
40
- * and the wait that was added to survive that race then locks the wrong answer
41
- * in on the first attempt, because it is a complete, live, plausible binding.
42
- *
43
- * Measured on two real 2.1.259 sessions: both Channels registered an endpoint
44
- * under the first client's pid. `bindNativeSession` refuses two registrations
45
- * for one pid, so the session that had been receiving live messages dropped
46
- * back to the durable inbox - and an `acc_reply` from the second window would
47
- * have been recorded as the first session's answer, which is a false record
48
- * rather than a lost message.
49
- *
50
- * This process was spawned by its client, so its own ancestry names that
51
- * client, and no race can change that. Ownership is decided by it.
52
- */
53
- export async function resolveSession({ runtimeDir, service, env, ownClientPid,
54
- listBindings = listSessionBindings }) {
55
- if (!Number.isInteger(ownClientPid)) return null;
56
- const bindings = await listBindings({ runtimeDir });
57
- if (bindings.length === 0) return null;
58
- const status = await service.collectStatus({});
59
- const live = new Set(status.participants
60
- .filter(participant => participant.presence !== "offline")
61
- .map(participant => participant.sessionId));
62
- const mine = bindings.filter(binding => live.has(binding.accSessionId)
63
- && binding.clientPid === ownClientPid);
64
- // One client process can outlive a session and open another, so the pid alone
65
- // can still name two. The harness session id the client exports separates
66
- // them; with nothing to separate them the answer is nobody, as before.
67
- const exported = new Set(Object.values(env ?? {}).filter(value => typeof value === "string"));
68
- const matched = mine.filter(binding => exported.has(binding.harnessSessionId));
69
- const chosen = mine.length === 1 ? mine[0] : matched.length === 1 ? matched[0] : null;
70
- return chosen === null ? null
71
- : { sessionId: chosen.accSessionId, generation: chosen.generation, clientPid: chosen.clientPid };
72
- }
73
-
74
- /** The client process this Channel was spawned by, or null when nobody knows. */
75
- export async function ownClient({ table = null, from = process.pid,
76
- command = createClaudeCodeAdapter().client.command } = {}) {
77
- return resolveClientPid({ table: table ?? await readProcessTable(), from, command });
78
- }
79
-
80
- // How long the Channel will wait for the hook to publish this session's
81
- // binding. Claude spawns this child while SessionStart is still running - both
82
- // landed in the same second on a real 2.1.259 launch - and a single lookup
83
- // loses that race often enough to make native delivery activate or not per
84
- // launch. Bounded, because a session with no ACC binding must still be answered.
85
- const BINDING_WAIT_MS = 5_000;
86
- const BINDING_POLL_MS = 100;
87
-
88
- /**
89
- * The session binding, once it exists - or null when the wait runs out.
90
- *
91
- * A binding with no `clientPid` names no process, and the Channel binds an
92
- * exact one, so it does not count as resolved: the hook writes the identity
93
- * first and the certified facts after, and reading in between must keep waiting
94
- * rather than settle for the half-written answer.
95
- */
96
- export async function resolveWithin({ resolve, deadline, intervalMs = BINDING_POLL_MS,
97
- now = () => Date.now(), sleep = ms => new Promise(resolve_ => setTimeout(resolve_, ms)) }) {
98
- for (;;) {
99
- const session = await resolve();
100
- if (session !== null && Number.isInteger(session?.clientPid)) return session;
101
- if (now() >= deadline) return null;
102
- await sleep(intervalMs);
103
- }
104
- }
105
-
106
- async function main() {
107
- const descriptor = await discoverWorkspace({ cwd: process.cwd(), env: process.env,
108
- gitProbe: createGitProbe() });
109
- const paths = runtimePaths({ dataHome: platformDataHome({ platform: process.platform,
110
- env: process.env }), workspaceId: descriptor.id, workspaceRoots: descriptor.roots });
111
- const store = await openFilesystemStore({ root: paths.root, clock, ids,
112
- workspaceId: descriptor.id });
113
- const service = createCoordinationService({ store, clock, ids });
114
- const write = payload => process.stdout.write(`${JSON.stringify(payload)}\n`);
115
- // Read once: the ancestry that decides ownership cannot change while this
116
- // process runs, and re-reading it on every poll would spawn `ps` in a loop.
117
- const clientPid = await ownClient();
118
- const session = await resolveWithin({
119
- resolve: () => resolveSession({ runtimeDir: paths.root, service, env: process.env,
120
- ownClientPid: clientPid }),
121
- deadline: Date.now() + BINDING_WAIT_MS });
122
- // No binding to serve - but Claude is already speaking MCP to this child, and
123
- // returning here left the event loop empty: the process exited in 75ms
124
- // without answering `initialize`, and Claude reported the server as failed to
125
- // connect on every session that enables the plugin without ACC's shim.
126
- if (session === null || !Number.isInteger(session.clientPid)) {
127
- const inert = createInertChannel({ write });
128
- pump(inert.handleLine, () => process.exit(0));
129
- return inert;
130
- }
131
-
132
- const channel = createAccChannel({
133
- endpointDir: endpointDir(paths.root),
134
- clientPid: session.clientPid,
135
- write,
136
- routeReply: ({ messageId, body }) => routeReply({ service, session, messageId, body }),
137
- routeAck: ({ messageId }) => routeAck({ service, session, messageId }),
138
- // This process is the only party that knows the endpoint is still being
139
- // served, and Claude publishes no heartbeat, so nothing else would move
140
- // ACC's lease while the session sits idle - which is when live delivery is
141
- // worth having.
142
- refreshBinding: leaseUntil => service.refreshDeliveryBinding({
143
- sessionId: session.sessionId, generation: session.generation, leaseUntil }),
144
- });
145
- await channel.listen();
146
- pump(channel.handleLine, () => { channel.close(); process.exit(0); });
147
- return channel;
148
- }
149
-
150
- /** One line-delimited JSON pump, for the bound server and the unbound one alike. */
151
- function pump(handleLine, shutdown) {
152
- let buffer = "";
153
- process.stdin.setEncoding("utf8");
154
- process.stdin.on("data", async chunk => {
155
- buffer += chunk;
156
- let newline = buffer.indexOf("\n");
157
- while (newline !== -1) {
158
- const line = buffer.slice(0, newline).trim();
159
- buffer = buffer.slice(newline + 1);
160
- newline = buffer.indexOf("\n");
161
- if (line !== "") await handleLine(line);
162
- }
163
- });
164
- process.stdin.on("end", shutdown);
165
- process.once("SIGTERM", shutdown);
166
- process.once("SIGINT", shutdown);
167
- // Keeps the child answerable for as long as Claude holds the transport open.
168
- process.stdin.resume();
169
- }
170
-
171
- const invokedDirectly = typeof process.argv[1] === "string"
172
- && realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url));
173
- if (invokedDirectly) {
174
- // Fail open: a Channel that cannot compose is simply absent, never a crash in
175
- // front of the user's session.
176
- await main().catch(() => { process.stdin.resume(); });
177
- }
3
+ import { invokedDirectly, runEntry } from "@agents-can-communicate/cli/managed-entry";
4
+ export const resolveSession = async options => (await import("./entrypoints/acc-claude-channel.mjs")).resolveSession(options);
5
+ export const ownClient = async options => (await import("./entrypoints/acc-claude-channel.mjs")).ownClient(options);
6
+ export const resolveWithin = async options => (await import("./entrypoints/acc-claude-channel.mjs")).resolveWithin(options);
7
+
8
+ if (invokedDirectly(import.meta.url)) await runEntry({
9
+ kind: "acc-claude-channel", packageRoot: fileURLToPath(new URL("..", import.meta.url)),
10
+ });