@sentropic/h2a 0.98.5 → 0.98.7-rc.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 (225) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/dist/cli-command-map.d.ts.map +1 -1
  4. package/dist/cli-command-map.js +1 -0
  5. package/dist/cli-command-map.js.map +1 -1
  6. package/dist/cli-contract.js +2 -2
  7. package/dist/cli-contract.js.map +1 -1
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +224 -16
  10. package/dist/cli.js.map +1 -1
  11. package/dist/hosts/agy.js +1 -1
  12. package/dist/hosts/agy.js.map +1 -1
  13. package/dist/hosts/installation-doctor.d.ts +1 -0
  14. package/dist/hosts/installation-doctor.d.ts.map +1 -1
  15. package/dist/hosts/installation-doctor.js +1 -1
  16. package/dist/hosts/installation-doctor.js.map +1 -1
  17. package/dist/hosts/muse.d.ts.map +1 -1
  18. package/dist/hosts/muse.js +2 -4
  19. package/dist/hosts/muse.js.map +1 -1
  20. package/dist/hosts/native-artifacts.d.ts +33 -0
  21. package/dist/hosts/native-artifacts.d.ts.map +1 -0
  22. package/dist/hosts/native-artifacts.js +104 -0
  23. package/dist/hosts/native-artifacts.js.map +1 -0
  24. package/dist/hosts/native-catalog.d.ts +19 -0
  25. package/dist/hosts/native-catalog.d.ts.map +1 -0
  26. package/dist/hosts/native-catalog.js +14 -0
  27. package/dist/hosts/native-catalog.js.map +1 -0
  28. package/dist/hosts/native-convergence.d.ts +132 -0
  29. package/dist/hosts/native-convergence.d.ts.map +1 -0
  30. package/dist/hosts/native-convergence.js +86 -0
  31. package/dist/hosts/native-convergence.js.map +1 -0
  32. package/dist/hosts/native-files.d.ts +40 -0
  33. package/dist/hosts/native-files.d.ts.map +1 -0
  34. package/dist/hosts/native-files.js +131 -0
  35. package/dist/hosts/native-files.js.map +1 -0
  36. package/dist/hosts/native-inspection.d.ts +31 -0
  37. package/dist/hosts/native-inspection.d.ts.map +1 -0
  38. package/dist/hosts/native-inspection.js +79 -0
  39. package/dist/hosts/native-inspection.js.map +1 -0
  40. package/dist/hosts/native-paths.d.ts +11 -0
  41. package/dist/hosts/native-paths.d.ts.map +1 -0
  42. package/dist/hosts/native-paths.js +21 -0
  43. package/dist/hosts/native-paths.js.map +1 -0
  44. package/dist/hosts/native-proof.d.ts +32 -0
  45. package/dist/hosts/native-proof.d.ts.map +1 -0
  46. package/dist/hosts/native-proof.js +31 -0
  47. package/dist/hosts/native-proof.js.map +1 -0
  48. package/dist/hosts/native-runtime-record.d.ts +3 -0
  49. package/dist/hosts/native-runtime-record.d.ts.map +1 -0
  50. package/dist/hosts/native-runtime-record.js +60 -0
  51. package/dist/hosts/native-runtime-record.js.map +1 -0
  52. package/dist/hosts/native-skills.d.ts +24 -0
  53. package/dist/hosts/native-skills.d.ts.map +1 -0
  54. package/dist/hosts/native-skills.js +56 -0
  55. package/dist/hosts/native-skills.js.map +1 -0
  56. package/dist/hosts/native-toml.d.ts +18 -0
  57. package/dist/hosts/native-toml.d.ts.map +1 -0
  58. package/dist/hosts/native-toml.js +91 -0
  59. package/dist/hosts/native-toml.js.map +1 -0
  60. package/dist/hosts/operator-notices.d.ts +3 -0
  61. package/dist/hosts/operator-notices.d.ts.map +1 -0
  62. package/dist/hosts/operator-notices.js +31 -0
  63. package/dist/hosts/operator-notices.js.map +1 -0
  64. package/dist/hosts/plugin.d.ts.map +1 -1
  65. package/dist/hosts/plugin.js +3 -2
  66. package/dist/hosts/plugin.js.map +1 -1
  67. package/dist/hosts/upgrade-equipment.d.ts +42 -0
  68. package/dist/hosts/upgrade-equipment.d.ts.map +1 -0
  69. package/dist/hosts/upgrade-equipment.js +26 -0
  70. package/dist/hosts/upgrade-equipment.js.map +1 -0
  71. package/dist/hosts/vibe-discovery.d.ts +12 -0
  72. package/dist/hosts/vibe-discovery.d.ts.map +1 -0
  73. package/dist/hosts/vibe-discovery.js +33 -0
  74. package/dist/hosts/vibe-discovery.js.map +1 -0
  75. package/dist/hosts/vibe-equipment.d.ts +71 -0
  76. package/dist/hosts/vibe-equipment.d.ts.map +1 -0
  77. package/dist/hosts/vibe-equipment.js +162 -0
  78. package/dist/hosts/vibe-equipment.js.map +1 -0
  79. package/dist/hosts/vibe-mcp.d.ts +32 -0
  80. package/dist/hosts/vibe-mcp.d.ts.map +1 -0
  81. package/dist/hosts/vibe-mcp.js +210 -0
  82. package/dist/hosts/vibe-mcp.js.map +1 -0
  83. package/dist/hosts/vibe.d.ts +12 -3
  84. package/dist/hosts/vibe.d.ts.map +1 -1
  85. package/dist/hosts/vibe.js +15 -7
  86. package/dist/hosts/vibe.js.map +1 -1
  87. package/dist/index.d.ts +2 -1
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +2 -1
  90. package/dist/index.js.map +1 -1
  91. package/dist/runtime/drive/consent.d.ts +1 -1
  92. package/dist/runtime/drive/consent.d.ts.map +1 -1
  93. package/dist/runtime/drive/consent.js +2 -2
  94. package/dist/runtime/drive/consent.js.map +1 -1
  95. package/dist/runtime/drive/index.d.ts +1 -1
  96. package/dist/runtime/drive/index.d.ts.map +1 -1
  97. package/dist/runtime/drive/index.js +3 -1
  98. package/dist/runtime/drive/index.js.map +1 -1
  99. package/dist/runtime/drumbeat/relaunchers.d.ts +1 -1
  100. package/dist/runtime/drumbeat/relaunchers.d.ts.map +1 -1
  101. package/dist/runtime/drumbeat/relaunchers.js +2 -1
  102. package/dist/runtime/drumbeat/relaunchers.js.map +1 -1
  103. package/dist/runtime/identity/binding-commit.d.ts +31 -0
  104. package/dist/runtime/identity/binding-commit.d.ts.map +1 -0
  105. package/dist/runtime/identity/binding-commit.js +211 -0
  106. package/dist/runtime/identity/binding-commit.js.map +1 -0
  107. package/dist/runtime/identity/bindings.d.ts +6 -30
  108. package/dist/runtime/identity/bindings.d.ts.map +1 -1
  109. package/dist/runtime/identity/bindings.js +85 -96
  110. package/dist/runtime/identity/bindings.js.map +1 -1
  111. package/dist/runtime/identity/durable.d.ts +7 -0
  112. package/dist/runtime/identity/durable.d.ts.map +1 -0
  113. package/dist/runtime/identity/durable.js +68 -0
  114. package/dist/runtime/identity/durable.js.map +1 -0
  115. package/dist/runtime/identity/live.d.ts +4 -1
  116. package/dist/runtime/identity/live.d.ts.map +1 -1
  117. package/dist/runtime/identity/live.js +59 -6
  118. package/dist/runtime/identity/live.js.map +1 -1
  119. package/dist/runtime/identity/possession.d.ts +34 -0
  120. package/dist/runtime/identity/possession.d.ts.map +1 -0
  121. package/dist/runtime/identity/possession.js +162 -0
  122. package/dist/runtime/identity/possession.js.map +1 -0
  123. package/dist/runtime/identity/worker.js +16 -5
  124. package/dist/runtime/identity/worker.js.map +1 -1
  125. package/dist/runtime/live/contracts.d.ts +55 -0
  126. package/dist/runtime/live/contracts.d.ts.map +1 -0
  127. package/dist/runtime/live/contracts.js +59 -0
  128. package/dist/runtime/live/contracts.js.map +1 -0
  129. package/dist/runtime/local-files/identity-fence.d.ts +164 -0
  130. package/dist/runtime/local-files/identity-fence.d.ts.map +1 -0
  131. package/dist/runtime/local-files/identity-fence.js +1338 -0
  132. package/dist/runtime/local-files/identity-fence.js.map +1 -0
  133. package/dist/runtime/local-files/index.d.ts +1 -0
  134. package/dist/runtime/local-files/index.d.ts.map +1 -1
  135. package/dist/runtime/local-files/index.js +1 -0
  136. package/dist/runtime/local-files/index.js.map +1 -1
  137. package/dist/runtime/local-files/legacy-identity-evidence.d.ts +26 -0
  138. package/dist/runtime/local-files/legacy-identity-evidence.d.ts.map +1 -0
  139. package/dist/runtime/local-files/legacy-identity-evidence.js +234 -0
  140. package/dist/runtime/local-files/legacy-identity-evidence.js.map +1 -0
  141. package/dist/runtime/local-files/locks.d.ts +3 -0
  142. package/dist/runtime/local-files/locks.d.ts.map +1 -1
  143. package/dist/runtime/local-files/locks.js +6 -5
  144. package/dist/runtime/local-files/locks.js.map +1 -1
  145. package/dist/runtime/local-files/orphan-gc.d.ts +3 -0
  146. package/dist/runtime/local-files/orphan-gc.d.ts.map +1 -0
  147. package/dist/runtime/local-files/orphan-gc.js +69 -0
  148. package/dist/runtime/local-files/orphan-gc.js.map +1 -0
  149. package/dist/runtime/local-files/presence.d.ts +5 -2
  150. package/dist/runtime/local-files/presence.d.ts.map +1 -1
  151. package/dist/runtime/local-files/presence.js +32 -29
  152. package/dist/runtime/local-files/presence.js.map +1 -1
  153. package/dist/runtime/local-files/recipient-hints.d.ts +10 -0
  154. package/dist/runtime/local-files/recipient-hints.d.ts.map +1 -0
  155. package/dist/runtime/local-files/recipient-hints.js +156 -0
  156. package/dist/runtime/local-files/recipient-hints.js.map +1 -0
  157. package/dist/runtime/local-files/store.d.ts +1 -1
  158. package/dist/runtime/local-files/store.d.ts.map +1 -1
  159. package/dist/runtime/local-files/store.js +12 -1
  160. package/dist/runtime/local-files/store.js.map +1 -1
  161. package/dist/runtime/local-files/succession-lock.d.ts +71 -6
  162. package/dist/runtime/local-files/succession-lock.d.ts.map +1 -1
  163. package/dist/runtime/local-files/succession-lock.js +226 -31
  164. package/dist/runtime/local-files/succession-lock.js.map +1 -1
  165. package/dist/runtime/mcp/handlers.d.ts +1 -0
  166. package/dist/runtime/mcp/handlers.d.ts.map +1 -1
  167. package/dist/runtime/mcp/handlers.js +7 -4
  168. package/dist/runtime/mcp/handlers.js.map +1 -1
  169. package/dist/runtime/mcp/identity-blocker-snapshot.d.ts +2 -0
  170. package/dist/runtime/mcp/identity-blocker-snapshot.d.ts.map +1 -0
  171. package/dist/runtime/mcp/identity-blocker-snapshot.js +98 -0
  172. package/dist/runtime/mcp/identity-blocker-snapshot.js.map +1 -0
  173. package/dist/runtime/mcp/identity-state.d.ts +20 -3
  174. package/dist/runtime/mcp/identity-state.d.ts.map +1 -1
  175. package/dist/runtime/mcp/identity-state.js +98 -13
  176. package/dist/runtime/mcp/identity-state.js.map +1 -1
  177. package/dist/runtime/mcp/notifications.d.ts +2 -1
  178. package/dist/runtime/mcp/notifications.d.ts.map +1 -1
  179. package/dist/runtime/mcp/notifications.js +16 -2
  180. package/dist/runtime/mcp/notifications.js.map +1 -1
  181. package/dist/runtime/mcp/server.d.ts +3 -0
  182. package/dist/runtime/mcp/server.d.ts.map +1 -1
  183. package/dist/runtime/mcp/server.js +31 -15
  184. package/dist/runtime/mcp/server.js.map +1 -1
  185. package/dist/runtime/mcp/sessions.d.ts +6 -6
  186. package/dist/runtime/mcp/sessions.d.ts.map +1 -1
  187. package/dist/runtime/mcp/sessions.js +18 -6
  188. package/dist/runtime/mcp/sessions.js.map +1 -1
  189. package/dist/runtime/mcp/stdio.d.ts.map +1 -1
  190. package/dist/runtime/mcp/stdio.js +11 -0
  191. package/dist/runtime/mcp/stdio.js.map +1 -1
  192. package/dist/runtime/mcp/tools.js +1 -1
  193. package/dist/runtime/mcp/tools.js.map +1 -1
  194. package/dist/runtime/remote/client.d.ts +1 -1
  195. package/dist/runtime/remote/client.d.ts.map +1 -1
  196. package/dist/runtime/remote/client.js +1 -1
  197. package/dist/runtime/remote/client.js.map +1 -1
  198. package/dist/runtime/send.d.ts +10 -0
  199. package/dist/runtime/send.d.ts.map +1 -1
  200. package/dist/runtime/send.js +80 -5
  201. package/dist/runtime/send.js.map +1 -1
  202. package/dist/runtime/upgrade/index.d.ts +1 -0
  203. package/dist/runtime/upgrade/index.d.ts.map +1 -1
  204. package/dist/runtime/upgrade/index.js +1 -0
  205. package/dist/runtime/upgrade/index.js.map +1 -1
  206. package/dist/vendor/engram-live/contracts.d.ts +208 -0
  207. package/dist/vendor/engram-live/contracts.js +558 -0
  208. package/fixtures/native-host-catalog.json +1 -0
  209. package/fixtures/native-host-history.json +1261 -0
  210. package/fixtures/native-host-renderers.json +1 -0
  211. package/hooks/deny-manual-h2a-cli.mjs +38 -0
  212. package/hooks/hooks.json +17 -0
  213. package/hooks/vibe-post-agent.mjs +29 -0
  214. package/hooks/vibe-pre-tool.mjs +40 -0
  215. package/package.json +9 -6
  216. package/scripts/qualification-budget.mjs +56 -0
  217. package/scripts/qualification-cleanup.mjs +15 -0
  218. package/scripts/qualification-oracles.mjs +44 -0
  219. package/scripts/qualification-patch.mjs +21 -0
  220. package/scripts/qualification-poll-hosts.mjs +19 -0
  221. package/scripts/qualification-probe.mjs +63 -0
  222. package/scripts/qualification-rpc.mjs +59 -0
  223. package/scripts/qualification-vibe.mjs +159 -0
  224. package/scripts/qualify-host.mjs +143 -0
  225. package/skills/h2a/SKILL.md +6 -2
