macro-agent 0.1.8 → 0.1.11

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 (306) hide show
  1. package/CLAUDE.md +263 -33
  2. package/README.md +781 -131
  3. package/dist/acp/claude-code-replay.d.ts +11 -0
  4. package/dist/acp/claude-code-replay.d.ts.map +1 -0
  5. package/dist/acp/claude-code-replay.js +190 -0
  6. package/dist/acp/claude-code-replay.js.map +1 -0
  7. package/dist/acp/macro-agent.d.ts.map +1 -1
  8. package/dist/acp/macro-agent.js +192 -7
  9. package/dist/acp/macro-agent.js.map +1 -1
  10. package/dist/acp/types.d.ts +9 -0
  11. package/dist/acp/types.d.ts.map +1 -1
  12. package/dist/acp/types.js.map +1 -1
  13. package/dist/adapters/tasks-adapter.d.ts.map +1 -1
  14. package/dist/adapters/tasks-adapter.js +3 -0
  15. package/dist/adapters/tasks-adapter.js.map +1 -1
  16. package/dist/adapters/types.d.ts +1 -0
  17. package/dist/adapters/types.d.ts.map +1 -1
  18. package/dist/agent/agent-manager-v2.d.ts +21 -0
  19. package/dist/agent/agent-manager-v2.d.ts.map +1 -1
  20. package/dist/agent/agent-manager-v2.js +308 -54
  21. package/dist/agent/agent-manager-v2.js.map +1 -1
  22. package/dist/agent/agent-manager.d.ts +12 -0
  23. package/dist/agent/agent-manager.d.ts.map +1 -1
  24. package/dist/agent/agent-manager.js.map +1 -1
  25. package/dist/agent/agent-store.d.ts +10 -0
  26. package/dist/agent/agent-store.d.ts.map +1 -1
  27. package/dist/agent/agent-store.js +22 -0
  28. package/dist/agent/agent-store.js.map +1 -1
  29. package/dist/agent/types.d.ts +15 -2
  30. package/dist/agent/types.d.ts.map +1 -1
  31. package/dist/agent/types.js.map +1 -1
  32. package/dist/boot-v2.d.ts +129 -1
  33. package/dist/boot-v2.d.ts.map +1 -1
  34. package/dist/boot-v2.js +359 -8
  35. package/dist/boot-v2.js.map +1 -1
  36. package/dist/cli/acp.js +4 -0
  37. package/dist/cli/acp.js.map +1 -1
  38. package/dist/cli/index.js +56 -0
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/cognitive/macro-agent-backend.d.ts.map +1 -1
  41. package/dist/cognitive/macro-agent-backend.js +40 -22
  42. package/dist/cognitive/macro-agent-backend.js.map +1 -1
  43. package/dist/integrations/skilltree.d.ts.map +1 -1
  44. package/dist/integrations/skilltree.js +1 -0
  45. package/dist/integrations/skilltree.js.map +1 -1
  46. package/dist/lifecycle/cascade.d.ts +25 -2
  47. package/dist/lifecycle/cascade.d.ts.map +1 -1
  48. package/dist/lifecycle/cascade.js +70 -2
  49. package/dist/lifecycle/cascade.js.map +1 -1
  50. package/dist/lifecycle/cleanup.d.ts +33 -2
  51. package/dist/lifecycle/cleanup.d.ts.map +1 -1
  52. package/dist/lifecycle/cleanup.js +28 -6
  53. package/dist/lifecycle/cleanup.js.map +1 -1
  54. package/dist/lifecycle/handlers-v2.d.ts +7 -0
  55. package/dist/lifecycle/handlers-v2.d.ts.map +1 -1
  56. package/dist/lifecycle/handlers-v2.js +28 -2
  57. package/dist/lifecycle/handlers-v2.js.map +1 -1
  58. package/dist/lifecycle/types.d.ts +11 -0
  59. package/dist/lifecycle/types.d.ts.map +1 -1
  60. package/dist/lifecycle/types.js.map +1 -1
  61. package/dist/map/acp-bridge.d.ts +9 -0
  62. package/dist/map/acp-bridge.d.ts.map +1 -1
  63. package/dist/map/acp-bridge.js +15 -2
  64. package/dist/map/acp-bridge.js.map +1 -1
  65. package/dist/map/cascade-action-handler.d.ts +24 -0
  66. package/dist/map/cascade-action-handler.d.ts.map +1 -0
  67. package/dist/map/cascade-action-handler.js +170 -0
  68. package/dist/map/cascade-action-handler.js.map +1 -0
  69. package/dist/map/cascade-bridge.d.ts +44 -0
  70. package/dist/map/cascade-bridge.d.ts.map +1 -0
  71. package/dist/map/cascade-bridge.js +294 -0
  72. package/dist/map/cascade-bridge.js.map +1 -0
  73. package/dist/map/coordination-handler.d.ts.map +1 -1
  74. package/dist/map/coordination-handler.js +12 -1
  75. package/dist/map/coordination-handler.js.map +1 -1
  76. package/dist/map/lifecycle-bridge.d.ts +1 -1
  77. package/dist/map/lifecycle-bridge.d.ts.map +1 -1
  78. package/dist/map/lifecycle-bridge.js +58 -23
  79. package/dist/map/lifecycle-bridge.js.map +1 -1
  80. package/dist/map/server.d.ts.map +1 -1
  81. package/dist/map/server.js +219 -7
  82. package/dist/map/server.js.map +1 -1
  83. package/dist/map/sidecar.d.ts.map +1 -1
  84. package/dist/map/sidecar.js +49 -2
  85. package/dist/map/sidecar.js.map +1 -1
  86. package/dist/map/types.d.ts +22 -0
  87. package/dist/map/types.d.ts.map +1 -1
  88. package/dist/mcp/tools/done-v2.d.ts.map +1 -1
  89. package/dist/mcp/tools/done-v2.js +8 -0
  90. package/dist/mcp/tools/done-v2.js.map +1 -1
  91. package/dist/teams/team-manager-v2.d.ts.map +1 -1
  92. package/dist/teams/team-manager-v2.js +26 -0
  93. package/dist/teams/team-manager-v2.js.map +1 -1
  94. package/dist/teams/team-runtime-v2.d.ts.map +1 -1
  95. package/dist/teams/team-runtime-v2.js +16 -3
  96. package/dist/teams/team-runtime-v2.js.map +1 -1
  97. package/dist/workspace/config.d.ts +10 -10
  98. package/dist/workspace/config.d.ts.map +1 -1
  99. package/dist/workspace/config.js +4 -4
  100. package/dist/workspace/config.js.map +1 -1
  101. package/dist/workspace/git-cascade-adapter.d.ts +510 -0
  102. package/dist/workspace/git-cascade-adapter.d.ts.map +1 -0
  103. package/dist/workspace/git-cascade-adapter.js +934 -0
  104. package/dist/workspace/git-cascade-adapter.js.map +1 -0
  105. package/dist/workspace/index.d.ts +3 -3
  106. package/dist/workspace/index.d.ts.map +1 -1
  107. package/dist/workspace/index.js +4 -4
  108. package/dist/workspace/index.js.map +1 -1
  109. package/dist/workspace/landing/direct-push.d.ts +20 -0
  110. package/dist/workspace/landing/direct-push.d.ts.map +1 -0
  111. package/dist/workspace/landing/direct-push.js +74 -0
  112. package/dist/workspace/landing/direct-push.js.map +1 -0
  113. package/dist/workspace/landing/index.d.ts +29 -0
  114. package/dist/workspace/landing/index.d.ts.map +1 -0
  115. package/dist/workspace/landing/index.js +37 -0
  116. package/dist/workspace/landing/index.js.map +1 -0
  117. package/dist/workspace/landing/merge-to-parent.d.ts +41 -0
  118. package/dist/workspace/landing/merge-to-parent.d.ts.map +1 -0
  119. package/dist/workspace/landing/merge-to-parent.js +186 -0
  120. package/dist/workspace/landing/merge-to-parent.js.map +1 -0
  121. package/dist/workspace/landing/optimistic-push.d.ts +16 -0
  122. package/dist/workspace/landing/optimistic-push.d.ts.map +1 -0
  123. package/dist/workspace/landing/optimistic-push.js +27 -0
  124. package/dist/workspace/landing/optimistic-push.js.map +1 -0
  125. package/dist/workspace/landing/queue-to-branch.d.ts +24 -0
  126. package/dist/workspace/landing/queue-to-branch.d.ts.map +1 -0
  127. package/dist/workspace/landing/queue-to-branch.js +79 -0
  128. package/dist/workspace/landing/queue-to-branch.js.map +1 -0
  129. package/dist/workspace/merge-queue/merge-queue.d.ts +10 -0
  130. package/dist/workspace/merge-queue/merge-queue.d.ts.map +1 -1
  131. package/dist/workspace/merge-queue/merge-queue.js +10 -0
  132. package/dist/workspace/merge-queue/merge-queue.js.map +1 -1
  133. package/dist/workspace/merge-queue/types.d.ts +16 -2
  134. package/dist/workspace/merge-queue/types.d.ts.map +1 -1
  135. package/dist/workspace/merge-queue/types.js +9 -0
  136. package/dist/workspace/merge-queue/types.js.map +1 -1
  137. package/dist/workspace/pool/types.d.ts +1 -0
  138. package/dist/workspace/pool/types.d.ts.map +1 -1
  139. package/dist/workspace/pool/worktree-pool.d.ts.map +1 -1
  140. package/dist/workspace/pool/worktree-pool.js +1 -0
  141. package/dist/workspace/pool/worktree-pool.js.map +1 -1
  142. package/dist/workspace/recovery/abandon.d.ts +15 -0
  143. package/dist/workspace/recovery/abandon.d.ts.map +1 -0
  144. package/dist/workspace/recovery/abandon.js +45 -0
  145. package/dist/workspace/recovery/abandon.js.map +1 -0
  146. package/dist/workspace/recovery/auto-resolve.d.ts +27 -0
  147. package/dist/workspace/recovery/auto-resolve.d.ts.map +1 -0
  148. package/dist/workspace/recovery/auto-resolve.js +99 -0
  149. package/dist/workspace/recovery/auto-resolve.js.map +1 -0
  150. package/dist/workspace/recovery/defer.d.ts +15 -0
  151. package/dist/workspace/recovery/defer.d.ts.map +1 -0
  152. package/dist/workspace/recovery/defer.js +16 -0
  153. package/dist/workspace/recovery/defer.js.map +1 -0
  154. package/dist/workspace/recovery/escalate.d.ts +16 -0
  155. package/dist/workspace/recovery/escalate.d.ts.map +1 -0
  156. package/dist/workspace/recovery/escalate.js +24 -0
  157. package/dist/workspace/recovery/escalate.js.map +1 -0
  158. package/dist/workspace/recovery/index.d.ts +32 -0
  159. package/dist/workspace/recovery/index.d.ts.map +1 -0
  160. package/dist/workspace/recovery/index.js +45 -0
  161. package/dist/workspace/recovery/index.js.map +1 -0
  162. package/dist/workspace/recovery/spawn-resolver.d.ts +45 -0
  163. package/dist/workspace/recovery/spawn-resolver.d.ts.map +1 -0
  164. package/dist/workspace/recovery/spawn-resolver.js +118 -0
  165. package/dist/workspace/recovery/spawn-resolver.js.map +1 -0
  166. package/dist/workspace/recovery/types.d.ts +63 -0
  167. package/dist/workspace/recovery/types.d.ts.map +1 -0
  168. package/dist/workspace/recovery/types.js +12 -0
  169. package/dist/workspace/recovery/types.js.map +1 -0
  170. package/dist/workspace/topology/index.d.ts +9 -0
  171. package/dist/workspace/topology/index.d.ts.map +1 -0
  172. package/dist/workspace/topology/index.js +8 -0
  173. package/dist/workspace/topology/index.js.map +1 -0
  174. package/dist/workspace/topology/no-workspace.d.ts +18 -0
  175. package/dist/workspace/topology/no-workspace.d.ts.map +1 -0
  176. package/dist/workspace/topology/no-workspace.js +25 -0
  177. package/dist/workspace/topology/no-workspace.js.map +1 -0
  178. package/dist/workspace/topology/types.d.ts +97 -0
  179. package/dist/workspace/topology/types.d.ts.map +1 -0
  180. package/dist/workspace/topology/types.js +20 -0
  181. package/dist/workspace/topology/types.js.map +1 -0
  182. package/dist/workspace/topology/yaml-driven.d.ts +69 -0
  183. package/dist/workspace/topology/yaml-driven.d.ts.map +1 -0
  184. package/dist/workspace/topology/yaml-driven.js +273 -0
  185. package/dist/workspace/topology/yaml-driven.js.map +1 -0
  186. package/dist/workspace/types-v3.d.ts +117 -0
  187. package/dist/workspace/types-v3.d.ts.map +1 -0
  188. package/dist/workspace/types-v3.js +20 -0
  189. package/dist/workspace/types-v3.js.map +1 -0
  190. package/dist/workspace/types.d.ts +162 -17
  191. package/dist/workspace/types.d.ts.map +1 -1
  192. package/dist/workspace/workspace-manager.d.ts +101 -13
  193. package/dist/workspace/workspace-manager.d.ts.map +1 -1
  194. package/dist/workspace/workspace-manager.js +416 -13
  195. package/dist/workspace/workspace-manager.js.map +1 -1
  196. package/dist/workspace/yaml-schema.d.ts +254 -0
  197. package/dist/workspace/yaml-schema.d.ts.map +1 -0
  198. package/dist/workspace/yaml-schema.js +170 -0
  199. package/dist/workspace/yaml-schema.js.map +1 -0
  200. package/docs/conflict-recovery.md +472 -0
  201. package/docs/design/task-dispatcher.md +880 -0
  202. package/docs/git-cascade-integration-gaps.md +678 -0
  203. package/docs/workspace-interfaces.md +731 -0
  204. package/docs/workspace-redesign-plan.md +302 -0
  205. package/package.json +6 -5
  206. package/src/__tests__/boot-v2.test.ts +435 -0
  207. package/src/__tests__/e2e/acp-over-map.e2e.test.ts +92 -0
  208. package/src/__tests__/e2e/auto-sync.e2e.test.ts +257 -0
  209. package/src/__tests__/e2e/bootstrap.e2e.test.ts +319 -0
  210. package/src/__tests__/e2e/cascade-rebase.e2e.test.ts +254 -0
  211. package/src/__tests__/e2e/cli-run.e2e.test.ts +167 -0
  212. package/src/__tests__/e2e/dispatch-coordination.e2e.test.ts +495 -0
  213. package/src/__tests__/e2e/dispatch-live.e2e.test.ts +564 -0
  214. package/src/__tests__/e2e/dispatch-opentasks.e2e.test.ts +496 -0
  215. package/src/__tests__/e2e/dispatch-phase2-live.e2e.test.ts +456 -0
  216. package/src/__tests__/e2e/dispatch-phase2.e2e.test.ts +386 -0
  217. package/src/__tests__/e2e/dispatch.e2e.test.ts +376 -0
  218. package/src/__tests__/e2e/self-driving-v3.e2e.test.ts +197 -0
  219. package/src/__tests__/e2e/spawn-resolver.e2e.test.ts +200 -0
  220. package/src/__tests__/e2e/workspace-lifecycle.e2e.test.ts +30 -22
  221. package/src/__tests__/e2e/workspace-v3.e2e.test.ts +413 -0
  222. package/src/acp/__tests__/claude-code-replay.test.ts +225 -0
  223. package/src/acp/__tests__/macro-agent.test.ts +39 -1
  224. package/src/acp/claude-code-replay.ts +208 -0
  225. package/src/acp/macro-agent.ts +203 -10
  226. package/src/acp/types.ts +10 -0
  227. package/src/adapters/__tests__/tasks-adapter.test.ts +1 -0
  228. package/src/adapters/tasks-adapter.ts +3 -0
  229. package/src/adapters/types.ts +1 -0
  230. package/src/agent/__tests__/agent-manager-topology.test.ts +73 -0
  231. package/src/agent/__tests__/agent-manager-v2.test.ts +66 -0
  232. package/src/agent/__tests__/agent-store.test.ts +52 -0
  233. package/src/agent/__tests__/task-ref-resolution.test.ts +231 -0
  234. package/src/agent/agent-manager-v2.ts +372 -59
  235. package/src/agent/agent-manager.ts +14 -0
  236. package/src/agent/agent-store.ts +24 -0
  237. package/src/agent/types.ts +16 -2
  238. package/src/boot-v2.ts +589 -35
  239. package/src/cli/acp.ts +4 -0
  240. package/src/cli/index.ts +61 -0
  241. package/src/cognitive/macro-agent-backend.ts +45 -29
  242. package/src/integrations/skilltree.ts +1 -0
  243. package/src/lifecycle/__tests__/cascade-consolidation.test.ts +240 -0
  244. package/src/lifecycle/cascade.ts +77 -2
  245. package/src/lifecycle/cleanup.ts +52 -3
  246. package/src/lifecycle/handlers-v2.ts +40 -3
  247. package/src/lifecycle/types.ts +12 -0
  248. package/src/map/__tests__/cascade-bridge.test.ts +229 -0
  249. package/src/map/__tests__/emit-event.test.ts +71 -0
  250. package/src/map/__tests__/lifecycle-bridge.test.ts +86 -10
  251. package/src/map/acp-bridge.ts +26 -3
  252. package/src/map/cascade-action-handler.ts +205 -0
  253. package/src/map/cascade-bridge.ts +339 -0
  254. package/src/map/coordination-handler.ts +13 -1
  255. package/src/map/lifecycle-bridge.ts +52 -17
  256. package/src/map/server.ts +225 -7
  257. package/src/map/sidecar.ts +48 -1
  258. package/src/map/types.ts +23 -0
  259. package/src/mcp/tools/done-v2.ts +9 -0
  260. package/src/teams/team-manager-v2.ts +37 -0
  261. package/src/teams/team-runtime-v2.ts +23 -3
  262. package/src/workspace/__tests__/{dataplane-adapter.test.ts → git-cascade-adapter.test.ts} +209 -14
  263. package/src/workspace/__tests__/land-dispatch.test.ts +214 -0
  264. package/src/workspace/__tests__/self-driving-yaml.test.ts +114 -0
  265. package/src/workspace/__tests__/shared-worktree-refcount.test.ts +154 -0
  266. package/src/workspace/__tests__/standalone-mode.test.ts +118 -0
  267. package/src/workspace/__tests__/workspace-manager-v3.test.ts +245 -0
  268. package/src/workspace/__tests__/yaml-schema.test.ts +210 -0
  269. package/src/workspace/config.ts +11 -11
  270. package/src/workspace/git-cascade-adapter.ts +1213 -0
  271. package/src/workspace/index.ts +11 -11
  272. package/src/workspace/landing/__tests__/strategies.test.ts +184 -0
  273. package/src/workspace/landing/direct-push.ts +91 -0
  274. package/src/workspace/landing/index.ts +40 -0
  275. package/src/workspace/landing/merge-to-parent.ts +229 -0
  276. package/src/workspace/landing/optimistic-push.ts +36 -0
  277. package/src/workspace/landing/queue-to-branch.ts +108 -0
  278. package/src/workspace/merge-queue/merge-queue.ts +10 -0
  279. package/src/workspace/merge-queue/types.ts +16 -2
  280. package/src/workspace/pool/__tests__/worktree-pool.integration.test.ts +5 -5
  281. package/src/workspace/pool/types.ts +1 -0
  282. package/src/workspace/pool/worktree-pool.ts +1 -0
  283. package/src/workspace/recovery/__tests__/auto-resolve-integration.test.ts +127 -0
  284. package/src/workspace/recovery/__tests__/spawn-resolver.test.ts +139 -0
  285. package/src/workspace/recovery/__tests__/strategies.test.ts +145 -0
  286. package/src/workspace/recovery/abandon.ts +51 -0
  287. package/src/workspace/recovery/auto-resolve.ts +119 -0
  288. package/src/workspace/recovery/defer.ts +23 -0
  289. package/src/workspace/recovery/escalate.ts +30 -0
  290. package/src/workspace/recovery/index.ts +58 -0
  291. package/src/workspace/recovery/spawn-resolver.ts +152 -0
  292. package/src/workspace/recovery/types.ts +54 -0
  293. package/src/workspace/topology/__tests__/yaml-driven.test.ts +345 -0
  294. package/src/workspace/topology/index.ts +18 -0
  295. package/src/workspace/topology/no-workspace.ts +39 -0
  296. package/src/workspace/topology/types.ts +116 -0
  297. package/src/workspace/topology/yaml-driven.ts +316 -0
  298. package/src/workspace/types-v3.ts +162 -0
  299. package/src/workspace/types.ts +211 -20
  300. package/src/workspace/workspace-manager.ts +533 -19
  301. package/src/workspace/yaml-schema.ts +216 -0
  302. package/dist/workspace/dataplane-adapter.d.ts +0 -260
  303. package/dist/workspace/dataplane-adapter.d.ts.map +0 -1
  304. package/dist/workspace/dataplane-adapter.js +0 -416
  305. package/dist/workspace/dataplane-adapter.js.map +0 -1
  306. package/src/workspace/dataplane-adapter.ts +0 -546
