macro-agent 0.1.7 → 0.1.10

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 (259) hide show
  1. package/CLAUDE.md +179 -38
  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 +155 -6
  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/agent/agent-manager-v2.d.ts +21 -0
  14. package/dist/agent/agent-manager-v2.d.ts.map +1 -1
  15. package/dist/agent/agent-manager-v2.js +234 -71
  16. package/dist/agent/agent-manager-v2.js.map +1 -1
  17. package/dist/agent/agent-manager.d.ts +12 -0
  18. package/dist/agent/agent-manager.d.ts.map +1 -1
  19. package/dist/agent/agent-manager.js.map +1 -1
  20. package/dist/agent/types.d.ts +15 -2
  21. package/dist/agent/types.d.ts.map +1 -1
  22. package/dist/agent/types.js.map +1 -1
  23. package/dist/boot-v2.d.ts +41 -0
  24. package/dist/boot-v2.d.ts.map +1 -1
  25. package/dist/boot-v2.js +34 -37
  26. package/dist/boot-v2.js.map +1 -1
  27. package/dist/cli/index.js +56 -0
  28. package/dist/cli/index.js.map +1 -1
  29. package/dist/cognitive/macro-agent-backend.d.ts.map +1 -1
  30. package/dist/cognitive/macro-agent-backend.js +40 -22
  31. package/dist/cognitive/macro-agent-backend.js.map +1 -1
  32. package/dist/integrations/skilltree.d.ts.map +1 -1
  33. package/dist/integrations/skilltree.js +1 -0
  34. package/dist/integrations/skilltree.js.map +1 -1
  35. package/dist/lifecycle/cleanup.d.ts +33 -2
  36. package/dist/lifecycle/cleanup.d.ts.map +1 -1
  37. package/dist/lifecycle/cleanup.js +28 -6
  38. package/dist/lifecycle/cleanup.js.map +1 -1
  39. package/dist/lifecycle/handlers-v2.d.ts +7 -0
  40. package/dist/lifecycle/handlers-v2.d.ts.map +1 -1
  41. package/dist/lifecycle/handlers-v2.js +28 -2
  42. package/dist/lifecycle/handlers-v2.js.map +1 -1
  43. package/dist/lifecycle/types.d.ts +11 -0
  44. package/dist/lifecycle/types.d.ts.map +1 -1
  45. package/dist/lifecycle/types.js.map +1 -1
  46. package/dist/map/acp-bridge.d.ts +9 -0
  47. package/dist/map/acp-bridge.d.ts.map +1 -1
  48. package/dist/map/acp-bridge.js +15 -2
  49. package/dist/map/acp-bridge.js.map +1 -1
  50. package/dist/map/cascade-bridge.d.ts +44 -0
  51. package/dist/map/cascade-bridge.d.ts.map +1 -0
  52. package/dist/map/cascade-bridge.js +257 -0
  53. package/dist/map/cascade-bridge.js.map +1 -0
  54. package/dist/map/lifecycle-bridge.d.ts +1 -8
  55. package/dist/map/lifecycle-bridge.d.ts.map +1 -1
  56. package/dist/map/lifecycle-bridge.js +76 -22
  57. package/dist/map/lifecycle-bridge.js.map +1 -1
  58. package/dist/map/server.d.ts.map +1 -1
  59. package/dist/map/server.js +47 -6
  60. package/dist/map/server.js.map +1 -1
  61. package/dist/map/sidecar.d.ts.map +1 -1
  62. package/dist/map/sidecar.js +33 -4
  63. package/dist/map/sidecar.js.map +1 -1
  64. package/dist/map/types.d.ts +20 -0
  65. package/dist/map/types.d.ts.map +1 -1
  66. package/dist/mcp/tools/done-v2.d.ts.map +1 -1
  67. package/dist/mcp/tools/done-v2.js +8 -0
  68. package/dist/mcp/tools/done-v2.js.map +1 -1
  69. package/dist/teams/team-manager-v2.d.ts.map +1 -1
  70. package/dist/teams/team-manager-v2.js +26 -0
  71. package/dist/teams/team-manager-v2.js.map +1 -1
  72. package/dist/teams/team-runtime-v2.d.ts.map +1 -1
  73. package/dist/teams/team-runtime-v2.js +16 -3
  74. package/dist/teams/team-runtime-v2.js.map +1 -1
  75. package/dist/workspace/config.d.ts +10 -10
  76. package/dist/workspace/config.d.ts.map +1 -1
  77. package/dist/workspace/config.js +4 -4
  78. package/dist/workspace/config.js.map +1 -1
  79. package/dist/workspace/git-cascade-adapter.d.ts +510 -0
  80. package/dist/workspace/git-cascade-adapter.d.ts.map +1 -0
  81. package/dist/workspace/git-cascade-adapter.js +908 -0
  82. package/dist/workspace/git-cascade-adapter.js.map +1 -0
  83. package/dist/workspace/index.d.ts +3 -3
  84. package/dist/workspace/index.d.ts.map +1 -1
  85. package/dist/workspace/index.js +4 -4
  86. package/dist/workspace/index.js.map +1 -1
  87. package/dist/workspace/landing/direct-push.d.ts +20 -0
  88. package/dist/workspace/landing/direct-push.d.ts.map +1 -0
  89. package/dist/workspace/landing/direct-push.js +74 -0
  90. package/dist/workspace/landing/direct-push.js.map +1 -0
  91. package/dist/workspace/landing/index.d.ts +29 -0
  92. package/dist/workspace/landing/index.d.ts.map +1 -0
  93. package/dist/workspace/landing/index.js +37 -0
  94. package/dist/workspace/landing/index.js.map +1 -0
  95. package/dist/workspace/landing/merge-to-parent.d.ts +41 -0
  96. package/dist/workspace/landing/merge-to-parent.d.ts.map +1 -0
  97. package/dist/workspace/landing/merge-to-parent.js +185 -0
  98. package/dist/workspace/landing/merge-to-parent.js.map +1 -0
  99. package/dist/workspace/landing/optimistic-push.d.ts +16 -0
  100. package/dist/workspace/landing/optimistic-push.d.ts.map +1 -0
  101. package/dist/workspace/landing/optimistic-push.js +27 -0
  102. package/dist/workspace/landing/optimistic-push.js.map +1 -0
  103. package/dist/workspace/landing/queue-to-branch.d.ts +24 -0
  104. package/dist/workspace/landing/queue-to-branch.d.ts.map +1 -0
  105. package/dist/workspace/landing/queue-to-branch.js +79 -0
  106. package/dist/workspace/landing/queue-to-branch.js.map +1 -0
  107. package/dist/workspace/merge-queue/merge-queue.d.ts +10 -0
  108. package/dist/workspace/merge-queue/merge-queue.d.ts.map +1 -1
  109. package/dist/workspace/merge-queue/merge-queue.js +10 -0
  110. package/dist/workspace/merge-queue/merge-queue.js.map +1 -1
  111. package/dist/workspace/merge-queue/types.d.ts +16 -2
  112. package/dist/workspace/merge-queue/types.d.ts.map +1 -1
  113. package/dist/workspace/merge-queue/types.js +9 -0
  114. package/dist/workspace/merge-queue/types.js.map +1 -1
  115. package/dist/workspace/pool/types.d.ts +1 -0
  116. package/dist/workspace/pool/types.d.ts.map +1 -1
  117. package/dist/workspace/pool/worktree-pool.d.ts.map +1 -1
  118. package/dist/workspace/pool/worktree-pool.js +1 -0
  119. package/dist/workspace/pool/worktree-pool.js.map +1 -1
  120. package/dist/workspace/recovery/abandon.d.ts +15 -0
  121. package/dist/workspace/recovery/abandon.d.ts.map +1 -0
  122. package/dist/workspace/recovery/abandon.js +45 -0
  123. package/dist/workspace/recovery/abandon.js.map +1 -0
  124. package/dist/workspace/recovery/auto-resolve.d.ts +27 -0
  125. package/dist/workspace/recovery/auto-resolve.d.ts.map +1 -0
  126. package/dist/workspace/recovery/auto-resolve.js +99 -0
  127. package/dist/workspace/recovery/auto-resolve.js.map +1 -0
  128. package/dist/workspace/recovery/defer.d.ts +15 -0
  129. package/dist/workspace/recovery/defer.d.ts.map +1 -0
  130. package/dist/workspace/recovery/defer.js +16 -0
  131. package/dist/workspace/recovery/defer.js.map +1 -0
  132. package/dist/workspace/recovery/escalate.d.ts +16 -0
  133. package/dist/workspace/recovery/escalate.d.ts.map +1 -0
  134. package/dist/workspace/recovery/escalate.js +24 -0
  135. package/dist/workspace/recovery/escalate.js.map +1 -0
  136. package/dist/workspace/recovery/index.d.ts +32 -0
  137. package/dist/workspace/recovery/index.d.ts.map +1 -0
  138. package/dist/workspace/recovery/index.js +45 -0
  139. package/dist/workspace/recovery/index.js.map +1 -0
  140. package/dist/workspace/recovery/spawn-resolver.d.ts +45 -0
  141. package/dist/workspace/recovery/spawn-resolver.d.ts.map +1 -0
  142. package/dist/workspace/recovery/spawn-resolver.js +111 -0
  143. package/dist/workspace/recovery/spawn-resolver.js.map +1 -0
  144. package/dist/workspace/recovery/types.d.ts +63 -0
  145. package/dist/workspace/recovery/types.d.ts.map +1 -0
  146. package/dist/workspace/recovery/types.js +12 -0
  147. package/dist/workspace/recovery/types.js.map +1 -0
  148. package/dist/workspace/topology/index.d.ts +9 -0
  149. package/dist/workspace/topology/index.d.ts.map +1 -0
  150. package/dist/workspace/topology/index.js +8 -0
  151. package/dist/workspace/topology/index.js.map +1 -0
  152. package/dist/workspace/topology/no-workspace.d.ts +18 -0
  153. package/dist/workspace/topology/no-workspace.d.ts.map +1 -0
  154. package/dist/workspace/topology/no-workspace.js +25 -0
  155. package/dist/workspace/topology/no-workspace.js.map +1 -0
  156. package/dist/workspace/topology/types.d.ts +97 -0
  157. package/dist/workspace/topology/types.d.ts.map +1 -0
  158. package/dist/workspace/topology/types.js +20 -0
  159. package/dist/workspace/topology/types.js.map +1 -0
  160. package/dist/workspace/topology/yaml-driven.d.ts +69 -0
  161. package/dist/workspace/topology/yaml-driven.d.ts.map +1 -0
  162. package/dist/workspace/topology/yaml-driven.js +273 -0
  163. package/dist/workspace/topology/yaml-driven.js.map +1 -0
  164. package/dist/workspace/types-v3.d.ts +110 -0
  165. package/dist/workspace/types-v3.d.ts.map +1 -0
  166. package/dist/workspace/types-v3.js +20 -0
  167. package/dist/workspace/types-v3.js.map +1 -0
  168. package/dist/workspace/types.d.ts +145 -17
  169. package/dist/workspace/types.d.ts.map +1 -1
  170. package/dist/workspace/workspace-manager.d.ts +92 -13
  171. package/dist/workspace/workspace-manager.d.ts.map +1 -1
  172. package/dist/workspace/workspace-manager.js +373 -13
  173. package/dist/workspace/workspace-manager.js.map +1 -1
  174. package/dist/workspace/yaml-schema.d.ts +254 -0
  175. package/dist/workspace/yaml-schema.d.ts.map +1 -0
  176. package/dist/workspace/yaml-schema.js +170 -0
  177. package/dist/workspace/yaml-schema.js.map +1 -0
  178. package/docs/conflict-recovery.md +472 -0
  179. package/docs/git-cascade-integration-gaps.md +678 -0
  180. package/docs/workspace-interfaces.md +731 -0
  181. package/docs/workspace-redesign-plan.md +302 -0
  182. package/package.json +4 -4
  183. package/src/__tests__/e2e/auto-sync.e2e.test.ts +257 -0
  184. package/src/__tests__/e2e/cascade-rebase.e2e.test.ts +254 -0
  185. package/src/__tests__/e2e/cli-run.e2e.test.ts +167 -0
  186. package/src/__tests__/e2e/self-driving-v3.e2e.test.ts +197 -0
  187. package/src/__tests__/e2e/spawn-resolver.e2e.test.ts +200 -0
  188. package/src/__tests__/e2e/workspace-lifecycle.e2e.test.ts +30 -22
  189. package/src/__tests__/e2e/workspace-v3.e2e.test.ts +413 -0
  190. package/src/acp/__tests__/claude-code-replay.test.ts +225 -0
  191. package/src/acp/__tests__/macro-agent.test.ts +39 -1
  192. package/src/acp/claude-code-replay.ts +208 -0
  193. package/src/acp/macro-agent.ts +167 -9
  194. package/src/acp/types.ts +10 -0
  195. package/src/agent/__tests__/agent-manager-topology.test.ts +73 -0
  196. package/src/agent/__tests__/agent-manager-v2.test.ts +71 -11
  197. package/src/agent/__tests__/task-ref-resolution.test.ts +231 -0
  198. package/src/agent/agent-manager-v2.ts +293 -77
  199. package/src/agent/agent-manager.ts +14 -0
  200. package/src/agent/types.ts +16 -2
  201. package/src/boot-v2.ts +87 -36
  202. package/src/cli/index.ts +61 -0
  203. package/src/cognitive/__tests__/macro-agent-backend.test.ts +47 -5
  204. package/src/cognitive/macro-agent-backend.ts +45 -29
  205. package/src/integrations/skilltree.ts +1 -0
  206. package/src/lifecycle/cleanup.ts +52 -3
  207. package/src/lifecycle/handlers-v2.ts +40 -3
  208. package/src/lifecycle/types.ts +12 -0
  209. package/src/map/__tests__/cascade-bridge.test.ts +229 -0
  210. package/src/map/__tests__/lifecycle-bridge.test.ts +165 -22
  211. package/src/map/acp-bridge.ts +26 -3
  212. package/src/map/cascade-bridge.ts +301 -0
  213. package/src/map/lifecycle-bridge.ts +77 -27
  214. package/src/map/server.ts +47 -6
  215. package/src/map/sidecar.ts +31 -3
  216. package/src/map/types.ts +20 -0
  217. package/src/mcp/tools/done-v2.ts +9 -0
  218. package/src/teams/team-manager-v2.ts +37 -0
  219. package/src/teams/team-runtime-v2.ts +23 -3
  220. package/src/workspace/__tests__/{dataplane-adapter.test.ts → git-cascade-adapter.test.ts} +209 -14
  221. package/src/workspace/__tests__/self-driving-yaml.test.ts +114 -0
  222. package/src/workspace/__tests__/shared-worktree-refcount.test.ts +154 -0
  223. package/src/workspace/__tests__/standalone-mode.test.ts +118 -0
  224. package/src/workspace/__tests__/workspace-manager-v3.test.ts +245 -0
  225. package/src/workspace/__tests__/yaml-schema.test.ts +210 -0
  226. package/src/workspace/config.ts +11 -11
  227. package/src/workspace/git-cascade-adapter.ts +1186 -0
  228. package/src/workspace/index.ts +11 -11
  229. package/src/workspace/landing/__tests__/strategies.test.ts +142 -0
  230. package/src/workspace/landing/direct-push.ts +91 -0
  231. package/src/workspace/landing/index.ts +40 -0
  232. package/src/workspace/landing/merge-to-parent.ts +228 -0
  233. package/src/workspace/landing/optimistic-push.ts +36 -0
  234. package/src/workspace/landing/queue-to-branch.ts +108 -0
  235. package/src/workspace/merge-queue/merge-queue.ts +10 -0
  236. package/src/workspace/merge-queue/types.ts +16 -2
  237. package/src/workspace/pool/__tests__/worktree-pool.integration.test.ts +5 -5
  238. package/src/workspace/pool/types.ts +1 -0
  239. package/src/workspace/pool/worktree-pool.ts +1 -0
  240. package/src/workspace/recovery/__tests__/auto-resolve-integration.test.ts +127 -0
  241. package/src/workspace/recovery/__tests__/spawn-resolver.test.ts +139 -0
  242. package/src/workspace/recovery/__tests__/strategies.test.ts +145 -0
  243. package/src/workspace/recovery/abandon.ts +51 -0
  244. package/src/workspace/recovery/auto-resolve.ts +119 -0
  245. package/src/workspace/recovery/defer.ts +23 -0
  246. package/src/workspace/recovery/escalate.ts +30 -0
  247. package/src/workspace/recovery/index.ts +58 -0
  248. package/src/workspace/recovery/spawn-resolver.ts +145 -0
  249. package/src/workspace/recovery/types.ts +54 -0
  250. package/src/workspace/topology/__tests__/yaml-driven.test.ts +345 -0
  251. package/src/workspace/topology/index.ts +18 -0
  252. package/src/workspace/topology/no-workspace.ts +39 -0
  253. package/src/workspace/topology/types.ts +116 -0
  254. package/src/workspace/topology/yaml-driven.ts +316 -0
  255. package/src/workspace/types-v3.ts +155 -0
  256. package/src/workspace/types.ts +191 -20
  257. package/src/workspace/workspace-manager.ts +474 -19
  258. package/src/workspace/yaml-schema.ts +216 -0
  259. package/src/workspace/dataplane-adapter.ts +0 -546