@@ -0,0 +1 @@
1
+ [{"release":"0.78.0","host":"agy","name":"h2a","source":"---\nname: h2a\nversion: 0.66.0\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nCompose and route an envelope to a named peer.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Compose an `H2AEnvelope` JSON:\n ```json\n {\n \"protocol\": \"sentropic.h2a\",\n \"version\": \"0.1\",\n \"id\": \"env:<epoch-ms>:<4hex>\",\n \"type\": \"event\",\n \"actor\": {\n \"instance\": \"<this-agent-instance>\",\n \"role\": \"<this-agent-role-or-AGENTS>\",\n \"scope\": \"<shared-scope-or-default>\"\n },\n \"body\": { \"kind\": \"message\", \"text\": \"<text>\" },\n \"createdAt\": \"<ISO-8601-now>\"\n }\n ```\n4. **Hard rule: the recipient MUST be host-qualified (`<host>:<label>`, e.g. `claude:radar-immobilier`). A bare label (e.g. `radar-immobilier`) is rejected — the same label can live on several hosts (claude, codex, …), so a bare label is ambiguous and routes to an orphan inbox nobody reads.**\n\n Call `h2a_inbox` with `{ action: \"put\", instance: \"<peer>\", envelope }`.\n\n **Conversation threading (optional, lightweight):** To continue an existing back-and-forth as a thread, add two top-level fields to the envelope JSON before putting it:\n - `\"threadId\": \"<id>\"` — reuse the `threadId` from the peer's previous envelope, or mint a fresh one as `thr:<epoch-ms>:<4hex>` to start a new thread.\n - `\"replyTo\": \"<prev-envelope-id>\"` — the `id` of the envelope you are replying to.\n\n To reconstruct the ordered fil of a thread (for supervision or before opening a formal negotiation):\n ```sh\n h2a thread --id <threadId> --instance <self-instance> --root <root>\n ```\n This returns the envelopes (from your inbox + outbox) that share that `threadId`, sorted ascending by `createdAt`, deduped. No new store — storage is derived on the fly.\n\n5. **Report honestly per the target's liveness** (h2a writes the inbox unconditionally — it does NOT yet error on a dead target, so YOU must say which it was):\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads (file pointer, deliverable, status update), set `body.kind` to a category and add the relevant fields; ask the user if ambiguous.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy>` — render the per-host MCP config / stop-hook glue (DEC-093/096).\n","rendered":"description = \"Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation. Use when the user wants the current CLI to interact with another agent through a shared workspace.\"\nprompt = '''\nYou are the h2a custom command for Gemini CLI.\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nCompose and route an envelope to a named peer.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Compose an `H2AEnvelope` JSON:\n ```json\n {\n \"protocol\": \"sentropic.h2a\",\n \"version\": \"0.1\",\n \"id\": \"env:<epoch-ms>:<4hex>\",\n \"type\": \"event\",\n \"actor\": {\n \"instance\": \"<this-agent-instance>\",\n \"role\": \"<this-agent-role-or-AGENTS>\",\n \"scope\": \"<shared-scope-or-default>\"\n },\n \"body\": { \"kind\": \"message\", \"text\": \"<text>\" },\n \"createdAt\": \"<ISO-8601-now>\"\n }\n ```\n4. **Hard rule: the recipient MUST be host-qualified (`<host>:<label>`, e.g. `claude:radar-immobilier`). A bare label (e.g. `radar-immobilier`) is rejected — the same label can live on several hosts (claude, codex, …), so a bare label is ambiguous and routes to an orphan inbox nobody reads.**\n\n Call `h2a_inbox` with `{ action: \"put\", instance: \"<peer>\", envelope }`.\n\n **Conversation threading (optional, lightweight):** To continue an existing back-and-forth as a thread, add two top-level fields to the envelope JSON before putting it:\n - `\"threadId\": \"<id>\"` — reuse the `threadId` from the peer's previous envelope, or mint a fresh one as `thr:<epoch-ms>:<4hex>` to start a new thread.\n - `\"replyTo\": \"<prev-envelope-id>\"` — the `id` of the envelope you are replying to.\n\n To reconstruct the ordered fil of a thread (for supervision or before opening a formal negotiation):\n ```sh\n h2a thread --id <threadId> --instance <self-instance> --root <root>\n ```\n This returns the envelopes (from your inbox + outbox) that share that `threadId`, sorted ascending by `createdAt`, deduped. No new store — storage is derived on the fly.\n\n5. **Report honestly per the target's liveness** (h2a writes the inbox unconditionally — it does NOT yet error on a dead target, so YOU must say which it was):\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads (file pointer, deliverable, status update), set `body.kind` to a category and add the relevant fields; ask the user if ambiguous.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy>` — render the per-host MCP config / stop-hook glue (DEC-093/096).\n\n'''\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"a6c021c6b14964ca90de6957681d942737f341aab4bbf893c1c8e2051b61555b"},{"release":"0.78.0","host":"gemini","name":"h2a","source":"---\nname: h2a\nversion: 0.66.0\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nCompose and route an envelope to a named peer.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Compose an `H2AEnvelope` JSON:\n ```json\n {\n \"protocol\": \"sentropic.h2a\",\n \"version\": \"0.1\",\n \"id\": \"env:<epoch-ms>:<4hex>\",\n \"type\": \"event\",\n \"actor\": {\n \"instance\": \"<this-agent-instance>\",\n \"role\": \"<this-agent-role-or-AGENTS>\",\n \"scope\": \"<shared-scope-or-default>\"\n },\n \"body\": { \"kind\": \"message\", \"text\": \"<text>\" },\n \"createdAt\": \"<ISO-8601-now>\"\n }\n ```\n4. **Hard rule: the recipient MUST be host-qualified (`<host>:<label>`, e.g. `claude:radar-immobilier`). A bare label (e.g. `radar-immobilier`) is rejected — the same label can live on several hosts (claude, codex, …), so a bare label is ambiguous and routes to an orphan inbox nobody reads.**\n\n Call `h2a_inbox` with `{ action: \"put\", instance: \"<peer>\", envelope }`.\n\n **Conversation threading (optional, lightweight):** To continue an existing back-and-forth as a thread, add two top-level fields to the envelope JSON before putting it:\n - `\"threadId\": \"<id>\"` — reuse the `threadId` from the peer's previous envelope, or mint a fresh one as `thr:<epoch-ms>:<4hex>` to start a new thread.\n - `\"replyTo\": \"<prev-envelope-id>\"` — the `id` of the envelope you are replying to.\n\n To reconstruct the ordered fil of a thread (for supervision or before opening a formal negotiation):\n ```sh\n h2a thread --id <threadId> --instance <self-instance> --root <root>\n ```\n This returns the envelopes (from your inbox + outbox) that share that `threadId`, sorted ascending by `createdAt`, deduped. No new store — storage is derived on the fly.\n\n5. **Report honestly per the target's liveness** (h2a writes the inbox unconditionally — it does NOT yet error on a dead target, so YOU must say which it was):\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads (file pointer, deliverable, status update), set `body.kind` to a category and add the relevant fields; ask the user if ambiguous.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy>` — render the per-host MCP config / stop-hook glue (DEC-093/096).\n","rendered":"description = \"Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation. Use when the user wants the current CLI to interact with another agent through a shared workspace.\"\nprompt = '''\nYou are the h2a custom command for Gemini CLI.\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nCompose and route an envelope to a named peer.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Compose an `H2AEnvelope` JSON:\n ```json\n {\n \"protocol\": \"sentropic.h2a\",\n \"version\": \"0.1\",\n \"id\": \"env:<epoch-ms>:<4hex>\",\n \"type\": \"event\",\n \"actor\": {\n \"instance\": \"<this-agent-instance>\",\n \"role\": \"<this-agent-role-or-AGENTS>\",\n \"scope\": \"<shared-scope-or-default>\"\n },\n \"body\": { \"kind\": \"message\", \"text\": \"<text>\" },\n \"createdAt\": \"<ISO-8601-now>\"\n }\n ```\n4. **Hard rule: the recipient MUST be host-qualified (`<host>:<label>`, e.g. `claude:radar-immobilier`). A bare label (e.g. `radar-immobilier`) is rejected — the same label can live on several hosts (claude, codex, …), so a bare label is ambiguous and routes to an orphan inbox nobody reads.**\n\n Call `h2a_inbox` with `{ action: \"put\", instance: \"<peer>\", envelope }`.\n\n **Conversation threading (optional, lightweight):** To continue an existing back-and-forth as a thread, add two top-level fields to the envelope JSON before putting it:\n - `\"threadId\": \"<id>\"` — reuse the `threadId` from the peer's previous envelope, or mint a fresh one as `thr:<epoch-ms>:<4hex>` to start a new thread.\n - `\"replyTo\": \"<prev-envelope-id>\"` — the `id` of the envelope you are replying to.\n\n To reconstruct the ordered fil of a thread (for supervision or before opening a formal negotiation):\n ```sh\n h2a thread --id <threadId> --instance <self-instance> --root <root>\n ```\n This returns the envelopes (from your inbox + outbox) that share that `threadId`, sorted ascending by `createdAt`, deduped. No new store — storage is derived on the fly.\n\n5. **Report honestly per the target's liveness** (h2a writes the inbox unconditionally — it does NOT yet error on a dead target, so YOU must say which it was):\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads (file pointer, deliverable, status update), set `body.kind` to a category and add the relevant fields; ask the user if ambiguous.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy>` — render the per-host MCP config / stop-hook glue (DEC-093/096).\n\n'''\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"a6c021c6b14964ca90de6957681d942737f341aab4bbf893c1c8e2051b61555b"},{"release":"0.97.5","host":"agy","name":"h2a","source":"---\nname: h2a\nversion: 0.85.6\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n","rendered":"description = \"Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\"\nprompt = '''\nYou are the h2a custom command for Gemini CLI.\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n\n'''\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"a1505c53c03d6a39882b7791409bdedaa73bc5beb959d51c8d70cc8b2fe8e105"},{"release":"0.97.5","host":"gemini","name":"h2a","source":"---\nname: h2a\nversion: 0.85.6\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n","rendered":"description = \"Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\"\nprompt = '''\nYou are the h2a custom command for Gemini CLI.\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n\n'''\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"a1505c53c03d6a39882b7791409bdedaa73bc5beb959d51c8d70cc8b2fe8e105"},{"release":"0.97.5","host":"muse","name":"h2a","source":"---\nname: h2a\nversion: 0.85.6\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n","rendered":"---\nname: h2a\nversion: 0.85.6\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"4fedfc550a3324946003c1e2721f8ec15462a551ae5f21239eeef01c99485b50"},{"release":"0.97.5","host":"agy","name":"harness-using-harness","source":"---\nname: harness-using-harness\ndescription: Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\n---\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n","rendered":"description = \"Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\"\nprompt = '''\nYou are the harness-using-harness custom command for Gemini CLI.\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n\n'''\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"de08bae87aa8a84a47055c4924ba4fa061e223d3c1bc6e9fa755c0c3f20e2d06"},{"release":"0.97.5","host":"gemini","name":"harness-using-harness","source":"---\nname: harness-using-harness\ndescription: Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\n---\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n","rendered":"description = \"Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\"\nprompt = '''\nYou are the harness-using-harness custom command for Gemini CLI.\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n\n'''\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"de08bae87aa8a84a47055c4924ba4fa061e223d3c1bc6e9fa755c0c3f20e2d06"},{"release":"0.97.5","host":"muse","name":"harness-using-harness","source":"---\nname: harness-using-harness\ndescription: Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\n---\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n","rendered":"---\nname: harness-using-harness\ndescription: Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\n---\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"545753d280796428470e18f358f45cb16879ef1deb63d9d575685c6376d76ce3"},{"release":"0.98.3","host":"agy","name":"h2a","source":"---\nname: h2a\nversion: 0.85.6\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Local LLM backend\n\nThe optional local gateway is composed through `@sentropic/cluster-mesh`. Its llm-mesh facade owns enrollment, credentials, provider transports, routing and affinity. H2A retains its local bearer registry and session ledger until convergence with Sentropic workspace/session notions (owner decision 2026-10-03), plus public configuration and daemon lifecycle. New launches default to direct authentication; Claude `--gw` / MCP `gateway: \"required\"` explicitly require the composed gateway. The CLI groups, MCP schema and session/status URLs remain compatible.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n","rendered":"description = \"Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\"\nprompt = '''\nYou are the h2a custom command for Gemini CLI.\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Local LLM backend\n\nThe optional local gateway is composed through `@sentropic/cluster-mesh`. Its llm-mesh facade owns enrollment, credentials, provider transports, routing and affinity. H2A retains its local bearer registry and session ledger until convergence with Sentropic workspace/session notions (owner decision 2026-10-03), plus public configuration and daemon lifecycle. New launches default to direct authentication; Claude `--gw` / MCP `gateway: \"required\"` explicitly require the composed gateway. The CLI groups, MCP schema and session/status URLs remain compatible.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n\n'''\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"581877af5a75a79cbb0c73d36388681a171051973e728ccaab9373452bd53d05"},{"release":"0.98.3","host":"gemini","name":"h2a","source":"---\nname: h2a\nversion: 0.85.6\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Local LLM backend\n\nThe optional local gateway is composed through `@sentropic/cluster-mesh`. Its llm-mesh facade owns enrollment, credentials, provider transports, routing and affinity. H2A retains its local bearer registry and session ledger until convergence with Sentropic workspace/session notions (owner decision 2026-10-03), plus public configuration and daemon lifecycle. New launches default to direct authentication; Claude `--gw` / MCP `gateway: \"required\"` explicitly require the composed gateway. The CLI groups, MCP schema and session/status URLs remain compatible.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n","rendered":"description = \"Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\"\nprompt = '''\nYou are the h2a custom command for Gemini CLI.\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Local LLM backend\n\nThe optional local gateway is composed through `@sentropic/cluster-mesh`. Its llm-mesh facade owns enrollment, credentials, provider transports, routing and affinity. H2A retains its local bearer registry and session ledger until convergence with Sentropic workspace/session notions (owner decision 2026-10-03), plus public configuration and daemon lifecycle. New launches default to direct authentication; Claude `--gw` / MCP `gateway: \"required\"` explicitly require the composed gateway. The CLI groups, MCP schema and session/status URLs remain compatible.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n\n'''\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"581877af5a75a79cbb0c73d36388681a171051973e728ccaab9373452bd53d05"},{"release":"0.98.3","host":"muse","name":"h2a","source":"---\nname: h2a\nversion: 0.85.6\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Local LLM backend\n\nThe optional local gateway is composed through `@sentropic/cluster-mesh`. Its llm-mesh facade owns enrollment, credentials, provider transports, routing and affinity. H2A retains its local bearer registry and session ledger until convergence with Sentropic workspace/session notions (owner decision 2026-10-03), plus public configuration and daemon lifecycle. New launches default to direct authentication; Claude `--gw` / MCP `gateway: \"required\"` explicitly require the composed gateway. The CLI groups, MCP schema and session/status URLs remain compatible.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n","rendered":"---\nname: h2a\nversion: 0.85.6\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Local LLM backend\n\nThe optional local gateway is composed through `@sentropic/cluster-mesh`. Its llm-mesh facade owns enrollment, credentials, provider transports, routing and affinity. H2A retains its local bearer registry and session ledger until convergence with Sentropic workspace/session notions (owner decision 2026-10-03), plus public configuration and daemon lifecycle. New launches default to direct authentication; Claude `--gw` / MCP `gateway: \"required\"` explicitly require the composed gateway. The CLI groups, MCP schema and session/status URLs remain compatible.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"6f3652d602ecc83e902827b44a69ad39ae23a87bbbc3026c62c74cc57e35ee52"},{"release":"0.98.3","host":"vibe","name":"h2a","source":"---\nname: h2a\nversion: 0.85.6\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Local LLM backend\n\nThe optional local gateway is composed through `@sentropic/cluster-mesh`. Its llm-mesh facade owns enrollment, credentials, provider transports, routing and affinity. H2A retains its local bearer registry and session ledger until convergence with Sentropic workspace/session notions (owner decision 2026-10-03), plus public configuration and daemon lifecycle. New launches default to direct authentication; Claude `--gw` / MCP `gateway: \"required\"` explicitly require the composed gateway. The CLI groups, MCP schema and session/status URLs remain compatible.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n","rendered":"---\nname: h2a\nversion: 0.85.6\ndescription: Coordinate with other CLI agents (Claude Code, Codex, Gemini) via the h2a protocol — open a live session, list peers, exchange messages, drive a signed negotiation or objective loop. Use when the user wants the current CLI to interact with another agent through a shared workspace.\n---\n\n# /h2a\n\nWhen invoked, parse the arguments and dispatch to the matching subcommand below. If no subcommand is given, default to `status`.\n\n```\n/h2a → status (alias)\n/h2a connect [root] → bootstrap a live session in this conversation\n/h2a status → show current session state and health summary\n/h2a discover [scope] → list live peer agents\n/h2a conductor [workspace] → who owns/conducts a workspace right now (null = none yet)\n/h2a conductor claim → claim conductor for a workspace (earliest live claimant wins)\n/h2a conductor release → release conductor claim (frees it for the next claimant)\n/h2a conductor-launch-check [workspace] → DRY-RUN: polls track; recommends launching a conductor if stalled + none live\n/h2a conductor-launch [workspace] → EMIT a launch REQUEST to remote when stalled+no conductor; capped 1/30min, requires --confirm; h2a never spawns\n/h2a send <peer> \"<text>\" → put a message envelope in a peer's inbox\n/h2a receive → read this agent's inbox and react to new envelopes\n/h2a negotiate <verb> ... → drive a negotiation lifecycle (open|offer|sign|stabilize)\n/h2a loop <verb> ... → create/join/report/done/stop an objective loop (multi-agent relay)\n/h2a model \"<situation>\" → propose a tailored h2a model for an org/situation\n/h2a disconnect → cleanly close the current session\n/h2a help → print this command map\n```\n\nThe user's raw arguments arrive appended below the prompt; treat anything after `/h2a` as the routing token.\n\n---\n\n## Routing\n\n### `/h2a connect [root]`\n\nBootstrap a live session so this agent can cooperate with other CLI agents.\n\nSteps:\n\n1. Verify the `h2a` binary is on PATH (`h2a --help`). If absent, instruct the user to run `npm i -g @sentropic/h2a-cli@latest` and stop.\n2. Decide the shared root. If `[root]` was passed, use it; otherwise prefer `<this-workspace>/.h2a`, else `~/h2a-workspace/.h2a`. Confirm with the user only if ambiguous.\n3. Run `h2a init --root <root>` (idempotent).\n4. **Resolve YOUR perennial identity — do NOT invent it.** Run `h2a connect --host <h> --root <root>`; it returns the perennial instance id `host:slug(label):uuid12` (DEC-114/116), bound per `(host, workspace)` and reclaimed on reconnect — the same workspace always gets the same id (never mint `host:workspace-leaf` by hand; that bare `host:label` form is the *channel* alias, see \"Identity & addressing\"). Use the returned `instance`.\n5. Call the MCP tool `h2a_session_open` with `{ instance, host, interests: { scopes: [\"scope:default\"], negotiations: [] } }` (instance = the resolved perennial id from step 4).\n6. Print a short summary: instance id, session id, peers currently live, the four notification topics this session is subscribed to.\n\nEnd with the cue: *\"Connected. Try `/h2a discover` to see who else is around, or `/h2a send <peer> \\\"hi\\\"` to message someone.\"*\n\n### `/h2a status`\n\nShow the current connectivity state. Steps:\n\n1. If no session has been opened yet in this conversation, say so and suggest `/h2a connect`.\n2. Otherwise call `h2a_discover_sessions` and find the session whose `sessionId` matches the one returned by `h2a_session_open`.\n3. Print: instance id, session id, state (`opening|live|draining|closed|expired`), `heartbeatAt`, count of peer sessions, count of unread inbox envelopes (call `h2a_inbox` with `action: \"read\"` and report length).\n4. If anything looks stale (no recent heartbeat, no peers when peers were expected), suggest `/h2a connect` to re-open.\n\n### `/h2a discover [scope]`\n\nList currently-live peer agents.\n\n**Peer resolution rule — always use `h2a_discover_sessions`, never grep the registry:**\nTo reach a peer by PURPOSE/role, RESOLVE it via `h2a_discover_sessions` filtering on `scope` (the canonical purpose key) or `name` (case-insensitive substring match on the agent's display name) — e.g. `{ scope: \"scope:chat\" }` or `{ name: \"radar\" }`. NEVER grep the registry for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and let the user pick (or pick the single live one); if none match, the agent has not advertised that scope/name yet.\n\nSteps:\n\n1. Call `h2a_discover_sessions` with `{ scope }` (omit if no argument); add `{ name: \"<substring>\" }` when the user asks to find a peer by friendly name.\n2. Filter out the current agent's own session (compare against `h2a_session_open`'s `sessionId` if known).\n3. For each remaining session, print: `instance`, `host`, `name` (if set), `interests.scopes` (comma-joined), a relative heartbeat age (\"12s ago\"), and `sessionId`.\n4. Sort by host then instance.\n5. If empty: say so and suggest the user check that the other CLIs ran `/h2a connect` against the same root.\n\nEnd with: *\"To message one of these: `/h2a send <instance> \\\"<text>\\\"`.\"*\n\n### `/h2a conductor [workspace]`\n\nResolve who owns/conducts a workspace right now. Call `h2a_conductor` (MCP) or `h2a conductor --workspace <id|path>` (CLI).\n\n- `conductor` = the earliest live active-claimant (WP-G1b, claim-based election), or a live in-workspace agent registered with role `CONDUCTOR` (back-compat), or `null` if none. **Null is the normal/expected state** today — agents auto-register as `AGENTS`, not `CONDUCTOR`. Do NOT treat `null` as an error; it means \"no designated owner yet.\"\n- `claimedBy` = the instance that won via claim-based election, or `null` if resolved by role or absent.\n- `candidates` = all in-workspace live agents (anyone who has a fresh presence record for that workspace), regardless of role.\n- `live` = `true` if at least one candidate is present.\n- `workspace` argument: a `ws:<uuid>` workspace id or a filesystem path (resolved via the same derivation presence uses). Defaults to cwd.\n\n**When to use it:** call `h2a_conductor` before acting in a workspace on behalf of another agent, to check whether a designated conductor is already live. If `conductor` is non-null, coordinate with them first rather than acting unilaterally.\n\n### `/h2a conductor claim [--instance <self>] [workspace]`\n\nClaim the conductor role for a workspace (WP-G1b — additive, reversible). Appends a `claim` event; returns the post-claim `conductorFor` result. The caller should be itself if it won (earliest live claimant wins; a later claimant is listed in candidates but does not displace the earlier one as long as it is still live).\n\nCLI: `h2a conductor claim --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_claim { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor release [--instance <self>] [workspace]`\n\nRelease the conductor claim for a workspace (WP-G1b — additive, reversible). Appends a `release` event; returns the post-release `conductorFor` result (conductor is the next live claimant, or null if no other claimant is live).\n\nCLI: `h2a conductor release --instance <self> [--workspace <id|path>] [--root <path>]`\nMCP: `h2a_conductor_release { instance, workspaceId|workspacePath }`\n\nExit 1 if `--instance` is missing.\n\n### `/h2a conductor-launch-check [workspace] [--idle-ms <ms>]`\n\n**DRY-RUN (D3).** Polls `track workspace-activity` and returns a recommendation to launch a conductor if work is durably stalled and no conductor is live.\n\n**h2a does NOT spawn anything.** A `recommendation === \"launch\"` result is purely advisory. The actual launch is **parked** pending a spawn-policy decision and remote-trigger support.\n\nCLI: `h2a conductor-launch-check [--workspace <id|path>] [--root <path>] [--idle-ms <ms>]`\nMCP: `h2a_conductor_launch_check { workspaceId|workspacePath, idleMs? }`\n\nReturn shape: `{ workspaceId, trackAvailable, conductor, conductorLive, pending, stalled, recommendation, reason, suggestedHosts? }`\n\n- `recommendation` is `\"launch\"` when: no conductor is live AND track reports at least one stalled item.\n- `suggestedHosts` = `[\"claude\", \"codex\", \"agy\"]` (user preference order) when `recommendation === \"launch\"`.\n- `trackAvailable: false` when `track` is not installed or errors — graceful, `recommendation` stays `\"none\"` (no false positives).\n- `--idle-ms` is the stall threshold passed to `track workspace-activity` (default 86400000 = 24h).\n\nA one-liner stderr note is emitted when `recommendation === \"launch\"` reminding callers this is a DRY-RUN.\n\n### `/h2a conductor-launch [workspace] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\n\n**D3 EMISSION.** When `conductorLaunchCheck` returns `recommendation=\"launch\"`, emits a `conductor-launch-request` envelope to a live remote agent.\n\n**h2a NEVER spawns a process.** It only puts a request envelope in the remote's inbox; the remote agent executes the actual spawn.\n\n**Gates (both must pass to emit):**\n1. **Human confirmation:** without `--confirm`, only preview the request (`action: \"would-emit\"`). With `--confirm`, emit + record the marker.\n2. **Cap/cooldown:** at most 1 emission per 30 minutes per workspace (`action: \"cooldown\"` if too recent).\n\n`--instance <self>` is required with `--confirm` (identifies the sender/signer).\n\n**Host preference in the request:** `[\"claude\", \"codex\", \"agy\"]`.\n\nCLI: `h2a conductor-launch [--workspace <id|path>] [--root <path>] [--idle-ms <ms>] [--confirm] [--remote <instance>] [--instance <self>]`\nMCP: `h2a_conductor_launch { workspaceId|workspacePath, idleMs?, confirm?, remote?, instance? }`\n\nReturn shape (all cases exit 0 except user errors):\n- `{ action: \"none\", reason, ...check }` — recommendation is not \"launch\".\n- `{ action: \"cooldown\", reason, lastSpawnAt }` — cooldown not elapsed.\n- `{ action: \"would-emit\", request, note }` — preview (no --confirm).\n- `{ action: \"no-remote\", reason }` — no live remote agent found (--confirm but no remote).\n- `{ action: \"emitted\", to, request }` — emitted + marker recorded.\n\n### `/h2a send <peer> \"<text>\"`\n\nSend an authenticated message to a named peer through the native core tool.\n\n**Resolve-before-send rule (0.59.0+):** Always resolve the peer to its LIVE full id (`host:label:uuid12`) via `h2a_discover_sessions` BEFORE sending. A bare `host:label` sent to an ambiguous target (>1 live agent sharing that alias) or a phantom target (0 live, 0 registered) is now **REFUSED** by `h2a_inbox put` / `h2a` CLI with exit 1. Never invent a sub-label. The safe pattern is: discover → pick the exact live `host:label:uuid12` → send to that. A bare alias is only acceptable for a dormant/wake-drop or exactly 1 live match (the tool surfaces the live candidate in `liveCandidate`).\n\nSteps:\n\n1. **Resolve the target + check liveness FIRST (`h2a_discover_sessions`).** Pick the addressing form (see \"Identity & addressing\"):\n - target is a **specific live agent** → use its **full perennial id** `host:slug:uuid12` from discover (NOT the bare `host:label`, which is ambiguous when several agents share a workspace);\n - target is a **role/channel or a known-dormant peer** → use the **channel** form `host:label`.\n - If the user names a peer by PURPOSE/role, call `h2a_discover_sessions` with `{ scope: \"<purpose>\" }`. If the user names a peer by FRIENDLY NAME, call `h2a_discover_sessions` with `{ name: \"<substring>\" }`. NEVER grep the registry for a name: instance ids are workspace-derived (`host:slug(workspace):uuid`) so a text search misses. If several match, list and ask; if none, the agent hasn't advertised that scope/name.\n - If `<peer>` is missing, list discover and ask the user to pick.\n2. If `\"<text>\"` is missing, prompt the user for the content.\n3. Call `h2a_send` with exactly `{ to: \"<peer>\", message: \"<text>\" }`.\n The local MCP sidecar supplies its trusted signing identity; never request,\n construct, or pass a private key or sender field. The tool resolves the peer,\n constructs the canonical envelope, verifies the sender's active key, and only\n then writes the inbox. If the tool is unavailable because the sidecar has no\n auto-open signing identity, report that error; do not fall back to unsigned\n `h2a_inbox put`.\n4. **Report honestly from the tool result:**\n - target was **live** in discover → *\"Delivered to `<peer>` (live) — push fires if subscribed.\"*\n - target was **NOT live** → *\"`<peer>` is dormant — envelope deposited for its wake (no live session; it will only see this once woken).\"* Never claim \"Delivered\" to a dormant/unknown peer.\n\nFor richer payloads, use the formal negotiation/inbox contracts; `h2a_send` is\ndeliberately the small signed text-message primitive.\n\n### `/h2a receive`\n\nRead this agent's inbox and react to whatever is new.\n\nSteps:\n\n1. Call `h2a_inbox` with `{ action: \"read\", instance: \"<this-agent-instance>\" }`.\n2. For each envelope, print: sender (`actor.instance`), `body.kind`, a short summary of the content, and the envelope id.\n3. Ask the user what to do with each (reply via `/h2a send`, mark read by calling `h2a_inbox` with `action: \"pop\"`, or ignore).\n4. If a `notifications/h2a` message with `topic: inbox.envelope_arrived` was just observed in the JSON-RPC stream, react immediately rather than waiting for the user to type `/h2a receive`.\n\n**Pop after processing (hygiene rule):** Once you have acted on an envelope, call `h2a_inbox` with `{ action: \"pop\", instance: \"<this-agent-instance>\", envelopeId: \"<id>\" }` to remove it from the inbox. `read` is non-destructive — an un-popped envelope resurfaces on every subsequent poll and masks genuinely new arrivals. Pop as soon as the envelope is handled, not just when explicitly instructed.\n\n### `/h2a negotiate <verb> ...`\n\nDrive a step of the h2a negotiation lifecycle. The subverb is one of:\n\n- `/h2a negotiate open <id> <scope> <parties> \"<subject>\"` — call `h2a_open_negotiation` with a fresh `H2ANegotiationRecord`.\n- `/h2a negotiate offer <id> <artifact-json>` — call `h2a_offer`.\n- `/h2a negotiate counter <id> <artifact-json>` — call `h2a_counteroffer`.\n- `/h2a negotiate sign <id> <artifact-json> [--key <pem-path>]` — call `h2a_sign` (the private key PEM path defaults to `<root>/keys/<instance>.key.pem` from `h2a keys generate`).\n- `/h2a negotiate stabilize <id>` — call `h2a_stabilize` once the quorum is signed.\n- `/h2a negotiate journal <id>` — print the journal entries.\n\nFor each verb, validate the required arguments, surface any tool error verbatim, and print a one-line confirmation with the latest journal entry id.\n\n### `/h2a loop <verb> ...`\n\nDrive an objective loop: a durable, shared relay state where several CLI agents can join, report progress, mark references done, or stop the loop.\n\n**Supported verbs:**\n\n- `/h2a loop create --goal \"<goal>\" [--name <name>] [--id <loop-id>] [--agent <host:role:local>] [--ref <ref>]` — create the loop. MCP create requires an explicit initial `instance`, unless `allowEmpty:true` explicitly requests a staged empty loop. CLI: `h2a loop create`. MCP: `h2a_loop_create`.\n- `/h2a loop join <loop-id> --instance <self> [--agent-id <id>] [--role <role>] [--required=false]` — join an existing loop or fill a predeclared agent slot. A strict Claude/Codex relaunch spec may be supplied as the MCP `launch` object, or to the CLI only through `--launch-stdin`; never place its prompt in argv. CLI: `h2a loop join`. MCP: `h2a_loop_join`.\n- `/h2a loop report <loop-id> --agent-id <id> [--note \"...\"]` — append an agent progress report. A legacy/staged empty loop may recover with explicit `autoJoin:true` + `instance`; this shortcut is refused once any participant exists. CLI: `h2a loop report`. MCP: `h2a_loop_report`.\n- `/h2a loop done <loop-id> --ref <ref> [--agent-id <id>] [--note \"...\"]` — mark one loop reference done. CLI: `h2a loop done`. MCP: `h2a_loop_done`.\n- `/h2a loop stop <loop-id> [--reason \"...\"]` — stop the loop; later `tick/run --execute` must not perform close actions. CLI: `h2a loop stop`. MCP: `h2a_loop_stop`.\n- `/h2a loop list` / `/h2a loop status <loop-id>` — read-only projections. CLI or MCP: `h2a_loop_list`, `h2a_loop_status`.\n- `/h2a loop run <loop-id>` — alias of `h2a loop watch`: continuously emits JSONL tick plans. Use `h2a loop tick <loop-id> --execute` for a single execution tick.\n\n**Routing guidance:**\n\n1. Prefer MCP tools when the host exposes them; otherwise call the CLI with `--root <root>`.\n2. Always use the current resolved perennial `instance` from `/h2a connect`; do not invent agent ids except as local slot ids (`agent-1`, `reviewer`, etc.).\n3. If the user asks for a Codex/Claude relay, create the loop with predeclared `--agent` slots, ask each live peer to `join`, then use `report`/`done` to converge.\n4. Treat an empty-loop `stalled` plan as recoverable: call `h2a_loop_join`, or use explicit empty-only `autoJoin:true` on the first report. Never infer the caller identity.\n5. A missing/dead agent is auto-launched only when its persisted `launch` spec is complete. `gateway:\"required\"` is Claude-only (Codex `auto` is effective `direct`). Wake and launch share one durable cooldown/maxRelaunches budget; human deferrals consume neither.\n6. Treat `stopped` as terminal. Do not restart or close a stopped loop unless the user explicitly creates a new loop.\n7. Print the loop id and the next concrete command/tool call for the peer.\n\n### `/h2a model \"<situation>\"`\n\nPropose a **tailored h2a model** for a free-form organization or situation (e.g. *\"a hospital coordinating with insurers and a regulator\"*, *\"a 3-team scaled-agile delivery with AI agents\"*). This is an **advisory mapping**, not a protocol action — it emits a design, it does not write to the store.\n\nMethod (follow it faithfully — do not invent vocabulary):\n\n1. **Ground in the canonical model first.** Read `VOCABULARY.md` for the frozen roles (`PRINCIPAL`, `EXECUTIF`, `CONDUCTOR`, `AGENTS`, `CONTROL`, `MANDATAIRE`) and substrate (`SCOPE`, `CONTRACT`, `POLICY`, `ENGAGEMENT`, `MANDATE`, `SLOT`, `BINDING`, `NEGOTIATION`, `AUTHORITY`), and skim `evaluations/README.md` (the common grid) plus the closest existing use-case in `evaluations/` (A enterprise, B ecosystem, C government, D 15-conductors, E agentic squad). Reuse their patterns; do not coin new roles or artifacts.\n2. **Map the situation** against the common grid: actors→roles, scopes, authority/mandate/signature, CONTRACT vs ENGAGEMENT vs POLICY, obligations/rights/clauses, controls, escalations, audit, deadlocks/precedence, gaps.\n3. **Respect the invariants** (these are load-bearing):\n - A `SCOPE` never signs; a **mandated INSTANCE** signs for a party/scope.\n - `ENGAGEMENT` *has* a scope — it is **not** the scope. Name both.\n - Anything that must be *owned* needs a `PRINCIPAL` (e.g. architecture ownership) — `CONTROL` only audits/vetoes, it owns nothing.\n - `POLICY` is a durable rule (standalone *or* a clause of a CONTRACT); prefer expressing rules as engagement clauses unless they are cross-cutting/imposed.\n - Delegated AI agents are `AGENTS` (or `SUBAGENTS`, parent-addressed) via `MANDATE`+`BINDING`, default **execution-only / non-signing**.\n - `MANDATAIRE` presents/records, never judges; escalation targets the scope's competent authority.\n4. **Output**, mirroring the `evaluations/*.md` structure:\n - a **Mermaid diagram** of roles/scopes/contract flows;\n - a **mapping table** (real element → h2a construct → note);\n - **contracts vs policies**, a multi-actor case, **gaps**, and a one-paragraph **compatibility hypothesis**;\n - the **nearest built-in profile** id (`A_ENTERPRISE` / `B_ECOSYSTEM` / `C_GOVERNMENT_CITIZEN` / `D_SAFE`) and how the situation differs from it.\n5. **Offer to persist**: ask whether to save the proposal as a new `evaluations/<slug>.md` (same format) for review. Only write the file if the user agrees.\n\nKeep it a proposal: surface assumptions and the genuine design forks (e.g. one scope with co-principals vs sub-scopes) rather than silently deciding them.\n\n### `/h2a disconnect`\n\nCleanly close the current session.\n\nSteps:\n\n1. Call `h2a_session_close` with `{ sessionId, state: \"closed\" }`.\n2. Confirm.\n\nThis is rarely needed manually — the session auto-closes when this CLI process exits, via the mcp-serve shutdown hook (DEC-051). Use it if the user wants to release the slot before exiting.\n\n### `/h2a help`\n\nPrint the command map at the top of this file. Concise, no extra prose.\n\n---\n\n## Keepalive (optional, launcher-side)\n\nWhen the launcher or remote infrastructure runs `h2a keepalive [--root <path>] [--interval <ms>]`, it acts as an external presence prober: it lists the live tmux panes via `tmux list-panes -aF '#{pane_id}'` and refreshes the `heartbeatAt` of every presence file whose `launchContext.tmux.pane` is still alive. This keeps pane-alive agents visible on the bus even if the host suspends the MCP child process's heartbeat interval. The `--once` flag does a single pass (useful for testing and scripting); without it, the prober loops on an unref'd interval. h2a works without it — keepalive is purely additive.\n\n---\n\n## Identity & addressing (DEC-114/116 — read before sending)\n\nThere are **two addressable forms**; pick deliberately:\n\n- **Agent (perennial, specific):** `host:slug(label):uuid12` — e.g.\n `claude:sentropic:cbf32fe0800b`. This is YOUR identity (resolved by `h2a\n connect`, reclaimed per `(host, workspace)`) and how you address **one specific\n live agent**. Get a peer's full id from `/h2a discover` — never guess the uuid.\n- **Channel (role / alias):** `host:label` — e.g. `claude:sentropic-scale`. The\n bare `host:label` form is a **named mailbox/alias**, not a specific agent; use\n it for a role, a known-dormant peer you want to leave a message for, or a wake\n drop. A perennial agent also reads its own `host:label` alias inbox (dedup), so\n channel messages reach whichever agent adopts that label.\n\n**Resolution rule — discover, never grep:** To reach a peer by PURPOSE/role, filter `h2a_discover_sessions` on `scope` (the canonical purpose key). To reach a peer by FRIENDLY NAME, filter on `name` (case-insensitive substring match on `session.name`). NEVER grep the registry file for a free-text name: instance ids are workspace-derived (`host:slug(workspace):uuid`), so a name grep misses. If several sessions match, list them and pick/ask; if none match, the agent hasn't advertised that scope/name yet.\n\nConsequences to respect:\n- **Addressing is case-insensitive; the label is slugified** (0.40.0+). The handle\n is canonicalized as `lower(host):slugify(label)[:lower(uuid)]`, so `claude:matchID`\n ≡ `claude:matchid` — both reach the one inbox. The canonical channel for a label\n is therefore `host:slugify(label)` (lowercased, `[a-z0-9._-]`), **not** the raw\n display case. Don't tell a peer to address you by a mixed-case label; it resolves\n the same either way. (Pre-0.40.0 deposits in a raw mis-cased dir are still read.)\n- **One perennial id per `(host, workspace)`** — several *concurrent sessions* of\n the same agent share that id and its inbox (they are distinguishable in\n `/h2a discover` by `sessionId`, but inbox delivery is per-agent, not\n per-session). To reach \"whoever is working in project X\", address the agent id;\n there is no per-session inbox today.\n- **Liveness is not enforced on send** — `h2a_inbox put` writes even to a dead\n target. Always `/h2a discover` first and report truthfully (see `/h2a send`):\n *delivered (live)* vs *deposited for wake (dormant)*.\n- **`recipientLive:false` / \"dormant\" ≠ \"not working\"** — liveness means only\n \"has a fresh `mcp-serve` presence session\", i.e. *reachable by a push now*. An\n agent doing real work **headless** (e.g. `codex exec`, a one-shot review) runs\n with **no presence session** and so shows as not-live while it is busy. **Never\n relaunch, reassign, or duplicate a task just because a peer reads as not-live.**\n Before assuming a peer is idle: check its `workStatus` (`working|blocked|…` in\n discover/`h2a status`, if it sets one), look for a recent delivery/report from\n it, or ask the human — do not infer \"free\" from \"not-live\". Liveness gates\n *delivery*, not *work in progress*.\n\n## Local LLM backend\n\nThe optional local gateway is composed through `@sentropic/cluster-mesh`. Its llm-mesh facade owns enrollment, credentials, provider transports, routing and affinity. H2A retains its local bearer registry and session ledger until convergence with Sentropic workspace/session notions (owner decision 2026-10-03), plus public configuration and daemon lifecycle. New launches default to direct authentication; Claude `--gw` / MCP `gateway: \"required\"` explicitly require the composed gateway. The CLI groups, MCP schema and session/status URLs remain compatible.\n\n## Defaults and conventions\n\n- **Auto-connect (recommended)**: register the MCP server with `mcp-serve --auto-open --host <h>` so a session opens at host startup (EVO-6/DEC-105); `/h2a disconnect` leaves early. `/h2a connect` stays available for manual/explicit connect.\n\n### Host MCP singleton\n\nEach supported host has **exactly one active `mcpServers.h2a` endpoint**. Select one transport and\nreconfigure the same entry; never stack a local h2a server, a remote h2a URL, or a separate Track server:\n\n- local stdio: `h2a host setup --host <host> --endpoint local --write <config.json>`;\n- remote HTTP: `h2a host setup --host <host> --endpoint remote --url <https://…/mcp> --write <config.json>`.\n\nRe-running `host setup --write` replaces the existing h2a entry and disables recognized standalone Track\nentries. **Never configure, call, or suggest `track-mcp` / `h2a track-mcp` as a host MCP endpoint.** The\nselected h2a endpoint exposes Track's read-only `track_*` tools; Track writes and imports remain `track` CLI\noperations from the designated repository root. The selected h2a endpoint is the only host MCP endpoint in\nthis bundle. Packaged plugin manifests are a fixed **local** bootstrap; before selecting a remote endpoint\nwith `host setup`, disable that package-managed local entry rather than enabling both configuration paths.\n\n- **Shared root**: same `<root>/.h2a/` for every cooperating CLI. If the user has not declared one, look for `<cwd>/.h2a/`, then `~/h2a-workspace/.h2a`, ask if neither exists.\n- **Instance id**: the **perennial** `host:slug(label):uuid12` resolved by `h2a connect` (reclaimed per `(host, workspace)`) — do NOT hand-mint `host:workspace-leaf`; that bare form is the channel alias.\n- **Subscriptions**: when opening a session, subscribe to all four canonical notification topics (`presence.peer_joined`, `presence.peer_left`, `inbox.envelope_arrived`, `negotiation.event_appended`) unless the user narrows the scope.\n- **JSON-RPC notifications**: `notifications/h2a` messages arrive on stdout interleaved with tool responses. They have no `id` field and use `method: \"notifications/h2a\"`. React to them in real time rather than polling.\n\n## Failure modes\n\n- Tool returns `{ error: ... }` → surface the error verbatim, stop the current subcommand.\n- `h2a` binary missing → install instruction + stop.\n- Root not initialized → suggest `/h2a connect`.\n- Session not open → suggest `/h2a connect` (do not silently bypass).\n- Peer not in `h2a_discover_sessions` → name it, suggest checking the spelling or that the peer ran `/h2a connect` against the same root.\n\n## Related commands shipped by `@sentropic/h2a-cli`\n\nThese can be invoked directly from the shell at any time, outside the slash-command flow:\n\n- `h2a doctor [--root <path>]` — quick health probe.\n- `h2a sessions [--root <path>]` — same listing as `/h2a discover` but from the shell.\n- `h2a status [--root <path>] [--scope <s>] [--instance <i>]` — inventory of connected sessions split **direct** (local mcp-serve heartbeat) vs **indirect** (mirrored in from a remote/sidecar), with counts.\n- `h2a keys generate --instance <id>` — produce an ed25519 PEM keypair.\n- `h2a install-skills --host <claude|codex|gemini|agy|hermes|opencode|muse>` — re-install or update this skill on another host. *(For **agy**/Antigravity the skill is written to the shared `~/.gemini/commands/h2a.toml`; the command then prints an `importHint` — run `agy plugin import gemini` (then `agy plugin enable h2a`) to pull it into agy. DEC-096/101. For **muse** the skill lands in `~/.config/muse/skills` (user scope, verified) or `<workspace>/.muse/skills` (project scope); verify pickup with `muse skills list`.)*\n\n**Operational surfaces** (also shell-invocable; matching `h2a_*` MCP tools where noted):\n\n- `h2a nhi report|inventory|attest|offboard|export` — Non-Human-Identity posture / inventory / signed attestation / coordinated offboard / SPIFFE-bundle export (`h2a_nhi_*`, DEC-087..090/094).\n- `h2a blockage raise|list|resolve` — the peer blockage feedback loop, distinct from the drumbeat and from escalation (`h2a_blockage_*`, DEC-092). Subscribed sessions get `peer.blocked`/`peer.unblocked` pushes.\n- `h2a drumbeat record|scan|clear|escalations|watch` — anti-stall relance daemon + escalation-to-PRINCIPAL (DEC-086/091/095). Gov D2/D4 (0.64.0): a claimed conductor owns its workspace's relances — peers defer on fresh stalls (relanceCount=0); a failsafe lets a peer step in if the conductor leaves an agent stuck (relanceCount>=1, preventing workspace freeze). Cross-workspace relances emit a CoI advisory (warn, not blocked). Both behaviors are opt-in and default-allow: pass `--instance <self>` to `h2a drumbeat watch` to activate them.\n- `h2a sysml verify --json <env> --public-key <pem>` — verify a SysML-v2 ref embedded in a signed envelope (commit-trust + content-integrity, DEC-099).\n- `h2a host setup|status|plugin --host <codex|claude|gemini|agy|hermes|opencode|muse>` — render the per-host singleton MCP config / stop-hook glue. `host setup --endpoint local|remote` selects one h2a endpoint and removes standalone Track MCP configuration. *(For **muse**: stdio pickup under `mcpServers` in `~/.config/muse/settings.json` is unconfirmed — only streamable-HTTP is documented — so verify with your muse build, else re-run with `--endpoint remote`. Muse is poll-only for the plugin surface.)*\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"6f3652d602ecc83e902827b44a69ad39ae23a87bbbc3026c62c74cc57e35ee52"},{"release":"0.98.3","host":"agy","name":"harness-using-harness","source":"---\nname: harness-using-harness\ndescription: Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\n---\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n","rendered":"description = \"Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\"\nprompt = '''\nYou are the harness-using-harness custom command for Gemini CLI.\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n\n'''\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"de08bae87aa8a84a47055c4924ba4fa061e223d3c1bc6e9fa755c0c3f20e2d06"},{"release":"0.98.3","host":"gemini","name":"harness-using-harness","source":"---\nname: harness-using-harness\ndescription: Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\n---\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n","rendered":"description = \"Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\"\nprompt = '''\nYou are the harness-using-harness custom command for Gemini CLI.\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n\n'''\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"de08bae87aa8a84a47055c4924ba4fa061e223d3c1bc6e9fa755c0c3f20e2d06"},{"release":"0.98.3","host":"muse","name":"harness-using-harness","source":"---\nname: harness-using-harness\ndescription: Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\n---\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n","rendered":"---\nname: harness-using-harness\ndescription: Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\n---\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"545753d280796428470e18f358f45cb16879ef1deb63d9d575685c6376d76ce3"},{"release":"0.98.3","host":"vibe","name":"harness-using-harness","source":"---\nname: harness-using-harness\ndescription: Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\n---\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n","rendered":"---\nname: harness-using-harness\ndescription: Load FIRST in any sentropic repo — establishes the harness method (branch/scope/test/debug/review/security/track-report/brainstorm/plan) and replaces legacy superpowers for those acts.\n---\n\n# Using harness\n\n`@sentropic/harness` is the native dev-discipline layer for sentropic repos. Its verbs and `harness/*`\nskills are the SINGLE front door for code-work and PR-workflow. This skill is the index — load it\nbefore any other so the replacement directive below is in effect.\n\n## Replacement Directive (MANDATORY)\n\n`harness/*` is the native sentropic method surface. Treat any installed superpowers skills as legacy\ncompatibility only. Do NOT invoke superpowers for acts covered here — use the harness equivalent:\n\n| Act | Use | NOT |\n|---|---|---|\n| ideation / spec design | `harness/brainstorm` | superpowers:brainstorming |\n| tests | `harness/test` | superpowers:test-driven-development |\n| debugging | `harness/debug` | superpowers:systematic-debugging |\n| code review | `harness/review` | superpowers:requesting/receiving-code-review |\n| dependency / vulnerability debt | `harness/security` | — |\n| track report / status / advancement | `harness/track-report` | — |\n| planning | `harness/plan` | superpowers:writing-plans / executing-plans |\n| branch lifecycle | `harness branch init|close` | superpowers:using-git-worktrees / finishing-a-development-branch |\n| scope / verification | `harness verify` · `harness check scope|branch` | superpowers:verification-before-completion |\n| repo onboarding | `harness/adopt` | — |\n\nDo not install, refresh, or route through superpowers for sentropic code-work. If a repo still has a\n`.superpowers/` directory, it is ignored local residue; harness is never a dependency or backend of it.\n\nCreate human/dev worktrees only under repo-local ignored paths, normally `tmp/worktrees/<slug>`.\nNever create branch worktrees under OS-global `/tmp`; delegated runtime jobs use their own\nrepo-local `.remote/jobs/<id>/wt` workspace.\n\n## The CLI\n\n`harness <verb> [<subject>] [--<option>]` — homogeneous with the sibling sentropic CLIs (`stp harness …`):\n\n- **Producers** (compute → emit a neutral `VerificationRun`): `check scope|branch`, `verify --category`,\n `audit`, `init`.\n- **Recorders** (emit a neutral `WorkEvent` + point to a skill): `brainstorm`, `test`, `debug`, `review`,\n `plan`, `branch init|close`, `skills install`.\n\nA recorder verb does NOT do the thinking — it scaffolds + records, and the `harness/<verb>` skill carries\nthe reasoning. Run the verb to open the act, then follow its skill.\n\n\n## Strict scope / minimal diff\n\nSolve only the explicit request and directly blocking defect. Before editing, identify the smallest\nnecessary file/line set. Preserve existing work: do not rewrite, reformat, move, rename, delete, refactor,\nadd dependencies, add abstractions, or clean up opportunistically unless required by the task. Prefer a\nlocal compatible fix over a broader redesign. If a useful improvement is outside scope, mention it as an\noptional follow-up instead of implementing it. Before finishing, check every hunk: if it does not directly\nserve the objective, remove it.\n\n### No-dead-end diagnosis\n\nTreat a gap, blocker, or missing implementation as actionable only when evidence shows that it prevents\nthe explicit objective or a required verification. Do not end with that diagnosis alone. If the smallest\ndirectly blocking change is both authorized by the request and within the agreed scope, resolve it. A\ndiagnosis-only request remains diagnosis-only. Otherwise provide one evidence-backed handoff:\nresponsible role (or `owner: to be assigned`), bounded scope, observable acceptance criterion, and\nproportionate verification.\n\nFor an evidenced, non-blocking observation outside the scope, do not implement it or create work by\ndefault. Mention it as an optional follow-up only when useful to the user, and cite the evidence. Record a\nfollow-up only when the request explicitly authorizes creating or updating tracked work, using the task's\nestablished tracking flow; otherwise recommend it without recording it. Never create, assign, or\nduplicate follow-up work from speculation. A handoff closes the diagnosed blocking item; it does not\nsatisfy or defer any remaining explicit objective.\n\n## Rebase, never cherry-pick\n\nTo move committed work between branches, rebase — never cherry-pick. Cherry-pick copies a commit under a\nnew SHA, so the same change now exists twice with different identities: history diverges, a later merge or\nrebase sees \"different\" commits, and the duplicate resurfaces in diffs, reviews, and merge-loss checks.\n\n- To retarget a branch onto an updated base, `git rebase <base>` (or `git rebase --onto <newbase> <upstream>`\n to replay only a specific range). The commits keep their logical identity and the branch stays linear.\n- To isolate one feature's commits from an entangled branch, `git rebase --onto origin/main <commit>~1 <branch>`\n replays exactly that range onto the base — a rebase, not a copy.\n- `git cherry-pick` is reserved for the narrow case of applying a change to a branch that will NEVER share\n history with the source (e.g. a backport to a frozen release line). It is not a tool for normal\n branch-to-branch movement, and never a substitute for rebasing a feature onto a fresh base.\n\nRationale: this is the same non-duplication discipline the branch-lifecycle event-containment gate enforces\nfor `.track` — a copied commit is a second identity for one change, and every downstream tool then has to\nreconcile two things that should have been one.\n\n## Discipline first\n\nProcess skills (`harness/brainstorm`, `harness/debug`) decide HOW to approach the task — invoke them\nbefore implementation skills. \"Let's build X\" → brainstorm first. \"Fix this bug\" → debug first.\n","functions":"function parseSkill(raw) {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/m.exec(raw);\n if (!match) {\n throw new Error(\"skill file missing YAML frontmatter (expected `---` delimiters)\");\n }\n const [, fmRaw, body] = match;\n const frontmatter = {};\n let currentKey;\n for (const line of fmRaw.split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z][\\w-]*)\\s*:\\s*(.*)$/.exec(line);\n if (kv) {\n currentKey = kv[1];\n frontmatter[currentKey] = kv[2].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n else if (currentKey && /^\\s+/.test(line)) {\n frontmatter[currentKey] = `${frontmatter[currentKey]} ${line.trim()}`;\n }\n }\n if (!frontmatter.name || !frontmatter.description) {\n throw new Error(\"skill frontmatter must declare both `name` and `description`\");\n }\n return {\n name: frontmatter.name,\n description: frontmatter.description,\n body: body.trimStart()\n };\n}\nfunction renderSkillAsGeminiToml(skill) {\n const escapedDescription = skill.description.replace(/\"/g, '\\\\\"');\n const promptHeader = `You are the ${skill.name} custom command for Gemini CLI.\\n\\n`;\n const promptBody = `${promptHeader}${skill.body}`;\n // TOML multiline literal: '''...''' is verbatim, no escaping needed beyond\n // disallowing the closing triple-quote in content. The bundled skills do\n // not contain '''.\n return [\n `description = \"${escapedDescription}\"`,\n `prompt = '''`,\n promptBody,\n `'''`,\n \"\"\n ].join(\"\\n\");\n}","sha256":"545753d280796428470e18f358f45cb16879ef1deb63d9d575685c6376d76ce3"}]