agents-can-communicate 0.10.4 → 0.11.1

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 (98) hide show
  1. package/README.md +29 -21
  2. package/bin/acc-indicator.mjs +5 -0
  3. package/bin/entrypoints/acc-antigravity-relay.mjs +2 -2
  4. package/bin/entrypoints/acc-hook.mjs +4 -24
  5. package/bin/entrypoints/acc-mcp.mjs +8 -6
  6. package/bin/entrypoints/acc.mjs +22 -11
  7. package/bin/entrypoints/antigravity-relay-binding.mjs +1 -1
  8. package/docs/CAPABILITIES.md +3 -0
  9. package/docs/CLI.md +34 -7
  10. package/docs/MCP.md +42 -2
  11. package/docs/PROTOCOL.md +19 -0
  12. package/docs/STATUS_INDICATOR.md +133 -0
  13. package/docs/TROUBLESHOOTING.md +2 -2
  14. package/docs/WHY_ACC.md +14 -8
  15. package/node_modules/@agents-can-communicate/adapter-antigravity/package.json +1 -1
  16. package/node_modules/@agents-can-communicate/adapter-antigravity/plugin/plugin.json +1 -1
  17. package/node_modules/@agents-can-communicate/adapter-antigravity/plugin/skills/acc/SKILL.md +29 -5
  18. package/node_modules/@agents-can-communicate/adapter-antigravity/src/adapter.mjs +3 -0
  19. package/node_modules/@agents-can-communicate/adapter-antigravity/src/indicator-install.mjs +80 -0
  20. package/node_modules/@agents-can-communicate/adapter-antigravity/src/indicator-render.mjs +8 -0
  21. package/node_modules/@agents-can-communicate/adapter-antigravity/src/install.mjs +7 -4
  22. package/node_modules/@agents-can-communicate/adapter-claude-code/package.json +1 -1
  23. package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/hooks/indicator.mjs +83 -0
  24. package/node_modules/@agents-can-communicate/adapter-claude-code/plugin/skills/acc/SKILL.md +29 -5
  25. package/node_modules/@agents-can-communicate/adapter-claude-code/src/adapter.mjs +1 -0
  26. package/node_modules/@agents-can-communicate/adapter-claude-code/src/install.mjs +16 -5
  27. package/node_modules/@agents-can-communicate/adapter-codex/package.json +1 -1
  28. package/node_modules/@agents-can-communicate/adapter-codex/plugin/skills/acc/SKILL.md +29 -5
  29. package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/gemini-extension.json +1 -1
  30. package/node_modules/@agents-can-communicate/adapter-gemini-cli/extension/skills/acc/SKILL.md +29 -5
  31. package/node_modules/@agents-can-communicate/adapter-gemini-cli/package.json +1 -1
  32. package/node_modules/@agents-can-communicate/adapter-grok/package.json +1 -1
  33. package/node_modules/@agents-can-communicate/adapter-grok/plugin/skills/acc/SKILL.md +29 -5
  34. package/node_modules/@agents-can-communicate/adapter-grok/src/adapter.mjs +4 -0
  35. package/node_modules/@agents-can-communicate/adapter-grok/src/indicator-install.mjs +30 -0
  36. package/node_modules/@agents-can-communicate/adapter-grok/src/indicator.mjs +23 -0
  37. package/node_modules/@agents-can-communicate/adapter-grok/src/install.mjs +9 -5
  38. package/node_modules/@agents-can-communicate/adapter-kimi/package.json +1 -1
  39. package/node_modules/@agents-can-communicate/adapter-kimi/plugin/skills/acc/SKILL.md +29 -5
  40. package/node_modules/@agents-can-communicate/adapter-kimi/src/adapter.mjs +4 -0
  41. package/node_modules/@agents-can-communicate/adapter-kimi/src/indicator-install.mjs +30 -0
  42. package/node_modules/@agents-can-communicate/adapter-kimi/src/indicator.mjs +17 -0
  43. package/node_modules/@agents-can-communicate/adapter-kimi/src/install.mjs +12 -6
  44. package/node_modules/@agents-can-communicate/adapter-sdk/package.json +1 -1
  45. package/node_modules/@agents-can-communicate/adapter-sdk/src/hook-shim.mjs +1 -0
  46. package/node_modules/@agents-can-communicate/adapter-sdk/src/index.mjs +5 -1
  47. package/node_modules/@agents-can-communicate/adapter-sdk/src/indicator-command.mjs +14 -0
  48. package/node_modules/@agents-can-communicate/adapter-sdk/src/indicator-text.mjs +13 -0
  49. package/node_modules/@agents-can-communicate/adapter-sdk/src/native-attempt-writer.mjs +1 -1
  50. package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation-order.mjs +12 -0
  51. package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation-writer.mjs +37 -0
  52. package/node_modules/@agents-can-communicate/adapter-sdk/src/offer-observation.mjs +47 -0
  53. package/node_modules/@agents-can-communicate/adapter-sdk/src/process-table.mjs +40 -27
  54. package/node_modules/@agents-can-communicate/adapter-sdk/src/toml-indicator.mjs +141 -0
  55. package/node_modules/@agents-can-communicate/adapter-sdk/src/toml-scan.mjs +99 -0
  56. package/node_modules/@agents-can-communicate/cli/package.json +8 -1
  57. package/node_modules/@agents-can-communicate/cli/src/adapter-catalog.mjs +33 -0
  58. package/node_modules/@agents-can-communicate/cli/src/args.mjs +5 -3
  59. package/node_modules/@agents-can-communicate/cli/src/claim-command.mjs +64 -0
  60. package/node_modules/@agents-can-communicate/cli/src/help.mjs +17 -11
  61. package/node_modules/@agents-can-communicate/cli/src/index.mjs +1 -0
  62. package/node_modules/@agents-can-communicate/cli/src/indicator-command.mjs +65 -0
  63. package/node_modules/@agents-can-communicate/cli/src/indicator-previous-command.mjs +84 -0
  64. package/node_modules/@agents-can-communicate/cli/src/indicator-previous-windows.mjs +8 -0
  65. package/node_modules/@agents-can-communicate/cli/src/indicator.mjs +112 -0
  66. package/node_modules/@agents-can-communicate/cli/src/install-command.mjs +4 -0
  67. package/node_modules/@agents-can-communicate/cli/src/main.mjs +38 -110
  68. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/entry.mjs +19 -0
  69. package/node_modules/@agents-can-communicate/cli/src/managed-runtime/launchers.mjs +5 -3
  70. package/node_modules/@agents-can-communicate/cli/src/native-session-diagnostics.mjs +1 -1
  71. package/node_modules/@agents-can-communicate/cli/src/recorded-text.mjs +32 -0
  72. package/node_modules/@agents-can-communicate/core/package.json +1 -1
  73. package/node_modules/@agents-can-communicate/core/src/claim-selectors.mjs +62 -0
  74. package/node_modules/@agents-can-communicate/core/src/claims.mjs +88 -81
  75. package/node_modules/@agents-can-communicate/core/src/next-turn-delivery.mjs +2 -1
  76. package/node_modules/@agents-can-communicate/core/src/sessions.mjs +5 -2
  77. package/node_modules/@agents-can-communicate/core/src/sync.mjs +2 -1
  78. package/node_modules/@agents-can-communicate/delivery-router/package.json +1 -1
  79. package/node_modules/@agents-can-communicate/delivery-router/src/router.mjs +19 -7
  80. package/node_modules/@agents-can-communicate/hook-runner/package.json +1 -1
  81. package/node_modules/@agents-can-communicate/hook-runner/src/client-pid.mjs +23 -11
  82. package/node_modules/@agents-can-communicate/hook-runner/src/runner.mjs +66 -26
  83. package/node_modules/@agents-can-communicate/installer/package.json +3 -2
  84. package/node_modules/@agents-can-communicate/installer/src/apply.mjs +3 -0
  85. package/node_modules/@agents-can-communicate/installer/src/ownership.mjs +2 -1
  86. package/node_modules/@agents-can-communicate/installer/src/plan.mjs +11 -2
  87. package/node_modules/@agents-can-communicate/mcp-server/package.json +1 -1
  88. package/node_modules/@agents-can-communicate/mcp-server/src/claim-tools.mjs +56 -0
  89. package/node_modules/@agents-can-communicate/mcp-server/src/input-validator.mjs +9 -0
  90. package/node_modules/@agents-can-communicate/mcp-server/src/server.mjs +7 -8
  91. package/node_modules/@agents-can-communicate/mcp-server/src/tools.mjs +27 -9
  92. package/node_modules/@agents-can-communicate/protocol/package.json +1 -1
  93. package/node_modules/@agents-can-communicate/protocol/src/index.mjs +1 -0
  94. package/node_modules/@agents-can-communicate/storage-filesystem/package.json +3 -2
  95. package/node_modules/@agents-can-communicate/storage-filesystem/src/index.mjs +1 -1
  96. package/node_modules/@agents-can-communicate/storage-filesystem/src/session-read.mjs +13 -0
  97. package/node_modules/@agents-can-communicate/storage-filesystem/src/state-reads.mjs +24 -7
  98. package/package.json +3 -1