package/README.md CHANGED
@@ -4,81 +4,476 @@ A multi-agent orchestration system for spawning and managing hierarchical AI cod
4
4
 
5
5
  macro-agent handles **orchestration** (agent lifecycle, team topology, workspace isolation, trigger/wake) and delegates **messaging** to [agent-inbox](https://github.com/alexngai/agent-inbox) and **task management** to [opentasks](https://github.com/alexngai/opentasks). It exposes ACP (WebSocket) and REST API servers, supports cross-instance federation, and can serve as a compute backend for [cognitive-core](https://github.com/alexngai/cognitive-core)/OpenHive.
6
6
 
7
- ## Features
8
-
9
- - **Hierarchical Agent Management** — Head manager spawns and coordinates child agents via acp-factory
10
- - **Role-Based Agents** — Worker, Integrator, Coordinator, Monitor, Analyst roles with distinct capabilities
11
- - **Team Templates** — Declarative YAML configs for multi-agent topologies with composite signal filtering
12
- - **Workspace Isolation** Each worker gets an isolated git worktree via git-cascade
13
- - **Merge Queue** — Serialized integration of worker changes with conflict resolution
14
- - **Control Socket** — NDJSON-over-UNIX-socket RPC for MCP subprocess lifecycle operations
15
- - **Trigger System** — Pluggable routing strategies (direct, role, head, AI router) for wake, cron, and webhook-based agent activation
16
- - **MCP Tools** — 5 core orchestration tools + 3 pull-mode claim tools per agent
17
- - **Task Modes** — Push (coordinator assigns) or pull (agents claim from pool)
18
- - **Agent Detection** — Auto-discovers installed CLI coding agents (Claude Code, Codex, etc.)
19
- - **ACP Protocol Server** — WebSocket transport bridging ACP protocol to macro-agent services
20
- - **REST API** — HTTP endpoints for agents, tasks, teams, and metrics
21
- - **Federation** — Cross-instance communication via federated agent-inbox (addressable as `agentId@systemId`)
22
- - **Cognitive-Core Backend** Serves as compute backend for OpenHive (analyst agent spawning, batch execution)
23
- - **Metrics** — Point-in-time snapshots of agent, task, and system health
24
-
25
- ## Installation
7
+ ---
8
+
9
+ ## Table of contents
10
+
11
+ - [Install](#install)
12
+ - [Your first run (5 minutes)](#your-first-run-5-minutes)
13
+ - [How it works](#how-it-works)
14
+ - [Team configuration](#team-configuration)
15
+ - [Minimum viable team](#minimum-viable-team)
16
+ - [Workspace topology](#workspace-topology)
17
+ - [Landing strategies](#landing-strategies)
18
+ - [Conflict recovery](#conflict-recovery)
19
+ - [Six team shapes](#six-team-shapes)
20
+ - [CLI reference](#cli-reference)
21
+ - [Programmatic API](#programmatic-api)
22
+ - [MCP tools agents get](#mcp-tools-agents-get)
23
+ - [Architecture](#architecture)
24
+ - [Design & internals](#design--internals)
25
+ - [Why V3 was needed](#why-v3-was-needed)
26
+ - [Workspace interfaces](#workspace-interfaces)
27
+ - [Conflict recovery mechanics](#conflict-recovery-mechanics)
28
+ - [Implementation status](#implementation-status)
29
+ - [Advanced integrations](#advanced-integrations)
30
+ - [Dependencies](#dependencies)
31
+ - [Testing](#testing)
32
+ - [License](#license)
33
+
34
+ ---
35
+
36
+ ## Install
26
37
 
27
38
  ```bash
28
39
  npm install macro-agent
29
40
  ```
30
41
 
31
- ## Quick Start
42
+ Peer dependency: [git-cascade](https://github.com/alexngai/git-cascade) `>=0.0.3` for the workspace layer.
32
43
 
33
- ### Programmatic Usage
44
+ ---
34
45
 
35
- ```typescript
36
- import { bootV2 } from 'macro-agent';
46
+ ## Your first run (5 minutes)
37
47
 
38
- // Boot the system initializes AgentStore, InboxAdapter, TasksAdapter,
39
- // AgentManager, TriggerSystem, and ControlServer
40
- const system = await bootV2({ cwd: process.cwd() });
48
+ The fastest way to use macro-agent is to run a team template with one command:
41
49
 
42
- // Create a head manager agent
43
- const headManager = await system.agentManager.getOrCreateHeadManager({
44
- cwd: process.cwd(),
45
- });
50
+ ```bash
51
+ # From a git repository with a .multiagent/teams/<name>/team.yaml
52
+ npx multiagent-cli run self-driving --task "implement a /status endpoint"
53
+ ```
46
54
 
47
- // Send a prompt and stream the response
48
- for await (const update of system.agentManager.prompt(headManager.id, 'Build feature X')) {
49
- // Handle streaming response
50
- }
55
+ That command does this:
51
56
 
52
- // Shut down cleanly
53
- await system.shutdown();
57
+ 1. Boots the full macro-agent system (inbox, tasks, agent manager, workspace layer).
58
+ 2. Loads `.multiagent/teams/self-driving/team.yaml` and its `macro_agent.workspace` block.
59
+ 3. Constructs a `YamlDrivenTopology` and wires it into the agent manager.
60
+ 4. Creates a `team:self-driving` integration stream (forked from `main`).
61
+ 5. Spawns the team's root agent (planner) + companions (judge) from the team YAML topology.
62
+ 6. Sends your task to the root agent and streams the response.
63
+ 7. On `Ctrl-C`: cleanly shuts down agents, closes worktrees, leaves the team stream intact for review.
64
+
65
+ Expected output (abridged):
66
+
67
+ ```
68
+ Booting macro-agent and starting team: self-driving
69
+ System booted.
70
+ Team started: self-driving (instance self-driving-1)
71
+ Prompting root agent (agent_ab...) with task...
72
+ [agent output streams here]
73
+ Press Ctrl+C to shut down.
74
+ ```
75
+
76
+ ---
77
+
78
+ ## How it works
79
+
80
+ The flow for a running team, end to end:
81
+
82
+ ```
83
+ 1. BOOT bootV2 → AgentStore · Inbox · Tasks · AgentManager · Triggers
84
+ 2. TEAM START TeamManager.startTeam → load YAML → YamlDrivenTopology
85
+ → onTeamStart creates team:<name> integration stream
86
+ → bootstrap root + companions
87
+ 3. SPAWN agentManager.spawn(role)
88
+ → topology.onAgentSpawn → WorkspaceDecision
89
+ → executeWorkspaceDecision: create/fork stream, allocate worktree
90
+ → Claude Code subprocess launched with MCP tools
91
+ 4. WORK Agent writes files in its isolated worktree
92
+ → commits via `commit` MCP tool (Change-Id tracked)
93
+ → sends messages via agent-inbox
94
+ → spawns sub-agents via `spawn_agent` (capability-gated)
95
+ 5. LAND Agent calls `done()`
96
+ → LandingStrategy invoked (merge-to-parent / queue-to-branch / etc.)
97
+ → cascade rebase optional (for stacked streams)
98
+ 6. RECOVER If landing conflicts: ConflictRecoveryStrategy dispatches
99
+ → defer / abandon / escalate / auto-resolve / spawn-resolver
100
+ 7. SYNC When a parent stream advances, roles with
101
+ `on_parent_advanced: sync_with_parent` auto-rebase
102
+ (coalesced 2s debounce)
103
+ 8. TERMINATE topology.onAgentComplete → deallocate worktree (ref-counted)
104
+ 9. TEAM STOP topology.onTeamStop → keep / merge-to-main / abandon the team stream
105
+ ```
106
+
107
+ Key separation:
108
+ - **YAML** is the source of truth for team shape (who exists, which streams, what landing/recovery).
109
+ - **MCP tools** are how agents make runtime decisions within capabilities granted by YAML.
110
+ - **Programmatic API** on `WorkspaceManager` is for library consumers that bypass team YAML.
111
+
112
+ ---
113
+
114
+ ## Team configuration
115
+
116
+ Teams live in `.multiagent/teams/<name>/`:
117
+
118
+ ```
119
+ .multiagent/teams/self-driving/
120
+ ├── team.yaml # Manifest: topology, communication, macro_agent block
121
+ ├── roles/
122
+ │ ├── planner.yaml # Custom role (extends coordinator)
123
+ │ ├── grinder.yaml # Custom role (extends worker)
124
+ │ └── judge.yaml # Custom role (extends monitor)
125
+ └── prompts/
126
+ ├── planner.md
127
+ ├── grinder.md
128
+ └── judge.md
129
+ ```
130
+
131
+ ### Minimum viable team
132
+
133
+ ```yaml
134
+ # team.yaml
135
+ name: my-team
136
+ version: 1
137
+ roles: [worker]
138
+
139
+ topology:
140
+ root:
141
+ role: worker
142
+ prompt: prompts/worker.md
143
+
144
+ communication:
145
+ enforcement: permissive
146
+
147
+ macro_agent:
148
+ workspace:
149
+ roles:
150
+ worker:
151
+ workspace: none # no git isolation; inherit parent cwd
152
+ ```
153
+
154
+ Run it:
155
+
156
+ ```bash
157
+ npx multiagent-cli run my-team --task "hello"
158
+ ```
159
+
160
+ ### Workspace topology
161
+
162
+ The `macro_agent.workspace` block drives stream allocation per role. Grammar summary:
163
+
164
+ ```yaml
165
+ macro_agent:
166
+ workspace:
167
+ default_stream:
168
+ fork_from: main # branch to fork team_root from
169
+ name_template: "{team}" # {team} is substituted at runtime
170
+ change_id_tracking: true
171
+
172
+ on_team_complete: keep # or: merge_to_main, abandon
173
+
174
+ roles:
175
+ <role_name>:
176
+ # What kind of workspace this role gets
177
+ workspace: none | share_parent_cwd | attach_to_team_root |
178
+ share_with_agent | new_stream
179
+
180
+ # When workspace: new_stream, how is the stream placed in the graph?
181
+ stream_lineage: from_team_root | fork_from_team_root |
182
+ fork_from_parent | independent | track_existing_branch
183
+
184
+ # How to finalize work (see Landing strategies below)
185
+ landing: merge_to_parent_stream | queue_to_branch |
186
+ direct_push | optimistic_push | none
187
+ landing_config: { } # strategy-specific options
188
+
189
+ # What to do on a landing conflict
190
+ on_conflict: abort | ours | theirs | defer | agent
191
+ on_conflict_recovery: defer | abandon | escalate |
192
+ auto-resolve | spawn-resolver
193
+
194
+ # Auto-rebase onto parent when parent advances
195
+ on_parent_advanced: sync_with_parent | none
196
+ cascade_on_parent_update: true | false
197
+
198
+ # Cross-role references
199
+ share_with: <role_name> # for workspace: share_with_agent
200
+ track_branch: <branch_name> # for stream_lineage: track_existing_branch
201
+
202
+ # MCP tool access for the agent
203
+ capabilities: [workspace.commit, workspace.land, ...]
204
+ ```
205
+
206
+ ### Landing strategies
207
+
208
+ When an agent calls `done()`, its role's `landing:` strategy finalizes the work.
209
+
210
+ | Strategy | What it does | Typical use |
211
+ |---|---|---|
212
+ | `merge_to_parent_stream` | `mergeStream(source → parent)`; optional cascade rebase for dependents | Stacked workflows, peer swarm |
213
+ | `queue_to_branch` | Adds to git-cascade's merge queue; integrator drains it later | Triad / many-writer flows |
214
+ | `direct_push` | `git rebase + git push` with retries | Trunk-based teams (self-driving's grinders) |
215
+ | `optimistic_push` | `direct_push` + emits validation event | Self-driving with judge reviewing after push |
216
+ | `none` | No landing (for read-only roles) | Researchers, judges, orchestrators |
217
+
218
+ Enable cascade rebase for stacked streams:
219
+
220
+ ```yaml
221
+ roles:
222
+ feature_owner:
223
+ landing: merge_to_parent_stream
224
+ landing_config:
225
+ cascade: true # propagate rebase to dependents
226
+ cascadeStrategy: defer_conflicts # or: stop_on_conflict, skip_conflicting
227
+ ```
228
+
229
+ ### Conflict recovery
230
+
231
+ When landing returns a conflict, macro-agent dispatches a `ConflictRecoveryStrategy` based on the role's `on_conflict_recovery` (or team default).
232
+
233
+ | Strategy | Mode | Behavior |
234
+ |---|---|---|
235
+ | `defer` | sync | Leave conflict record in place; human/external resolves |
236
+ | `abandon` | sync | Abandon the conflicted stream — throwaway work |
237
+ | `escalate` | async | Pause stream, notify human, await external resolve_conflict |
238
+ | `auto-resolve` | sync | Replay merge with `-X ours/theirs/union`; commit; unblock |
239
+ | `spawn-resolver` | async | Spawn an LLM resolver agent; times out → escalates |
240
+
241
+ Example:
242
+
243
+ ```yaml
244
+ macro_agent:
245
+ workspace:
246
+ conflict_recovery:
247
+ default_strategy: spawn-resolver
248
+ default_config:
249
+ role: resolver
250
+ timeout_ms: 1800000 # 30 min
251
+ max_recovery_depth: 3
252
+
253
+ roles:
254
+ coder:
255
+ landing: queue_to_branch
256
+ on_conflict_recovery: spawn-resolver # can override team default
257
+ hotfix:
258
+ on_conflict_recovery: auto-resolve
259
+ conflict_recovery_config:
260
+ strategy: ours
261
+ ```
262
+
263
+ For `spawn-resolver`, define the resolver role:
264
+
265
+ ```yaml
266
+ roles:
267
+ resolver:
268
+ workspace: new_stream
269
+ stream_lineage: track_existing_branch # attach to the conflicted branch
270
+ landing: none # resolver doesn't land itself
271
+ capabilities:
272
+ - workspace.commit
273
+ - workspace.resolve # unlocks resolve_conflict MCP tool
274
+ - workspace.read
275
+ ```
276
+
277
+ ### Six team shapes
278
+
279
+ The workspace layer is designed to express 6 common multi-agent patterns. See [docs/git-cascade-integration-gaps.md](docs/git-cascade-integration-gaps.md) §5 for traces.
280
+
281
+ **1. Solo stack** — one agent, chain of forked streams:
282
+ ```yaml
283
+ roles:
284
+ author:
285
+ workspace: new_stream
286
+ stream_lineage: fork_from_team_root
287
+ landing: merge_to_parent_stream
288
+ cascade_on_parent_update: true
289
+ ```
290
+
291
+ **2. Triad** — coordinator + integrator + N workers:
292
+ ```yaml
293
+ roles:
294
+ coordinator: { workspace: attach_to_team_root }
295
+ worker:
296
+ workspace: new_stream
297
+ stream_lineage: fork_from_parent
298
+ landing: queue_to_branch
299
+ landing_config: { target: "stream:team_root" }
300
+ integrator:
301
+ workspace: attach_to_team_root
302
+ capabilities: [workspace.merge, merge_queue.drain]
303
+ ```
304
+
305
+ **3. Peer swarm** — N equal agents:
306
+ ```yaml
307
+ roles:
308
+ orchestrator: { workspace: none }
309
+ peer:
310
+ workspace: new_stream
311
+ stream_lineage: fork_from_team_root
312
+ landing: merge_to_parent_stream
54
313
  ```
55
314
 
56
- ### CLI
315
+ **4. Pipeline** — planner → coder → reviewer → integrator:
316
+ ```yaml
317
+ roles:
318
+ planner: { workspace: none }
319
+ coder:
320
+ workspace: new_stream
321
+ stream_lineage: fork_from_team_root
322
+ landing: queue_to_branch
323
+ reviewer:
324
+ workspace: share_with_agent
325
+ share_with: coder
326
+ landing: none
327
+ integrator:
328
+ workspace: attach_to_team_root
329
+ capabilities: [workspace.merge, merge_queue.drain]
330
+ ```
331
+
332
+ **5. Research / read-only** — agents don't commit:
333
+ ```yaml
334
+ roles:
335
+ researcher:
336
+ workspace: none
337
+ capabilities: []
338
+ ```
339
+
340
+ **6. Long-lived feature + subtasks** — parent rebases onto main as it advances:
341
+ ```yaml
342
+ roles:
343
+ feature_owner:
344
+ workspace: new_stream
345
+ stream_lineage: fork_from_team_root
346
+ landing: merge_to_parent_stream
347
+ cascade_on_parent_update: true
348
+ on_parent_advanced: sync_with_parent
349
+ subtask:
350
+ workspace: new_stream
351
+ stream_lineage: fork_from_parent
352
+ landing: merge_to_parent_stream
353
+ ```
354
+
355
+ ---
356
+
357
+ ## CLI reference
57
358
 
58
359
  ```bash
59
- # Start the system and enter interactive chat
60
- npx multiagent-cli chat
360
+ # Run a team with optional initial task
361
+ npx multiagent-cli run <teamName> [--task "..."] [--cwd <path>] [--base-path <path>]
362
+
363
+ # Interactive chat with a head manager (no team)
364
+ npx multiagent-cli chat [--cwd <path>]
61
365
 
62
- # Check system status
366
+ # System status (agent count, active sessions)
63
367
  npx multiagent-cli status
64
368
 
65
- # View agent hierarchy
66
- npx multiagent-cli hierarchy
369
+ # Agent hierarchy tree
370
+ npx multiagent-cli hierarchy [rootId]
67
371
 
68
- # List all agents
69
- npx multiagent-cli agents
372
+ # List agents (optional filter)
373
+ npx multiagent-cli agents [agentId]
70
374
 
71
- # Stop an agent or all agents
375
+ # Stop a specific agent or all
72
376
  npx multiagent-cli stop <agentId>
73
377
  npx multiagent-cli stop --all
74
378
 
75
- # Clear all data (agents.db, inbox.db)
379
+ # Wipe local state (agents.db, inbox.db, worktrees)
76
380
  npx multiagent-cli clear
77
381
 
78
- # Start as ACP server (for embedding via acp-factory)
382
+ # ACP stdio server (for embedding via acp-factory)
79
383
  npx multiagent --acp
80
384
  ```
81
385
 
386
+ `run` exits cleanly on `SIGINT` (Ctrl-C). Exit code `0` on normal shutdown, non-zero if team startup fails.
387
+
388
+ ---
389
+
390
+ ## Programmatic API
391
+
392
+ For library consumers (tools, tests, cognitive-core):
393
+
394
+ ```typescript
395
+ import { bootV2 } from 'macro-agent';
396
+
397
+ const system = await bootV2({
398
+ cwd: process.cwd(),
399
+ // Optional: enable extras
400
+ api: { enabled: true, port: 3000 },
401
+ acp: { enabled: true, port: 8080 },
402
+ federation: { systemId: 'dev-laptop' },
403
+ });
404
+
405
+ // Option A: start a team with auto-wired V3 topology
406
+ const teamManager = new TeamManagerV2({
407
+ agentManager: system.agentManager,
408
+ inboxAdapter: system.inboxAdapter,
409
+ tasksAdapter: system.tasksAdapter,
410
+ workspaceManager: system.workspaceManager,
411
+ });
412
+ teamManager.install();
413
+ await teamManager.startTeam('self-driving');
414
+
415
+ // Option B: drive agents directly (no team YAML)
416
+ const head = await system.agentManager.getOrCreateHeadManager({ cwd: process.cwd() });
417
+ for await (const update of system.agentManager.prompt(head.id, 'Do the thing')) {
418
+ // stream updates
419
+ }
420
+
421
+ await system.shutdown();
422
+ ```
423
+
424
+ Workspace API for direct control:
425
+
426
+ ```typescript
427
+ import { DefaultWorkspaceManager, createGitCascadeAdapter } from 'macro-agent';
428
+
429
+ const adapter = createGitCascadeAdapter({ enabled: true, repoPath, dbPath });
430
+ const ws = createWorkspaceManagerWithAdapter(adapter);
431
+
432
+ // Stream-first primitives
433
+ const stream = ws.createStreamV3({ name: 'feature-x', ownerId: 'team:app', forkFrom: 'main' });
434
+ const child = ws.forkStream({ parentStreamId: stream, name: 'sub', ownerId: 'agent-1' });
435
+ const wt = ws.allocateWorktree({ agentId: 'agent-1', streamId: child });
436
+
437
+ // Change-Id tracked commit
438
+ const { commit, changeId } = ws.commitChanges({
439
+ agentId: 'agent-1', streamId: child, worktree: wt.path, message: 'feat: x',
440
+ });
441
+
442
+ // Land via strategy
443
+ const result = await ws.land({ agentId: 'agent-1', streamId: child, strategyName: 'merge-to-parent' });
444
+ ```
445
+
446
+ ---
447
+
448
+ ## MCP tools agents get
449
+
450
+ Registered per role based on capabilities declared in team YAML:
451
+
452
+ | Source | Tools | Capability required |
453
+ |---|---|---|
454
+ | macro-agent | `done`, `spawn_agent`, `stop_agent`, `get_hierarchy`, `inject_context` | always available |
455
+ | macro-agent | `claim_task`, `unclaim_task`, `list_claimable_tasks` | `task.claim` |
456
+ | macro-agent | `commit` | `workspace.commit` |
457
+ | macro-agent | `land` | `workspace.land` |
458
+ | macro-agent | `resolve_conflict`, `list_conflicts`, `get_conflict` | `workspace.resolve` |
459
+ | macro-agent | `next_merge_request`, `mark_merge_complete` | `merge_queue.drain` |
460
+ | agent-inbox | `send_message`, `check_inbox`, `read_thread`, `list_agents` | always available |
461
+ | opentasks | `task`, `link`, `annotate`, `query` | always available |
462
+
463
+ Role YAML grants capabilities:
464
+
465
+ ```yaml
466
+ # roles/grinder.yaml
467
+ name: grinder
468
+ extends: worker
469
+ capabilities_add:
470
+ - workspace.commit
471
+ - workspace.land
472
+ - task.claim
473
+ ```
474
+
475
+ ---
476
+
82
477
  ## Architecture
83
478
 
84
479
  ```
@@ -96,105 +491,356 @@ npx multiagent --acp
96
491
  │ │ │ │ │ (RPC) │ │ (WS) │ │ (HTTP) │
97
492
  │ spawn │ │ router │ └────┬────┘ └────────┘ └───────────┘
98
493
  │ prompt │ │ wake │ │
99
- │ terminate│ │ cron │ MCP subprocesses
100
- └─────┬─────┘ │ webhook │ (per agent)
494
+ │ terminate│ │ cron │ MCP subprocesses (per agent)
495
+ └─────┬─────┘ │ webhook │
101
496
  │ │ ai-router│
102
497
  ┌─────┼───────┘──────────┐
103
498
  │ │ │
104
- ┌▼────┐┌▼──────────┐ ┌───▼────────┐
105
- │Roles││ Workspace │ │ Adapters │
106
- │ ││ Worktrees │ │ │
107
- │ ││ Strategies │ │ InboxAdapter ──► agent-inbox (embedded)
108
- │ ││ MergeQueue │ │ TasksAdapter ──► opentasks (IPC daemon)
109
- └────┘└────────────┘ │ Federation ──► remote instances
110
- └────────────┘
499
+ ┌▼────┐┌▼──────────────┐ ┌───▼────────┐
500
+ │Roles││ Workspace (V3) │ │ Adapters │
501
+ │ ││ TopologyPolicy │ │ │
502
+ │ ││ LandingStrategy│ │ InboxAdapter ──► agent-inbox (embedded)
503
+ │ ││ ConflictRecov. │ │ TasksAdapter ──► opentasks (IPC daemon)
504
+ │ ││ GitCascadeAdpt Federation ──► remote instances
505
+ └────┘└────────────────┘ └────────────┘
111
506
  ```
112
507
 
113
- **Three subsystems:**
114
- - **macro-agent** — Orchestration, lifecycle, teams, workspace, triggers, ACP/REST servers, federation, cognitive backend, metrics
115
- - **agent-inbox** — Messaging (embedded in-process, IPC server for subprocesses, federation)
116
- - **opentasks** — Task management (separate daemon, IPC client)
508
+ Three subsystems:
509
+ - **macro-agent** — orchestration, lifecycle, teams, workspace, triggers, ACP/REST, federation, cognitive backend
510
+ - **agent-inbox** — messaging (embedded in-process, IPC server for subprocesses, federation)
511
+ - **opentasks** — task management (separate daemon, IPC client)
117
512
 
118
- ## Team Templates
513
+ For full design rationale and interface contracts:
514
+ - [docs/workspace-interfaces.md](docs/workspace-interfaces.md) — V3 TypeScript contracts
515
+ - [docs/git-cascade-integration-gaps.md](docs/git-cascade-integration-gaps.md) — design narrative + 6 workflow traces
516
+ - [docs/conflict-recovery.md](docs/conflict-recovery.md) — recovery strategy design
517
+ - [docs/workspace-redesign-plan.md](docs/workspace-redesign-plan.md) — implementation plan + status
119
518
 
120
- Teams define multi-agent topologies as YAML configuration:
519
+ The four subsections below summarize those docs so this README is useful standalone.
121
520
 
122
- ```bash
123
- # Start with a team template
124
- npx multiagent --team self-driving
521
+ ---
522
+
523
+ ## Design & internals
524
+
525
+ ### Why V3 was needed
526
+
527
+ The original workspace layer was **role-shaped**: every agent had to be a `coordinator`, `worker`, or `integrator`, and the dispatch path in `AgentManagerV2` hardcoded a `switch(role)` that decided what kind of workspace to allocate. The API surface — `createWorkerWorkspace`, `createIntegratorWorkspace`, `createCoordinatorWorkspace`, `createIntegrationStream`, `getMergeQueue` — reflected this bias.
528
+
529
+ **Problems in the old model:**
530
+
531
+ | Symptom | Cause |
532
+ |---|---|
533
+ | One stream per team, owned by a coordinator | Hardcoded in `TeamRuntimeV2` at bootstrap |
534
+ | Cascade rebase (git-cascade's namesake) never called | Adapter never surfaced it |
535
+ | Change-IDs never tracked | Agents used raw `git commit`, bypassing `commitChanges` |
536
+ | Merge queue duplicated | `src/workspace/merge-queue/` replicated git-cascade's built-in with incompatible semantics |
537
+ | Only 20% of git-cascade's API used | Role-shaped wrapper hid most of the library |
538
+ | Peer-swarm / solo-stack / pipeline shapes unexpressible | No role name mapped to them |
539
+
540
+ **What V3 changed:**
541
+
542
+ 1. **Stream-first primitives.** `createStreamV3`, `forkStream`, `allocateWorktree`, `commitChanges`, `land` — all role-neutral. Any `Principal` (real `AgentId` or pseudo like `team:<name>`) can own a stream.
543
+ 2. **YAML-driven topology.** Team YAML's `macro_agent.workspace` block declares per-role workspace decisions. `YamlDrivenTopology` compiles this into per-spawn `WorkspaceDecision` objects.
544
+ 3. **Pluggable landing strategies.** `merge-to-parent`, `queue-to-branch`, `direct-push`, `optimistic-push` replace the dead `IntegrationStrategy` abstraction.
545
+ 4. **Pluggable conflict recovery.** `defer` / `abandon` / `escalate` / `auto-resolve` (real git `-X` merge) / `spawn-resolver` (LLM agent).
546
+ 5. **git-cascade 0.0.3 alignment.** `cascade` namespace export + `emit` callback wired, unlocking `cascadeRebase` and event-driven auto-sync.
547
+ 6. **Legacy path retained.** Programmatic callers that bypass team YAML still use capability-based dispatch (`workspace.worktree` / `workspace.stream` / `workspace.integrate`).
548
+
549
+ Three control layers coexist:
550
+
551
+ | Layer | Used by | What it controls |
552
+ |---|---|---|
553
+ | YAML (`macro_agent.workspace`) | Team authors | Static shape: who gets a stream, lineage, landing, recovery |
554
+ | MCP tools (`commit`, `land`, `fork_stream`, `resolve_conflict`, ...) | Agents at runtime | Runtime judgment within YAML-granted capabilities |
555
+ | Programmatic API on `WorkspaceManager` | Tools, tests, cognitive-core | Full control without team YAML |
556
+
557
+ ### Workspace interfaces
558
+
559
+ Three interfaces form the V3 workspace layer. Types live in `src/workspace/types-v3.ts`.
560
+
561
+ **`WorkspaceManager`** — the full API surface, grouped by concern:
562
+
563
+ ```typescript
564
+ interface WorkspaceManager {
565
+ // Streams
566
+ createStreamV3(spec: StreamSpec): StreamId;
567
+ forkStream(opts: { parentStreamId, name, ownerId, metadata? }): StreamId;
568
+ mergeStream(opts: { sourceStreamId, targetStreamId, agentId, worktree }): MergeResult;
569
+ syncWithParent(opts: { streamId, agentId, worktree, onConflict? }): RebaseResult;
570
+ abandonStream(streamId, opts?): void;
571
+ pauseStream(streamId, reason?): void;
572
+ resumeStream(streamId): void;
573
+ listStreams(filter?): Stream[];
574
+ getStream(streamId): Stream | null;
575
+
576
+ // Changes (Change-Id tracking via git-cascade)
577
+ commitChanges(opts): { commit: string; changeId: ChangeId };
578
+ markChangesMerged(changeIds: ChangeId[]): void;
579
+ getChange(changeId): Change | null;
580
+ getChangeByCommit(commit): Change | null;
581
+
582
+ // Worktrees
583
+ allocateWorktree(opts: AllocateWorktreeOpts): Worktree;
584
+ deallocateWorkspace(agentId): void;
585
+ getWorktreeForAgent(agentId): Worktree | null;
586
+
587
+ // Landing + recovery
588
+ registerLandingStrategy(strategy: LandingStrategy): void;
589
+ land(opts): Promise<MergeResult>;
590
+ resolveConflict(opts: { conflictId, resolvedBy, resolutionCommit? }): void;
591
+
592
+ // Events + lifecycle
593
+ onEvent(callback: WorkspaceEventCallback): () => void;
594
+ reconcileV3(): MacroReconcileResult;
595
+ close(): void;
596
+ }
125
597
  ```
126
598
 
127
- Teams are stored in `.multiagent/teams/<name>/`:
599
+ **Core types:**
128
600
 
601
+ ```typescript
602
+ // A principal — either a real agent or a pseudo-principal for team/system ownership
603
+ type Principal = AgentId | `team:${string}` | `system:${string}`;
604
+
605
+ interface StreamSpec {
606
+ name: string;
607
+ ownerId: Principal;
608
+ parent?: StreamId; // if set, forks from this parent stream
609
+ forkFrom?: string; // otherwise forks from this branch (default: "main")
610
+ metadata?: Record<string, unknown>;
611
+ }
612
+
613
+ interface AllocateWorktreeOpts {
614
+ agentId: Principal;
615
+ streamId?: StreamId;
616
+ sharedWithAgent?: AgentId; // ref-counted co-location
617
+ branch?: string;
618
+ baseDir?: string;
619
+ }
129
620
  ```
130
- .multiagent/teams/self-driving/
131
- ├── team.yaml # Team manifest (topology, communication, strategy)
132
- ├── roles/
133
- │ ├── planner.yaml # Custom role (extends coordinator)
134
- │ └── grinder.yaml # Custom role (extends worker)
135
- └── prompts/
136
- ├── planner.md # Role-specific system prompt
137
- └── grinder.md
621
+
622
+ **`TopologyPolicy`** — compiles team YAML into per-spawn decisions:
623
+
624
+ ```typescript
625
+ interface TopologyPolicy {
626
+ readonly name: string;
627
+ onTeamStart(ctx): Promise<TeamStartPlan>; // create team-root stream
628
+ onAgentSpawn(ctx): Promise<WorkspaceDecision>; // per-spawn workspace choice
629
+ onAgentComplete(ctx): Promise<void>; // deallocate worktree
630
+ onTeamStop(ctx): Promise<void>; // apply on_team_complete
631
+ }
632
+
633
+ type WorkspaceDecision =
634
+ | { kind: 'none' }
635
+ | { kind: 'share-parent-cwd' }
636
+ | { kind: 'share-with-agent'; agentId: AgentId }
637
+ | { kind: 'attach-to-stream'; streamId: StreamId; allocateWorktree: boolean }
638
+ | { kind: 'new-stream'; streamSpec: StreamSpec; allocateWorktree: boolean };
138
639
  ```
139
640
 
140
- Key team features:
141
- - **Topology**: Root + companion agents spawned at bootstrap, with spawn rules for dynamic workers
142
- - **Communication**: Topic-based channels with per-role signal filtering and peer-to-peer routing
143
- - **Multi-team**: Multiple teams run concurrently with composite signal filters and emission validators
144
- - **Integration strategies**: `queue` (merge queue), `trunk` (direct push), `optimistic` (push + validation)
145
- - **Task modes**: `push` (coordinator assigns) or `pull` (agents claim from pool)
641
+ Three built-in policies:
642
+ - **`YamlDrivenTopology`** the default; compiles `macro_agent.workspace` YAML
643
+ - **`NoWorkspaceTopology`** null policy returning `share-parent-cwd` for every spawn
644
+ - **Custom** implement the interface for bespoke topologies
146
645
 
147
- See [docs/teams.md](docs/teams.md) for the full schema reference.
646
+ **`LandingStrategy`** finalizes work at `done()` time:
148
647
 
149
- ## MCP Tools
648
+ ```typescript
649
+ interface LandingStrategy {
650
+ readonly name: string;
651
+ canLand?(ctx: LandingContext): boolean;
652
+ land(ctx: LandingContext): Promise<MergeResult>;
653
+ initialize?(): Promise<void>;
654
+ close?(): Promise<void>;
655
+ }
150
656
 
151
- Each agent gets tools from three sources:
657
+ interface LandingContext {
658
+ agentId: AgentId;
659
+ streamId: StreamId;
660
+ sourceWorktree: string;
661
+ targetStreamId?: StreamId;
662
+ strategyConfig?: Record<string, unknown>; // from YAML landing_config
663
+ workspaceManager: WorkspaceManager;
664
+ }
665
+ ```
152
666
 
153
- | Source | Tools |
154
- |--------|-------|
155
- | **macro-agent** | `done`, `spawn_agent`, `stop_agent`, `get_hierarchy`, `inject_context` |
156
- | **macro-agent** (pull mode) | `claim_task`, `unclaim_task`, `list_claimable_tasks` |
157
- | **agent-inbox** (IPC) | `send_message`, `check_inbox`, `read_thread`, `list_agents` |
158
- | **opentasks** (IPC) | `task`, `link`, `annotate`, `query` |
667
+ Registered via `workspaceManager.registerLandingStrategy()` at boot. YAML `landing:` selects per role; MCP `land()` tool arguments can override per call.
159
668
 
160
- ## Role System
669
+ **Events** all operations emit through a single channel:
161
670
 
162
- | Role | Purpose | Key Capabilities |
163
- |------|---------|------------------|
164
- | **Worker** | Execute tasks in isolated workspace | File I/O, git operations, task completion |
165
- | **Integrator** | Manage merge queue and resolve conflicts | Merge operations, branch management |
166
- | **Coordinator** | Orchestrate workers and manage tasks | Spawn agents, assign tasks, broadcast |
167
- | **Monitor** | Health monitoring and alerts | Read-only access, activity watching |
671
+ ```typescript
672
+ type WorkspaceEventType =
673
+ | 'stream:created' | 'stream:forked' | 'stream:committed'
674
+ | 'stream:merged' | 'stream:conflicted' | 'stream:abandoned'
675
+ | 'stream:paused' | 'stream:resumed'
676
+ | 'worktree:allocated' | 'worktree:shared' | 'worktree:released'
677
+ | 'change:merged' | 'change:dropped'
678
+ | 'conflict:created' | 'conflict:resolved'
679
+ | 'landing:started' | 'landing:completed'
680
+ | 'cascade:completed'
681
+ | 'mergeQueue:added' | 'mergeQueue:ready' | 'mergeQueue:cancelled' | 'mergeQueue:removed';
682
+ ```
683
+
684
+ Subscribers include `YamlDrivenTopology` (for `on_parent_advanced` auto-sync) and the conflict recovery dispatcher (awaiting `conflict:resolved`).
685
+
686
+ ### Conflict recovery mechanics
687
+
688
+ Conflicts originate from four operations:
689
+
690
+ | Operation | How conflict surfaces |
691
+ |---|---|
692
+ | `mergeStream(source → target)` | Result has `success: false`, `conflictId` present |
693
+ | `syncWithParent(stream)` | Rebase fails with `ConflictStrategy != 'ours'/'theirs'` |
694
+ | `rebaseOntoStream(target)` | Same as syncWithParent |
695
+ | `cascadeRebase({ root })` | `CascadeResult.failed[]` populated |
168
696
 
169
- Custom roles extend built-in roles via YAML with `capabilities_add`/`capabilities_remove`.
697
+ **Dispatch flow:**
170
698
 
171
- ## ACP Protocol Server
699
+ ```
700
+ Agent calls done()
701
+
702
+ Role's LandingStrategy invoked
703
+
704
+ LandingStrategy returns { success: false, conflictId }
705
+
706
+ done() handler looks up role's on_conflict_recovery (or team default)
707
+
708
+ workspaceManager dispatches to the matching ConflictRecoveryStrategy
709
+
710
+ Strategy runs sync (returns immediately) or async (awaits conflict:resolved event)
711
+
712
+ Resolution: resolved | deferred | abandoned | escalated | retry-after | failed
713
+ ```
714
+
715
+ Landing strategies **never** dispatch recovery themselves. They return the conflict up; the agent's `done()` flow owns recovery selection. This keeps strategies free of role-level policy (which lives in YAML).
172
716
 
173
- The ACP server bridges the [Agent Client Protocol](https://github.com/anthropics/acp) to macro-agent:
717
+ **`ConflictRecoveryStrategy` interface:**
174
718
 
175
719
  ```typescript
176
- const system = await bootV2({
177
- acp: { enabled: true, port: 8080 },
178
- });
720
+ interface ConflictRecoveryStrategy {
721
+ readonly name: string;
722
+ readonly mode: 'sync' | 'async';
723
+ canHandle?(ctx: ConflictContext): boolean;
724
+ recover(ctx: ConflictContext): Promise<ConflictResolution>;
725
+ }
726
+
727
+ interface ConflictContext {
728
+ conflictId: string;
729
+ streamId: StreamId;
730
+ paths: string[];
731
+ operation: 'merge' | 'sync' | 'rebase' | 'cascade';
732
+ landingAgentId?: AgentId;
733
+ worktree?: string; // required for auto-resolve
734
+ recoveryDepth: number; // for bounded recursion
735
+ strategyConfig?: Record<string, unknown>; // from YAML conflict_recovery_config
736
+ workspaceManager: WorkspaceManager;
737
+ }
738
+
739
+ type ConflictResolution =
740
+ | { kind: 'resolved'; resolutionCommit: string }
741
+ | { kind: 'deferred'; reason: string }
742
+ | { kind: 'abandoned'; streamId: StreamId; reason: string }
743
+ | { kind: 'escalated'; escalatedTo: Principal | 'human' }
744
+ | { kind: 'retry-after'; backoffMs: number; reason: string }
745
+ | { kind: 'failed'; error: string };
179
746
  ```
180
747
 
181
- - Maps `session/new` → head manager creation, `session/prompt` → streaming responses
182
- - Extension methods: `_macro/spawnAgent`, `_macro/getHierarchy`, `_macro/mountAgent`, `_macro/forkAgent`, etc.
183
- - WebSocket transport for real-time communication
748
+ **Built-in strategy details:**
749
+
750
+ - **`defer`** no-op. Returns `deferred`. Leaves the conflict record; a human or external process resolves later.
751
+ - **`abandon`** — calls `workspaceManager.abandonStream(streamId, { reason })`. Returns `abandoned`. For throwaway workflows.
752
+ - **`escalate`** — async. `pauseStream(streamId)` + emit escalation event. Returns `escalated` immediately; waits for an external `resolve_conflict` MCP call to unblock. Suitable when humans must review.
753
+ - **`auto-resolve`** — sync. Only handles `operation: 'merge'`. Replays the failed merge in `ctx.worktree` with `git merge -X ours|theirs|union`, commits the resolution, calls `workspaceManager.resolveConflict`. Returns `resolved` with the new commit hash.
754
+ - **`spawn-resolver`** — async. Spawns a resolver agent via `AgentManager.spawn({ role, ... })` with `workspace.resolve` capability. The resolver reads conflict markers, resolves, commits via the `commit` MCP tool, then calls `resolve_conflict` which emits `conflict:resolved`. The awaiting strategy promise resolves with the resolution commit. On timeout → `escalated`. Configurable concurrency cap (`max_concurrent` per stream) prevents resolver spawn storms.
755
+
756
+ **Safety controls:**
757
+
758
+ | Control | Location | Default |
759
+ |---|---|---|
760
+ | `max_recovery_depth` | `macro_agent.workspace.conflict_recovery.max_recovery_depth` | 3 |
761
+ | Per-stream recovery lock | Module-level in `spawn-resolver` | Auto |
762
+ | `max_concurrent` resolvers per stream | Strategy config | 2 |
763
+ | `timeout_ms` for async strategies | Strategy config | 30 min |
764
+
765
+ Recursion: if a resolver agent's resolution itself produces a new conflict, `recoveryDepth` increments. When it exceeds `max_recovery_depth`, the strategy falls back to `escalate`.
766
+
767
+ ### Implementation status
768
+
769
+ The V3 redesign shipped as 10 phases plus 6 follow-up fixes. All are in `main`.
770
+
771
+ **Completed:**
772
+
773
+ | # | Phase | What shipped |
774
+ |---|---|---|
775
+ | 0 | GitCascadeAdapter expansion | 40+ git-cascade primitives surfaced (streams, forks, merges, cascade, changes, events) |
776
+ | 1 | WorkspaceManager V3 surface | Stream-first methods alongside legacy role-shaped ones |
777
+ | 2 | YAML Zod schema | `macro_agent.workspace` validated at team load |
778
+ | 3 | TopologyPolicy + YamlDrivenTopology | Declarative topology compiler |
779
+ | 4 | AgentManagerV2 delegates to TopologyPolicy | V3 dispatch path with legacy capability fallback |
780
+ | 5 | LandingStrategy integration | 4 built-in strategies registered |
781
+ | 6 | MergeQueue marked `@deprecated` | Duplicate kept for legacy callers; scheduled for removal |
782
+ | 7 | ConflictRecoveryStrategy | 5 built-in strategies (including real-git `auto-resolve` + `spawn-resolver`) |
783
+ | 8 | Role-name fallback removed | `switch(role)` deleted; capability-based path retained |
784
+ | 9 | Legacy methods retained (not hard-removed) | Reframed: they serve programmatic callers |
785
+ | 10 | `macro-agent run <team>` CLI | Single-command team launch |
184
786
 
185
- ## REST API
787
+ **Follow-up fixes (post-plan):**
788
+
789
+ | # | Fix | Verified by |
790
+ |---|---|---|
791
+ | a | git-cascade 0.0.3 event wiring + cascade namespace | Adapter forwards `x-cascade/*` events into `WorkspaceEvent` stream |
792
+ | b | `macro-agent run` CLI e2e (subprocess spawn, SIGINT exit) | 2 e2e tests |
793
+ | c | self-driving team migrated to V3 YAML | 4 e2e tests; caught duplicate-stream bug in TeamRuntime |
794
+ | d | `spawn-resolver` real-spawn e2e | 4 unit + 2 e2e tests |
795
+ | e | Shared worktree ref-counting (Gap 3) | Fixed 2 latent bugs: sharer dealloc leaked refs; owner dealloc tore down path while sharers alive. 6 unit tests cover lifecycle |
796
+ | f | Cascade worktree provider (Gap 1) | Replaced null-returning stub with real provider: reuses live worktrees, allocates ephemeral `system:cascade-<id>` worktrees, cleans up in `finally`. Per-root-stream lock prevents parallel cascades racing. 4 e2e tests |
797
+ | g | `on_parent_advanced: sync_with_parent` auto-sync (Gap 2) | Full implementation: event subscription, 2-second coalescing debounce, role-scoped dispatch. 3 e2e tests |
798
+
799
+ **Test counts after all fixes:**
800
+
801
+ - 998 unit tests (59 files)
802
+ - 183 e2e tests (25 files) — all previously skipped `RUN_FULL_AGENT_TESTS` tests pass with real Claude Code
803
+ - Zero regressions, clean typecheck
804
+
805
+ **Known open items / follow-ups:**
806
+
807
+ | Item | Severity | Notes |
808
+ |---|---|---|
809
+ | Hard removal of legacy capability dispatch | Low | Retained as programmatic API; not a gap, a supported path |
810
+ | `on_team_complete: merge_to_main` implementation | Low | Currently leaves stream active. Requires landing strategy on team stream; deferred |
811
+ | Cross-team conflict policy | Low | When conflicts span teams, owner team's policy applies; federation-specific edge cases |
812
+ | Recovery observability dashboard | Low | `conflict:*` events fire; no built-in UI yet |
813
+
814
+ **Coverage gaps intentionally accepted:**
815
+
816
+ - Cascade with >3 levels under `stop_on_conflict` — tested at 3 levels only
817
+ - Shared worktree edge case: sharer outlives owner for >1 hour (no TTL) — accepted; `reconcileV3` cleans stale entries on boot
818
+
819
+ ---
820
+
821
+ ## Advanced integrations
822
+
823
+ ### ACP Protocol Server
824
+
825
+ Bridges the [Agent Client Protocol](https://github.com/anthropics/acp) to macro-agent so external clients can connect:
186
826
 
187
827
  ```typescript
188
- const system = await bootV2({
189
- api: { enabled: true, port: 3000 },
190
- });
828
+ const system = await bootV2({ acp: { enabled: true, port: 8080 } });
829
+ // session/new head manager creation
830
+ // session/prompt → streaming responses
831
+ // Extension methods: _macro/spawnAgent, _macro/getHierarchy, _macro/forkAgent, etc.
191
832
  ```
192
833
 
193
- HTTP endpoints for agents, tasks, teams, and metrics. Used for dashboards and external tooling.
834
+ ### REST API
835
+
836
+ ```typescript
837
+ const system = await bootV2({ api: { enabled: true, port: 3000 } });
838
+ // HTTP endpoints for agents, tasks, teams, metrics — used for dashboards
839
+ ```
194
840
 
195
- ## Federation
841
+ ### Federation
196
842
 
197
- Connect multiple macro-agent instances for cross-instance agent communication:
843
+ Connect multiple macro-agent instances for cross-instance messaging:
198
844
 
199
845
  ```typescript
200
846
  const system = await bootV2({
@@ -204,53 +850,55 @@ const system = await bootV2({
204
850
  trust: { allowedSystems: ['ci-server'] },
205
851
  },
206
852
  });
853
+ // Agents address with agentId@systemId (e.g., coordinator@ci-server)
207
854
  ```
208
855
 
209
- Agents address across instances with `agentId@systemId` (e.g., `coordinator@ci-server`).
210
-
211
- ## Cognitive-Core Backend
856
+ ### Cognitive-core backend
212
857
 
213
- macro-agent can serve as a compute backend for [cognitive-core](https://github.com/alexngai/cognitive-core) / OpenHive:
858
+ Serve as compute backend for [cognitive-core](https://github.com/alexngai/cognitive-core) / OpenHive:
214
859
 
215
860
  ```typescript
216
861
  import { MacroAgentBackend } from 'macro-agent/cognitive';
217
-
218
862
  const backend = new MacroAgentBackend(system.agentManager, {
219
863
  tasksAdapter: system.tasksAdapter,
220
864
  inboxAdapter: system.inboxAdapter,
221
865
  });
222
866
  ```
223
867
 
224
- Spawns analyst agents, manages sessions with timeouts, and reports completion. The swarm is pure compute — atlas, trajectory extraction, and team coordination are handled by OpenHive.
868
+ The swarm is pure compute — atlas, trajectory extraction, and team coordination are handled by OpenHive.
869
+
870
+ ---
225
871
 
226
872
  ## Dependencies
227
873
 
228
874
  | Package | Purpose |
229
- |---------|---------|
875
+ |---|---|
230
876
  | [agent-inbox](https://github.com/alexngai/agent-inbox) | Messaging, threading, federation |
231
877
  | [opentasks](https://github.com/alexngai/opentasks) | Task graph, dependencies, claiming |
232
878
  | [acp-factory](https://github.com/alexngai/acp-factory) | Agent process management |
233
879
  | [openteams](https://github.com/alexngai/openteams) | Team template resolution |
234
- | [git-cascade](https://github.com/alexngai/git-cascade) | Git worktree and merge operations |
235
- | [express](https://expressjs.com/) | REST API server |
236
- | [ws](https://github.com/websockets/ws) | ACP WebSocket transport |
880
+ | [git-cascade](https://github.com/alexngai/git-cascade) | Git worktrees, stream/fork/merge, Change-Id tracking, cascade rebase (≥0.0.3) |
881
+ | express | REST API server |
882
+ | ws | ACP WebSocket transport |
883
+
884
+ ---
237
885
 
238
886
  ## Testing
239
887
 
240
888
  ```bash
241
- # Unit tests (watch mode)
242
- npm test
243
-
244
- # Unit tests (single run)
245
- npx vitest run
889
+ # Unit tests (59 files, ~1000 tests)
890
+ npm test # watch
891
+ npx vitest run # single run
246
892
 
247
- # E2E tests (mocked agent sessions)
248
- npm run test:e2e
893
+ # E2E tests (24 files, ~180 tests — mocked agent sessions)
894
+ RUN_E2E_TESTS=true npm run test:e2e
249
895
 
250
- # E2E tests with real agent spawning
251
- RUN_FULL_AGENT_TESTS=true npm run test:e2e-full-agents
896
+ # Full e2e with real Claude Code agents
897
+ RUN_FULL_AGENT_TESTS=true RUN_E2E_TESTS=true npm run test:e2e
252
898
  ```
253
899
 
900
+ ---
901
+
254
902
  ## Development
255
903
 
256
904
  ```bash
@@ -259,6 +907,8 @@ npm run build # Build (TypeScript → dist/)
259
907
  npm run dev # Watch mode build
260
908
  ```
261
909
 
910
+ ---
911
+
262
912
  ## License
263
913
 
264
914
  MIT