@@ -0,0 +1,678 @@
1
+ # git-cascade Integration: Surface Analysis & Redesign
2
+
3
+ Working doc for rethinking how macro-agent integrates with git-cascade (and, next, cc-swarm). Iterative — sections are discussion-ready, not committed.
4
+
5
+ ---
6
+
7
+ ## 1. Framing
8
+
9
+ The previous draft of this doc catalogued bugs in the "coordinator / integrator / worker" flow and called them integration gaps. That framing was wrong. The real issue is the **shape of the abstraction**, not holes within it.
10
+
11
+ - **git-cascade** (the library) is a general stream-stacking system. It has no notion of roles, no assumption of a coordinator, no requirement that work accumulates a specific way. A single agent, a stack, a swarm of peers — all are valid.
12
+ - **macro-agent's `WorkspaceManager`** projects that general model onto exactly one topology: one team → one stream → one coordinator → one integrator → N workers. Any agent outside that triad gets no workspace; any workflow that isn't "workers merge into a shared integration branch" is unreachable.
13
+
14
+ This doc (a) catalogues git-cascade's capability surface, (b) shows how narrow macro-agent's exposure of it is, and (c) sketches a stream-first redesign of `WorkspaceManager`.
15
+
16
+ cc-swarm integration is out of scope for this doc but will follow once the workspace abstraction is settled.
17
+
18
+ ---
19
+
20
+ ## 2. git-cascade capability surface
21
+
22
+ From `node_modules/git-cascade/dist/tracker.d.ts` and the README. The library's primary API is `MultiAgentRepoTracker` plus namespace modules. Core concepts:
23
+
24
+ ### 2.1 Streams as first-class units of work
25
+
26
+ | API | Purpose |
27
+ |---|---|
28
+ | `createStream({ name, agentId, enableStackedReview? })` | Create a stream owned by some agent. `agentId` is identity, not role. |
29
+ | `getStream` / `listStreams({ agentId?, status? })` | Enumerate streams. Status: `active`, `merged`, `abandoned`, `conflicted`. |
30
+ | `updateStream` / `abandonStream({ cascade? })` | Lifecycle transitions with cascading abandonment. |
31
+ | `pauseStream` / `resumeStream` | Temporary halt without abandoning. |
32
+ | `trackExistingBranch({ branch, agentId })` | Treat an existing branch as a stream without creating `stream/<id>`. |
33
+ | `getStreamHierarchy(rootStreamId?)` | Tree of parent/child streams with active tasks. |
34
+
35
+ ### 2.2 Stacking primitives
36
+
37
+ | API | Purpose |
38
+ |---|---|
39
+ | `forkStream({ parentStreamId, name, agentId })` | Fork a **child stream** off a parent. The building block for stacked diffs. |
40
+ | `syncWithParent(streamId, agentId, worktree, onConflict)` | Rebase child onto parent as parent advances. Conflict strategies: `abort`, `ours`, `theirs`, `agent` (callback). |
41
+ | `rebaseOntoStream(opts)` / `rebaseOntoStreamAsync(opts)` | Generalized rebase with async conflict handlers. |
42
+ | `mergeStream({ sourceStream, targetStream, agentId, worktree })` | Stream-to-stream merge preserving change tracking. |
43
+ | `cascade.cascadeRebase({ rootStream, strategy: 'skip_conflicting' \| ... })` | **Auto-propagate a rebase through all dependent streams.** The library's namesake feature. |
44
+ | `addDependency` / `getDependencies` / `getDependents` | Stream dependency graph. |
45
+ | `findCommonAncestor(streamA, streamB)` | Stream-level ancestor queries. |
46
+
47
+ ### 2.3 Stable change identity
48
+
49
+ | API | Purpose |
50
+ |---|---|
51
+ | `commitChanges({ streamId, agentId, worktree, message })` | Commit with an auto-generated `Change-Id` trailer. Returns `{ commit, changeId }`. |
52
+ | `getChangeByCommit` / `getChangeByHistoricalCommit` | Look up a change by any of its commits (past or current). |
53
+ | `recordSquash(absorbed[], target, resultCommit)` | Record squash so identity tracking survives. |
54
+ | `recordSplit(originalId, stream, newCommits[])` | Record split similarly. |
55
+ | `markChangesMerged` / `markChangeDropped` | Change lifecycle. |
56
+
57
+ Change-Ids are the mechanism by which git-cascade tracks a logical change across rebases, squashes, and splits. Macro-agent currently bypasses this entirely by using plain `git commit`.
58
+
59
+ ### 2.4 Merge queue (built into git-cascade)
60
+
61
+ | API | Purpose |
62
+ |---|---|
63
+ | `addToMergeQueue({ streamId, targetBranch, ... })` | Submit a stream for merging. |
64
+ | `getMergeQueue({ targetBranch?, status? })` | Inspect queue. |
65
+ | `getNextToMerge(targetBranch?)` | Deterministic dequeue. |
66
+ | `processMergeQueue(opts)` | Drain loop. |
67
+ | `markMergeQueueReady` / `cancelMergeQueueEntry` / `removeFromMergeQueue` / `getMergeQueuePosition` | Full queue management. |
68
+
69
+ **Macro-agent built its own MergeQueue** (`src/workspace/merge-queue/`) in parallel, storing rows in the same SQLite database under the `macro_` table prefix, ignoring git-cascade's `mergeQueue` module. This is pure duplication.
70
+
71
+ ### 2.5 Worker task lifecycle (one specific workflow git-cascade ships)
72
+
73
+ | API | Purpose |
74
+ |---|---|
75
+ | `createTask({ streamId, title, priority? })` | Create a task under a stream. |
76
+ | `startTask({ taskId, agentId, worktree })` | Assign agent, cut worker branch. |
77
+ | `completeTask(opts)` | Merge worker branch into stream (with `--no-ff`). |
78
+ | `abandonTask` / `releaseTask` | Task lifecycle recovery. |
79
+ | `listTasks(streamId, opts)` | Query. |
80
+ | `cleanupWorkerBranches({ olderThan, deleteOrphaned })` | Branch GC. |
81
+
82
+ Note: **this is one workflow the library provides**, not the library's core model. `workerTasks` is an optional module for the specific "N workers merging into a shared stream" pattern. A single-agent stacking workflow wouldn't use it at all.
83
+
84
+ ### 2.6 Review & diff stacks
85
+
86
+ | API | Purpose |
87
+ |---|---|
88
+ | `createReviewBlock` / `getReviewBlock` / `getStack` / `setReviewStatus` | PR-like review units. |
89
+ | `addCommitsToBlock` / `removeCommitsFromBlock` / `splitReviewBlock` / `mergeReviewBlocks` | Review block manipulation. |
90
+ | `rebuildStack` / `autoPopulateStack` / `listStacks` | Stack management. |
91
+ | `createCheckpointsFromStream(streamId, opts)` | Make checkpoints from commits in range. |
92
+ | `createStackFromStream(opts)` → `DiffStackWithCheckpoints` | Group checkpoints into a reviewable diff stack. |
93
+ | `cherryPickStackToTarget(stackId, worktree)` | Cherry-pick an approved stack onto a target. |
94
+
95
+ ### 2.7 Conflict handling
96
+
97
+ | API | Purpose |
98
+ |---|---|
99
+ | `createConflict` / `getConflict` / `getConflictForStream` | Conflict records as first-class objects. |
100
+ | Conflict strategies: `abort` / `ours` / `theirs` / `agent` | Configurable on any rebase/sync. |
101
+
102
+ Conflicts are recorded and deferred rather than blocking. Macro-agent does raw `git rebase`/`git merge` in its strategies and fails hard on conflicts.
103
+
104
+ ### 2.8 Operation log, rollback, reconciliation, health
105
+
106
+ | API | Purpose |
107
+ |---|---|
108
+ | `recordOperation` / `getOperation` / `getOperations` / `getOperationChain` | Audit log of all state changes. |
109
+ | `rollbackToOperation` / `rollbackN` / `rollbackToForkPoint` | Undo via op log. |
110
+ | `checkStreamSync` / `checkAllStreamsSync` / `reconcile` / `ensureStreamInSync` | Detect and heal git↔db drift. |
111
+ | `healthCheck()` | Stream counts, agents, stale locks, incomplete ops, orphaned conflicts. |
112
+ | `gc.*` | Auto-archive on merge/abandon, retention, branch deletion. |
113
+
114
+ The reconcile/health/gc tooling already solves what was listed as "Gap 7: no reconciliation between pool and git-cascade state" in the previous draft — macro-agent just doesn't call it.
115
+
116
+ ---
117
+
118
+ ## 3. What macro-agent currently exposes
119
+
120
+ | Capability | Status | Where |
121
+ |---|---|---|
122
+ | `createStream` | Used (once per team, owner = coordinator) | `workspace-manager.ts:136` |
123
+ | `createWorktree` | Used | `workspace-manager.ts` |
124
+ | `workerTasks.startTask` / `completeTask` | Used (via `claimTask`) | `dataplane-adapter.ts`, `agent-manager-v2.ts:469` |
125
+ | `deallocateWorktree` | Used | `workspace-manager.ts:391` |
126
+ | `workerTasks.detectTaskConflicts` | Surfaced in adapter, **no callers** | `dataplane-adapter.ts:379` |
127
+ | `diffStacks.createCheckpointsFromStream` | Surfaced in adapter, **no callers** | `dataplane-adapter.ts:431` |
128
+ | `workerTasks.cleanupWorkerBranches` | Surfaced in adapter, **no callers** | `dataplane-adapter.ts:486` |
129
+ | `forkStream` | **Never used.** No way to stack child streams. | — |
130
+ | `syncWithParent` / `rebaseOntoStream` | **Never used.** | — |
131
+ | `mergeStream` | **Never used.** Macro-agent uses raw `git merge`/`execSync` in strategies. | — |
132
+ | `cascade.cascadeRebase` | **Never used.** The library's namesake feature. | — |
133
+ | `commitChanges` (Change-Id tracking) | **Never used.** Workers use plain `git commit`. | — |
134
+ | Built-in `mergeQueue.*` | **Never used.** Macro-agent duplicates it with its own `MergeQueue`. | `src/workspace/merge-queue/` |
135
+ | Review blocks / stacks / checkpoints | **Never used.** | — |
136
+ | Conflict records | **Never used.** Strategies swallow conflicts via raw git. | — |
137
+ | `recordOperation` / rollback APIs | **Never used.** | — |
138
+ | `checkStreamSync` / `reconcile` / `healthCheck` | **Never used.** | — |
139
+ | `gc.*` / auto-archive | **Never configured.** | — |
140
+ | `trackExistingBranch` | **Never used.** Every stream creates a new `stream/<id>` branch. | — |
141
+ | `pauseStream` / `resumeStream` | **Never used.** | — |
142
+ | `addDependency` / `getDependents` | **Never used.** | — |
143
+ | `getStreamHierarchy` | **Never used.** | — |
144
+
145
+ Roughly **20% of git-cascade's surface is touched**, and the 80% that's ignored includes every primitive that would make topologies other than the triad workable.
146
+
147
+ ---
148
+
149
+ ## 4. The current topology as a case study
150
+
151
+ The triad is one valid workflow. It's worth describing precisely so it can be one of several supported topologies, not the only one.
152
+
153
+ ### 4.1 Actors and bootstrapping
154
+
155
+ - **One coordinator** per team, owning one stream. Coordinator's `agentId` is stored as `stream.agentId`.
156
+ - **Zero or one integrator** per team (team YAML must declare a role with `workspace.integrate` capability).
157
+ - **N workers** siblings of the coordinator.
158
+ - Stream is created eagerly at team bootstrap in `team-runtime-v2.ts:850-853` with `name = manifest.name` and `forkFrom = "main"`.
159
+
160
+ ### 4.2 Normal completion flow
161
+
162
+ 1. Worker spawn → `createWorkerWorkspace` creates a detached worktree, `claimTask` calls `startTask` which cuts `worker/<agentId>/<taskId>@<ts>`.
163
+ 2. Worker runs, commits with plain `git commit` (no Change-Id).
164
+ 3. On `done(status: "completed")`, AgentManagerV2 submits to the **macro_** merge queue (not git-cascade's).
165
+ 4. `mr:submitted` event fires; TeamRuntime prompts any `workspace.integrate`-capable agent with freeform "process the merge queue."
166
+ 5. Integrator LLM is expected to dequeue, merge, push. Strategy `.land()` is never called; `trunk` / `optimistic` are dead code.
167
+
168
+ ### 4.3 What this topology bakes in
169
+
170
+ | Assumption | Where | Consequence |
171
+ |---|---|---|
172
+ | Stream owner = coordinator | `stream.agentId = coordinatorId` | No stream without a coordinator. |
173
+ | One stream per team | `team-runtime-v2.ts:850`, `teamStreamId` | No parallel features per team. |
174
+ | Coordinator writes to stream branch | `CoordinatorWorkspace.branch = getStreamBranchName(streamId)` | Race with integrator's merges. |
175
+ | Integrator branch naming off coordinator ID | `integrator/${stream.agentId}@${ts}` | Nonsense if stream has no coordinator. |
176
+ | Role-name dispatch | `agent-manager-v2.ts:281-306` | Any role outside `{coordinator, integrator, worker}` gets no workspace. |
177
+ | `forkFrom: "main"` default | `team-runtime-v2.ts:852` | Assumes single trunk, always off `main`. |
178
+ | Workers can only land via merge queue | `agent-manager-v2.ts:687-695` | No other completion paths. |
179
+
180
+ ---
181
+
182
+ ## 5. Topologies that don't fit today
183
+
184
+ | Topology | Why it fails |
185
+ |---|---|
186
+ | **Single agent stacking** — one agent owns stream A, forks B off A, forks C off B, squash-merges | No `forkStream` wrapper. Stream owner coupling means the one agent has to play "coordinator" to get a stream at all. No Change-Id tracking. No `cascadeRebase` to propagate parent updates. |
187
+ | **Peer swarm** — N equal agents, no coordinator, each working on its own stream | No stream owner assigned at team start. Agents have role-name fallback returning `undefined`. No workspace isolation. |
188
+ | **Stacked diffs across team** — feature A (stream 1) depends on feature B (stream 2) which depends on main | No `forkStream`. `StreamConfig.forkFrom` is a branch name string, not a stream reference. No dependency graph. |
189
+ | **Nested coordinators** — parent coord spawns child coord for a sub-feature | Child coord creating a new stream via `workspace.stream` creates a stream forked from `"main"`, not from parent's stream. |
190
+ | **Multi-stream per team** — team runs feature A and feature B in parallel | One team = one stream, hardcoded at bootstrap. |
191
+ | **Non-worker leaf roles** — reviewer, judge, researcher, analyst | Role-name fallback returns `undefined`. Share parent cwd; no isolation even if they write files. |
192
+ | **Workers without integrator** | MRs submit and pile up with no drainer. |
193
+ | **Change identity across rebases** — "what was this change's ID before it got rebased?" | Never tracked; `commitChanges` not used. |
194
+ | **Auto-cascade on parent update** — merge main → rebase all child streams | `cascadeRebase` never called; no listener on parent-stream updates. |
195
+ | **Deferred conflict resolution** | Conflicts aren't recorded via git-cascade's conflict model; strategies fail hard on raw `git rebase`. |
196
+
197
+ ---
198
+
199
+ ## 6. Layers of control
200
+
201
+ Three distinct paths drive git-cascade behavior. The redesign must serve all three without letting any one become the single source of truth.
202
+
203
+ ### 6.1 Team YAML — declarative static shape (primary path)
204
+
205
+ Loaded once at team start. Describes what the team *always* does:
206
+
207
+ - Which roles get workspaces, and what kind (new stream, shared stream, shared worktree, none)
208
+ - Stream lineage per role (`from_team_root`, `fork_from_parent`, `fork_from_team_root`, `independent`, `track_existing_branch`)
209
+ - Default landing strategy per role
210
+ - Change-ID tracking on/off (defaults on)
211
+ - Default conflict strategy per role
212
+ - `cascade_on_parent_update` flag per stream
213
+ - Capability grants — which runtime MCP tools each role can call
214
+
215
+ Lives inside `macro_agent.workspace` at team level and inside per-role YAML via the `macro_agent` passthrough field on `RoleDefinition`. **No openteams schema changes required** — `TeamManifest.macro_agent` and `RoleDefinition.macro_agent` are both `Record<string, unknown>` by design, explicitly opaque to openteams. Macro-agent validates its own schema inside those envelopes.
216
+
217
+ ### 6.2 MCP tools — runtime dynamic decisions
218
+
219
+ Currently not exposed as tools; should be. Agents make decisions at runtime within the envelope granted by YAML capabilities:
220
+
221
+ | Tool | Capability gate | Purpose |
222
+ |---|---|---|
223
+ | `fork_stream({ name, parent? })` | `workspace.fork` | Create a child stream at runtime (experiment, sub-feature) |
224
+ | `land({ strategy?, target? })` | `workspace.land` | Finalize current stream using role default or override |
225
+ | `sync_with_parent({ onConflict? })` | `workspace.sync` | Rebase current stream onto advanced parent |
226
+ | `merge_stream({ target })` | `workspace.merge` | Merge this stream into a specific target |
227
+ | `request_cascade({ root })` | `workspace.cascade` | Trigger `cascadeRebase` from a root stream |
228
+ | `stream_status({ streamId? })` | `workspace.read` | Inspect stream state, dependencies, conflicts |
229
+ | `commit({ message })` | `workspace.commit` | Commit via `commitChanges` (replaces raw `git commit` for streamed agents) |
230
+
231
+ Capabilities gate *what's callable*; the agent's judgment governs *when* and *how*. Tool registration gating already exists in `mcp-server-v2.ts` via `isToolAllowedForRole()`.
232
+
233
+ ### 6.3 Programmatic API — library consumers
234
+
235
+ `cognitive-core` (`references/cognitive-core/src/atlas.ts:321`) constructs a `WorkspaceManager` directly and never loads a team YAML. Other library consumers will follow (e.g., future cc-swarm orchestration).
236
+
237
+ The `WorkspaceManager` interface must therefore stand on its own as a plain API — not degenerate into a "YAML interpreter." YAML is *compiled into* API calls; the API is the source of truth.
238
+
239
+ ### 6.4 Division of responsibility
240
+
241
+ | Decision | Source |
242
+ |---|---|
243
+ | "This role gets a new stream at spawn" | YAML |
244
+ | "This role's default landing is `queue_to_parent`" | YAML |
245
+ | "This role can fork sub-streams at runtime" | YAML capability grant |
246
+ | "I (agent) want to fork a sub-stream right now" | MCP tool call |
247
+ | "Pick strategy X for this specific land" | MCP tool args |
248
+ | "cognitive-core spawns an analyst and allocates a worktree" | Programmatic API |
249
+ | "Reconcile state on boot / run gc" | Programmatic API (called by `boot-v2`) |
250
+ | "If conflict density > N, spawn extra integrators" | `TopologyPolicy` plugin (not YAML) |
251
+
252
+ ### 6.5 Design constraints across layers
253
+
254
+ - **YAML must not encode runtime logic.** Conditional behavior belongs in a `TopologyPolicy` plugin, not config.
255
+ - **MCP tools must not bypass YAML capability grants.** A role without `workspace.fork` cannot call `fork_stream`, period. Enforced at tool registration time, not runtime check.
256
+ - **Programmatic callers are not bound by YAML.** They provide their own policies when constructing `WorkspaceManager` — YAML compilation is just one entry point.
257
+ - **All three layers emit the same events.** Whether a decision comes from YAML-compiled topology call, MCP tool invocation, or direct API use, observers see the same event stream. No divergent observation paths.
258
+ - **Capability grants are compositional, not role-name-specific.** `workspace.fork` granted to `planner` means the same thing as granted to `researcher`. Role names are human-readable labels; capabilities are the actual contract.
259
+
260
+ ---
261
+
262
+ ## 7. Redesign sketch: stream-first `WorkspaceManager`
263
+
264
+ The core move: **drop role-shaped APIs; expose streams and worktrees as primitives; make topologies a policy layer on top.** The interface below is what all three control layers (§6) compile into.
265
+
266
+ ### 7.1 Core abstractions
267
+
268
+ - **`Stream`** — a named line of work with an owner, a base, and optional parent stream. What git-cascade already has.
269
+ - **`Worktree`** — a filesystem checkout associated with an agent and optionally a stream. Role-neutral.
270
+ - **`LandingStrategy`** — decides how changes from a worktree land somewhere (merge into parent stream, submit to merge queue, cherry-pick as stack, etc.). Strategy is per-stream or per-agent, not per-team.
271
+ - **`TopologyPolicy`** — maps team shape → stream graph + spawn-time workspace decisions. Teams configure this; it's not baked into the manager.
272
+
273
+ ### 7.2 Proposed `WorkspaceManager` interface
274
+
275
+ ```ts
276
+ interface WorkspaceManager {
277
+ // ── Streams (direct pass-through of git-cascade's model) ─────────
278
+ createStream(opts: {
279
+ name: string;
280
+ ownerAgentId: AgentId;
281
+ parentStreamId?: StreamId; // Enables stacking natively
282
+ forkFrom?: string | StreamId; // Branch name OR stream reference
283
+ metadata?: Record<string, unknown>;
284
+ }): StreamId;
285
+
286
+ forkStream(opts: {
287
+ parentStreamId: StreamId;
288
+ name: string;
289
+ ownerAgentId: AgentId;
290
+ }): StreamId;
291
+
292
+ mergeStream(opts: {
293
+ sourceStreamId: StreamId;
294
+ targetStreamId: StreamId;
295
+ agentId: AgentId;
296
+ worktree: string;
297
+ }): MergeResult;
298
+
299
+ syncWithParent(
300
+ streamId: StreamId,
301
+ agentId: AgentId,
302
+ worktree: string,
303
+ onConflict?: ConflictStrategy
304
+ ): RebaseResult;
305
+
306
+ cascadeRebase(opts: { rootStreamId: StreamId; strategy: CascadeStrategy }): void;
307
+
308
+ abandonStream(streamId: StreamId, opts?: { cascade?: boolean }): void;
309
+ pauseStream(streamId: StreamId, reason?: string): void;
310
+ resumeStream(streamId: StreamId): void;
311
+
312
+ getStream(streamId: StreamId): Stream | null;
313
+ getStreamHierarchy(rootStreamId?: StreamId): StreamNode | StreamNode[];
314
+ listStreams(filter?: StreamFilter): Stream[];
315
+
316
+ // ── Worktrees (role-neutral) ─────────────────────────────────────
317
+ allocateWorktree(opts: {
318
+ agentId: AgentId;
319
+ streamId?: StreamId; // Optional — worktree can be detached
320
+ baseDir?: string;
321
+ reuseFromPool?: boolean;
322
+ }): Worktree;
323
+
324
+ deallocateWorktree(agentId: AgentId): void;
325
+ getWorktreeForAgent(agentId: AgentId): Worktree | null;
326
+ listWorktrees(): Worktree[];
327
+
328
+ // ── Changes (use git-cascade's Change-Id tracking) ───────────────
329
+ commitChanges(opts: {
330
+ agentId: AgentId;
331
+ streamId: StreamId;
332
+ worktree: string;
333
+ message: string;
334
+ }): { commit: string; changeId: ChangeId };
335
+
336
+ getChangeByCommit(commit: string): Change | null;
337
+ getChangesForStream(streamId: StreamId, filter?: ChangeFilter): Change[];
338
+
339
+ // ── Landing (strategy-driven) ────────────────────────────────────
340
+ registerLandingStrategy(name: string, strategy: LandingStrategy): void;
341
+
342
+ land(opts: {
343
+ agentId: AgentId;
344
+ streamId: StreamId;
345
+ strategyName?: string; // Defaults to stream's configured strategy
346
+ targetStreamId?: StreamId; // For stream-to-stream landings
347
+ }): LandingResult;
348
+
349
+ // ── Merge queue (use git-cascade's built-in) ─────────────────────
350
+ addToMergeQueue(opts: AddToQueueOptions): QueueEntryId;
351
+ getNextToMerge(targetBranch?: string): MergeQueueEntry | null;
352
+ processMergeQueue(opts: ProcessQueueOptions): ProcessQueueResult;
353
+
354
+ // ── Reconciliation & health ──────────────────────────────────────
355
+ reconcile(opts?: ReconcileOptions): ReconcileResult;
356
+ healthCheck(): HealthCheckResult;
357
+
358
+ // ── Lifecycle ────────────────────────────────────────────────────
359
+ onEvent(cb: WorkspaceEventCallback): () => void;
360
+ close(): void;
361
+ }
362
+ ```
363
+
364
+ ### 7.3 `LandingStrategy` interface
365
+
366
+ ```ts
367
+ interface LandingStrategy {
368
+ readonly name: string;
369
+ canLand(ctx: LandingContext): boolean;
370
+ land(ctx: LandingContext): Promise<LandingResult>;
371
+ initialize?(): Promise<void>;
372
+ close?(): Promise<void>;
373
+ }
374
+
375
+ // Built-in strategies:
376
+ // - "merge-to-parent" — mergeStream(source → parent), optional cascade rebase
377
+ // - "queue-to-branch" — addToMergeQueue(targetBranch), deterministic drain
378
+ // - "stack-cherry-pick" — createStackFromStream + cherryPickStackToTarget
379
+ // - "direct-push" — rebase + push (current trunk strategy)
380
+ // - "optimistic" — direct-push + emit validation:requested
381
+ // - "no-land" — worktree-only, landing is out of band
382
+ ```
383
+
384
+ Strategies no longer live at the team level. A stream can carry its own `landingStrategy` in metadata, set at stream creation.
385
+
386
+ ### 7.4 `TopologyPolicy` layer (replaces role-name dispatch)
387
+
388
+ Topology is declarative, not hardcoded in AgentManagerV2:
389
+
390
+ ```ts
391
+ interface TopologyPolicy {
392
+ readonly name: string; // "triad" | "peer-swarm" | "solo-stack" | custom
393
+ onTeamStart(ctx: TeamContext): Promise<TeamStreamPlan>;
394
+ onAgentSpawn(ctx: SpawnContext): Promise<WorkspaceDecision>;
395
+ onAgentComplete(ctx: CompleteContext): Promise<void>;
396
+ }
397
+
398
+ type WorkspaceDecision =
399
+ | { kind: "none" } // No workspace
400
+ | { kind: "share-parent-worktree" } // Inherit cwd
401
+ | { kind: "new-worktree"; streamId: StreamId } // Attach to existing stream
402
+ | { kind: "new-stream"; parent?: StreamId; name: string } // Fork new stream
403
+ | { kind: "track-branch"; branch: string }; // trackExistingBranch
404
+ ```
405
+
406
+ AgentManagerV2 loses `createWorkspaceForRole`. It calls `topology.onAgentSpawn(...)` and gets a decision back. The decision is enacted via `workspaceManager.allocateWorktree` / `createStream` / `forkStream`.
407
+
408
+ Built-in topologies:
409
+ - **`triad`** — current behavior, for backward compat.
410
+ - **`peer-swarm`** — every spawned agent gets its own stream forked off team's root stream.
411
+ - **`solo-stack`** — one agent owns a chain of forked streams, `forkStream` on demand.
412
+ - **`shared-worktree`** — all agents share one worktree, landing is out-of-band.
413
+ - **`no-workspace`** — no isolation at all (default for teams that don't want it).
414
+
415
+ ### 7.5 What this buys us
416
+
417
+ Every row in the §5 failure table becomes expressible:
418
+
419
+ | Topology | How it works |
420
+ |---|---|
421
+ | Single agent stacking | `solo-stack` topology; `forkStream` on demand; `cascadeRebase` on parent update |
422
+ | Peer swarm | `peer-swarm` topology; each agent → own stream; `mergeStream` when done |
423
+ | Stacked diffs across team | Use `parentStreamId` + `addDependency`; `cascadeRebase` propagates |
424
+ | Nested coordinators | Child coord's `onAgentSpawn` returns `new-stream` with parent = current stream |
425
+ | Multi-stream per team | Triad topology extended to create N streams |
426
+ | Non-worker leaf roles | `WorkspaceDecision.share-parent-worktree` or `none` |
427
+ | Change identity | `commitChanges` (mandatory path), replaces raw `git commit` |
428
+ | Deferred conflicts | Landing strategies route through `rebaseOntoStream` with conflict records |
429
+
430
+ ### 7.6 git-cascade behavior notes (verified from source)
431
+
432
+ Before committing to the interface above, key behaviors were verified against git-cascade source at `references/git-cascade/src/`. Corrections to earlier assumptions:
433
+
434
+ - **`mergeStream` leaves the worktree on the target branch** (`streams.ts:638-717`). Checks out target, performs merge, does NOT restore source branch. On conflict, calls `mergeAbort()` but stays on target. → Implication: `LandingStrategy` doesn't need to restore state; the worktree is deallocated right after landing anyway.
435
+ - **`reconcile()` only handles stream↔git divergence** (`reconcile.ts:237-284`). Detects missing branches and diverged HEAD. Does **NOT** clean orphan worktrees or in-progress multi-step ops. → macro-agent ships its own `reconcile()` wrapper on top that handles worktree pool state, orphan worktrees, and agent↔worktree mapping drift.
436
+ - **No public worktree branch-switch API**. `updateWorktreeStream()` (`worktrees.ts:113-162`) is private to the tracker. → Pool reuse across streams requires raw `git checkout` in macro-agent (bypassing cascade's op log). Accepted; tracked as follow-up to petition git-cascade.
437
+ - **`cascadeRebase` uses a callback-based worktree provider** (`cascade.ts:84`); doesn't require all dependent streams to be pre-allocated. → `WorkspaceManager.cascadeRebase` takes `worktreeProvider: (streamId) => string | null`; macro-agent resolves lazily.
438
+ - **Cascade conflict strategies** (`models/dependency.ts:65-68`): `stop_on_conflict` / `skip_conflicting` / `defer_conflicts`. Maps directly to YAML.
439
+ - **`commitChanges` stages ALL files** (`tracker.ts:715`); trailer format `Change-Id: c-xxxxxxxx` (`git/commands.ts:764`); throws on no-op. → No file filtering; agents manage staging manually if scoped commits are needed.
440
+ - **Events** use configurable prefix (default `x-cascade/`): `stream.opened` / `stream.committed` / `stream.merged` / `stream.conflicted` / `stream.abandoned`. Synchronous callback, exceptions discarded by emitter. → macro-agent subscribes once in `WorkspaceManager` and re-emits structured `WorkspaceEvent`.
441
+
442
+ ---
443
+
444
+ ### 7.7 Worked example: peer swarm
445
+
446
+ The forcing function for the interface above. Three `peer` agents each own a stream forked off a team-level root stream, merge back independently.
447
+
448
+ **YAML:**
449
+
450
+ ```yaml
451
+ name: peer-swarm
452
+ roles: [orchestrator, peer]
453
+
454
+ topology:
455
+ root: { role: orchestrator, prompt: prompts/orchestrator.md }
456
+ spawn_rules:
457
+ orchestrator: [peer]
458
+ peer: []
459
+
460
+ macro_agent:
461
+ workspace:
462
+ default_stream: { fork_from: main, change_id_tracking: true }
463
+ on_team_complete: keep
464
+ roles:
465
+ orchestrator: { workspace: none, allocation: inherit_parent_cwd, landing: none }
466
+ peer:
467
+ workspace: new_stream
468
+ stream_lineage: fork_from_team_root
469
+ allocation: new_worktree
470
+ landing: merge_to_parent_stream
471
+ on_conflict: defer
472
+ capabilities:
473
+ peer: [workspace.commit, workspace.land, workspace.read]
474
+ ```
475
+
476
+ **Phase-by-phase:**
477
+
478
+ | Phase | Action | API calls |
479
+ |---|---|---|
480
+ | 1. Boot | Load YAML, construct `WorkspaceManager`, call `reconcile()`, create team stream | `createStream({ name: "peer-swarm", ownerId: "team:peer-swarm", forkFrom: "main" })` |
481
+ | 2. Spawn orchestrator | Topology decides `{ kind: "share-parent-cwd" }` | — (no workspace calls) |
482
+ | 3. Spawn peer | Topology decides `{ kind: "new-stream", streamSpec, worktree }` | `forkStream(teamStream)` + `allocateWorktree({ agentId, streamId, pooled: true })` |
483
+ | 4. Peer commits | MCP `commit` tool | `commitChanges({ agentId, streamId, worktree, message })` → Change-Id assigned |
484
+ | 5. Peer done | MCP `land()` tool → `merge-to-parent` strategy | `mergeStream(peer → team_root)`; if `cascade_on_parent_update`, `cascadeRebase` |
485
+ | 6. Peer terminate | AgentManager cleanup | `deallocateWorktree(agentId)` |
486
+ | 7. Team done | Orchestrator calls `done()` | `on_team_complete: keep` → team stream stays for human PR |
487
+
488
+ **Interface pieces exercised:** `createStream`, `forkStream`, `mergeStream`, `commitChanges`, `allocateWorktree`, `deallocateWorktree`, `land` + `LandingStrategy`, `WorkspaceEvent` stream, `TopologyPolicy.onAgentSpawn/onAgentComplete`.
489
+
490
+ **Surfaced design decisions:**
491
+ - **Pseudo-principal `team:<name>`** owns team streams. Tagged string type.
492
+ - **`onAgentSpawn` returns a `WorkspaceDecision`** (declarative), not a `Workspace` (imperative). AgentManager executes it.
493
+ - **`commit` MCP tool is the mandatory path** for Change-Id tracking; bypassing via raw `Bash: git commit` is documented as unsupported, not enforced.
494
+ - **`LandingStrategy.land(ctx)` receives structured context** (agentId, streamId, sourceWorktree, targetStreamId, strategyConfig, workspaceManager). Strategy decides internals (merge + cascade, queue, cherry-pick, etc.).
495
+ - **Landing happens in `done()` / `land()` MCP tool**, NOT in `terminate()`. Terminate is pure cleanup.
496
+
497
+ ---
498
+
499
+ ### 7.8 Generalizing: other workflows
500
+
501
+ The peer swarm interface was tested against the other 5 workflows from §5. Summary:
502
+
503
+ **Solo stack (sequential)** — One agent forks chains of streams, lands each back up.
504
+
505
+ ```yaml
506
+ roles:
507
+ author:
508
+ workspace: new_stream
509
+ stream_lineage: fork_from_team_root
510
+ landing: merge_to_parent_stream
511
+ cascade_on_parent_update: true
512
+ capabilities: [workspace.commit, workspace.land, workspace.fork, workspace.sync, workspace.read]
513
+ ```
514
+
515
+ Interface addition needed: **agent's active stream is mutable**. `fork_stream` MCP tool implicitly moves agent to the new child; `checkout_stream` returns to parent after landing. Simultaneous multi-stream attachment (Graphite-style) is explicitly out of scope.
516
+
517
+ **Triad (current topology)** — coordinator + integrator + N workers, ported to new interface.
518
+
519
+ ```yaml
520
+ roles:
521
+ coordinator: { workspace: attach_to_team_root, landing: none, capabilities: [workspace.read] }
522
+ worker:
523
+ workspace: new_stream
524
+ stream_lineage: fork_from_parent
525
+ landing: queue_to_branch
526
+ landing_config: { target_stream: team_root }
527
+ capabilities: [workspace.commit, workspace.land, workspace.read]
528
+ integrator:
529
+ workspace: attach_to_team_root
530
+ landing: none
531
+ capabilities: [workspace.merge, workspace.read, merge_queue.drain]
532
+ ```
533
+
534
+ Changes from today: macro-agent's duplicate merge queue is deleted; git-cascade's built-in queue is used. Integrator gets structured MCP tools (`next_merge_request`, `merge_stream`, `mark_merge_complete`) instead of freeform "process the merge queue" prompt. Integrator wake trigger is `x-cascade/stream.committed` event on team root, not a custom `mr:submitted`.
535
+
536
+ **Pipeline (planner → coder → reviewer → integrator)** — sequential handoffs with cross-role worktree sharing.
537
+
538
+ ```yaml
539
+ roles:
540
+ planner: { workspace: none, landing: none }
541
+ coder:
542
+ workspace: new_stream
543
+ stream_lineage: fork_from_team_root
544
+ landing: queue_to_branch
545
+ landing_config: { target_role: integrator }
546
+ reviewer:
547
+ workspace: share_with_agent
548
+ share_with: coder
549
+ landing: none
550
+ capabilities: [workspace.read]
551
+ integrator: { workspace: attach_to_team_root, capabilities: [workspace.merge, merge_queue.drain] }
552
+ ```
553
+
554
+ Interface addition needed: **`share_with_agent` workspace decision**. Reviewer co-locates on coder's worktree path (ref-counted deallocation — last-out wins). `workspace.commit` capability withheld; raw `git commit` via Bash is not enforced-against.
555
+
556
+ **Research / read-only** — agents read the repo, never commit.
557
+
558
+ ```yaml
559
+ roles:
560
+ researcher: { workspace: none, allocation: inherit_parent_cwd, landing: none, capabilities: [] }
561
+ ```
562
+
563
+ Interface holds trivially. No MCP workspace tools registered; git-cascade dormant for this role.
564
+
565
+ **Long-lived feature + subtasks** — parent stream lives for days, children fork and merge back, parent rebases onto `main` periodically.
566
+
567
+ ```yaml
568
+ roles:
569
+ feature_owner:
570
+ workspace: new_stream
571
+ stream_lineage: fork_from_team_root
572
+ landing: merge_to_parent_stream
573
+ cascade_on_parent_update: true
574
+ on_parent_advanced: sync_with_parent
575
+ capabilities: [workspace.commit, workspace.land, workspace.sync, workspace.fork, workspace.read]
576
+ subtask:
577
+ workspace: new_stream
578
+ stream_lineage: fork_from_parent
579
+ landing: merge_to_parent_stream
580
+ capabilities: [workspace.commit, workspace.land, workspace.read]
581
+ ```
582
+
583
+ Interface addition needed: **`on_parent_advanced` directive + event subscription**. TopologyPolicy subscribes to `x-cascade/stream.committed` on parent stream; schedules `syncWithParent` call on the feature stream via WakeManager (fires as a system event into the agent). Coalesced (max once per N seconds).
584
+
585
+ **Verdict — interface generalizes with three additions:**
586
+
587
+ 1. **`share_with_agent: <role>`** workspace decision (pipeline reviewer).
588
+ 2. **Mutable agent-active-stream** — `fork_stream` / `checkout_stream` MCP tools for solo stack.
589
+ 3. **`on_parent_advanced: sync_with_parent`** auto-sync directive driven by event subscription (long-lived feature).
590
+
591
+ Plus one carve-out: **Graphite-style simultaneous stacks** (multiple active streams per agent) deferred as future extension.
592
+
593
+ ---
594
+
595
+ ## 8. Migration plan (sketch)
596
+
597
+ 1. **Surface more git-cascade** — extend `DataplaneAdapter` to cover `forkStream`, `mergeStream`, `syncWithParent`, `cascadeRebase`, `commitChanges`, built-in merge queue, reconcile, health. No consumer changes yet. **Safe, additive.**
598
+
599
+ 2. **Add new `WorkspaceManager` methods alongside existing ones** — `allocateWorktree`, `createStream` (new signature), `land`, `commitChanges`. Old methods stay; implementations delegate. **Safe, additive.**
600
+
601
+ 3. **Introduce `TopologyPolicy`** — extract triad logic out of `agent-manager-v2.ts:281-306` into `TriadPolicy`. AgentManagerV2 gets a `topology?: TopologyPolicy` field, defaults to Triad for backward compat. **Invisible to existing callers.**
602
+
603
+ 4. **Migrate landing** — `IntegrationStrategy` → `LandingStrategy` (rename + generalize). AgentManagerV2 on worker completion calls `workspaceManager.land(...)` instead of `mergeQueue.submit(...)` directly. Queue strategy uses git-cascade's built-in queue. **Kills the duplicate merge queue.**
604
+
605
+ 5. **Drop role-name dispatch** — remove the `switch(role)` in AgentManagerV2 once all topologies are expressed as policies. Role capabilities still gate spawn, but workspace allocation is policy-driven. **Breaking for custom role names relying on the fallback — needs migration note.**
606
+
607
+ 6. **Deprecate old WorkspaceManager methods** — `createWorkerWorkspace` / `createIntegratorWorkspace` / `createCoordinatorWorkspace` move to `TriadPolicy` internals; public interface becomes stream-first.
608
+
609
+ Each step is individually reviewable and runnable. We don't need to break anything in one big drop.
610
+
611
+ ---
612
+
613
+ ## 9. Open questions
614
+
615
+ ### Resolved
616
+
617
+ - ✅ **Pseudo-principals** — team-owned streams owned by `team:<name>` tagged string; never terminates. Regular agents own stream via their `AgentId`.
618
+ - ✅ **`mergeStream` worktree semantics** — verified from source: leaves worktree on target. Clean up after landing.
619
+ - ✅ **Cascade triggering** — `LandingStrategy.land()` decides whether to `cascadeRebase` after merge. `mergeStream` stays narrow. YAML `cascade_on_parent_update` configures the *strategy*, not the primitive. Agent's `done()` → opentasks task completion → `land()` → strategy → cascade is the full chain.
620
+ - ✅ **Landing strategy = per-stream, not per-team** — strategies register globally; YAML role config picks which strategy each stream uses. Agent can override via MCP tool args.
621
+ - ✅ **Team stream on completion** — YAML `on_team_complete: keep | merge_to_main | abandon`. Default `keep`.
622
+ - ✅ **Recovery** — macro-agent ships a `reconcile()` wrapper on top of git-cascade's (which only handles stream↔git sync). Wrapper handles worktree pool, orphan worktrees, agent↔worktree drift. Called on boot; runtime drift tolerated until next boot.
623
+ - ✅ **Pool behavior** — config-driven: `pool.reuse_across_streams: bool`. If `true`, raw `git checkout` on reuse (bypasses cascade op log, accepted). If `false`, fresh worktree per stream.
624
+ - ✅ **Commit path** — `commit` MCP tool is the mandatory path for Change-Id tracking. Agents with workspace access get the tool; raw `Bash: git commit` isn't enforced-against but is documented as unsupported.
625
+
626
+ ### Open
627
+
628
+ - **Conflict recovery strategy** — deferred to a dedicated design doc. Options: auto-resolve (git strategies), spawn resolver agent, human-in-the-loop. Stream marked `conflicted` + conflict record + recovery strategy kicks off asynchronously.
629
+ - **Simultaneous multi-stream per agent (Graphite-style)** — explicitly out of scope for v1. The solo-stack workflow uses sequential streams. Flagging so the interface doesn't preclude a future extension.
630
+ - **Reviewer-outlives-coder lifecycle** — ref-counted shared worktree deallocation. Needs a small lifecycle hook; not complex.
631
+ - **Sync-with-main triggering** — event-driven via `x-cascade/stream.committed` on parent + WakeManager coalescing (max once per N seconds). Needs WakeManager integration.
632
+ - **Worktree branch-switch** — macro-agent does raw `git checkout` for pool reuse across streams. Follow-up: petition git-cascade to expose `updateWorktreeStream` publicly.
633
+ - **Integrator structured tools** — `next_merge_request`, `merge_stream`, `mark_merge_complete`. New MCP tool surface for `merge_queue.drain` capability.
634
+ - ~~**Backward compatibility with cognitive-core**~~ — ✅ resolved. Pressure test showed cognitive-core imports `WorkspaceManager` from a separate `agent-workspace` package, not macro-agent's. No git-cascade usage. No overlap. The `src/cognitive/` bridge in macro-agent also makes no `WorkspaceManager` calls. **No shim required; redesign has no external consumer constraints.** Sole production consumers are `src/agent/agent-manager-v2.ts` (~6 call sites) and `src/teams/team-runtime-v2.ts` (~3 call sites).
635
+ - **cc-swarm consumption** — deferred to separate follow-up doc. Likely consumes `WorkspaceManager` directly as a library, skipping team YAML layer.
636
+
637
+ ---
638
+
639
+ ## 10. Follow-ups
640
+
641
+ - cc-swarm integration doc — how the redesigned WorkspaceManager composes with cc-swarm's orchestration primitives.
642
+ - Concrete API shape for `TopologyPolicy` (this doc's sketch needs fleshing out with a working peer-swarm example).
643
+ - Review with cognitive-core owners on backward compat.
644
+
645
+ ---
646
+
647
+ ## Appendix A — Original gap list (within the triad topology)
648
+
649
+ These were the items in the previous draft. They remain valid *within the current triad model*, but most dissolve once the stream-first interface is in place. Annotated with how they map to the redesign:
650
+
651
+ | # | Original gap | Disposition under redesign |
652
+ |---|---|---|
653
+ | 1 | `IntegrationStrategy.land()` never called | Dissolved — `LandingStrategy.land()` is on the critical path in `workspaceManager.land()` |
654
+ | 2 | Merge queue has no deterministic drainer | Dissolved — use git-cascade's built-in `processMergeQueue` |
655
+ | 3 | `getNextTask()` orphaned | Deleted — workspace-side tasks collapse into opentasks or into git-cascade's `workerTasks` directly |
656
+ | 4 | No integrator auto-spawn | Becomes a topology policy concern, not a lifecycle hack |
657
+ | 5 | Conflict detection & checkpoints unused | Exposed via new interface; topologies can opt in |
658
+ | 6 | Cascade termination bypasses integration | Cascade calls `workspaceManager.land()` same as normal completion |
659
+ | 7 | No reconciliation between pool and git-cascade | Dissolved — call `reconcile()` on boot |
660
+ | 8 | No pre-submit validation on MR branches | Lives in the specific landing strategy |
661
+ | 9 | No default strategy outside team runtime | Dissolved — strategies are per-stream, not per-team |
662
+
663
+ ## Appendix B — Duplicated vs ignored, at a glance
664
+
665
+ **Duplicated** (macro-agent built its own alongside git-cascade's):
666
+ - Merge queue (`src/workspace/merge-queue/` vs git-cascade's `mergeQueue.*`)
667
+ - Worktree pool (`src/workspace/pool/` vs git-cascade's `listWorktrees` / `deallocateWorktree` + reconcile)
668
+ - Branch creation via `execSync` (vs `forkStream` / `commitChanges`)
669
+
670
+ **Ignored** (exposed by git-cascade, never called):
671
+ - `forkStream`, `mergeStream`, `syncWithParent`, `cascadeRebase`
672
+ - `commitChanges` / Change-IDs
673
+ - Review blocks, diff stacks, checkpoints
674
+ - Conflict records
675
+ - `recordOperation`, rollback APIs
676
+ - `reconcile`, `healthCheck`, gc
677
+ - `trackExistingBranch`, `pauseStream`, `resumeStream`
678
+ - `addDependency`, `getDependents`, `getStreamHierarchy`