package/README.md CHANGED
@@ -3,9 +3,11 @@
3
3
  **The message your clients can’t send each other.**
4
4
 
5
5
  Claude Code can message your other Claude Code sessions, and Codex can queue a message for
6
- another Codex session. Neither client offers a way to message the other’s sessions. ACC
7
- carries questions, reviews and handoffs between sessions in different vendors’ clients, on
8
- your machine.
6
+ another Codex session. From Claude Code, OpenAI’s Codex plugin can ask Codex for a review,
7
+ hand it a task or move the conversation into Codex; it runs Codex under Claude Code, in that
8
+ direction only. Neither client offers a way to message a session you opened yourself in the
9
+ other one. ACC carries questions, reviews and handoffs between those sessions, in either
10
+ direction, on your machine.
9
11
 
10
12
  You open each client normally and choose its work. Every session keeps its own model,
11
13
  conversation, and permissions. Coordination runs locally, with no lead agent managing the
@@ -45,16 +47,17 @@ flowchart TB
45
47
 
46
48
  ## When ACC helps
47
49
 
48
- - **Get a second opinion from another vendor’s model.** Ask a Codex session to review a change
49
- your Claude Code session just made, and send its findings back to the session that wrote the
50
- code.
51
- - **Bring parallel features together.** Let sessions in different clients ask each other about
52
- a shared API before they build around different assumptions.
50
+ - **Run parallel work across clients.** Start each task in whichever client has limit left,
51
+ and let the sessions see who is working on what, ask each other about a shared API, and
52
+ agree who takes which issue before they build around different assumptions.
53
+ - **Get a second opinion from another vendor’s model, in either direction.** Ask a Codex
54
+ session you already have open to review a change your Claude Code session just made, and
55
+ send its findings back to the session that wrote the code; or let Codex ask Claude Code.
53
56
  - **Switch clients mid-feature.** When a limit approaches or another model suits the work
54
- better, leave a handoff with decisions and unfinished work for a session in the client you
55
- open next.
57
+ better, leave a handoff with decisions, unfinished work and what was verified, rather than a
58
+ transcript, for a session in the client you open next.
56
59
 
57
- ## Try one review across clients
60
+ ## Try one feature across two clients
58
61
 
59
62
  You’ll need **macOS, Linux or Windows 10/11, Node.js 24 or newer**, and supported coding
60
63
  clients on the same machine and operating-system user. On Windows, ACC runs natively, with no
@@ -70,24 +73,29 @@ The installer connects supported clients it finds. Follow its activation instruc
70
73
  any required hook or plugin trust, then restart your clients from the project directory. The
71
74
  [setup guide](docs/GETTING_STARTED.md) covers client-specific steps.
72
75
 
73
- Open Claude Code and Codex in the same project. After Claude Code has changed something, for
74
- example an account-registration form, ask it:
76
+ Open Claude Code and Codex in the same project and give each one its own part of one feature.
77
+ Ask Codex:
75
78
 
76
79
  ```text
77
- Ask the Codex session in ACC to review the registration form change
78
- you just made. Name the files and what it should check.
80
+ Add an account-registration endpoint.
79
81
  ```
80
82
 
81
- Then ask Codex:
83
+ And ask Claude Code:
82
84
 
83
85
  ```text
84
- Answer the review request in ACC. Read the files it names, check
85
- what it asks, and reply with what you found.
86
+ Build the account-registration screen.
86
87
  ```
87
88
 
88
- Codex should find the request without you pasting it, and Claude Code should see the findings
89
- at its next turn without you copying them back. The sender can check whether its message was
90
- delivered and answered.
89
+ Those are the whole prompts. Each session sees that the other is present and what it is
90
+ working on. When the screen needs the endpoint’s request and response shape, the Claude Code
91
+ session can ask the Codex session and get the answer at its next turn, without you carrying
92
+ it across; the sender can check whether its question was delivered and answered. The agents
93
+ decide when to coordinate; ACC does not guarantee they will notice every dependency.
94
+
95
+ The same channel carries a review: ask the session that made a change to request a review
96
+ from the other session in ACC, naming the files, and ask the other to answer it. The
97
+ [setup guide](docs/GETTING_STARTED.md#2-open-two-sessions-and-give-them-ordinary-tasks)
98
+ walks through both.
91
99
 
92
100
  ## Client support
93
101
 
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ // Deliberately outside runEntry: observation must not acquire a runtime lease,
3
+ // schedule updates or open/recover the coordination store.
4
+ import { runIndicator } from "@agents-can-communicate/cli/indicator";
5
+ await runIndicator();
@@ -11,11 +11,11 @@ import { createRelay } from "@agents-can-communicate/adapter-antigravity/relay";
11
11
  import { listRegistrations, newRelayId, relayDir } from "@agents-can-communicate/adapter-antigravity/relay-endpoint";
12
12
  import { findConversation, spawnRelay, startRelay } from "@agents-can-communicate/adapter-antigravity/relay-start";
13
13
  import { loadSessionBinding, readProcessArgs } from "@agents-can-communicate/adapter-sdk";
14
- import { platformDataHome } from "@agents-can-communicate/cli";
14
+ import { platformDataHome } from "@agents-can-communicate/cli/runtime-paths";
15
15
  import { createCoordinationService } from "@agents-can-communicate/core";
16
16
  import { resolveClientPid } from "@agents-can-communicate/hook-runner/client-pid";
17
17
  import { readProcessTable } from "@agents-can-communicate/hook-runner/process-table";
18
- import { readInstalledLivePolicy } from "@agents-can-communicate/installer";
18
+ import { readInstalledLivePolicy } from "@agents-can-communicate/installer/live-policy";
19
19
  import { createId } from "@agents-can-communicate/protocol";
20
20
  import { openFilesystemStore } from "@agents-can-communicate/storage-filesystem";
21
21
 
@@ -12,33 +12,13 @@ import { createId } from "@agents-can-communicate/protocol";
12
12
  import { runHook } from "@agents-can-communicate/hook-runner";
13
13
  import { hookEntrypointFor, resolvePinnedGeneration }
14
14
  from "@agents-can-communicate/cli/hook-support";
15
+ import { loadAdapters } from "@agents-can-communicate/cli/adapters";
15
16
 
16
17
  // A hook runs one client's adapter, and loads only that one: every other
17
18
  // adapter was a set of modules loaded on each turn and never run, about a
18
- // millisecond each on windows-latest.
19
- const ADAPTERS = {
20
- // Registered like any other client. Its hook commands carry an extra
21
- // argument - the event name - because this client's payload has none.
22
- antigravity: () => import("@agents-can-communicate/adapter-antigravity")
23
- .then(module => module.createAntigravityAdapter()),
24
- claude_code: () => import("@agents-can-communicate/adapter-claude-code")
25
- .then(module => module.createClaudeCodeAdapter()),
26
- codex: () => import("@agents-can-communicate/adapter-codex")
27
- .then(module => module.createCodexAdapter()),
28
- gemini_cli: () => import("@agents-can-communicate/adapter-gemini-cli")
29
- .then(module => module.createGeminiCliAdapter()),
30
- grok: () => import("@agents-can-communicate/adapter-grok")
31
- .then(module => module.createGrokAdapter()),
32
- kimi: () => import("@agents-can-communicate/adapter-kimi")
33
- .then(module => module.createKimiAdapter()),
34
- };
35
-
36
- // The adapters this hook can use: its own, or none for an id nobody registered,
37
- // which runHook answers the way it always has.
38
- async function adaptersFor(adapterId) {
39
- if (!Object.hasOwn(ADAPTERS, adapterId)) return {};
40
- return { [adapterId]: await ADAPTERS[adapterId]() };
41
- }
19
+ // millisecond each on windows-latest. An id nobody registered gets none, which
20
+ // runHook answers the way it always has.
21
+ const adaptersFor = adapterId => loadAdapters([adapterId]);
42
22
 
43
23
  const readStdin = () => new Promise(resolve => {
44
24
  // A hook is always given its payload on stdin, but a client that closes it
@@ -3,12 +3,14 @@ import { randomBytes } from "node:crypto";
3
3
 
4
4
  import { EXIT, createId } from "@agents-can-communicate/protocol";
5
5
  import { createCoordinationService } from "@agents-can-communicate/core";
6
- import { readInstalledLivePolicy } from "@agents-can-communicate/installer";
6
+ import { readInstalledLivePolicy } from "@agents-can-communicate/installer/live-policy";
7
7
  import { createDeliveryRouter } from "@agents-can-communicate/delivery-router";
8
8
  import { registerDiscoveredSessions } from "@agents-can-communicate/hook-runner";
9
9
  import { openFilesystemStore } from "@agents-can-communicate/storage-filesystem";
10
- import { ALL_ADAPTERS, createGitProbe, discoverWorkspace, platformDataHome, runtimePaths }
11
- from "@agents-can-communicate/cli";
10
+ import { loadAdapter, loadAdapters } from "@agents-can-communicate/cli/adapters";
11
+ import { createGitProbe } from "@agents-can-communicate/cli/git-probe";
12
+ import { platformDataHome, runtimePaths } from "@agents-can-communicate/cli/runtime-paths";
13
+ import { discoverWorkspace } from "@agents-can-communicate/cli/workspace-discovery";
12
14
  import { serve } from "@agents-can-communicate/mcp-server";
13
15
 
14
16
  export async function main({ managerRoot = null, packageRoot } = {}) {
@@ -46,7 +48,6 @@ const paths = runtimePaths({
46
48
  const store = await openFilesystemStore({ root: paths.root, clock, ids,
47
49
  workspaceId: descriptor.id });
48
50
  const service = createCoordinationService({ store, clock, ids });
49
- const adapters = Object.fromEntries(ALL_ADAPTERS().map(adapter => [adapter.id, adapter]));
50
51
 
51
52
  await serve({
52
53
  input: process.stdin,
@@ -54,14 +55,15 @@ await serve({
54
55
  log: message => process.stderr.write(`acc-mcp: ${message}\n`),
55
56
  context: {
56
57
  service,
57
- deliveryRouter: createDeliveryRouter({ service, adapters, clock,
58
+ // Each recipient's adapter loads with the first message routed to it (#270).
59
+ deliveryRouter: createDeliveryRouter({ service, loadAdapter, clock,
58
60
  readLivePolicy: ({ adapter }) => readInstalledLivePolicy({ dataHome,
59
61
  adapterId: adapter.id }) }),
60
62
  workspaceId: descriptor.id,
61
63
  participantId,
62
64
  descriptor,
63
65
  runtimeDir: paths.root,
64
- registerNativeSessions: () => registerDiscoveredSessions({ adapters,
66
+ registerNativeSessions: () => registerDiscoveredSessions({ loadAdapters,
65
67
  workspaceId: descriptor.id, dataHome, env: process.env }),
66
68
  },
67
69
  });
@@ -3,13 +3,26 @@ import { randomBytes } from "node:crypto";
3
3
  import { readFile } from "node:fs/promises";
4
4
 
5
5
  import { createId } from "@agents-can-communicate/protocol";
6
- import { readInstalledLivePolicy } from "@agents-can-communicate/installer";
7
- import { createDeliveryRouter } from "@agents-can-communicate/delivery-router";
8
- import { registerDiscoveredSessions } from "@agents-can-communicate/hook-runner";
9
- import { ALL_ADAPTERS, askConfirmation, main as runCli } from "@agents-can-communicate/cli";
6
+ import { loadAdapter, loadAdapters } from "@agents-can-communicate/cli/adapters";
7
+ import { askConfirmation } from "@agents-can-communicate/cli/confirm";
8
+ import { main as runCli } from "@agents-can-communicate/cli/main";
9
+
10
+ // A command loads what it uses: `acc version` no client adapter, store or
11
+ // router, and a message only its recipients' adapters (#270).
12
+ const lazyRouter = ({ service, clock, dataHome }) => {
13
+ let router;
14
+ return { offer: async message => {
15
+ router ??= Promise.all([import("@agents-can-communicate/delivery-router"),
16
+ import("@agents-can-communicate/installer/live-policy")])
17
+ .then(([{ createDeliveryRouter }, { readInstalledLivePolicy }]) =>
18
+ createDeliveryRouter({ service, loadAdapter, clock,
19
+ readLivePolicy: ({ adapter }) => readInstalledLivePolicy({ dataHome,
20
+ adapterId: adapter.id }) }));
21
+ return (await router).offer(message);
22
+ } };
23
+ };
10
24
 
11
25
  export async function main({ managerRoot = null, packageRoot, managementOnly = false } = {}) {
12
- const adapters = Object.fromEntries(ALL_ADAPTERS().map(adapter => [adapter.id, adapter]));
13
26
 
14
27
  // The composition root is the only place allowed to reach for ambient time and
15
28
  // randomness; everything below it receives them as ports.
@@ -24,14 +37,12 @@ const runtime = {
24
37
  stderr: process.stderr,
25
38
  clock: { now: () => new Date().toISOString() },
26
39
  ids: { next: kind => createId(kind, randomBytes) },
27
- createDeliveryRouter: ({ service, clock, dataHome }) =>
28
- createDeliveryRouter({ service, adapters, clock,
29
- readLivePolicy: ({ adapter }) => readInstalledLivePolicy({ dataHome,
30
- adapterId: adapter.id }) }),
40
+ createDeliveryRouter: lazyRouter,
31
41
  // Chats a client holds before their first turn, registered before status
32
42
  // is read so a peer can address them (#167).
33
- registerNativeSessions: ({ workspaceId, dataHome }) =>
34
- registerDiscoveredSessions({ adapters, workspaceId, dataHome, env: process.env }),
43
+ registerNativeSessions: async ({ workspaceId, dataHome }) =>
44
+ (await import("@agents-can-communicate/hook-runner")).registerDiscoveredSessions({
45
+ loadAdapters, workspaceId, dataHome, env: process.env }),
35
46
  // Asked only by `acc config init`, and only when stdout is a terminal. There
36
47
  // was no port here at all, so the question went to the fallback that always
37
48
  // answers no: in a real terminal the command printed "not written" and never
@@ -3,7 +3,7 @@ import { loadSessionBinding, storeNativeAttempt } from "@agents-can-communicate/
3
3
  import { createCoordinationService } from "@agents-can-communicate/core";
4
4
  import { establishNativeBinding } from "@agents-can-communicate/hook-runner/native-binding";
5
5
  import { withSessionLifecycle } from "@agents-can-communicate/hook-runner/session-lifecycle";
6
- import { readInstalledLivePolicyState } from "@agents-can-communicate/installer";
6
+ import { readInstalledLivePolicyState } from "@agents-can-communicate/installer/live-policy";
7
7
  import { openFilesystemStore } from "@agents-can-communicate/storage-filesystem";
8
8
 
9
9
  // No hook runs when the agent starts a relay mid-turn, and the next
@@ -28,6 +28,9 @@ Run `acc doctor` in the project when observed behavior differs from this page. I
28
28
  the installed client version, platform, effective capability, and fallback instead of
29
29
  assuming that a newer or differently packaged client behaves like a captured one.
30
30
 
31
+ The optional [ACC indicator](STATUS_INDICATOR.md) shows this chat's reception mode and
32
+ known failures in supported client footers. It reads local state; it is not a transport probe.
33
+
31
34
  ## Certified support
32
35
 
33
36
  Each column names the version that recorded the capture, on `darwin-arm64`. Every later
package/docs/CLI.md CHANGED
@@ -37,8 +37,8 @@ option value remains data: `--body --help` sends the literal body `--help`.
37
37
  | `acc status` | — | `--session`, `--generation`, `--participant`, `--all` |
38
38
  | `acc sync` | — | `--session`, `--generation`, `--cursor`, `--limit`, `--scope delta|full|history`, `--type`, `--message`, `--current` |
39
39
  | `acc work` | `--summary` unless `--clear` | `--session`, `--generation`, `--mode`, `--state`, repeated `--hint`, `--clear` |
40
- | `acc claim` | `--resource` | `--session`, `--generation`, `--mode`, `--enforcement`, `--reason`, `--lease` |
41
- | `acc release` | `--claim` or `--resource` | `--session`, `--generation`, `--authority` (`human` or `policy`), `--reason` |
40
+ | `acc claim` | one or more `--resource` | `--session`, `--generation`, `--mode`, `--enforcement`, `--reason`, `--lease` |
41
+ | `acc release` | exactly one selector family: repeated `--claim`, repeated `--resource`, or `--all` | `--session`, `--generation`, `--authority` (`human` or `policy`, single target only), `--reason` |
42
42
  | `acc message` | `--subject`, `--body` | repeated `--to`, `--supersedes` or `--withdraws`, `--type`, `--obligation`, `--client-message-id`, owner flags |
43
43
  | `acc request` | `--to`, `--title` | `--detail`, `--client-message-id`, owner flags |
44
44
  | `acc inbox` | — | `--message`, `--cursor`, `--limit`, owner flags |
@@ -175,6 +175,12 @@ held.
175
175
  ```bash
176
176
  acc claim --resource 'file:packages/core/**' --reason "editing receipt logic"
177
177
  acc release --resource 'file:packages/core/**'
178
+
179
+ acc claim --resource 'file:packages/core/**' \
180
+ --resource 'file:packages/protocol/**' --reason "updating claim validation"
181
+ acc release --resource 'file:packages/core/**' \
182
+ --resource 'file:packages/protocol/**'
183
+ acc release --all
178
184
  ```
179
185
 
180
186
  File resources use repository-relative paths. A directory claim ends in `/**`. The example
@@ -182,10 +188,31 @@ creates an advisory claim: omitted `--enforcement` always means `advisory`, even
182
188
  certified clients. Request `--enforcement guarded` explicitly when needed; an incapable
183
189
  live participant still downgrades workspace protection. MCP claims are always advisory.
184
190
 
185
- Exit code `5` means a conflict. Ordinary sessions release only their own claims. Releasing
186
- another owner's claim requires `--authority human` or `--authority policy`, identifying the
187
- actual human decision or approved policy that permits the release; explain it with
188
- `--reason`. A peer's request alone is not force-release authority.
191
+ Repeat `--resource` to acquire several claims atomically. The shared mode, enforcement,
192
+ reason, and lease apply to every resource. ACC rejects duplicate resources after
193
+ normalization. A conflict exits `5` without creating any claims or renewing existing ones.
194
+ Batch error `details.conflicts` identifies each blocked requested resource and its holders.
195
+ Repeating a successful claim command renews this session's existing claims on those resources.
196
+
197
+ Release accepts exactly one selector family: one or more `--resource`, one or more
198
+ `--claim`, or `--all`. Duplicate selectors after normalization are rejected.
199
+ Ordinary explicit targets must exist and belong to this session. A missing or foreign
200
+ target fails the whole release without removing any claims. Repeating an explicit
201
+ release after its targets were removed remains an error.
202
+
203
+ `--all` releases only this session's claims in the selected workspace. An empty set
204
+ succeeds, including for a solo ephemeral session. It selects the current owned set on
205
+ each call, so a retry can release claims acquired since the first call. Release keeps
206
+ the session and intent open. `work --clear` clears intent, `ack` acknowledges a message,
207
+ and `finish` records a handoff and closes presence.
208
+
209
+ With `--json`, one acquisition returns a claim record as `data`; one release returns
210
+ `data: {claimId}`. Multiple resources return `data: {claims: [...]}`. Multiple release
211
+ selectors and `--all` return `data: {claimIds: [...]}`.
212
+
213
+ A single target can still use `--authority human` or `--authority policy` to release
214
+ another owner's claim. Name the actual human decision or approved policy with `--reason`.
215
+ Batch release and `--all` reject authority. A peer's request alone is not force-release authority.
189
216
 
190
217
  ### Messages and requests
191
218
 
@@ -360,7 +387,7 @@ before leaving, request the concrete continuation and obtain a substantive reply
360
387
 
361
388
  | Command | Flags |
362
389
  |---|---|
363
- | `acc install` | `--adapter`, `--home`, `--delivery off|actionable|all`, `--dry-run`, `--downgrade` |
390
+ | `acc install` | `--adapter`, `--home`, `--delivery off|actionable|all`, `--indicator on|off`, `--dry-run`, `--downgrade` |
364
391
  | `acc uninstall` | `--adapter`, `--home`, `--dry-run` |
365
392
  | `acc doctor` | `--home`, `--repair`, `--migrate-store` |
366
393
  | `acc config init` | `--yes`, `--force` |
package/docs/MCP.md CHANGED
@@ -50,8 +50,8 @@ successfully yet refuse tool calls; that is distinct from a protocol handshake f
50
50
  | `acc_status` | — | — |
51
51
  | `acc_sync` | — | `cursor`, `scope: delta|full|history`, `limit: 1..500`, `kind`, `messageId`, `current` |
52
52
  | `acc_work` | `summary` and `mode`, or `clear: true` | `state`, `resourceHints` |
53
- | `acc_claim` | `action`; `resource` for acquire, `claimId` for renew | `mode`, `reason`, `leaseSeconds` where valid |
54
- | `acc_release` | `claimId` | — |
53
+ | `acc_claim` | `action`; exactly one of `resource` or `resources` for acquire, `claimId` for renew | `mode`, `reason`, `leaseSeconds` where valid |
54
+ | `acc_release` | exactly one of `claimId`, `claimIds`, `resource`, `resources`, or `all: true` | — |
55
55
  | `acc_message` | `to`, `subject`, `body` | `kind`, `obligation`, `clientMessageId`, `supersedes`, `withdraws` |
56
56
  | `acc_request` | `toParticipantId`, `title` | `detail`, `clientMessageId` |
57
57
  | `acc_inbox` | — | `messageId`, `cursor`, `limit: 1..500` |
@@ -108,6 +108,46 @@ session that has not joined, omit `toParticipantId` to leave a workspace handoff
108
108
  session can recover that historical handoff through the history list and exact read;
109
109
  its addressed inbox will not contain past workspace broadcasts.
110
110
 
111
+ ## Acquire and release claims
112
+
113
+ Acquire one resource with `acc_claim {action: "acquire", resource: "file:src/a.mjs"}`.
114
+ Use a nonempty `resources` array for an atomic batch:
115
+
116
+ ```json
117
+ {
118
+ "action": "acquire",
119
+ "resources": ["file:src/a.mjs", "file:src/b.mjs"],
120
+ "mode": "exclusive",
121
+ "reason": "updating both modules",
122
+ "leaseSeconds": 1800
123
+ }
124
+ ```
125
+
126
+ Shared mode, reason, and lease apply to every resource. Duplicate resources after
127
+ normalization are rejected. A conflict changes no claims, including existing leases.
128
+ Batch error `details.conflicts` identifies each blocked requested resource and its holders.
129
+ Repeating acquisition renews this session's existing claims on those resources.
130
+ `action: "renew"` still accepts only one `claimId` and its optional lease.
131
+
132
+ Release uses one mutually exclusive selector: `claimId`, a nonempty `claimIds` array,
133
+ `resource`, a nonempty `resources` array, or `all: true`. For example,
134
+ `acc_release {resources: ["file:src/a.mjs", "file:src/b.mjs"]}` releases both claims atomically.
135
+ Duplicate selectors after normalization are rejected. Explicit targets must exist and
136
+ belong to this session. A missing or foreign target fails without removing any claims.
137
+ MCP offers no force-release authority.
138
+
139
+ `acc_release {all: true}` releases only this session's current claims in its workspace.
140
+ An empty set succeeds, including for a solo ephemeral session. Release keeps the session
141
+ and intent open. `acc_work {clear: true}` clears intent, `acc_ack` acknowledges a message,
142
+ and `acc_finish` records a handoff and closes presence.
143
+
144
+ Scalar acquisition returns the existing Claim. Scalar release returns `{released: claimId}`.
145
+ Array acquisition returns `{claims: [...]}`. Array release and `all: true` return
146
+ `{released: [...]}`. Array inputs keep these shapes even with one element.
147
+ `all: true` can return `{released: []}`.
148
+ Repeating an explicit release after its targets were removed remains an error.
149
+ Each `all: true` call selects the current owned set, so a retry can release newly acquired claims.
150
+
111
151
  ## Account for the manual boundary
112
152
 
113
153
  The generic MCP capability declaration is all false:
package/docs/PROTOCOL.md CHANGED
@@ -45,6 +45,25 @@ exclusive mode, advisory or guarded enforcement, reason, and lease timestamps. C
45
45
  acquisition and conflict detection are atomic. Presence becoming stale never releases a
46
46
  claim; expiry or an explicit release does.
47
47
 
48
+ Batch acquisition validates a nonempty resource list before writing. Duplicate resources
49
+ after normalization are rejected. Mode, enforcement, reason, and lease apply to the whole
50
+ batch. If any requested resource conflicts, no claim is created or renewed. Batch error
51
+ `details.conflicts` lists the blocked requested resources and their blocking claims.
52
+ A successful repeated acquisition renews the owner's existing claims on those resources.
53
+
54
+ Batch release selects claims by IDs, canonical resources, or the calling session's whole
55
+ owned set. Exactly one selector family is accepted. Explicit selectors must be nonempty
56
+ and unique after normalization. A missing or foreign target prevents every removal.
57
+ The whole-set selector releases only that session's claims in its workspace and succeeds
58
+ when the set is empty, including for a solo ephemeral session. Batch release has no
59
+ force-release authority. The existing single-claim human or policy release remains separate.
60
+
61
+ Explicit release retries still fail once their targets were removed. A whole-set retry
62
+ selects the current owned set, which can include claims acquired after the first call.
63
+ Release keeps the session and intent open. Clearing intent, acknowledging messages, and
64
+ finishing with a handoff remain separate operations. Batch operations retain individual
65
+ claim records and per-claim events. They add no record schema or event type.
66
+
48
67
  ## Message envelope
49
68
 
50
69
  Every message contains:
@@ -0,0 +1,133 @@
1
+ # The ACC indicator
2
+
3
+ The indicator describes incoming messages for the current chat. It does not describe
4
+ other chats, confirm that a message was read, or promise when an agent will answer.
5
+
6
+ In Claude Code, only the status glyph carries color: green for `●`, warning color for
7
+ `!`, and neutral for `…`. All supported clients use the same fixed green (`#2c7a39`) for
8
+ `●`, without dimming. Claude uses its theme for the other states. The name
9
+ and `turn`/`inbox` qualifier keep the ordinary footer color. No background is added.
10
+
11
+ Antigravity's command emits ANSI foreground color around only the glyph, even when
12
+ stdout is a pipe. Existing installed commands need no new arguments. `--json` and
13
+ `--details` keep their plain, uncolored output.
14
+
15
+ | Display | Meaning |
16
+ |---|---|
17
+ | `ACC ●` | ACC is active. This chat has an automatic delivery binding with no newer recorded failure. A busy client can queue a request. |
18
+ | `ACC ● · turn` | ACC is active. Messages arrive on the next normal turn. |
19
+ | `ACC ● · inbox` | ACC is active. The agent reads messages through `acc inbox`. This does not imply a polling schedule. |
20
+ | `ACC …` | The Claude indicator is reading state or waiting up to five seconds for startup hooks. Failed reads keep it until a read answers or three reads in a row fail. |
21
+ | `ACC ! · turn` or `ACC ! · inbox` | ACC observed a failure. The qualifier names the remaining reception path. |
22
+ | `ACC !` | The chat is not registered, or the indicator cannot read its state. |
23
+
24
+ An unsupported wake-up capability is a normal `turn` or `inbox` mode. A failure of an
25
+ expected automatic channel retains `!`; it does not silently become a normal fallback.
26
+ The current `--delivery off` setting also uses the normal fallback. Details explain that
27
+ setting. Enabling the indicator does not enable automatic delivery or change its consent.
28
+
29
+ An idle chat does not lose its indicator because its heartbeat or delivery lease is old.
30
+ The sender verifies and renews an expired lease when it next attempts delivery. The badge
31
+ uses local observations. It does not test the endpoint on each refresh. Lease validity is
32
+ available in JSON as `leaseCurrent`, separately from reception and health.
33
+ Offer diagnostics are published separately from delivery. A slow diagnostic write
34
+ does not hold up offers to the next participant or change delivery receipts.
35
+
36
+ ## Enable or disable
37
+
38
+ ```sh
39
+ acc install --adapter claude_code --indicator on
40
+ acc install --adapter antigravity --indicator on
41
+ acc install --adapter kimi --indicator on
42
+ acc install --adapter grok --indicator on
43
+ acc install --adapter claude_code --indicator off
44
+ ```
45
+
46
+ The initial preference is off. A later install or automatic update keeps the saved choice
47
+ when `--indicator` is omitted. `--dry-run` makes no changes. Normal uninstall removes the
48
+ indicator and keeps status-line settings that the user changed.
49
+
50
+ ## Client surfaces
51
+
52
+ | Client | Integration and limits |
53
+ |---|---|
54
+ | Claude Code | From 2.1.287: a plugin mod adds a native footer label. It does not change `settings.statusLine`. Use `/reload-plugins` in an open session after installing. Client policy can disable mods. |
55
+ | Antigravity CLI | A status-line command adds ACC below the built-in line. If a custom command exists, ACC passes it the original stdin and appends the badge. Existing padding and stacking choices remain. Start a new CLI session after changing settings. |
56
+ | Codex and Gemini CLI | No automatic indicator installation. Their native status lines do not expose this command surface. |
57
+ | Kimi Code | From 2.1.1: compose one line with the existing custom command, or available mode/model/cwd/branch fields. Run `/reload-tui`. The native context/warnings line remains. |
58
+ | Grok | From 1.0.46: compose the optional status row with the existing command, or configured built-in items. ACC adds idle refresh once per second unless an interval is already configured. Start a new Grok session. |
59
+ | Other hosts | A host that provides the native session id can run `acc-indicator` as a custom widget. This does not certify that host's UI integration. |
60
+
61
+ Claude prints one diagnostic when a new problem appears. `/acc-status` shows the current
62
+ explanation and recovery step without a model request. Healthy refreshes do not print
63
+ messages. A read that fails or does not answer describes the indicator, not the chat.
64
+ The badge keeps the last observed state until three reads in a row fail; only then
65
+ does it show `!` and print the diagnostic. A slow read says so and does not suggest
66
+ reinstalling, because a reinstall cannot make a busy machine answer sooner. Antigravity's command surface has no equivalent notification: only a problem
67
+ adds `acc doctor` to the compact line. Run that command in the project for diagnostics.
68
+
69
+ The Antigravity wrapper runs an existing enabled command with a 700 ms limit and a 64 KiB
70
+ output limit. A disabled old command stays disabled. Disabling ACC restores only the
71
+ fields ACC changed and still owns. A user replacement command takes precedence.
72
+ Removing or replacing Antigravity's ACC command also survives repeated updates.
73
+ To add ACC again after that edit, disable the indicator and then enable it.
74
+
75
+ On POSIX, timeout, output overflow and indicator cancellation stop the previous
76
+ command's owned process group. Windows uses a detached Node launcher because a
77
+ detached shell loses its standard input handles. The launcher starts a hidden shell
78
+ with the original stdin/stdout. ACC stops the launcher and its descendants with
79
+ `taskkill /T /F`. Scripts that leave background processes
80
+ running after the shell exits must stop those processes themselves on Windows.
81
+
82
+ ## Kimi and Grok composition
83
+
84
+ ACC puts its compact badge first so a narrow terminal cannot truncate it behind a long
85
+ path. Existing custom commands receive the original stdin. Kimi keeps their first output
86
+ line; Grok retains the remaining lines. Disabling or uninstalling restores the old command
87
+ and only the presentation fields ACC still owns. A later user replacement takes precedence.
88
+
89
+ Kimi passes `sessionId`; Grok passes `session_id`. An empty Kimi ID is its welcome screen,
90
+ before a session exists, so ACC retains the footer without a registration error.
91
+ A registered Kimi normally shows `ACC ● · turn`; Grok shows `ACC ● · inbox`.
92
+
93
+ Kimi's snapshot does not expose goals, background task counts, thinking effort, swarm/tower
94
+ badges, detailed Git status, or rotating tips. These first-line elements cannot be retained
95
+ when composing the built-in footer; the native context/warnings line remains. Existing
96
+ custom commands can retain any extra information they already render. Kimi limits the entire
97
+ command to 300 ms; ACC bounds its own work to 180 ms after module loading and the previous
98
+ command to 80 ms. A host timeout can retain the last line until a successful refresh.
99
+
100
+ TOML comments and unrelated settings are retained. Ambiguous inline status tables or dotted
101
+ status declarations are refused without rewriting them; use a normal `[status_line]` or
102
+ `[ui.status_line]` table. The version floors above reflect native UI captures, not new
103
+ message-delivery certification.
104
+
105
+ ## Read-only command
106
+
107
+ ```sh
108
+ printf '%s' '{"session_id":"native-session-id"}' | acc-indicator --adapter claude_code
109
+ acc-indicator --adapter claude_code --native-session native-session-id --details
110
+ acc-indicator --adapter claude_code --native-session native-session-id --json
111
+ ```
112
+
113
+ Antigravity supplies `conversation_id`; `session_id` is also accepted. The reader selects
114
+ the saved room for that adapter and native id. It never guesses from the current directory
115
+ or scans other sessions. Output contains no generation token, endpoint, or message body.
116
+
117
+ The reader does not acquire a runtime lease, schedule updates, create a workspace,
118
+ recover a journal, send a heartbeat, renew delivery, or contact a client socket. The
119
+ managed launcher resolves the active runtime on each call. A concurrent update can cause
120
+ one failed read; a later refresh can recover without retaining the outgoing generation.
121
+
122
+ The router publishes an optional, bounded observation after a transport accepts or rejects
123
+ a send. For records with equal timestamps, a delayed older write cannot replace a newer
124
+ success or failure.
125
+ The indicator compares the resulting observation with the latest hook handshake for the same generation.
126
+ This diagnostic contains only time, outcome, and a closed reason code. Delivery receipts
127
+ and immutable history remain authoritative. An unavailable diagnostic cannot fail a send.
128
+
129
+ An unreadable state produces a closed error and a recovery command. It never renders raw
130
+ file content. A command stops waiting after 1.5 seconds. Claude refreshes every five seconds,
131
+ with one-second checks during its bounded startup period. Claude allows each read five
132
+ seconds: on a loaded machine the command's own start took up to 1.3 seconds inside
133
+ Claude, before its 1.5-second wait begins.
@@ -212,8 +212,8 @@ per-session lines in `acc doctor`, or `nativeDelivery.sessions[].lastAttempt` in
212
212
 
213
213
  - An absent or `off` policy means the installation record has no live-delivery consent
214
214
  for that client. Run `acc install --adapter <adapter> --delivery actionable` (or `all`).
215
- - `client_process_unknown` means ACC could not identify the client process. A new client
216
- session repeats that lookup.
215
+ - `client_process_unknown` means ACC could not identify the client process, for example
216
+ when a loaded machine slowed the lookup at session start. Each later prompt repeats it.
217
217
  - For Claude Code, `native_endpoint_unavailable` means the hook environment had no
218
218
  `CLAUDE_CODE_MESSAGING_SOCKET`, or the socket failed ACC's safety checks.
219
219
  `native_session_unavailable` means the session registry is missing or names another
package/docs/WHY_ACC.md CHANGED
@@ -3,11 +3,14 @@
3
3
  ACC fits work that spans clients from different vendors. Claude Code sessions can message
4
4
  each other through Claude Code's
5
5
  [cross-session messaging](https://code.claude.com/docs/en/cross-session-messaging), and
6
- `codex queue` queues a message for another Codex session. Neither client offers a way to
7
- message the other's sessions. When you ask another vendor's model for a review,
8
- build related features in two clients, or switch clients in the middle of a feature, the
9
- sessions need to ask and answer each other without making you carry every sentence between
10
- windows.
6
+ `codex queue` queues a message for another Codex session. From Claude Code,
7
+ [OpenAI's Codex plugin](https://github.com/openai/codex-plugin-cc) can ask Codex for a
8
+ review, hand it a task, or move the conversation into a Codex thread; it runs Codex under
9
+ Claude Code, in that direction only, and Codex can import Claude Code sessions the same way.
10
+ Neither client offers a way to message a session you opened yourself in the other one. When
11
+ you build related features in two clients, ask another vendor's model for a review from either
12
+ side, or switch clients in the middle of a feature, the sessions need to ask and answer each
13
+ other without making you carry every sentence between windows.
11
14
 
12
15
  Each session keeps its own context, permissions, checkout, and model.
13
16
 
@@ -22,7 +25,9 @@ resources, and hand off context.
22
25
  ```mermaid
23
26
  flowchart TD
24
27
  A["Do all your sessions run in Claude Code, or all in Codex?"] -->|yes| V["Try the client's own messaging first"]
25
- A -->|no| B["Must they keep separate ownership and permissions?"]
28
+ A -->|no| A2["Do you only need Claude Code to call Codex for a review, a task or a handoff?"]
29
+ A2 -->|yes| P["OpenAI's Codex plugin for Claude Code does that from inside Claude Code"]
30
+ A2 -->|no| B["Must they keep separate ownership and permissions?"]
26
31
  B -->|no| M["A managed agent runtime may fit better"]
27
32
  B -->|yes| C["Do they need direct questions, durable replies, or claim awareness?"]
28
33
  C -->|yes| Y["ACC fits this workflow"]
@@ -58,8 +63,9 @@ session that is not polling for anything. For clients without an integration, AC
58
63
  own [MCP server](MCP.md); without hooks, the agent there reads its inbox when it chooses to.
59
64
 
60
65
  Claude Code documents its inbox socket for scripts and hooks, and `codex queue` is a command
61
- any process can run, so two sessions can be wired together by hand. What that leaves to you is
62
- what ACC does: one list of peers across clients, so a session finds the other without a socket
66
+ any process can run, so two sessions can be wired together by hand. OpenAI's plugin covers one
67
+ direction, Claude Code calling Codex, with Codex started under Claude Code. What that leaves to
68
+ you is what ACC does: one list of peers across clients, so a session finds the other without a socket
63
69
  path or a thread id; a reply that returns to the sender in its own client; messages and
64
70
  handoffs kept for a session that is closed or not open yet; receipts that show what happened
65
71
  to each message; and instructions installed in each client, so agents use it without being
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-antigravity",
3
- "version": "0.10.4",
3
+ "version": "0.11.1",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "acc",
3
- "version": "0.10.4",
3
+ "version": "0.11.1",
4
4
  "description": "Coordinate this Antigravity CLI session with other AI agent sessions working in the same workspace."
5
5
  }