macro-agent 0.1.1 → 0.1.2

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 (406) hide show
  1. package/.sudocode/issues.jsonl +28 -0
  2. package/.sudocode/specs.jsonl +4 -0
  3. package/CLAUDE.md +9 -3
  4. package/dist/agent/agent-manager.d.ts.map +1 -1
  5. package/dist/agent/agent-manager.js +111 -48
  6. package/dist/agent/agent-manager.js.map +1 -1
  7. package/dist/agent/types.d.ts +7 -0
  8. package/dist/agent/types.d.ts.map +1 -1
  9. package/dist/agent/types.js.map +1 -1
  10. package/dist/api/server.d.ts +5 -1
  11. package/dist/api/server.d.ts.map +1 -1
  12. package/dist/api/server.js +100 -3
  13. package/dist/api/server.js.map +1 -1
  14. package/dist/api/types.d.ts +1 -1
  15. package/dist/api/types.d.ts.map +1 -1
  16. package/dist/cli/acp.d.ts.map +1 -1
  17. package/dist/cli/acp.js +71 -1
  18. package/dist/cli/acp.js.map +1 -1
  19. package/dist/cli/index.js +5 -1
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/cli/mcp.js +27 -8
  22. package/dist/cli/mcp.js.map +1 -1
  23. package/dist/config/project-config.d.ts +13 -2
  24. package/dist/config/project-config.d.ts.map +1 -1
  25. package/dist/config/project-config.js +12 -2
  26. package/dist/config/project-config.js.map +1 -1
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/lifecycle/handlers/index.d.ts +7 -3
  32. package/dist/lifecycle/handlers/index.d.ts.map +1 -1
  33. package/dist/lifecycle/handlers/index.js +25 -8
  34. package/dist/lifecycle/handlers/index.js.map +1 -1
  35. package/dist/lifecycle/types.d.ts +2 -0
  36. package/dist/lifecycle/types.d.ts.map +1 -1
  37. package/dist/lifecycle/types.js.map +1 -1
  38. package/dist/map/adapter/extensions/index.d.ts +4 -1
  39. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  40. package/dist/map/adapter/extensions/index.js +27 -0
  41. package/dist/map/adapter/extensions/index.js.map +1 -1
  42. package/dist/map/adapter/extensions/streams.d.ts +95 -0
  43. package/dist/map/adapter/extensions/streams.d.ts.map +1 -0
  44. package/dist/map/adapter/extensions/streams.js +515 -0
  45. package/dist/map/adapter/extensions/streams.js.map +1 -0
  46. package/dist/map/adapter/index.d.ts +1 -1
  47. package/dist/map/adapter/index.d.ts.map +1 -1
  48. package/dist/map/adapter/index.js +3 -1
  49. package/dist/map/adapter/index.js.map +1 -1
  50. package/dist/map/adapter/types.d.ts +1 -1
  51. package/dist/map/adapter/types.d.ts.map +1 -1
  52. package/dist/mcp/mcp-server.d.ts +2 -0
  53. package/dist/mcp/mcp-server.d.ts.map +1 -1
  54. package/dist/mcp/mcp-server.js +12 -3
  55. package/dist/mcp/mcp-server.js.map +1 -1
  56. package/dist/mcp/tools/done.d.ts.map +1 -1
  57. package/dist/mcp/tools/done.js +18 -0
  58. package/dist/mcp/tools/done.js.map +1 -1
  59. package/dist/roles/builtin/coordinator.d.ts.map +1 -1
  60. package/dist/roles/builtin/coordinator.js +2 -1
  61. package/dist/roles/builtin/coordinator.js.map +1 -1
  62. package/dist/roles/builtin/integrator.d.ts.map +1 -1
  63. package/dist/roles/builtin/integrator.js +2 -1
  64. package/dist/roles/builtin/integrator.js.map +1 -1
  65. package/dist/roles/builtin/worker.d.ts.map +1 -1
  66. package/dist/roles/builtin/worker.js +3 -1
  67. package/dist/roles/builtin/worker.js.map +1 -1
  68. package/dist/roles/capabilities.d.ts +6 -0
  69. package/dist/roles/capabilities.d.ts.map +1 -1
  70. package/dist/roles/capabilities.js +10 -0
  71. package/dist/roles/capabilities.js.map +1 -1
  72. package/dist/roles/config-loader.d.ts +1 -1
  73. package/dist/roles/config-loader.d.ts.map +1 -1
  74. package/dist/roles/config-loader.js +3 -2
  75. package/dist/roles/config-loader.js.map +1 -1
  76. package/dist/roles/types.d.ts +3 -1
  77. package/dist/roles/types.d.ts.map +1 -1
  78. package/dist/server/combined-server.d.ts +8 -1
  79. package/dist/server/combined-server.d.ts.map +1 -1
  80. package/dist/server/combined-server.js +6 -2
  81. package/dist/server/combined-server.js.map +1 -1
  82. package/dist/store/event-store.d.ts.map +1 -1
  83. package/dist/store/event-store.js +12 -5
  84. package/dist/store/event-store.js.map +1 -1
  85. package/dist/store/instance.d.ts +1 -1
  86. package/dist/store/instance.d.ts.map +1 -1
  87. package/dist/store/instance.js +2 -2
  88. package/dist/store/instance.js.map +1 -1
  89. package/dist/store/types/agents.d.ts +5 -0
  90. package/dist/store/types/agents.d.ts.map +1 -1
  91. package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -1
  92. package/dist/task/backend/opentasks/daemon-manager.js +1 -1
  93. package/dist/task/backend/opentasks/daemon-manager.js.map +1 -1
  94. package/dist/teams/index.d.ts +3 -1
  95. package/dist/teams/index.d.ts.map +1 -1
  96. package/dist/teams/index.js +2 -0
  97. package/dist/teams/index.js.map +1 -1
  98. package/dist/teams/seed-defaults.d.ts +20 -0
  99. package/dist/teams/seed-defaults.d.ts.map +1 -0
  100. package/dist/teams/seed-defaults.js +71 -0
  101. package/dist/teams/seed-defaults.js.map +1 -0
  102. package/dist/teams/team-loader.d.ts +6 -2
  103. package/dist/teams/team-loader.d.ts.map +1 -1
  104. package/dist/teams/team-loader.js +154 -162
  105. package/dist/teams/team-loader.js.map +1 -1
  106. package/dist/teams/team-manager.d.ts +112 -0
  107. package/dist/teams/team-manager.d.ts.map +1 -0
  108. package/dist/teams/team-manager.js +305 -0
  109. package/dist/teams/team-manager.js.map +1 -0
  110. package/dist/teams/team-runtime.d.ts +125 -19
  111. package/dist/teams/team-runtime.d.ts.map +1 -1
  112. package/dist/teams/team-runtime.js +527 -119
  113. package/dist/teams/team-runtime.js.map +1 -1
  114. package/dist/teams/types.d.ts +41 -151
  115. package/dist/teams/types.d.ts.map +1 -1
  116. package/dist/teams/types.js +2 -3
  117. package/dist/teams/types.js.map +1 -1
  118. package/docs/teams.md +73 -0
  119. package/package.json +2 -1
  120. package/references/minimem/.claude/settings.json +7 -0
  121. package/references/minimem/.sudocode/issues.jsonl +18 -0
  122. package/references/minimem/.sudocode/specs.jsonl +1 -0
  123. package/references/minimem/CLAUDE.md +310 -0
  124. package/references/minimem/README.md +562 -0
  125. package/references/minimem/claude-plugin/.claude-plugin/plugin.json +10 -0
  126. package/references/minimem/claude-plugin/.mcp.json +7 -0
  127. package/references/minimem/claude-plugin/README.md +158 -0
  128. package/references/minimem/claude-plugin/commands/recall.md +47 -0
  129. package/references/minimem/claude-plugin/commands/remember.md +41 -0
  130. package/references/minimem/claude-plugin/hooks/__tests__/hooks.test.ts +272 -0
  131. package/references/minimem/claude-plugin/hooks/hooks.json +27 -0
  132. package/references/minimem/claude-plugin/hooks/session-end.sh +86 -0
  133. package/references/minimem/claude-plugin/hooks/session-start.sh +85 -0
  134. package/references/minimem/claude-plugin/skills/memory/SKILL.md +108 -0
  135. package/references/minimem/media/banner.png +0 -0
  136. package/references/minimem/package-lock.json +5373 -0
  137. package/references/minimem/package.json +72 -0
  138. package/references/minimem/scripts/postbuild.js +35 -0
  139. package/references/minimem/src/__tests__/edge-cases.test.ts +371 -0
  140. package/references/minimem/src/__tests__/errors.test.ts +265 -0
  141. package/references/minimem/src/__tests__/helpers.ts +199 -0
  142. package/references/minimem/src/__tests__/internal.test.ts +407 -0
  143. package/references/minimem/src/__tests__/knowledge.test.ts +287 -0
  144. package/references/minimem/src/__tests__/minimem.integration.test.ts +1127 -0
  145. package/references/minimem/src/__tests__/session.test.ts +190 -0
  146. package/references/minimem/src/cli/__tests__/commands.test.ts +759 -0
  147. package/references/minimem/src/cli/commands/__tests__/conflicts.test.ts +141 -0
  148. package/references/minimem/src/cli/commands/append.ts +76 -0
  149. package/references/minimem/src/cli/commands/config.ts +262 -0
  150. package/references/minimem/src/cli/commands/conflicts.ts +413 -0
  151. package/references/minimem/src/cli/commands/daemon.ts +169 -0
  152. package/references/minimem/src/cli/commands/index.ts +12 -0
  153. package/references/minimem/src/cli/commands/init.ts +88 -0
  154. package/references/minimem/src/cli/commands/mcp.ts +177 -0
  155. package/references/minimem/src/cli/commands/push-pull.ts +213 -0
  156. package/references/minimem/src/cli/commands/search.ts +158 -0
  157. package/references/minimem/src/cli/commands/status.ts +84 -0
  158. package/references/minimem/src/cli/commands/sync-init.ts +290 -0
  159. package/references/minimem/src/cli/commands/sync.ts +70 -0
  160. package/references/minimem/src/cli/commands/upsert.ts +197 -0
  161. package/references/minimem/src/cli/config.ts +584 -0
  162. package/references/minimem/src/cli/index.ts +264 -0
  163. package/references/minimem/src/cli/shared.ts +161 -0
  164. package/references/minimem/src/cli/sync/__tests__/central.test.ts +152 -0
  165. package/references/minimem/src/cli/sync/__tests__/conflicts.test.ts +209 -0
  166. package/references/minimem/src/cli/sync/__tests__/daemon.test.ts +118 -0
  167. package/references/minimem/src/cli/sync/__tests__/detection.test.ts +207 -0
  168. package/references/minimem/src/cli/sync/__tests__/integration.test.ts +476 -0
  169. package/references/minimem/src/cli/sync/__tests__/registry.test.ts +363 -0
  170. package/references/minimem/src/cli/sync/__tests__/state.test.ts +255 -0
  171. package/references/minimem/src/cli/sync/__tests__/validation.test.ts +193 -0
  172. package/references/minimem/src/cli/sync/__tests__/watcher.test.ts +178 -0
  173. package/references/minimem/src/cli/sync/central.ts +292 -0
  174. package/references/minimem/src/cli/sync/conflicts.ts +204 -0
  175. package/references/minimem/src/cli/sync/daemon.ts +407 -0
  176. package/references/minimem/src/cli/sync/detection.ts +138 -0
  177. package/references/minimem/src/cli/sync/index.ts +107 -0
  178. package/references/minimem/src/cli/sync/operations.ts +373 -0
  179. package/references/minimem/src/cli/sync/registry.ts +279 -0
  180. package/references/minimem/src/cli/sync/state.ts +355 -0
  181. package/references/minimem/src/cli/sync/validation.ts +206 -0
  182. package/references/minimem/src/cli/sync/watcher.ts +234 -0
  183. package/references/minimem/src/cli/version.ts +34 -0
  184. package/references/minimem/src/core/index.ts +9 -0
  185. package/references/minimem/src/core/indexer.ts +628 -0
  186. package/references/minimem/src/core/searcher.ts +221 -0
  187. package/references/minimem/src/db/schema.ts +183 -0
  188. package/references/minimem/src/db/sqlite-vec.ts +24 -0
  189. package/references/minimem/src/embeddings/__tests__/embeddings.test.ts +431 -0
  190. package/references/minimem/src/embeddings/batch-gemini.ts +392 -0
  191. package/references/minimem/src/embeddings/batch-openai.ts +409 -0
  192. package/references/minimem/src/embeddings/embeddings.ts +434 -0
  193. package/references/minimem/src/index.ts +109 -0
  194. package/references/minimem/src/internal.ts +299 -0
  195. package/references/minimem/src/minimem.ts +1276 -0
  196. package/references/minimem/src/search/__tests__/hybrid.test.ts +247 -0
  197. package/references/minimem/src/search/graph.ts +234 -0
  198. package/references/minimem/src/search/hybrid.ts +151 -0
  199. package/references/minimem/src/search/search.ts +256 -0
  200. package/references/minimem/src/server/__tests__/mcp.test.ts +341 -0
  201. package/references/minimem/src/server/__tests__/tools.test.ts +364 -0
  202. package/references/minimem/src/server/mcp.ts +326 -0
  203. package/references/minimem/src/server/tools.ts +720 -0
  204. package/references/minimem/src/session.ts +460 -0
  205. package/references/minimem/tsconfig.json +19 -0
  206. package/references/minimem/tsup.config.ts +26 -0
  207. package/references/minimem/vitest.config.ts +24 -0
  208. package/references/openteams/.claude/settings.json +6 -0
  209. package/references/openteams/README.md +1 -0
  210. package/references/openteams/SKILL.md +341 -0
  211. package/references/openteams/design.md +411 -0
  212. package/references/openteams/examples/bmad-method/prompts/analyst/ROLE.md +16 -0
  213. package/references/openteams/examples/bmad-method/prompts/analyst/SOUL.md +5 -0
  214. package/references/openteams/examples/bmad-method/prompts/architect/ROLE.md +24 -0
  215. package/references/openteams/examples/bmad-method/prompts/architect/SOUL.md +5 -0
  216. package/references/openteams/examples/bmad-method/prompts/developer/ROLE.md +25 -0
  217. package/references/openteams/examples/bmad-method/prompts/developer/SOUL.md +5 -0
  218. package/references/openteams/examples/bmad-method/prompts/master/ROLE.md +21 -0
  219. package/references/openteams/examples/bmad-method/prompts/master/SOUL.md +5 -0
  220. package/references/openteams/examples/bmad-method/prompts/pm/ROLE.md +20 -0
  221. package/references/openteams/examples/bmad-method/prompts/pm/SOUL.md +5 -0
  222. package/references/openteams/examples/bmad-method/prompts/qa/ROLE.md +17 -0
  223. package/references/openteams/examples/bmad-method/prompts/qa/SOUL.md +5 -0
  224. package/references/openteams/examples/bmad-method/prompts/quick-flow-dev/ROLE.md +23 -0
  225. package/references/openteams/examples/bmad-method/prompts/quick-flow-dev/SOUL.md +5 -0
  226. package/references/openteams/examples/bmad-method/prompts/scrum-master/ROLE.md +27 -0
  227. package/references/openteams/examples/bmad-method/prompts/scrum-master/SOUL.md +5 -0
  228. package/references/openteams/examples/bmad-method/prompts/tech-writer/ROLE.md +21 -0
  229. package/references/openteams/examples/bmad-method/prompts/tech-writer/SOUL.md +5 -0
  230. package/references/openteams/examples/bmad-method/prompts/ux-designer/ROLE.md +16 -0
  231. package/references/openteams/examples/bmad-method/prompts/ux-designer/SOUL.md +5 -0
  232. package/references/openteams/examples/bmad-method/roles/analyst.yaml +9 -0
  233. package/references/openteams/examples/bmad-method/roles/architect.yaml +9 -0
  234. package/references/openteams/examples/bmad-method/roles/developer.yaml +8 -0
  235. package/references/openteams/examples/bmad-method/roles/master.yaml +8 -0
  236. package/references/openteams/examples/bmad-method/roles/pm.yaml +9 -0
  237. package/references/openteams/examples/bmad-method/roles/qa.yaml +8 -0
  238. package/references/openteams/examples/bmad-method/roles/quick-flow-dev.yaml +8 -0
  239. package/references/openteams/examples/bmad-method/roles/scrum-master.yaml +9 -0
  240. package/references/openteams/examples/bmad-method/roles/tech-writer.yaml +8 -0
  241. package/references/openteams/examples/bmad-method/roles/ux-designer.yaml +8 -0
  242. package/references/openteams/examples/bmad-method/team.yaml +161 -0
  243. package/references/openteams/examples/get-shit-done/prompts/codebase-mapper/ROLE.md +17 -0
  244. package/references/openteams/examples/get-shit-done/prompts/codebase-mapper/SOUL.md +5 -0
  245. package/references/openteams/examples/get-shit-done/prompts/debugger/ROLE.md +25 -0
  246. package/references/openteams/examples/get-shit-done/prompts/debugger/SOUL.md +5 -0
  247. package/references/openteams/examples/get-shit-done/prompts/executor/ROLE.md +34 -0
  248. package/references/openteams/examples/get-shit-done/prompts/executor/SOUL.md +5 -0
  249. package/references/openteams/examples/get-shit-done/prompts/integration-checker/ROLE.md +18 -0
  250. package/references/openteams/examples/get-shit-done/prompts/integration-checker/SOUL.md +3 -0
  251. package/references/openteams/examples/get-shit-done/prompts/orchestrator/ROLE.md +42 -0
  252. package/references/openteams/examples/get-shit-done/prompts/orchestrator/SOUL.md +5 -0
  253. package/references/openteams/examples/get-shit-done/prompts/phase-researcher/ROLE.md +15 -0
  254. package/references/openteams/examples/get-shit-done/prompts/phase-researcher/SOUL.md +3 -0
  255. package/references/openteams/examples/get-shit-done/prompts/plan-checker/ROLE.md +17 -0
  256. package/references/openteams/examples/get-shit-done/prompts/plan-checker/SOUL.md +3 -0
  257. package/references/openteams/examples/get-shit-done/prompts/planner/ROLE.md +28 -0
  258. package/references/openteams/examples/get-shit-done/prompts/planner/SOUL.md +5 -0
  259. package/references/openteams/examples/get-shit-done/prompts/project-researcher/ROLE.md +16 -0
  260. package/references/openteams/examples/get-shit-done/prompts/project-researcher/SOUL.md +3 -0
  261. package/references/openteams/examples/get-shit-done/prompts/research-synthesizer/ROLE.md +13 -0
  262. package/references/openteams/examples/get-shit-done/prompts/research-synthesizer/SOUL.md +3 -0
  263. package/references/openteams/examples/get-shit-done/prompts/roadmapper/ROLE.md +14 -0
  264. package/references/openteams/examples/get-shit-done/prompts/roadmapper/SOUL.md +3 -0
  265. package/references/openteams/examples/get-shit-done/prompts/verifier/ROLE.md +19 -0
  266. package/references/openteams/examples/get-shit-done/prompts/verifier/SOUL.md +5 -0
  267. package/references/openteams/examples/get-shit-done/roles/codebase-mapper.yaml +8 -0
  268. package/references/openteams/examples/get-shit-done/roles/debugger.yaml +8 -0
  269. package/references/openteams/examples/get-shit-done/roles/executor.yaml +8 -0
  270. package/references/openteams/examples/get-shit-done/roles/integration-checker.yaml +8 -0
  271. package/references/openteams/examples/get-shit-done/roles/orchestrator.yaml +9 -0
  272. package/references/openteams/examples/get-shit-done/roles/phase-researcher.yaml +7 -0
  273. package/references/openteams/examples/get-shit-done/roles/plan-checker.yaml +8 -0
  274. package/references/openteams/examples/get-shit-done/roles/planner.yaml +8 -0
  275. package/references/openteams/examples/get-shit-done/roles/project-researcher.yaml +8 -0
  276. package/references/openteams/examples/get-shit-done/roles/research-synthesizer.yaml +7 -0
  277. package/references/openteams/examples/get-shit-done/roles/roadmapper.yaml +7 -0
  278. package/references/openteams/examples/get-shit-done/roles/verifier.yaml +8 -0
  279. package/references/openteams/examples/get-shit-done/team.yaml +154 -0
  280. package/references/openteams/package-lock.json +2181 -0
  281. package/references/openteams/package.json +48 -0
  282. package/references/openteams/schema/role.schema.json +125 -0
  283. package/references/openteams/schema/team.schema.json +284 -0
  284. package/references/openteams/src/cli/agent.ts +104 -0
  285. package/references/openteams/src/cli/cli.test.ts +381 -0
  286. package/references/openteams/src/cli/generate.ts +220 -0
  287. package/references/openteams/src/cli/message.ts +241 -0
  288. package/references/openteams/src/cli/task.ts +154 -0
  289. package/references/openteams/src/cli/team.ts +104 -0
  290. package/references/openteams/src/cli/template.ts +207 -0
  291. package/references/openteams/src/cli.ts +45 -0
  292. package/references/openteams/src/db/database.test.ts +185 -0
  293. package/references/openteams/src/db/database.ts +240 -0
  294. package/references/openteams/src/generators/agent-prompt-generator.test.ts +332 -0
  295. package/references/openteams/src/generators/agent-prompt-generator.ts +521 -0
  296. package/references/openteams/src/generators/package-generator.test.ts +129 -0
  297. package/references/openteams/src/generators/package-generator.ts +102 -0
  298. package/references/openteams/src/generators/skill-generator.test.ts +246 -0
  299. package/references/openteams/src/generators/skill-generator.ts +374 -0
  300. package/references/openteams/src/index.ts +104 -0
  301. package/references/openteams/src/services/agent-service.test.ts +158 -0
  302. package/references/openteams/src/services/agent-service.ts +84 -0
  303. package/references/openteams/src/services/communication-service.test.ts +455 -0
  304. package/references/openteams/src/services/communication-service.ts +371 -0
  305. package/references/openteams/src/services/message-service.test.ts +342 -0
  306. package/references/openteams/src/services/message-service.ts +203 -0
  307. package/references/openteams/src/services/task-service.test.ts +434 -0
  308. package/references/openteams/src/services/task-service.ts +239 -0
  309. package/references/openteams/src/services/team-service.test.ts +181 -0
  310. package/references/openteams/src/services/team-service.ts +139 -0
  311. package/references/openteams/src/services/template-service.test.ts +306 -0
  312. package/references/openteams/src/services/template-service.ts +182 -0
  313. package/references/openteams/src/spawner/acp-factory.ts +96 -0
  314. package/references/openteams/src/spawner/interface.ts +31 -0
  315. package/references/openteams/src/spawner/mock.test.ts +93 -0
  316. package/references/openteams/src/spawner/mock.ts +59 -0
  317. package/references/openteams/src/template/loader.test.ts +1319 -0
  318. package/references/openteams/src/template/loader.ts +698 -0
  319. package/references/openteams/src/template/types.ts +200 -0
  320. package/references/openteams/src/types.ts +205 -0
  321. package/references/openteams/tsconfig.json +18 -0
  322. package/references/openteams/vitest.config.ts +9 -0
  323. package/references/skill-tree/.claude/settings.json +6 -0
  324. package/references/skill-tree/.sudocode/issues.jsonl +11 -0
  325. package/references/skill-tree/.sudocode/specs.jsonl +1 -0
  326. package/references/skill-tree/CLAUDE.md +150 -0
  327. package/references/skill-tree/README.md +324 -0
  328. package/references/skill-tree/docs/GAPS_v1.md +221 -0
  329. package/references/skill-tree/docs/INTEGRATION_PLAN.md +467 -0
  330. package/references/skill-tree/docs/TODOS.md +91 -0
  331. package/references/skill-tree/docs/anthropic_skill_guide.md +1364 -0
  332. package/references/skill-tree/docs/design/federated-skill-trees.md +524 -0
  333. package/references/skill-tree/docs/design/multi-agent-sync.md +759 -0
  334. package/references/skill-tree/docs/scraper/BRAINSTORM.md +583 -0
  335. package/references/skill-tree/docs/scraper/POC_PLAN.md +420 -0
  336. package/references/skill-tree/docs/scraper/README.md +170 -0
  337. package/references/skill-tree/examples/basic-usage.ts +190 -0
  338. package/references/skill-tree/package-lock.json +1509 -0
  339. package/references/skill-tree/package.json +66 -0
  340. package/references/skill-tree/scraper/README.md +123 -0
  341. package/references/skill-tree/scraper/docs/DESIGN.md +683 -0
  342. package/references/skill-tree/scraper/docs/PLAN.md +336 -0
  343. package/references/skill-tree/scraper/drizzle.config.ts +10 -0
  344. package/references/skill-tree/scraper/package-lock.json +6329 -0
  345. package/references/skill-tree/scraper/package.json +68 -0
  346. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-description.md +7 -0
  347. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-name.md +7 -0
  348. package/references/skill-tree/scraper/test/fixtures/minimal-skill/SKILL.md +27 -0
  349. package/references/skill-tree/scraper/test/fixtures/skill-json/SKILL.json +21 -0
  350. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/SKILL.md +54 -0
  351. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/_meta.json +24 -0
  352. package/references/skill-tree/scraper/test/fixtures/valid-skill/SKILL.md +93 -0
  353. package/references/skill-tree/scraper/test/fixtures/valid-skill/_meta.json +22 -0
  354. package/references/skill-tree/scraper/tsup.config.ts +14 -0
  355. package/references/skill-tree/scraper/vitest.config.ts +17 -0
  356. package/references/skill-tree/scripts/convert-to-vitest.ts +166 -0
  357. package/references/skill-tree/skills/skill-writer/SKILL.md +339 -0
  358. package/references/skill-tree/skills/skill-writer/references/examples.md +326 -0
  359. package/references/skill-tree/skills/skill-writer/references/patterns.md +210 -0
  360. package/references/skill-tree/skills/skill-writer/references/quality-checklist.md +123 -0
  361. package/references/skill-tree/test/run-all.ts +106 -0
  362. package/references/skill-tree/test/utils.ts +128 -0
  363. package/references/skill-tree/vitest.config.ts +16 -0
  364. package/src/agent/agent-manager.ts +143 -72
  365. package/src/agent/types.ts +9 -0
  366. package/src/api/__tests__/server.test.ts +203 -4
  367. package/src/api/server.ts +130 -5
  368. package/src/api/types.ts +3 -1
  369. package/src/cli/acp.ts +68 -1
  370. package/src/cli/index.ts +5 -1
  371. package/src/cli/mcp.ts +27 -13
  372. package/src/config/project-config.ts +27 -3
  373. package/src/index.ts +3 -0
  374. package/src/lifecycle/__tests__/handlers.test.ts +53 -0
  375. package/src/lifecycle/handlers/index.ts +25 -8
  376. package/src/lifecycle/types.ts +3 -0
  377. package/src/map/adapter/__tests__/stream-extensions.test.ts +494 -0
  378. package/src/map/adapter/extensions/index.ts +36 -0
  379. package/src/map/adapter/extensions/streams.ts +839 -0
  380. package/src/map/adapter/index.ts +5 -0
  381. package/src/map/adapter/types.ts +8 -1
  382. package/src/mcp/mcp-server.ts +14 -3
  383. package/src/mcp/tools/done.ts +19 -0
  384. package/src/roles/builtin/coordinator.ts +2 -0
  385. package/src/roles/builtin/integrator.ts +2 -0
  386. package/src/roles/builtin/worker.ts +3 -0
  387. package/src/roles/capabilities.ts +11 -0
  388. package/src/roles/config-loader.ts +3 -2
  389. package/src/roles/types.ts +7 -0
  390. package/src/server/combined-server.ts +15 -1
  391. package/src/store/__tests__/event-store-oob.test.ts +109 -0
  392. package/src/store/event-store.ts +13 -3
  393. package/src/store/instance.ts +2 -2
  394. package/src/store/types/agents.ts +5 -0
  395. package/src/task/backend/__tests__/memory-pull-mode.test.ts +153 -0
  396. package/src/task/backend/opentasks/daemon-manager.ts +4 -1
  397. package/src/teams/CLAUDE.md +180 -0
  398. package/src/teams/__tests__/e2e/workspace-isolation.e2e.test.ts +1263 -0
  399. package/src/teams/__tests__/team-manager.test.ts +814 -0
  400. package/src/teams/__tests__/team-system.test.ts +1291 -8
  401. package/src/teams/index.ts +21 -3
  402. package/src/teams/seed-defaults.ts +79 -0
  403. package/src/teams/team-loader.ts +200 -234
  404. package/src/teams/team-manager.ts +387 -0
  405. package/src/teams/team-runtime.ts +590 -121
  406. package/src/teams/types.ts +99 -200
@@ -153,3 +153,31 @@
153
153
  {"id":"i-96z9","uuid":"13867978-72d1-4e65-b99d-5a0f0e762f37","title":"Add test coverage for monitorContinuations()","content":"\n`monitorContinuations()` in `team-runtime.ts` has zero test coverage. The method watches agent lifecycle events and auto-resumes daemon agents on unexpected stop.\n\n**Test cases needed:**\n1. Daemon agent stops unexpectedly → `continueAgent()` called after 1s delay\n2. Agent stops with \"completed\" status → no continuation triggered\n3. Agent stops with \"cancelled\" status → no continuation triggered\n4. Continuation spawn failure → error caught, no crash\n5. Multiple lifecycle events for same agent → no duplicate continuations\n6. Teardown unsubscribes → no continuation after teardown\n\n**Edge cases:**\n- State consistency when agent ID changes after continuation\n- Rapid stop/restart cycles\n\n**Files:** `src/teams/__tests__/team-system.test.ts` or new `continuation.test.ts`\n","status":"closed","priority":2,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-07 21:27:09","updated_at":"2026-02-08 08:08:45","closed_at":"2026-02-08 08:08:45","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-96z9","from_type":"issue","to":"s-5w36","to_type":"spec","type":"implements"}],"tags":["continuations","teams","testing"],"feedback":[{"id":"ff29220b-52ce-4b49-b720-5971ce0fb376","from_id":"i-96z9","to_id":"s-5w36","feedback_type":"comment","content":"Implemented 6 test cases for `monitorContinuations()` in `src/teams/__tests__/team-system.test.ts`:\n1. Auto-continue root agent on unexpected stop\n2. Auto-continue companion agent on unexpected stop\n3. No continuation on completed status stop\n4. No continuation on cancelled status stop\n5. No trigger for non-monitored agents\n6. Unsubscribe on teardown prevents continuation\n\nAll tests passing.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-08T08:08:36.918Z","updated_at":"2026-02-08T08:08:36.918Z"}]}
154
154
  {"id":"i-3y08","uuid":"1c832346-74f6-4683-a01d-1dc3af035277","title":"Wire TrunkStrategy conflictAction and strategy lifecycle hooks","content":"\nTwo minor gaps in the integration strategy subsystem:\n\n1. **`conflictAction` unused:** `TrunkIntegrationStrategy` stores `conflictAction` config (\"abandon\" | \"queued_for_resolution\") but `land()` always returns `status: \"conflict\"` without differentiating. Should set `action` field on the conflict result based on config.\n\n2. **`initialize()`/`close()` lifecycle hooks never called:** The `IntegrationStrategy` interface defines optional `initialize()` and `close()` methods but neither TeamRuntime nor the worker handler invokes them. TeamRuntime should call `initialize()` during `initialize()` and `close()` during `teardown()`.\n\n**Files:** `src/workspace/strategies/trunk.ts`, `src/teams/team-runtime.ts`\n","status":"closed","priority":3,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-07 21:27:15","updated_at":"2026-02-08 08:08:46","closed_at":"2026-02-08 08:08:46","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-3y08","from_type":"issue","to":"s-6ok3","to_type":"spec","type":"implements"}],"tags":["gap","integration-strategies","teams"],"feedback":[{"id":"fb19956e-2987-4024-8bbc-23a8282af3f3","from_id":"i-3y08","to_id":"s-6ok3","feedback_type":"comment","content":"Both gaps addressed:\n\n1. **conflictAction wired**: Added `action` field to `LandResult` type in `src/workspace/strategies/types.ts`. `TrunkIntegrationStrategy.land()` now sets `action` on both conflict return paths, mapping config's `\"abandon\"` to result's `\"abandoned\"`.\n\n2. **Strategy lifecycle hooks called**: `TeamRuntime.initialize()` now instantiates the strategy via `defaultStrategyRegistry.get()` and calls `strategy.initialize()`. `TeamRuntime.teardown()` calls `strategy.close()`. Both wrapped in try/catch for best-effort semantics. Added `getIntegrationStrategy()` getter.\n\nFiles modified: `src/workspace/strategies/types.ts`, `src/workspace/strategies/trunk.ts`, `src/teams/team-runtime.ts`","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-08T08:08:41.672Z","updated_at":"2026-02-08T08:08:41.672Z"}]}
155
155
  {"id":"i-1zso","uuid":"3573f69b-89c2-499f-ba0c-faaa578b5165","title":"Implement emission restrictions and enforcement mode","content":"\nTwo related features that are loaded/stored but not enforced at runtime:\n\n1. **Emission restrictions:** `communication.emissions` maps roles to allowed signals. Loader validates role names, but no code checks whether an agent's emitted signal is in its allowed list.\n\n2. **Enforcement mode:** `communication.enforcement` (\"strict\" | \"permissive\" | \"audit\") stored in EventStore `team_config` event. Never retrieved or branched on.\n\n**Implementation per A10 in implementation-details.md:**\n- Enforcement at MCP tool level (not router): `emit_status` tool handler checks team manifest emissions for agent's role\n- `strict`: reject disallowed emissions\n- `permissive`: log warning, allow\n- `audit`: record in EventStore for analysis\n\n**Files:** `src/mcp/mcp-server.ts` or `src/mcp/tools/`, `src/router/message-router.ts`\n","status":"closed","priority":3,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-07 21:27:20","updated_at":"2026-02-09 05:45:05","closed_at":"2026-02-09 05:45:05","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-1zso","from_type":"issue","to":"i-3o8g","to_type":"issue","type":"depends-on"},{"from":"i-1zso","from_type":"issue","to":"s-29pg","to_type":"spec","type":"implements"}],"tags":["communication","enforcement","gap","teams"],"feedback":[{"id":"9abcdf0a-c065-4814-8a0a-db59d15b8ae2","from_id":"i-1zso","to_id":"s-29pg","feedback_type":"comment","content":"Implemented emission restrictions and enforcement mode.\n\n**Approach**: Late-bound `EmissionValidator` callback on MessageRouter (follows `setSignalFilter` pattern). TeamRuntime installs the validator during bootstrap.\n\n**How it works**:\n1. `emitStatus()` extracts `details.signal` from the status event\n2. Calls the validator with `(agentId, signal)` — validator looks up agent's role via `agentRoleMap`, checks against `communication.emissions[role]`\n3. Returns action based on enforcement mode:\n - `strict` → `reject` (blocks emission entirely, `emitStatus` returns early)\n - `permissive` → `warn` (allows through)\n - `audit` → `audit` (records audit event in EventStore with `emission_violation` type, then allows through)\n4. Untagged events (no `details.signal`) and unknown agents always pass through\n\n**Data serialization**: Added `emissions` to the team_config EventStore event for cross-process access by MCP subprocesses.\n\n**Files modified**: `src/router/message-router.ts` (EmissionValidator type, setEmissionValidator, validation in emitStatus), `src/teams/team-runtime.ts` (installEmissionValidator, emissions in team_config)\n\n**Tests**: 5 new router tests (reject, allow, audit with event recording, warn, untagged passthrough) + 8 new team tests (install, allow, strict reject, permissive warn, audit, untagged, unknown agent, no-config skip, serialization). All 3,095 tests pass.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-09T05:45:00.325Z","updated_at":"2026-02-09T05:45:00.325Z"}]}
156
+ {"id":"i-96li","uuid":"70912635-b104-4bf9-a2f7-6c2c22b9f030","title":"A1: Capability composition syntax alignment in openteams","content":"\n**Spec**: [[s-50b3]]\n\n**File**: `references/openteams/src/template/loader.ts`, `references/openteams/src/template/types.ts`\n\nAdd support for the flat `capabilities_add`/`capabilities_remove` syntax alongside the existing `CapabilityComposition` (`{ add, remove }`) syntax.\n\n### Changes\n\n1. **types.ts** — Add optional fields to `RoleDefinition`:\n ```typescript\n capabilities_add?: string[];\n capabilities_remove?: string[];\n ```\n\n2. **loader.ts** — In `resolveRole()`, normalize: if `capabilities_add`/`capabilities_remove` present AND `capabilities` is not a `CapabilityComposition`, treat as composition. Merge into the same `CapabilityComposition` path.\n\n3. **Validation**: Error if both `CapabilityComposition` inside `capabilities` AND flat `capabilities_add/remove` are present simultaneously.\n\n4. **loader.ts** — In `resolveInheritance()`, ensure the flat syntax roles are resolved identically to `CapabilityComposition` roles.\n\n### Tests\n- Role with `capabilities_add` only → inherits parent + additions\n- Role with `capabilities_remove` only → inherits parent - removals\n- Role with both flat fields → correct merge\n- Error when both syntaxes used simultaneously\n- Existing `CapabilityComposition` tests still pass\n","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:20:55","updated_at":"2026-02-20 21:51:06","closed_at":"2026-02-20 21:51:06","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-96li","from_type":"issue","to":"s-50b3","to_type":"spec","type":"implements"}],"tags":["openteams","schema"]}
157
+ {"id":"i-7t87","uuid":"85635900-9169-475e-b9d1-c22aa8bd8713","title":"A2: RoleRegistry integration hook + A5: Async loader variant","content":"\n**Spec**: [[s-50b3]]\n\n**File**: `references/openteams/src/template/loader.ts`, `references/openteams/src/template/types.ts`\n\nAdd `LoadOptions` to `TemplateLoader.load()` and a new `TemplateLoader.loadAsync()` variant for consumers that need async hooks (e.g., macro-agent resolving roles from a registry).\n\n### Changes\n\n1. **types.ts** — Add option interfaces:\n ```typescript\n export interface LoadOptions {\n resolveExternalRole?: (name: string) => ResolvedRole | null;\n postProcessRole?: (role: ResolvedRole, manifest: TeamManifest) => ResolvedRole;\n postProcess?: (template: ResolvedTemplate) => ResolvedTemplate;\n }\n\n export interface AsyncLoadOptions {\n resolveExternalRole?: (name: string) => Promise<ResolvedRole | null> | ResolvedRole | null;\n postProcessRole?: (role: ResolvedRole, manifest: TeamManifest) => Promise<ResolvedRole> | ResolvedRole;\n postProcess?: (template: ResolvedTemplate) => Promise<ResolvedTemplate> | ResolvedTemplate;\n }\n ```\n\n2. **loader.ts** — Update `TemplateLoader.load(dir, options?)`:\n - In `resolveInheritance()`: when a role's `extends` target is NOT in the local roles map, call `options.resolveExternalRole()` if provided — use returned `ResolvedRole` as parent for capability merging\n - After resolving each role: call `options.postProcessRole()` if provided\n - After full resolution: call `options.postProcess()` if provided\n\n3. **loader.ts** — Add `TemplateLoader.loadAsync(dir, options?)`:\n - Same logic as `load()` but hooks can return Promises\n - File I/O remains sync (fs.readFileSync is fine)\n - Awaits each hook call\n\n4. Keep existing `load()` signature backward-compatible (options param is optional).\n\n### Tests\n- `load()` without options → identical to current behavior\n- `load()` with `resolveExternalRole` → role extending external parent gets merged capabilities\n- `load()` with `postProcessRole` → role is transformed after resolution\n- `load()` with `postProcess` → template is transformed after full loading\n- `loadAsync()` with async hooks → correct resolution\n- External role not found (returns null) → falls back to implicit role (empty capabilities)\n","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:21:06","updated_at":"2026-02-20 21:53:06","closed_at":"2026-02-20 21:53:06","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-7t87","from_type":"issue","to":"s-50b3","to_type":"spec","type":"implements"}],"tags":["openteams","schema"]}
158
+ {"id":"i-4fwm","uuid":"32ddcd39-e74a-4a8c-a098-e3b2de5c32ee","title":"A3: MCP server config support in openteams","content":"\n**Spec**: [[s-50b3]]\n\n**File**: `references/openteams/src/template/loader.ts`, `references/openteams/src/template/types.ts`\n\nAdd support for loading `tools/mcp-servers.json` — per-role MCP server configurations.\n\n### Changes\n\n1. **types.ts** — Add type:\n ```typescript\n export interface McpServerEntry {\n name: string;\n command: string;\n args?: string[];\n env?: Record<string, string>;\n }\n ```\n\n2. **types.ts** — Add field to `ResolvedTemplate`:\n ```typescript\n export interface ResolvedTemplate {\n manifest: TeamManifest;\n roles: Map<string, ResolvedRole>;\n prompts: Map<string, ResolvedPrompts>;\n mcpServers: Map<string, McpServerEntry[]>; // NEW\n sourcePath: string;\n }\n ```\n\n3. **loader.ts** — In `TemplateLoader.load()`, after role/prompt resolution:\n - Check for `tools/mcp-servers.json` in template directory\n - If exists, parse as `Record<string, { servers: McpServerEntry[] }>`\n - Populate `mcpServers` map (role name → server entries)\n - If not exists, return empty map\n\n4. **loader.ts** — Update `loadFromManifest()` to set `mcpServers: new Map()`\n\n### Tests\n- Template with `tools/mcp-servers.json` → correctly loaded per role\n- Template without `tools/` → empty map, no error\n- Malformed JSON → error with clear message\n- Multiple roles with different server configs → correct per-role mapping\n","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:21:13","updated_at":"2026-02-20 21:54:53","closed_at":"2026-02-20 21:54:53","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-4fwm","from_type":"issue","to":"s-50b3","to_type":"spec","type":"implements"}],"tags":["openteams","schema"]}
159
+ {"id":"i-8ycw","uuid":"d8a126c8-7a66-4c8c-b0fe-907e3cd03a8a","title":"A6: Export alignment + A7: JSON schema updates","content":"\n**Spec**: [[s-50b3]]\n\n**Files**: `references/openteams/src/index.ts`, `references/openteams/schema/role.schema.json`, `references/openteams/schema/team.schema.json`\n\nEnsure all new types are exported and JSON schemas are updated.\n\n### Changes\n\n1. **index.ts** — Add exports:\n ```typescript\n export type { McpServerEntry, LoadOptions, AsyncLoadOptions } from \"./template/types\";\n ```\n\n2. **schema/role.schema.json** — Add:\n - `capabilities_add`: `{ \"type\": \"array\", \"items\": { \"type\": \"string\" } }` (optional)\n - `capabilities_remove`: `{ \"type\": \"array\", \"items\": { \"type\": \"string\" } }` (optional)\n - Document mutual exclusivity with `CapabilityComposition` in `capabilities`\n\n3. **schema/team.schema.json** — Add:\n - Document `tools/` directory convention in description\n - Document `macro_agent` as a known extension namespace\n\n### Verification\n- `npm run build` succeeds with all exports\n- JSON schemas validate existing team.yaml files\n- JSON schemas validate new `capabilities_add/remove` syntax\n","status":"closed","priority":2,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:21:18","updated_at":"2026-02-20 21:55:46","closed_at":"2026-02-20 21:55:46","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-8ycw","from_type":"issue","to":"i-4fwm","to_type":"issue","type":"depends-on"},{"from":"i-8ycw","from_type":"issue","to":"i-7t87","to_type":"issue","type":"depends-on"},{"from":"i-8ycw","from_type":"issue","to":"i-96li","to_type":"issue","type":"depends-on"},{"from":"i-8ycw","from_type":"issue","to":"s-50b3","to_type":"spec","type":"implements"}],"tags":["openteams","schema"]}
160
+ {"id":"i-4fln","uuid":"2118e06b-4a6e-436f-9d2c-7913509cb2ae","title":"B1: Add openteams as dependency to macro-agent","content":"\n**Spec**: [[s-50b3]]\n\n**File**: `package.json`\n\nAdd openteams as a local dependency and verify it links correctly.\n\n### Changes\n\n1. Add to `package.json` dependencies:\n ```json\n \"openteams\": \"file:references/openteams\"\n ```\n\n2. Run `npm install` to link the local package\n\n3. Verify: create a smoke test file that imports from openteams:\n ```typescript\n import { TemplateLoader, type TeamManifest } from \"openteams\";\n ```\n\n4. Ensure `npm run build` succeeds with the new dependency\n\n### Notes\n- Using `file:` reference initially; will switch to npm package once openteams is published\n- openteams must be built first (`cd references/openteams && npm run build`)\n","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:21:27","updated_at":"2026-02-20 21:57:52","closed_at":"2026-02-20 21:57:52","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-4fln","from_type":"issue","to":"i-8ycw","to_type":"issue","type":"depends-on"},{"from":"i-4fln","from_type":"issue","to":"s-50b3","to_type":"spec","type":"implements"}],"tags":["macro-agent","migration"],"feedback":[{"id":"a728dfc1-2b32-421a-9fcd-28da4839af02","from_id":"i-4fln","to_id":"s-50b3","feedback_type":"comment","content":"B1 complete: `openteams` added as `file:references/openteams` dependency. `npm install` and `npm run build` both succeed cleanly.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-20T21:57:52.265Z","updated_at":"2026-02-20T21:57:52.265Z"}]}
161
+ {"id":"i-7sew","uuid":"252d9c34-dbc1-4e13-8057-976cbaa27f54","title":"B2: Replace team types with openteams imports + B7: Routing status","content":"\n**Spec**: [[s-50b3]]\n\n**File**: `src/teams/types.ts`\n\nReplace generic schema types with imports from openteams. Keep macro-agent enforcement types local. Create backward-compatible aliases.\n\n### Changes\n\n1. **Import from openteams**:\n ```typescript\n import type {\n TeamManifest as OpenTeamsManifest,\n TopologyConfig,\n TopologyNode,\n TopologyNodeConfig,\n CommunicationConfig,\n ChannelDefinition,\n SubscriptionEntry,\n RoutingConfig,\n PeerRoute,\n RoleDefinition as OpenTeamsRoleDefinition,\n CapabilityComposition,\n ResolvedTemplate,\n ResolvedRole,\n ResolvedPrompts,\n PromptSection,\n McpServerEntry,\n } from \"openteams\";\n ```\n\n2. **Re-export with backward-compatible aliases**:\n ```typescript\n // Aliases for macro-agent's original names\n export type TeamTopology = TopologyConfig;\n export type TeamCommunication = CommunicationConfig;\n export type ChannelSubscription = SubscriptionEntry;\n export type CommunicationRouting = RoutingConfig;\n export type PeerConnection = PeerRoute;\n export type CommunicationEnforcement = \"strict\" | \"permissive\" | \"audit\";\n export type TeamRoleDefinition = OpenTeamsRoleDefinition;\n ```\n\n3. **Re-export openteams types** that consumers need:\n ```typescript\n export type {\n TopologyConfig, TopologyNode, TopologyNodeConfig,\n CommunicationConfig, ChannelDefinition, SubscriptionEntry,\n RoutingConfig, PeerRoute, CapabilityComposition,\n ResolvedTemplate, ResolvedRole, ResolvedPrompts, PromptSection,\n McpServerEntry,\n };\n ```\n\n4. **Keep local** (unchanged):\n - `MacroAgentExtensions`, `TaskAssignmentConfig`, `IntegrationConfig`, `LifecycleConfig`, `ObservabilityConfig`\n - `TeamRoleMacroAgent`\n - `ResolvedTeamRole`\n - `TeamLoadError`, `TeamLoadErrorCode`\n\n5. **B7 — Routing status**: The `CommunicationRouting` alias now inherits openteams' `\"upstream\" | \"none\"` via `RoutingConfig`. Update any runtime code that reads `communication.routing.status` to handle `\"none\"` (disable status propagation).\n\n6. **Remove** all type definitions that are now imported from openteams (the original `TeamTopology`, `TopologyNode`, `ChannelDefinition`, `PeerConnection`, etc.)\n\n### Verification\n- `npm run build` passes with no type errors\n- All existing imports of these types from `src/teams/types.ts` still resolve\n- grep for any direct usage of removed type names\n","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:21:40","updated_at":"2026-02-20 22:02:00","closed_at":"2026-02-20 22:02:00","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-7sew","from_type":"issue","to":"i-4fln","to_type":"issue","type":"depends-on"},{"from":"i-7sew","from_type":"issue","to":"s-50b3","to_type":"spec","type":"implements"}],"tags":["macro-agent","migration"],"feedback":[{"id":"1f31e282-f082-426b-ad81-70b85bb549bf","from_id":"i-7sew","to_id":"s-50b3","feedback_type":"comment","content":"B2+B7 complete: Replaced all generic schema types in `src/teams/types.ts` with imports from openteams. Created backward-compatible aliases (`TeamTopology`, `TeamCommunication`, `ChannelSubscription`, `CommunicationRouting`, `PeerConnection`, `TeamRoleDefinition`). `MacroAgentExtensions` gained index signature for `Record<string, unknown>` compatibility. `team-loader.ts` updated to cast `macro_agent` through `TeamRoleMacroAgent`. Routing status now supports `\"none\"` via openteams' `RoutingConfig`. All 3296 tests pass.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-20T22:01:59.782Z","updated_at":"2026-02-20T22:01:59.782Z"}]}
162
+ {"id":"i-4xo6","uuid":"611fba3f-3755-4ffe-af27-fa3bccd09857","title":"B3: Adopt ResolvedTemplate architecture","content":"\n**Spec**: [[s-50b3]]\n\n**File**: `src/teams/types.ts`\n\nIntroduce `MacroResolvedTemplate` — macro-agent's enriched wrapper around openteams' `ResolvedTemplate`.\n\n### Changes\n\n1. **Add new type** to `src/teams/types.ts`:\n ```typescript\n /**\n * macro-agent's enriched team resolution result.\n * Wraps openteams' ResolvedTemplate with enforcement-enriched roles.\n */\n export interface MacroResolvedTemplate {\n /** openteams resolved template (manifest + generic roles + prompts) */\n template: ResolvedTemplate;\n\n /** Enforcement-enriched roles mapped to macro-agent's RoleDefinition */\n resolvedRoles: Map<string, ResolvedTeamRole>;\n\n /** MCP server configs per role (from template.mcpServers) */\n mcpServers: Map<string, McpServerEntry[]>;\n\n /** Parsed macro-agent extensions (typed from manifest.macro_agent) */\n macroAgent: MacroAgentExtensions;\n }\n ```\n\n2. **Keep `ResolvedTeamRole` unchanged** — it already maps openteams roles to macro-agent's internal `RoleDefinition` with enforcement:\n ```typescript\n export interface ResolvedTeamRole {\n name: string;\n baseRole: string;\n capabilities: Capability[];\n prompt?: string;\n roleDefinition: RoleDefinition;\n }\n ```\n\n3. **Remove `_resolvedRoles`, `_loadedPrompts`, `_mcpServers` from the old `TeamManifest`** interface (these are now on `MacroResolvedTemplate` and `ResolvedTemplate`).\n\n4. **Export** `MacroResolvedTemplate` from `src/teams/index.ts`.\n\n### Notes\n- This issue only defines the type. B4 (loader) and B6 (runtime) will produce and consume it.\n- The old `TeamManifest` with `_` prefixed fields is no longer defined locally — replaced by `MacroResolvedTemplate`.\n","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:21:50","updated_at":"2026-02-20 22:02:51","closed_at":"2026-02-20 22:02:51","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-4xo6","from_type":"issue","to":"i-7sew","to_type":"issue","type":"depends-on"},{"from":"i-4xo6","from_type":"issue","to":"s-50b3","to_type":"spec","type":"implements"}],"tags":["macro-agent","migration"],"feedback":[{"id":"fbccc52a-3d32-4c9e-a766-7c91fa282d68","from_id":"i-4xo6","to_id":"s-50b3","feedback_type":"comment","content":"B3 complete: Added `MacroResolvedTemplate` interface wrapping openteams' `ResolvedTemplate` with enforcement-enriched roles and typed `MacroAgentExtensions`. Exported from `src/teams/index.ts`. Old `_` fields on `TeamManifest` kept (deprecated) until B4/B6 migrate consumers. Build clean.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-20T22:02:50.839Z","updated_at":"2026-02-20T22:02:50.839Z"}]}
163
+ {"id":"i-7u03","uuid":"a436d112-08fc-48e7-b8fd-b1639444af0d","title":"B4: Replace team-loader.ts with openteams TemplateLoader","content":"\n**Spec**: [[s-50b3]]\n\n**File**: `src/teams/team-loader.ts`\n\nReplace the current 434-line `loadTeam()` with a thin wrapper around openteams' `TemplateLoader.loadAsync()`.\n\n### Changes\n\n1. **Replace `loadTeam()` implementation**:\n ```typescript\n export async function loadTeam(\n teamName: string,\n roleRegistry: RoleRegistry,\n basePath?: string\n ): Promise<MacroResolvedTemplate> {\n const root = basePath ?? process.cwd();\n const teamDir = path.join(root, TEAMS_DIR, teamName);\n\n // 1. Load via openteams TemplateLoader\n const template = await TemplateLoader.loadAsync(teamDir, {\n resolveExternalRole: (name) => mapRegistryRole(roleRegistry, name),\n postProcessRole: (role, manifest) =>\n enrichRoleWithSpawnRules(role, manifest),\n });\n\n // 2. Build macro-agent enriched roles\n const resolvedRoles = buildResolvedRoles(template, roleRegistry);\n\n // 3. Parse macro_agent extensions\n const macroAgent = parseMacroAgentExtensions(\n template.manifest.macro_agent\n );\n\n // 4. Validate communication\n validateCommunication(\n template.manifest.communication,\n template.manifest.roles,\n teamName\n );\n\n return { template, resolvedRoles, mcpServers: template.mcpServers, macroAgent };\n }\n ```\n\n2. **Add helper functions**:\n - `mapRegistryRole(registry, name)`: Looks up a role in macro-agent's RoleRegistry, converts to openteams `ResolvedRole` format\n - `enrichRoleWithSpawnRules(role, manifest)`: Translates `spawn_rules` into capability additions (`agent.spawn.<target>`)\n - `buildResolvedRoles(template, registry)`: For each role in template, creates `ResolvedTeamRole` with enforcement-enriched `RoleDefinition` (workspace, lifecycle, tools, protocol from parent role + macro_agent overrides from role YAML)\n - `parseMacroAgentExtensions(raw)`: Takes opaque `Record<string, unknown>` from manifest, returns typed `MacroAgentExtensions`\n\n3. **Remove**: All the old functions that are now handled by openteams:\n - `validateManifest()` → openteams handles\n - `resolveTeamRole()` → replaced by hooks + `buildResolvedRoles()`\n - `collectPromptRefs()` → openteams handles prompt loading\n - `loadMcpServers()` → openteams handles (A3)\n - Keep `validateCommunication()` (macro-agent may have stricter validation than openteams)\n\n4. **Error mapping**: Catch openteams errors and wrap in `TeamLoadError` with appropriate codes for backward compatibility.\n\n### Tests\n- Load self-driving template → same result as before\n- Load structured template → same result as before\n- Role extending built-in (worker, coordinator) → correctly resolves via registry hook\n- spawn_rules translated to capabilities → verified on resolved roles\n- macro_agent extensions parsed → typed correctly\n- Missing template dir → TeamLoadError with MANIFEST_NOT_FOUND\n- Invalid YAML → TeamLoadError with INVALID_MANIFEST\n","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:22:06","updated_at":"2026-02-20 22:07:33","closed_at":"2026-02-20 22:07:33","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-7u03","from_type":"issue","to":"i-4xo6","to_type":"issue","type":"depends-on"},{"from":"i-7u03","from_type":"issue","to":"i-7sew","to_type":"issue","type":"depends-on"},{"from":"i-7u03","from_type":"issue","to":"s-50b3","to_type":"spec","type":"implements"}],"tags":["macro-agent","migration"],"feedback":[{"id":"0dc57289-38de-480e-adcf-c3556677dea6","from_id":"i-7u03","to_id":"s-50b3","feedback_type":"comment","content":"B4 complete: Replaced `team-loader.ts` internals with openteams `TemplateLoader.loadAsync()`. Three hooks: `mapRegistryRole` (external role resolution), `enrichRoleWithSpawnRules` (spawn_rules → capabilities), `buildResolvedTeamRole` (enforcement enrichment). Error mapping to `TeamLoadError` preserved. `_loadedPrompts` backward compat maintained via multi-key mapping from openteams prompt resolution. All 3296 tests pass (100 team tests).","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-20T22:07:33.452Z","updated_at":"2026-02-20T22:07:33.452Z"}]}
164
+ {"id":"i-4l1z","uuid":"99b438bb-d9b7-4cd2-8826-4b24c581b745","title":"B5: Adopt multi-file prompts from openteams","content":"\n**Spec**: [[s-50b3]]\n\n**File**: `src/teams/team-runtime.ts` (spawn interceptor)\n\nAdopt openteams' `ResolvedPrompts` model (primary + additional sections) instead of single-file prompts.\n\n### Changes\n\n1. **In `createSpawnInterceptor()`**: Replace current prompt reading logic:\n ```typescript\n // OLD: single string from _loadedPrompts\n const promptContent = manifest._loadedPrompts.get(promptPath);\n\n // NEW: structured prompts from ResolvedTemplate\n const resolvedPrompts = result.template.prompts.get(roleName);\n if (resolvedPrompts) {\n let fullPrompt = resolvedPrompts.primary;\n for (const section of resolvedPrompts.additional) {\n fullPrompt += `\\n\\n## ${section.name}\\n\\n${section.content}`;\n }\n // ... use fullPrompt as customPrompt\n }\n ```\n\n2. **Section ordering**: openteams already ensures SOUL.md comes first in additional sections. Macro-agent just concatenates.\n\n3. **Interaction patterns**: Continue appending interaction pattern sections (pull mode, trunk strategy) AFTER the role prompt — this is macro-agent-specific and stays unchanged.\n\n4. **Backward compatibility**: Existing single-file prompts (e.g., `prompts/planner.md`) are loaded by openteams as `{ primary: content, additional: [] }` — no change in behavior.\n\n### Tests\n- Single-file prompt → same behavior as before\n- Directory prompt (ROLE.md + SOUL.md) → SOUL.md content appears in assembled prompt\n- Directory prompt (ROLE.md + multiple .md) → all sections included in order\n- `prompts:` field in role YAML → explicit file ordering respected\n- Interaction patterns still appended after role prompt\n","status":"closed","priority":2,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:22:16","updated_at":"2026-02-20 22:08:26","closed_at":"2026-02-20 22:08:26","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-4l1z","from_type":"issue","to":"i-7u03","to_type":"issue","type":"depends-on"},{"from":"i-4l1z","from_type":"issue","to":"s-50b3","to_type":"spec","type":"implements"}],"tags":["macro-agent","migration"],"feedback":[{"id":"50995660-4059-4c8d-8342-3513add89ca0","from_id":"i-4l1z","to_id":"s-50b3","feedback_type":"comment","content":"B5 complete: Multi-file prompt assembly added in `team-loader.ts`. When building `_loadedPrompts`, additional sections from openteams' `ResolvedPrompts` are concatenated after the primary content with `## section_name` headers. Single-file prompts unchanged (additional is empty). Runtime transparent — no changes needed to `team-runtime.ts`. All 100 team tests pass.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-20T22:08:25.857Z","updated_at":"2026-02-20T22:08:25.857Z"}]}
165
+ {"id":"i-97rn","uuid":"c48894be-6dfb-43cb-ac14-5c137892df81","title":"B6: Update team-runtime.ts to consume MacroResolvedTemplate","content":"\n**Spec**: [[s-50b3]]\n\n**File**: `src/teams/team-runtime.ts`\n\nUpdate `TeamRuntime` to accept and consume `MacroResolvedTemplate` instead of the old `TeamManifest` with `_` prefixed fields.\n\n### Changes\n\n1. **Constructor**: Change parameter type:\n ```typescript\n // OLD\n constructor(private manifest: TeamManifest, ...)\n // NEW\n constructor(private resolved: MacroResolvedTemplate, ...)\n ```\n\n2. **Access patterns** — update throughout the class:\n | Old | New |\n |-----|-----|\n | `this.manifest.topology` | `this.resolved.template.manifest.topology` |\n | `this.manifest.communication` | `this.resolved.template.manifest.communication` |\n | `this.manifest.macro_agent` | `this.resolved.macroAgent` |\n | `this.manifest._resolvedRoles` | `this.resolved.resolvedRoles` |\n | `this.manifest._loadedPrompts` | `this.resolved.template.prompts` (now `ResolvedPrompts`) |\n | `this.manifest._mcpServers` | `this.resolved.mcpServers` |\n | `this.manifest.name` | `this.resolved.template.manifest.name` |\n | `this.manifest.roles` | `this.resolved.template.manifest.roles` |\n\n3. **`initialize()`**:\n - Register roles from `this.resolved.resolvedRoles`\n - Emit `team_config` with data from `this.resolved.template.manifest` + `this.resolved.macroAgent`\n - Install spawn interceptor using new access patterns\n\n4. **`bootstrap()`**:\n - Read topology from `this.resolved.template.manifest.topology`\n - Companions from same path\n\n5. **`createSpawnInterceptor()`**:\n - Prompts: use `this.resolved.template.prompts.get(roleName)` → `ResolvedPrompts` (ties into B5)\n - MCP servers: use `this.resolved.mcpServers.get(roleName)`\n - Task mode: use `this.resolved.macroAgent.task_assignment?.mode`\n - Strategy: use `this.resolved.macroAgent.integration?.strategy`\n\n6. **`installSignalFilter()`** and **`installEmissionValidator()`**:\n - Communication config from `this.resolved.template.manifest.communication`\n\n7. **Getters**:\n - `getManifest()` → return `this.resolved.template.manifest`\n - `getTaskMode()` → use `this.resolved.macroAgent`\n - `getStrategyName()` → use `this.resolved.macroAgent`\n - Add `getResolvedTemplate()` → return full `this.resolved`\n\n8. **Handle `routing.status: \"none\"`** (B7): In the status propagation setup, check if `routing.status === \"none\"` and skip automatic parent→child status wiring.\n\n### Tests\n- All existing TeamRuntime tests pass with updated fixture construction\n- New `MacroResolvedTemplate` fixtures work correctly\n- Getters return correct values\n","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:22:28","updated_at":"2026-02-20 22:12:27","closed_at":"2026-02-20 22:12:27","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-97rn","from_type":"issue","to":"i-4l1z","to_type":"issue","type":"depends-on"},{"from":"i-97rn","from_type":"issue","to":"i-4xo6","to_type":"issue","type":"depends-on"},{"from":"i-97rn","from_type":"issue","to":"i-7u03","to_type":"issue","type":"depends-on"},{"from":"i-97rn","from_type":"issue","to":"s-50b3","to_type":"spec","type":"implements"}],"tags":["macro-agent","migration"],"feedback":[{"id":"2a7238f9-e9c3-4d75-8c0a-10e3a6d3d028","from_id":"i-97rn","to_id":"s-50b3","feedback_type":"comment","content":"B6 complete: `TeamRuntime` now accepts both `MacroResolvedTemplate` (new) and `TeamManifest` (legacy) via runtime detection. Internally always uses `MacroResolvedTemplate` with convenience accessors (`this.manifest`, `this.communication`, `this.resolved`). Added `manifestToResolved()` converter. New `getResolvedTemplate()` getter. Zero changes to CLI or tests — backward compatible. All 3296 tests pass.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-20T22:12:27.091Z","updated_at":"2026-02-20T22:12:27.091Z"}]}
166
+ {"id":"i-5yzm","uuid":"8496765e-0f77-46ea-8a50-07bd282c6eaf","title":"B8: Update imports across codebase + B9: Update tests","content":"\n**Spec**: [[s-50b3]]\n\nUpdate all files that import from `src/teams/types.ts` and update test fixtures to use new types.\n\n### B8: Import Updates\n\nFiles that import from `src/teams/types.ts` or `src/teams/index.ts`:\n- `src/teams/team-runtime.ts` — updated in B6\n- `src/teams/team-loader.ts` — updated in B4\n- `src/teams/index.ts` — re-export new types + `MacroResolvedTemplate`\n- `src/api/server.ts` — team endpoint uses `TeamManifest` for response; update to access via `MacroResolvedTemplate`\n- `src/cli/index.ts` — calls `loadTeam()`, now returns `MacroResolvedTemplate`; update to pass to `TeamRuntime`\n- Any other files found via grep\n\nFor each file:\n- Update imports to use new type names (aliases ensure most won't break)\n- Update any code that accesses `manifest._resolvedRoles`, `manifest._loadedPrompts`, `manifest._mcpServers` to use `MacroResolvedTemplate` accessors\n\n### B9: Test Updates\n\n**Files**: `src/teams/__tests__/team-system.test.ts`, `src/teams/__tests__/cross-subsystem.integration.test.ts`\n\n1. **Update test fixtures** that construct `TeamManifest` objects:\n - Remove `_resolvedRoles`, `_loadedPrompts`, `_mcpServers` from inline manifests\n - Construct `MacroResolvedTemplate` where tests need resolved state\n - For tests that only need the manifest, use openteams' `TeamManifest` directly\n\n2. **Update mock constructors**: Tests that mock `TeamRuntime` need updated constructor signatures\n\n3. **Add new tests**:\n - Multi-file prompt loading (ROLE.md + SOUL.md directory)\n - `capabilities_add`/`capabilities_remove` flat syntax (via openteams loader)\n - External role registry resolution via hooks\n - `routing.status: \"none\"` handling\n - Round-trip: load template → verify `MacroResolvedTemplate` fields match expectations\n\n4. **Verify**:\n - All 71 existing team tests pass\n - All 3,052 total tests pass\n - `npm run build` succeeds\n - Existing `self-driving` and `structured` templates load without modification\n","status":"closed","priority":2,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:22:40","updated_at":"2026-02-20 22:13:50","closed_at":"2026-02-20 22:13:50","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-5yzm","from_type":"issue","to":"i-7u03","to_type":"issue","type":"depends-on"},{"from":"i-5yzm","from_type":"issue","to":"i-97rn","to_type":"issue","type":"depends-on"},{"from":"i-5yzm","from_type":"issue","to":"s-50b3","to_type":"spec","type":"implements"}],"tags":["macro-agent","migration"],"feedback":[{"id":"b8e83dca-12a5-4caa-ac36-5e03fed4522e","from_id":"i-5yzm","to_id":"s-50b3","feedback_type":"comment","content":"B8+B9 complete: Updated `src/teams/index.ts` to re-export openteams canonical types (TopologyConfig, CommunicationConfig, SubscriptionEntry, RoutingConfig, PeerRoute, etc.) alongside backward-compatible aliases. No other files outside `src/teams/` reference team-specific types. All 3296 tests pass, build clean. The backward-compatible approach (TeamRuntime accepts both types) means existing tests work without modification — full migration of test fixtures to `MacroResolvedTemplate` can happen incrementally.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-20T22:13:49.706Z","updated_at":"2026-02-20T22:13:49.706Z"}]}
167
+ {"id":"i-809b","uuid":"eb561d6a-468e-43bf-aa31-2917da2781da","title":"Refactor TeamRuntime to expose interceptor/filters instead of installing them","content":"Refactor `src/teams/team-runtime.ts` so that TeamRuntime **exposes** its spawn interceptor, signal filter, and emission validator as methods instead of **installing** them directly on services.\n\n**Changes:**\n- `initialize()`: Remove `agentManager.setSpawnInterceptor()` call. Keep role registration, team_config event, strategy creation.\n- `bootstrap()`: Remove `this.installSignalFilter()` and `this.installEmissionValidator()` calls. Keep agent spawning, peer route wiring, continuation monitoring. The internal state (agentRoleMap, peerSignalFilters, roleAllowedSignals) should still be populated.\n- Add `createSpawnInterceptor(): SpawnInterceptor` — returns the interceptor function (extracted from current `createSpawnInterceptor` private method, made public)\n- Add `createSignalFilter(): (from, to, signal) => boolean` — returns the filter function (extracted from current `installSignalFilter`)\n- Add `createEmissionValidator(): (agentId, signal) => { action, message? }` — returns the validator (extracted from `installEmissionValidator`)\n\n**Backward compat:** Existing tests that verify interceptor/filter installation will need updating — they should now test that the exposed methods return correct functions, and that TeamManager (once created) installs them.\n\n**Key constraint:** TeamRuntime must still work standalone (without TeamManager) for tests. Consider a `installOnServices()` convenience method that calls all three for backward compat, or update tests to use TeamManager.","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 05:04:25","updated_at":"2026-02-21 05:18:02","closed_at":"2026-02-21 05:18:02","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-809b","from_type":"issue","to":"i-2mhu","to_type":"issue","type":"blocks"},{"from":"i-809b","from_type":"issue","to":"s-488j","to_type":"spec","type":"implements"}],"tags":["refactor","teams"],"feedback":[{"id":"0776dcd2-da0b-45c6-aade-11f1f434aa1b","from_id":"i-809b","to_id":"s-488j","feedback_type":"comment","content":"Completed TeamRuntime refactoring:\n\n**Changes to `team-runtime.ts`:**\n- `initialize()` no longer installs spawn interceptor on AgentManager\n- `bootstrap()` no longer installs signal filter or emission validator on MessageRouter\n- Added public factory methods: `createSpawnInterceptor()`, `createSignalFilter()`, `createEmissionValidator()`\n- Added `installOnServices()` / `uninstallFromServices()` convenience methods for standalone use\n- Added `getAgentRoleMap()`, `registerAgent()`, `hasAgent()` for TeamManager agent-team tracking\n- `teardown()` no longer clears interceptor (caller responsibility)\n- Pre-computed `roleAllowedSignals` via `computeRoleAllowedSignals()` during bootstrap\n\n**Test updates (107 tests, all passing):**\n- Updated 20+ existing tests to use `installOnServices()` pattern\n- Added 9 new tests for exposed factory methods, agent registration, and uninstall behavior\n- Signal filtering/emission validation \"installs\" tests now verify bootstrap alone doesn't install (new behavior)\n- Teardown tests verify interceptor is NOT cleared (caller responsibility) + uninstallFromServices works","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T05:18:02.170Z","updated_at":"2026-02-21T05:18:02.170Z"}]}
168
+ {"id":"i-2mhu","uuid":"b49c4fde-729a-4e6f-9e1b-48dc2b725614","title":"Create TeamManager module with composite dispatch","content":"Create `src/teams/team-manager.ts` — the central owner of team instance lifecycle.\n\n**Core responsibilities:**\n- Hold `Map<string, TeamInstance>` of active team instances\n- `startTeam(templateName, basePath?)`: load template via `loadTeam()`, create TeamRuntime, initialize + bootstrap, assign instance ID\n- `stopTeam(instanceId)`: teardown TeamRuntime, remove from map\n- `teardownAll()`: stop all instances (for server shutdown)\n- `getTeamForAgent(agentId)`: look up which team instance an agent belongs to (in-memory cache)\n- `install()`: install composite spawn interceptor, signal filter, and emission validator on shared services\n\n**Composite interceptor logic:**\n```typescript\n(options) => {\n const parentTeam = this.getTeamForAgent(options.parent);\n if (parentTeam) {\n return parentTeam.runtime.createSpawnInterceptor()(options);\n }\n return options; // No team — pass through\n}\n```\n\nSimilar composition for signal filter and emission validator — delegate to the team instance that owns the agent.\n\n**Agent-to-team mapping:**\n- Populated during `startTeam()` bootstrap (root + companion agents)\n- Updated by the composite interceptor (child agents inherit parent's team)\n- `Map<AgentId, string>` mapping agent ID → instance ID\n\n**Instance ID generation:**\n- Format: `{templateName}-{counter}` (e.g., `self-driving-1`)\n\n**Option B constraint:** `startTeam()` rejects if a team is already running. Document that this is relaxed for Option A.\n\n**Export from `src/teams/index.ts`.**","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 05:04:34","updated_at":"2026-02-21 05:22:51","closed_at":"2026-02-21 05:22:51","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-2mhu","from_type":"issue","to":"i-2f41","to_type":"issue","type":"blocks"},{"from":"i-2mhu","from_type":"issue","to":"i-7rtm","to_type":"issue","type":"blocks"},{"from":"i-2mhu","from_type":"issue","to":"s-488j","to_type":"spec","type":"implements"}],"tags":["new-module","teams"],"feedback":[{"id":"c5742661-3588-41c6-a8d4-fa8fa2f7f46f","from_id":"i-2mhu","to_id":"s-488j","feedback_type":"comment","content":"Created TeamManager module at `src/teams/team-manager.ts`.\n\n**Implementation:**\n- `startTeam()`: loads template via loadTeam(), creates TeamRuntime, initializes + bootstraps, assigns instance ID\n- `stopTeam()`: tears down runtime, clears agent mapping and caches\n- `teardownAll()`: stops all instances + removes lifecycle listener\n- `install()`: installs composite spawn interceptor, signal filter, emission validator on shared services\n- `uninstall()`: clears interceptor + unsubscribes lifecycle listener\n- Agent-to-team mapping: bootstrap agents mapped explicitly, child agents auto-registered via lifecycle listener\n- Cached factory outputs per instance for efficient composite dispatch\n- Option B: startTeam() rejects if team already running\n\n**Tests (32 passing):**\n- Lifecycle: start, stop, teardown, Option B rejection, sequential IDs\n- Composite interceptor: team context injection, pass-through for non-team agents\n- Composite signal filter: delegation to correct team, non-team pass-through\n- Composite emission validator: delegation to correct team, non-team allow\n- Lifecycle listener: auto-registration of child agents, ignore non-team/non-spawn events\n- Uninstall: clears interceptor, unsubscribes listener\n\nExported from `src/teams/index.ts`.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T05:22:50.697Z","updated_at":"2026-02-21T05:22:50.697Z"}]}
169
+ {"id":"i-43a3","uuid":"fabea70f-c0e7-4fb4-8eaa-477d33b7ba28","title":"Add team_instance field to EventStore agent records","content":"Add an optional `team_instance` field to agent records in EventStore so team membership survives server restarts.\n\n**Changes:**\n- `src/store/types/agents.ts`: Add `team_instance?: string` to `Agent` type\n- `src/store/event-store.ts`: Handle `team_instance` in agent materialized view (set from spawn event payload)\n- The spawn interceptor (in TeamManager) should include `team_instance` in the spawn options/event payload\n\n**On server restart:** TeamManager can rehydrate agent-to-team mapping from EventStore by querying agents with `team_instance` set.\n\nThis is the durable backing for the in-memory cache in TeamManager.","status":"closed","priority":2,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 05:04:38","updated_at":"2026-02-21 05:41:40","closed_at":"2026-02-21 05:41:40","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-43a3","from_type":"issue","to":"s-488j","to_type":"spec","type":"implements"}],"tags":["store","teams"],"feedback":[{"id":"a478a833-a86b-4a8d-bf7b-c8b7a089fc73","from_id":"i-43a3","to_id":"s-488j","feedback_type":"comment","content":"Added `team_instance` field to agent records for durable team membership tracking:\n\n**Type changes:**\n- `src/store/types/agents.ts`: Added `team_instance?: string` to `Agent` and `AgentMetadataUpdate`\n- `src/agent/types.ts`: Added `team_instance?: string` to `SpawnAgentOptions`\n\n**EventStore:**\n- `applySpawnEvent`: Stores `team_instance` from spawn event payload\n- `rowToAgent`: Hydrates `team_instance` from store row\n- `updateAgentMetadata`: Handles `team_instance` updates\n\n**Agent Manager (`src/agent/agent-manager.ts`):**\n- `spawn()`: Destructures `team_instance` from options, includes it in spawn event payload\n- Fork path: Inherits `team_instance` from source agent\n\n**TeamManager (`src/teams/team-manager.ts`):**\n- Composite interceptor: Tags child agents with `team_instance: parentTeam.id`\n- `startTeam()`: Tags bootstrap agents (root + companions) via `updateAgentMetadata`\n\n**Tests:** 2 new tests in `team-manager.test.ts` — team_instance set on child agents + bootstrap agents tagged in EventStore. All 3413 tests pass.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T05:41:37.457Z","updated_at":"2026-02-21T05:41:37.457Z"}]}
170
+ {"id":"i-2f41","uuid":"0e5ed162-1cd0-4647-b3ac-c3626c9f0ebc","title":"Wire TeamManager into acp.ts server startup","content":"Integrate TeamManager into the primary `multiagent` server entry point (`src/cli/acp.ts`).\n\n**Changes to `acp.ts`:**\n1. Import TeamManager and loadTeam\n2. After creating AgentManager, MessageRouter, EventStore — create TeamManager:\n ```typescript\n const teamManager = new TeamManager({ agentManager, messageRouter, eventStore });\n teamManager.install(); // composite interceptor/filters\n ```\n3. Read team from config and auto-start:\n ```typescript\n const mergedConfig = loadMergedConfig(defaultCwd);\n if (mergedConfig.team) {\n await teamManager.startTeam(mergedConfig.team, defaultCwd);\n }\n ```\n4. Pass `teamManager` to `createCombinedServer()` (requires updating CombinedServer to accept it)\n5. Add `teamManager.teardownAll()` to the cleanup function\n\n**Only in server mode** (not `--acp` stdio mode).\n\n**CombinedServer changes:** `createCombinedServer` signature needs a `teamManager` option. It passes it through to the API app for team endpoints.","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 05:04:44","updated_at":"2026-02-21 05:24:41","closed_at":"2026-02-21 05:24:41","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-2f41","from_type":"issue","to":"i-41zo","to_type":"issue","type":"blocks"},{"from":"i-2f41","from_type":"issue","to":"s-488j","to_type":"spec","type":"implements"}],"tags":["server","teams"],"feedback":[{"id":"3ea1ab0a-e267-4c7e-8c87-5830f90d9e2e","from_id":"i-2f41","to_id":"s-488j","feedback_type":"comment","content":"Wired TeamManager into acp.ts server startup.\n\n**Changes:**\n- `src/cli/acp.ts`: Import TeamManager, create after services, install composites, auto-start from `mergedConfig.team`, pass to CombinedServer, add teardown to cleanup\n- `src/server/combined-server.ts`: Added `teamManager?: TeamManager` to `CombinedServerServices` interface\n\n**Flow:**\n1. TeamManager created after agentManager/messageRouter/eventStore\n2. `teamManager.install()` installs composite interceptor/filter/validator\n3. If `mergedConfig.team` is set, auto-starts team (server mode only, not --acp stdio)\n4. TeamManager passed to CombinedServer for API endpoint access\n5. `teamManager.teardownAll()` called during cleanup (before agentManager.close)","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T05:24:41.460Z","updated_at":"2026-02-21T05:24:41.460Z"}]}
171
+ {"id":"i-41zo","uuid":"86ca3a9f-19f7-4fa1-9053-33910b4f1cb3","title":"Add REST API team management endpoints","content":"Add team management REST endpoints to the API server, accessible via CombinedServer.\n\n**New endpoints:**\n\n`POST /api/teams` — Start a team instance\n- Body: `{ template: \"self-driving\" }`\n- Calls `teamManager.startTeam(template, defaultCwd)`\n- Returns: `{ id, templateName, rootAgentId, companionAgentIds }`\n- Option B: Returns 409 if a team is already running\n\n`GET /api/teams` — List running team instances\n- Returns: `[{ id, templateName, rootAgentId, companionAgentIds, taskMode, strategy }]`\n\n`GET /api/teams/:id` — Get team instance details\n- Returns: full manifest info, agent list, strategy, task mode, communication config\n- Returns 404 if instance not found\n\n`DELETE /api/teams/:id` — Teardown a team instance\n- Calls `teamManager.stopTeam(id)`\n- Returns: `{ success: true }`\n- Returns 404 if instance not found\n\n**Deprecation:**\n- `GET /api/team` (singular): Keep working but add deprecation header, internally delegate to `GET /api/teams/:activeId`\n\n**Location:** Add to `src/api/server.ts` in both `createAPIApp` (shared) and `createAPIServer` (standalone) handler sets. TeamManager is passed in via the services/state object.\n\n**WebSocket:** Emit events on `teams` channel when teams start/stop.","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 05:04:51","updated_at":"2026-02-21 05:33:52","closed_at":"2026-02-21 05:33:52","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-41zo","from_type":"issue","to":"i-6gff","to_type":"issue","type":"blocks"},{"from":"i-41zo","from_type":"issue","to":"s-488j","to_type":"spec","type":"implements"}],"tags":["api","teams"],"feedback":[{"id":"076d9b27-b866-4710-817d-4b1f78906d21","from_id":"i-41zo","to_id":"s-488j","feedback_type":"comment","content":"Implemented REST API team management endpoints:\n\n**Shared helper** `registerTeamRoutes()` in `src/api/server.ts`:\n- `POST /api/teams` — Start a team instance (body: `{ template: string }`)\n- `GET /api/teams` — List running team instances\n- `GET /api/teams/:id` — Get team instance details (includes manifest roles + communication)\n- `DELETE /api/teams/:id` — Teardown a team instance\n\n**Wired into both server modes:**\n- Standalone `createAPIServer` — uses `broadcastToChannel` for WS events\n- Shared `createAPIApp` — accepts `defaultCwd` and `teamManager` via config/services, uses `state.broadcast`\n- `combined-server.ts` passes `defaultCwd` through to `createAPIApp`\n\n**Type updates:**\n- Added `\"team_started\" | \"team_stopped\"` to `WSMessageType` in `api/types.ts`\n- `registerTeamRoutes` follows `registerConversationRoutes` pattern (accepts `sendError` callback)\n\n**Error handling:**\n- 400 for missing template, 409 for team already running, 404 for unknown team ID, 500 for start/stop failures\n\n**Tests:** 12 new tests in `src/api/__tests__/server.test.ts` covering all endpoints, error cases, and no-teamManager fallback. All 3411 tests pass.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T05:33:48.466Z","updated_at":"2026-02-21T05:33:48.466Z"}]}
172
+ {"id":"i-6gff","uuid":"1247032e-821e-4bfc-a8ce-bbe2d4206fd4","title":"Deprecate multiagent-cli start --team in favor of multiagent server","content":"Mark the legacy `multiagent-cli start --team` path as deprecated.\n\n**Changes:**\n- `src/cli/index.ts` `start` command: Add deprecation warning when `--team` is used:\n ```\n console.warn('[DEPRECATED] --team flag on multiagent-cli start is deprecated. Use multiagent server with .multiagent/config.json instead.');\n ```\n- Keep functional for backward compat (don't remove yet)\n- Update CLAUDE.md to reference `multiagent` as the primary entry point for teams\n- Deprecate `GET /api/team` (singular) with `Deprecation` response header","status":"closed","priority":3,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 05:04:55","updated_at":"2026-02-21 05:35:24","closed_at":"2026-02-21 05:35:24","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-6gff","from_type":"issue","to":"s-488j","to_type":"spec","type":"implements"}],"tags":["deprecation","teams"],"feedback":[{"id":"0a1d4a45-ca68-44e1-bc93-e7043aca290c","from_id":"i-6gff","to_id":"s-488j","feedback_type":"comment","content":"Deprecation markers added:\n\n1. **CLI `--team` flag** (`src/cli/index.ts`): Prints yellow deprecation warning when `--team` is used, directing users to `multiagent` with `.multiagent/config.json`. Functionality preserved.\n\n2. **`GET /api/team` endpoint** (`src/api/server.ts`): Added `Deprecation: true` and `Link: </api/teams>; rel=\"successor-version\"` response headers. Functionality preserved.\n\nCLAUDE.md already references `multiagent` as the primary entry point, no update needed.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T05:35:21.364Z","updated_at":"2026-02-21T05:35:21.364Z"}]}
173
+ {"id":"i-7rtm","uuid":"adab8a12-341c-40b6-a3b4-c6dea96a8bbd","title":"Add TeamManager tests","content":"Comprehensive tests for TeamManager and the refactored TeamRuntime.\n\n**Test areas:**\n\n1. **TeamManager lifecycle:**\n - `startTeam()` loads template, creates runtime, bootstraps\n - `stopTeam()` tears down runtime, removes from map\n - `teardownAll()` cleans up everything\n - Option B: `startTeam()` rejects second team (409 equivalent)\n\n2. **Composite spawn interceptor:**\n - Child of team agent gets team config injected\n - Standalone agent (no team parent) passes through unchanged\n - Agent-to-team mapping updated on spawn\n\n3. **Composite signal filter:**\n - Delegates to correct team instance based on agent membership\n - Non-team agents pass through unfiltered\n\n4. **Composite emission validator:**\n - Delegates to correct team instance\n - Non-team agents allowed\n\n5. **Agent-to-team mapping:**\n - Root/companion agents mapped during bootstrap\n - Child agents mapped via interceptor\n - Mapping cleared on team stop\n\n6. **Config auto-start:**\n - TeamManager starts team from config on boot\n - No config = no team started\n\n7. **REST API endpoints:**\n - POST /api/teams — creates instance\n - GET /api/teams — lists instances\n - GET /api/teams/:id — returns details\n - DELETE /api/teams/:id — teardown\n - POST /api/teams when team running → 409\n\n8. **Updated TeamRuntime tests:**\n - `createSpawnInterceptor()` returns correct function\n - `createSignalFilter()` returns correct function\n - `createEmissionValidator()` returns correct function\n - Existing behavior preserved through TeamManager","status":"closed","priority":2,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 05:05:02","updated_at":"2026-02-21 05:35:53","closed_at":"2026-02-21 05:35:53","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-7rtm","from_type":"issue","to":"s-488j","to_type":"spec","type":"implements"}],"tags":["teams","testing"],"feedback":[{"id":"297afdc4-4249-4cf9-b5a4-d906a1ac1c5e","from_id":"i-7rtm","to_id":"s-488j","feedback_type":"comment","content":"All test areas from this issue were covered during implementation of the other issues:\n\n- **TeamManager lifecycle + composite dispatch + agent mapping + Option B**: 32 tests in `src/teams/__tests__/team-manager.test.ts` (i-2mhu)\n- **Updated TeamRuntime factory methods**: 9 new tests + 20+ updated tests in `src/teams/__tests__/team-system.test.ts` (i-809b)\n- **REST API endpoints**: 12 tests in `src/api/__tests__/server.test.ts` (i-41zo)\n- **Config auto-start**: Wired in `src/cli/acp.ts` (i-2f41). This is an integration concern — requires real team YAML + filesystem — better suited for E2E tests.\n\nTotal new/updated tests across all issues: ~75 tests. Full suite: 3411 tests passing.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T05:35:48.868Z","updated_at":"2026-02-21T05:35:48.868Z"}]}
174
+ {"id":"i-263i","uuid":"9aabcfb5-2342-4085-a522-2c9c8b22bb24","title":"Lift single-team constraint in TeamManager","content":"Remove the Option B guard in `TeamManager.startTeam()` (lines 77-84 of `src/teams/team-manager.ts`) that rejects when `instances.size > 0`.\n\n**Changes:**\n- `src/teams/team-manager.ts`: Delete the `if (this.instances.size > 0)` block in `startTeam()`\n- `src/teams/__tests__/team-manager.test.ts`: Change \"Option B: rejects if a team is already running\" test to \"allows multiple concurrent teams\" — start two teams and verify both are tracked\n\nThe composite dispatch already routes per agent-to-team mapping, so no other changes needed.","status":"closed","priority":0,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 07:46:42","updated_at":"2026-02-21 07:59:29","closed_at":"2026-02-21 07:59:29","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-263i","from_type":"issue","to":"i-28px","to_type":"issue","type":"blocks"},{"from":"i-263i","from_type":"issue","to":"i-5tax","to_type":"issue","type":"blocks"},{"from":"i-263i","from_type":"issue","to":"i-6370","to_type":"issue","type":"blocks"},{"from":"i-263i","from_type":"issue","to":"s-9v71","to_type":"spec","type":"implements"}],"tags":["option-a","teams"],"feedback":[{"id":"b439a928-46b7-4e6f-805d-56de7ee4d740","from_id":"i-263i","to_id":"s-9v71","feedback_type":"comment","content":"Removed the Option B single-team constraint from `TeamManager.startTeam()`. Updated test to verify multiple concurrent teams are allowed. All 3413 tests pass.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T07:59:28.741Z","updated_at":"2026-02-21T07:59:28.741Z"}]}
175
+ {"id":"i-9yhi","uuid":"08f572cf-c924-4887-bf5d-213fbca979e0","title":"Scope team_config events by team instance","content":"Each team emits a `team_config` event during `initialize()` with no instance scoping. MCP subprocess discovery (`src/cli/mcp.ts:259`) uses `.find(e => e.payload?.team_config != null)` which returns an arbitrary config with multiple teams.\n\n**Changes:**\n\n1. **`src/teams/team-runtime.ts` (line 192-209)**: Add `team_instance` field to the team_config event payload. TeamRuntime needs to accept an optional `teamInstanceId` parameter (passed from TeamManager during `startTeam`) to include in the event.\n\n2. **`src/cli/mcp.ts` (lines 258-284)**: Change `.find()` to filter by the calling agent's team name via `process.env.MACRO_TEAM_NAME`:\n ```typescript\n const myTeamName = process.env.MACRO_TEAM_NAME;\n const teamConfigEvent = teamEvents.find(\n (e) => e.payload?.team_config?.teamName === myTeamName\n );\n ```\n Falls back to first team_config if `MACRO_TEAM_NAME` is not set (backward compat).\n\n3. **Tests**: Update `team-system.test.ts` team_config assertions to verify `team_instance` is included.","status":"closed","priority":0,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 07:46:48","updated_at":"2026-02-21 08:01:15","closed_at":"2026-02-21 08:01:15","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-9yhi","from_type":"issue","to":"s-9v71","to_type":"spec","type":"implements"}],"tags":["mcp","option-a","teams"],"feedback":[{"id":"352e8cac-4cb5-44d8-ab0a-c7d5a995a05a","from_id":"i-9yhi","to_id":"s-9v71","feedback_type":"comment","content":"Scoped team_config events by team instance:\n\n1. **TeamRuntime.initialize()**: Accepts optional `{ teamInstanceId }` param, includes `team_instance` in team_config event payload.\n2. **TeamManager.startTeam()**: Computes instance ID before `initialize()`, passes it through.\n3. **MCP subprocess discovery** (`src/cli/mcp.ts`): Filters team_config events by `MACRO_TEAM_NAME` env var. Falls back to first team_config if env var not set (backward compat).\n\nAll 3413 tests pass.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T08:01:14.946Z","updated_at":"2026-02-21T08:01:14.946Z"}]}
176
+ {"id":"i-28px","uuid":"c304f906-aac0-4da7-98f7-52536d98bc65","title":"Add cross-team signal filter test coverage","content":"The composite signal filter already prioritizes the recipient's team filter for cross-team messages (`const team = recipientTeam ?? senderTeam`). Verify this is correct with explicit test coverage.\n\n**Add tests in `src/teams/__tests__/team-manager.test.ts`:**\n- Agent in team A sends signal to agent in team B → recipient's team filter applies\n- Agent in team A sends signal to non-team agent → sender's team filter applies\n- Non-team agent sends to agent in team B → recipient's team filter applies\n- Both sender and recipient in different teams → recipient's filter takes precedence\n\n**Note:** The existing code may already handle this correctly. The goal is verification through tests, not code changes (unless tests reveal a bug).","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 07:46:52","updated_at":"2026-02-21 08:06:25","closed_at":"2026-02-21 08:06:25","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-28px","from_type":"issue","to":"s-9v71","to_type":"spec","type":"implements"}],"tags":["option-a","teams","testing"],"feedback":[{"id":"1928d466-58af-469c-bdb5-df7c16a129b2","from_id":"i-28px","to_id":"s-9v71","feedback_type":"comment","content":"Added 4 cross-team signal filter tests to `team-manager.test.ts`:\n1. **Cross-team (A→B)**: grinder→developer uses recipient's (structured) filter — developer's `{TASK_ASSIGNED}` applies\n2. **Team→non-team**: grinder→outsider uses sender's (self-driving) filter — outsider has no role in team A, so all signals allowed\n3. **Non-team→team**: outsider→developer uses recipient's (structured) filter — developer's `{TASK_ASSIGNED}` applies\n4. **Bidirectional precedence**: grinder↔developer — each direction uses recipient's filter, confirming `recipientTeam ?? senderTeam` logic\n\nNo code changes needed — the existing composite filter handles all cross-team scenarios correctly.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T08:06:21.069Z","updated_at":"2026-02-21T08:06:21.069Z"}]}
177
+ {"id":"i-6370","uuid":"83b6052f-ede8-4795-a5be-c9697ef27171","title":"Update config schema for multi-team support","content":"Add optional `teams` field to `MultiagentConfig` for declaring additional team templates.\n\n**Changes:**\n\n1. **`src/config/project-config.ts`**: Add to `MultiagentConfig`:\n ```typescript\n /** Additional teams available for dynamic or auto-start loading */\n teams?: Record&lt;string, TeamConfigEntry&gt;;\n ```\n Add new interface:\n ```typescript\n export interface TeamConfigEntry {\n /** Template name (defaults to the key) */\n template?: string;\n /** Auto-start on server boot (default: false) */\n autoStart?: boolean;\n }\n ```\n\n2. **`src/cli/acp.ts`**: After starting the default `mergedConfig.team`, iterate `mergedConfig.teams` entries with `autoStart: true` and call `teamManager.startTeam()` for each:\n ```typescript\n if (mergedConfig.teams) {\n for (const [name, entry] of Object.entries(mergedConfig.teams)) {\n if (entry.autoStart) {\n const template = entry.template ?? name;\n await teamManager.startTeam(template, defaultCwd);\n }\n }\n }\n ```\n\n3. **Env var override**: Add `MACRO_TEAMS` env var support (comma-separated template names for auto-start) in `loadMergedConfig()`.\n\nBackward compatible — existing `team: \"...\"` configs continue to work unchanged.","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 07:46:58","updated_at":"2026-02-21 08:07:52","closed_at":"2026-02-21 08:07:52","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-6370","from_type":"issue","to":"s-9v71","to_type":"spec","type":"implements"}],"tags":["config","option-a","teams"],"feedback":[{"id":"8799e1a2-a388-4c72-a3df-5dd57a186620","from_id":"i-6370","to_id":"s-9v71","feedback_type":"comment","content":"Added multi-team config support:\n\n1. **`project-config.ts`**: Added `TeamConfigEntry` interface (`template?`, `autoStart?`) and `teams?: Record<string, TeamConfigEntry>` field to `MultiagentConfig`\n2. **`project-config.ts`**: Added `MACRO_TEAMS` env var support in `loadMergedConfig()` — comma-separated template names auto-merged with `autoStart: true`\n3. **`acp.ts`**: After starting default `mergedConfig.team`, iterates `mergedConfig.teams` entries with `autoStart: true` and starts each\n\nFully backward compatible — existing `team: \"...\"` configs work unchanged. Example multi-team config:\n```json\n{\n \"team\": \"self-driving\",\n \"teams\": {\n \"structured\": { \"autoStart\": true },\n \"custom\": { \"template\": \"self-driving\", \"autoStart\": false }\n }\n}\n```","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T08:07:49.981Z","updated_at":"2026-02-21T08:07:49.981Z"}]}
178
+ {"id":"i-5tax","uuid":"10aba4ae-28be-4d3a-9881-0a48f84bebe1","title":"Clean up API 409 handling for POST /api/teams","content":"With multiple teams allowed, the 409 \"already running\" error from `POST /api/teams` is no longer applicable from the single-team constraint. Clean up the error handling.\n\n**Changes in `src/api/server.ts` (`registerTeamRoutes`):**\n- Remove the special-case `if (message.includes(\"already running\")) return sendError(res, 409, ...)` \n- Any `startTeam` failure returns 500 `TEAM_START_FAILED`\n\n**Tests in `src/api/__tests__/server.test.ts`:**\n- Remove or update the \"should return 409 when team already running\" test\n- Add test: starting two different teams both succeed (201)","status":"closed","priority":0,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 07:47:02","updated_at":"2026-02-21 08:01:56","closed_at":"2026-02-21 08:01:56","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-5tax","from_type":"issue","to":"s-9v71","to_type":"spec","type":"implements"}],"tags":["api","option-a","teams"],"feedback":[{"id":"7593b0e6-5961-4a7f-a7be-ef2eb404df86","from_id":"i-5tax","to_id":"s-9v71","feedback_type":"comment","content":"Removed 409 \"already running\" special case from `POST /api/teams`. Replaced test with \"should allow starting multiple teams\" — verifies two sequential POST calls both return 201.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T08:01:56.013Z","updated_at":"2026-02-21T08:01:56.013Z"}]}
179
+ {"id":"i-3yqs","uuid":"7ba89fc8-63cd-455e-b6e1-669f34c25cb3","title":"Role registration conflict detection for multi-team","content":"If two teams define the same custom role name with different capabilities, the second registration silently overwrites the first in the shared `RoleRegistry`.\n\n**Changes:**\n- `src/teams/team-runtime.ts` `initialize()`: Before registering each role, check if it already exists in the registry with different capabilities. If so, log a warning (audit mode).\n- Optionally: prefix custom role names with team name in registry (e.g., `self-driving:grinder`) while keeping short names for intra-team agent role maps.\n\n**Lower priority** — role name collisions are unlikely in practice. This is hardening for correctness.\n\n**Files:** `src/teams/team-runtime.ts`, potentially `src/roles/registry.ts`","status":"closed","priority":2,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 07:47:07","updated_at":"2026-02-21 08:09:34","closed_at":"2026-02-21 08:09:34","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-3yqs","from_type":"issue","to":"s-9v71","to_type":"spec","type":"implements"}],"tags":["hardening","option-a","teams"],"feedback":[{"id":"9b7f86f0-5d39-41a5-b596-cb0a8779636a","from_id":"i-3yqs","to_id":"s-9v71","feedback_type":"comment","content":"Added role conflict detection in `TeamRuntime.initialize()`:\n- Before `registerRole()`, checks if the role already exists in the registry with different capabilities\n- Compares sorted capability arrays for mismatch\n- Logs a descriptive `console.warn` including team name, existing vs new capabilities\n- Does NOT block registration — warn-only to avoid breaking startup\n\nAdded 3 tests in `team-manager.test.ts`:\n1. Two different teams with non-overlapping custom roles → no warning\n2. Same team started twice → no warning (identical capabilities)\n3. Pre-registered role with different capabilities → warning detected","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T08:09:31.700Z","updated_at":"2026-02-21T08:09:31.700Z"}]}
180
+ {"id":"i-3q4b","uuid":"32d26c74-bec1-4bc3-8652-55e066aaf9f8","title":"Gate pull-mode MCP tools by taskMode","content":"Add `&& services.taskMode === \"pull\"` to the 3 pull-mode tool registration conditions in `src/mcp/mcp-server.ts`:\n- `claim_task` (line ~1094)\n- `unclaim_task` (line ~1107)\n- `list_claimable_tasks` (line ~1120)\n\nCurrently they check only `services.taskBackend` — push-mode agents can call claim tools.\n\nAdd test verifying claim tools are not registered when taskMode is \"push\".","status":"closed","priority":0,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 09:35:33","updated_at":"2026-02-21 09:37:32","closed_at":"2026-02-21 09:37:32","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-3q4b","from_type":"issue","to":"s-5lao","to_type":"spec","type":"implements"}],"tags":["gap-1","mcp","task-mode"],"feedback":[{"id":"957cefdd-dbad-4348-8f30-c4ee55be1f76","from_id":"i-3q4b","to_id":"s-5lao","feedback_type":"comment","content":"Added `&& services.taskMode === \"pull\"` to the 3 pull-mode tool registration conditions in `mcp-server.ts` (lines 1094, 1107, 1120). Push-mode agents can no longer see or call `claim_task`, `unclaim_task`, or `list_claimable_tasks`.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T09:37:32.364Z","updated_at":"2026-02-21T09:37:32.364Z"}]}
181
+ {"id":"i-5hia","uuid":"c0c1be3f-bc5b-41eb-a7fc-305194cc2add","title":"Add spawn rules defense-in-depth check in composite interceptor","content":"Agent-manager.ts already enforces spawn capabilities (lines 602-625). Add a second layer in TeamManager's composite spawn interceptor (`team-manager.ts` `install()` method).\n\nThe interceptor has `options.parent` and the parent's team instance. Look up parent's role from `runtime.getAgentRoleMap()`, get `topology.spawn_rules[parentRole]`, and verify `options.role` is in the allowed list. Throw if not.\n\nAdd test: spawn with disallowed child role via interceptor should throw.","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 09:35:36","updated_at":"2026-02-21 09:41:19","closed_at":"2026-02-21 09:41:19","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-5hia","from_type":"issue","to":"s-5lao","to_type":"spec","type":"implements"}],"tags":["gap-2","spawn-rules","teams"],"feedback":[{"id":"ee670a03-5fc1-46e8-95e6-38f261f8553a","from_id":"i-5hia","to_id":"s-5lao","feedback_type":"comment","content":"Implemented spawn rules defense-in-depth check in TeamManager's composite spawn interceptor (`team-manager.ts:install()`). When a parent agent's role has an entry in `topology.spawn_rules`, the interceptor verifies the child role is in the allowed list before delegating to the team's cached interceptor. Throws `Spawn rules violation` error if disallowed.\n\nThis is a second enforcement layer on top of the existing capability-based check in `agent-manager.ts:602-625`. Added 4 tests: disallowed spawn throws, allowed spawn succeeds, unlisted parent role passes through, roleless child passes through.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T09:41:16.386Z","updated_at":"2026-02-21T09:41:16.386Z"}]}
182
+ {"id":"i-1j12","uuid":"97db3bbd-d626-405b-9d26-6da66413d4f0","title":"Wire WorkspaceManager into server startup","content":"WorkspaceManager exists with full API but is never instantiated. Wire it through:\n\n1. **acp.ts**: Create via `createWorkspaceManager({ repoPath: defaultCwd })`, pass to AgentManager config (field already exists)\n2. **MCPServices**: Add `workspaceManager?` field, pass to `createDoneHandler()` in done tool registration\n3. **CombinedServerServices**: Add `workspaceManager?` field, pass through\n4. **Merge queue**: After team strategy instantiation, call `strategy.setMergeQueue(workspaceManager.getMergeQueue())` if strategy is queue type\n\n**Files:** `src/cli/acp.ts`, `src/mcp/mcp-server.ts`, `src/server/combined-server.ts`, `src/teams/team-runtime.ts`","status":"closed","priority":1,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 09:35:40","updated_at":"2026-02-21 09:47:08","closed_at":"2026-02-21 09:47:08","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-1j12","from_type":"issue","to":"i-84rt","to_type":"issue","type":"blocks"},{"from":"i-1j12","from_type":"issue","to":"s-5lao","to_type":"spec","type":"implements"}],"tags":["gap-3","wiring","workspace"],"feedback":[{"id":"a82a8810-85c8-47d3-850b-7ae7eb7a3ab4","from_id":"i-1j12","to_id":"s-5lao","feedback_type":"comment","content":"Wired WorkspaceManager into server startup:\n\n1. **`acp.ts`**: Creates `WorkspaceManager` via `createWorkspaceManager()` with pool config from `MACRO_WORKSPACE_POOL_SIZE` env var. Wrapped in try/catch since it requires a git repo. Passed to both `AgentManager` config (existing `workspaceManager` field) and `CombinedServerServices`.\n\n2. **`MCPServices`** (`mcp-server.ts`): Added `workspaceManager?` field. Passed to `createDoneHandler()` in done tool registration, enabling workspace path resolution and merge queue access in worker completion flow.\n\n3. **`CombinedServerServices`** (`combined-server.ts`): Added `workspaceManager?` field for pass-through from acp.ts.\n\n4. **`TeamServices`** (`team-runtime.ts`): Added optional `workspaceManager` field. After strategy instantiation in `initialize()`, if strategy is \"queue\" and has `setMergeQueue`, wires `workspaceManager.getMergeQueue()` to the strategy.\n\n5. **`TeamManager`** (`acp.ts`): Receives workspaceManager in TeamServices, which flows through to TeamRuntime for merge queue wiring.","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T09:47:05.365Z","updated_at":"2026-02-21T09:47:05.365Z"}]}
183
+ {"id":"i-84rt","uuid":"ad341c43-0b89-4d2e-a969-9087e48885b4","title":"Implement auto-scaling via monitorScaling()","content":"Add `monitorScaling()` to TeamRuntime following `monitorContinuations()` pattern:\n\n1. Wire `taskBackend` into TeamServices (optional field)\n2. In `monitorScaling()`: check `scaling.scale_on === \"task_queue_depth\"` feature flag\n3. Periodic timer (5s default): count pending tasks via `listClaimable()`, count active workers\n4. Scale up: spawn worker as child of root when `pending > active && active < max_workers`\n5. Scale down: let idle_drain handle (workers self-terminate after idle_timeout_s)\n6. Cooldown: minimum 10s between scale-up actions\n7. Emit scaling events to EventStore\n8. Call from `bootstrap()` after `monitorContinuations()`\n\n**Files:** `src/teams/team-runtime.ts`, `src/teams/types.ts` (TeamServices)","status":"closed","priority":2,"assignee":null,"archived":0,"archived_at":null,"created_at":"2026-02-21 09:35:44","updated_at":"2026-02-21 09:51:26","closed_at":"2026-02-21 09:51:26","parent_id":null,"parent_uuid":null,"relationships":[{"from":"i-84rt","from_type":"issue","to":"s-5lao","to_type":"spec","type":"implements"}],"tags":["gap-4","scaling","teams"],"feedback":[{"id":"fb6a1278-552d-4b94-a2fb-c39fd82f95d1","from_id":"i-84rt","to_id":"s-5lao","feedback_type":"comment","content":"Implemented auto-scaling via `monitorScaling()` in TeamRuntime:\n\n1. **TeamServices**: Added optional `taskBackend` field. Passed from `acp.ts`.\n\n2. **`monitorScaling()`**: Follows `monitorContinuations()` pattern:\n - Guards on `scaling.scale_on === \"task_queue_depth\"` and `taskBackend.listClaimable` availability\n - Determines worker roles by checking `baseRole === \"worker\"` in resolvedRoles\n - Periodic timer (5s) counts claimable tasks and active workers in the team\n - Spawns worker as child of root when `pending > active && active < max_workers`\n - 10s cooldown between scale-up actions prevents thrashing\n - Scale-down via idle_drain (workers self-terminate after `idle_timeout_s`)\n - Emits scaling events to EventStore for observability\n - Timer uses `unref()` to not prevent process exit\n\n3. **Lifecycle**: Called from `bootstrap()` after `monitorContinuations()`. Timer cleaned up in `teardown()`.\n\n4. **Tests** (4 new in team-system.test.ts):\n - Spawns worker when queue depth exceeds active workers\n - Respects max_workers cap\n - No spawns when scale_on !== \"task_queue_depth\"\n - Respects 10s cooldown between scale-up actions","agent":"alexngai","anchor":null,"dismissed":false,"created_at":"2026-02-21T09:51:23.855Z","updated_at":"2026-02-21T09:51:23.855Z"}]}
@@ -50,3 +50,7 @@
50
50
  {"id":"s-931n","uuid":"2d8ea3d7-c317-4d2e-8bb7-bd47d4a2affe","title":"Runtime Configuration Manager","file_path":"specs/s-931n_runtime_configuration_manager.md","content":"\n# Runtime Configuration Manager\n\n## Overview\n\nAdd a `ConfigManager` service that holds runtime configuration in memory, exposes typed getters/setters, and notifies subscribers of changes via an EventEmitter pattern. API endpoints write to ConfigManager; subscribing services (TeamRuntime, RoleRegistry) react to changes and update their own behavior accordingly.\n\n## Design Principles\n\n- **API-first**: Config changes flow through API endpoints, not file edits\n- **Decoupled**: ConfigManager doesn't know about MessageRouter, AgentManager, etc. — subscribers own the wiring to their services\n- **Layered**: File-based config is the base layer; runtime changes are an overlay that takes precedence\n- **Optional persistence**: Some changes write back to files (roles), others are ephemeral (tuning knobs reset to file defaults on restart)\n\n## Configuration Tiers\n\n### Tier 1: Infrastructure (static, load-once)\n**NOT managed by ConfigManager.** Stays as-is in `loadMergedConfig()`.\n- `port`, `host`\n- `auth.disabled`, `auth.secret`\n- `task.backend`, `task.opentasks.socket_path`\n\n### Tier 2: Templates (runtime-writable, affects future spawns)\n- **Role definitions** — capabilities, workspace, lifecycle, tools, prompts\n- **Team role definitions** — team-specific role overrides\n\n### Tier 3: Tuning (runtime-writable, affects running system)\n- `communication.enforcement` — strict | permissive | audit\n- `macro_agent.task_assignment.pull.*` — idle_timeout_s, claim_retry_delay_ms, max_concurrent_per_agent\n- `macro_agent.lifecycle.scaling.*` — min_workers, max_workers, idle_drain\n- `macro_agent.observability.*` — metrics_window_s, snapshot_interval_s\n- `macro_agent.integration.config.*` — max_retries, conflict_action (strategy params, not strategy choice)\n\n## ConfigManager Interface\n\n```typescript\ninterface ConfigManager extends EventEmitter {\n // ─── Read ────────────────────────────────────────────────\n /** Get a config value by dot-path. Returns runtime override if set, else file-based default. */\n get<T>(path: string): T | undefined;\n\n /** Get full section (e.g., \"roles\", \"tuning.scaling\") */\n getSection<T>(section: string): T | undefined;\n\n /** Get effective config: file base merged with runtime overrides */\n getEffective(): RuntimeConfig;\n\n // ─── Write ───────────────────────────────────────────────\n /** Set a runtime override. Emits \"config:<section>\" event. */\n set(path: string, value: unknown): void;\n\n /** Merge a partial config into a section. Emits \"config:<section>\" event. */\n merge(section: string, partial: Record<string, unknown>): void;\n\n /** Remove a runtime override, reverting to file-based default. */\n unset(path: string): void;\n\n // ─── Persistence ─────────────────────────────────────────\n /** Persist current runtime overrides to file (for sections that support it) */\n persist(section?: string): Promise<void>;\n\n // ─── Lifecycle ───────────────────────────────────────────\n /** Initialize from file-based config */\n initialize(fileConfig: MultiagentConfig, teamManifest?: TeamManifest): void;\n}\n```\n\n## Config Sections & Events\n\n| Section | Event name | Subscriber | Action on change |\n|---------|-----------|------------|-----------------|\n| `roles.<name>` | `config:roles` | RoleRegistry | `registerRole()` with updated definition |\n| `enforcement` | `config:enforcement` | TeamRuntime | Re-install emission validator via `setEmissionValidator()` |\n| `tuning.scaling` | `config:tuning.scaling` | TeamRuntime | Update scaling params (affects future spawn decisions) |\n| `tuning.task_assignment` | `config:tuning.task_assignment` | TeamRuntime | Update spawn interceptor with new pull-mode params |\n| `tuning.observability` | `config:tuning.observability` | Metrics service | Update metrics window/snapshot interval |\n| `tuning.integration` | `config:tuning.integration` | IntegrationStrategy | Update strategy params (max_retries, conflict_action) |\n\n## RuntimeConfig Schema\n\n```typescript\ninterface RuntimeConfig {\n /** Role overrides (Tier 2) */\n roles: Record<string, Partial<RoleDefinition>>;\n\n /** Communication enforcement level (Tier 3) */\n enforcement?: \"strict\" | \"permissive\" | \"audit\";\n\n /** Tuning knobs (Tier 3) */\n tuning: {\n scaling?: {\n min_workers?: number;\n max_workers?: number;\n idle_drain?: boolean;\n };\n task_assignment?: {\n idle_timeout_s?: number;\n claim_retry_delay_ms?: number;\n max_concurrent_per_agent?: number;\n };\n observability?: {\n metrics_window_s?: number;\n snapshot_interval_s?: number;\n };\n integration?: {\n max_retries?: number;\n conflict_action?: string;\n [key: string]: unknown; // strategy-specific params\n };\n };\n}\n```\n\n## API Endpoints\n\n```\nGET /api/config → full effective config (file base + runtime overrides)\nGET /api/config/:section → single section (e.g., /api/config/enforcement)\nPUT /api/config/:section → replace a section\nPATCH /api/config/:section → merge into a section\nDELETE /api/config/:section/:key → unset a runtime override (revert to file default)\nPOST /api/config/persist → write runtime overrides to disk (optional, section filter)\n```\n\n### Example requests\n\n```\nPATCH /api/config/enforcement\n{ \"value\": \"permissive\" }\n\nPATCH /api/config/tuning/scaling\n{ \"max_workers\": 8, \"idle_drain\": true }\n\nPUT /api/config/roles/worker\n{ \"capabilities\": [\"file.read\", \"file.write\", \"git.commit\", \"exec.command\"] }\n\nDELETE /api/config/tuning/scaling/max_workers\n(reverts to team.yaml default)\n```\n\n## Subscriber Wiring\n\nSubscribers register during initialization, not inside ConfigManager:\n\n```typescript\n// In TeamRuntime.initialize():\nconfigManager.on(\"config:enforcement\", (value) => {\n const newValidator = this.createEmissionValidator(value);\n this.messageRouter.setEmissionValidator(newValidator);\n});\n\nconfigManager.on(\"config:tuning.task_assignment\", (value) => {\n // Rebuild spawn interceptor with updated pull-mode params\n this.agentManager.setSpawnInterceptor(this.createSpawnInterceptor());\n});\n\n// In RoleRegistry (or wherever roles are managed):\nconfigManager.on(\"config:roles\", (roles) => {\n for (const [name, definition] of Object.entries(roles)) {\n registry.registerRole({ name, ...definition });\n }\n});\n```\n\n## Cross-Process Visibility\n\nWhen ConfigManager applies a change, it optionally emits a `config_update` event to EventStore:\n\n```typescript\neventStore.emit({\n type: \"config_update\",\n source: { agent_id: \"system\" },\n payload: {\n section: \"enforcement\",\n value: \"permissive\",\n timestamp: Date.now()\n }\n});\n```\n\nMCP subprocesses that need to read current config can query EventStore for the latest `config_update` events. This is secondary to the in-memory path — not all config changes need cross-process visibility.\n\n## Persistence Strategy\n\n| Section | Persists to | On restart |\n|---------|------------|-----------|\n| `roles.*` | `.multiagent/roles.json` | Roles survive restart |\n| `enforcement` | Not persisted | Reverts to `team.yaml` default |\n| `tuning.*` | Not persisted | Reverts to `team.yaml` default |\n\nRationale: Role changes are definitional (you want them to stick). Tuning knobs are operational (the YAML file is the source of truth for defaults; runtime tweaks are temporary adjustments).\n\nUsers can explicitly call `POST /api/config/persist` to write tuning overrides to file if they want them to survive restarts.\n\n## Initialization Flow\n\n```\nServer startup:\n 1. loadMergedConfig() → infrastructure config (port, host, auth, task)\n 2. new ConfigManager()\n 3. configManager.initialize(mergedConfig, teamManifest)\n → loads file-based defaults for roles, team tuning\n → runtime overlay starts empty\n 4. TeamRuntime.initialize(configManager)\n → subscribes to config:enforcement, config:tuning.*\n 5. RoleRegistry loaded, subscribes to config:roles\n 6. API server started with configManager reference\n```\n\n## File Layout\n\n```\nsrc/config/\n├── project-config.ts # Existing: static config loader (unchanged)\n├── config-manager.ts # NEW: runtime config manager\n├── types.ts # NEW: RuntimeConfig, ConfigSection types\n└── index.ts # Updated: export ConfigManager\n```\n\n## Out of Scope\n\n- Changing topology at runtime (root, companions, spawn rules, channels, subscriptions)\n- Swapping integration strategy (queue → trunk)\n- Changing task backend (memory → opentasks)\n- Config validation schemas (can add later)\n- Config diffing / rollback\n- WebSocket config change notifications to clients (can add later)\n","priority":1,"archived":0,"archived_at":null,"created_at":"2026-02-18 23:35:39","updated_at":"2026-02-18 23:35:39","parent_id":null,"parent_uuid":null,"relationships":[],"tags":["api","config","runtime"]}
51
51
  {"id":"s-573k","uuid":"68b7357d-feaa-4200-abad-c689f9208ed9","title":"Recursive Teams: Composable Multi-Team Support","file_path":"specs/s-573k_recursive_teams_composable_multi_team_support.md","content":"## Overview\n\nEnable teams to be **composable and recursive** -- a team's topology can reference sub-teams, whose roots become children of the parent team's agents. This enables hierarchical multi-agent structures while keeping each team config self-contained and reusable.\n\n## Design Model\n\nTeams nest via the agent hierarchy. A sub-team's root agent is spawned as a **child** of a parent team agent. Each team is autonomous internally (own roles, communication, integration strategy). Cross-team communication flows through the hierarchy (parent-child subtree subscriptions) and optionally through shared topics.\n\n```\n[coordinator] team: project ← parent team's root\n├── [backend.lead] team: backend ← sub-team root (child of coordinator)\n│ ├── [worker] team: backend\n│ └── [reviewer] team: backend\n├── [frontend.lead] team: frontend ← sub-team root (child of coordinator)\n│ ├── [designer] team: frontend\n│ └── [implementer] team: frontend\n└── [qa-monitor] team: project ← parent team's companion\n```\n\n### Key Principles\n\n1. **Teams are self-contained**: A team.yaml doesn't know or care whether it's used standalone or as a sub-team\n2. **Nesting uses agent hierarchy**: Sub-team roots become children, not peers. Communication flows through parent-child relationships naturally\n3. **Each team governs itself**: Roles, communication channels, signal filters, emission validation, and integration strategy are scoped to each team's own agents\n4. **Cross-team communication**: Flows through hierarchy (subtree subscriptions) or shared topics bridged via the parent team\n\n## Config Schema\n\n### Sub-Team Reference (v1 - minimal)\n\nNew field `topology.teams` on team.yaml:\n\n```yaml\n# .multiagent/teams/project/team.yaml\nname: project\nroles: [coordinator, qa-monitor]\n\ntopology:\n root:\n role: coordinator\n companions:\n - role: qa-monitor\n teams: # NEW\n - name: backend # loads .multiagent/teams/backend/team.yaml\n - name: coding-team # can reuse same template twice\n as: frontend # instance name (becomes team_id)\n parent: root # which topology node owns this sub-team\n topics: [coordination] # parent-level topics sub-team root subscribes to\n\ncommunication:\n channels:\n - name: coordination\n signals: [status_update, blocking_issue, handoff]\n subscriptions:\n coordinator:\n - channel: coordination\n```\n\n### Sub-Team Reference Fields\n\n| Field | Required | Default | Description |\n|-------|----------|---------|-------------|\n| `name` | yes | — | Team template directory name under `.multiagent/teams/` |\n| `as` | no | same as `name` | Instance name. Becomes `team_id` for agents. Required when same template used twice. |\n| `parent` | no | `root` | Role name of the topology node that spawns this sub-team's root as its child |\n| `topics` | no | `[]` | Parent-level topic names the sub-team root auto-subscribes to |\n\n### Sub-team template (standalone, reusable)\n\n```yaml\n# .multiagent/teams/backend/team.yaml\nname: backend\nroles: [lead, worker, reviewer]\n\ntopology:\n root:\n role: lead\n companions:\n - role: worker\n - role: reviewer\n\ncommunication:\n channels:\n - name: work_coordination\n signals: [task_assigned, review_request, task_completed]\n subscriptions:\n lead:\n - channel: work_coordination\n worker:\n - channel: work_coordination\n reviewer:\n - channel: work_coordination\n```\n\nThis template works identically whether used standalone (`--team backend`) or as a sub-team of another team. When used as a sub-team, the only difference is its root agent gets a parent (instead of `parent: null`).\n\n### Recursion\n\nSub-teams can themselves reference sub-teams:\n\n```yaml\n# .multiagent/teams/backend/team.yaml\nname: backend\ntopology:\n root:\n role: lead\n companions:\n - role: reviewer\n teams:\n - name: api-team\n - name: database-team\n```\n\nThis composes arbitrarily deep.\n\n## Agent Records: `team_id`\n\nEvery agent gets a `team_id` field identifying which team it belongs to:\n\n- Set at spawn time (via spawn event payload)\n- Inherited from team context during bootstrap, or injected by spawn interceptor for dynamically spawned children\n- Persisted in EventStore agent materialized view\n- Used by TeamManager to dispatch callbacks to the correct TeamRuntime\n\n## TeamManager (Multiplexer)\n\nA flat registry of all active TeamRuntime instances (parent + all sub-teams). Installs single composite callbacks on global services:\n\n### Composite Spawn Interceptor\n1. Look up parent agent's `team_id` from EventStore\n2. If parent is in a team → delegate to that team's spawn interceptor\n3. Inject `team_id` into child spawn options (team membership inherits)\n4. For bootstrap spawns (`parent: null`), `team_id` is set explicitly\n\n### Composite Signal Filter\n1. Look up source and target agents' `team_id`\n2. Same team → delegate to that team's signal filter\n3. Cross-team → allow (the hierarchy handles visibility via subtree subscriptions)\n4. Unaffiliated → allow (no filtering for non-team agents)\n\n### Composite Emission Validator\n1. Look up emitting agent's `team_id`\n2. If in a team → delegate to that team's emission validator\n3. Unaffiliated → allow\n\n## Recursive Bootstrap Flow\n\n1. Parent team bootstraps normally (spawn root + companions)\n2. For each sub-team reference in `topology.teams`:\n a. Resolve the `parent` role → get parent agent ID from roleAgentMap\n b. Create child TeamRuntime from pre-loaded sub-team manifest\n c. Register child TeamRuntime with TeamManager\n d. Bootstrap child with `parentAgentId` set (root spawned as child, not peer)\n e. Subscribe sub-team root to bridged `topics`\n3. Sub-team may recursively bootstrap its own sub-teams (same process)\n\n## Role Namespacing\n\nWhen multiple teams define the same role name (e.g., both \"backend\" and \"frontend\" define \"lead\"):\n\n- **Internal to each team**: roles use short names (\"lead\", \"worker\")\n- **At parent level**: auto-prefixed with team instance name (\"backend.lead\", \"frontend.lead\")\n- **RoleRegistry**: team-scoped registration (`registerTeamRole(teamName, role)`)\n- **Resolution**: `resolveRole(\"lead\", teamName: \"backend\")` → backend's lead definition\n\n## Cross-Team Communication Patterns\n\n### Through Hierarchy (default)\nParent agent (coordinator) subscribes to sub-team root's subtree. Sees all events. Can relay messages between sub-teams.\n\n### Through Shared Topics (explicit)\nSub-team refs specify `topics: [coordination]`. Sub-team roots subscribe to parent-level topic channels. Enables direct pub/sub between sub-teams on parent-defined channels.\n\n### Direct Addressing (always available)\nAny agent can send to any other agent by ID. Team boundaries don't block direct messages -- they only scope signal filters and emission validators.\n\n## Backward Compatibility\n\n- No `topology.teams` → identical behavior to today\n- Existing team YAMLs → valid as-is, usable both standalone and as sub-team templates\n- Agents without `team_id` → unaffiliated, unchanged behavior\n- Single `--team` flag → TeamManager wraps the single team transparently\n","priority":1,"archived":0,"archived_at":null,"created_at":"2026-02-18 23:38:34","updated_at":"2026-02-18 23:38:34","parent_id":null,"parent_uuid":null,"relationships":[],"tags":["architecture","multi-team","recursive","teams"]}
52
52
  {"id":"s-8bbq","uuid":"b03dc85d-f7f9-4f1b-9933-1fa945bfc9c4","title":"Auto-Start OpenTasks Daemon with Central + Per-Project Connection Model","file_path":"specs/s-8bbq_auto_start_opentasks_daemon_with_central_per_proje.md","content":"## Context\n\nThe macro-agent server orchestrates agents across arbitrary working directories. Each project may have its own `.opentasks/` graph (git-tracked task/spec data). The macro-agent needs a unified task view for orchestration while preserving per-project task ownership.\n\nCurrently, the opentasks backend requires a **pre-running external daemon** — if the daemon isn't available, macro-agent falls back to an in-memory task backend. This spec defines how macro-agent auto-starts and manages opentasks daemons.\n\n## Key Design Constraint: Task Provider Lifecycle\n\n**Daemon spawning is part of the task provider lifecycle.** The `createTaskBackend()` factory owns daemon start/stop — callers (CLI entry points) don't need to manage daemon lifecycle separately. This keeps daemon management encapsulated within the task backend module.\n\n```\ncreateTaskBackend({ backend: { type: \"opentasks\" } })\n └── DaemonManager.ensureDaemon()\n ├── checkExistingDaemon(centralPath)\n │ ├── Running → connect to existing socket\n │ └── Not running → createDaemonWithStore() + start()\n └── Return { client, socketPath, ownsDaemon }\n\nTaskBackendResult.shutdown()\n └── DaemonManager.shutdown()\n ├── ownsDaemon=true → daemon.stop()\n └── ownsDaemon=false → client.disconnect() only\n```\n\n## Architecture: Central Daemon + Per-Project Connections\n\n```\n~/.multiagent/\n├── config.json # global config (layered config system)\n├── opentasks/ # central opentasks location\n│ ├── graph.jsonl # orchestration-level tasks\n│ ├── config.json # location identity + connections list\n│ ├── daemon.sock # IPC socket\n│ ├── daemon.lock # exclusive lock\n│ └── cache.db # SQLite query cache\n└── <instanceId>/ # EventStore data (per-instance)\n └── events.db\n\n/projects/frontend/.opentasks/ # pre-existing project opentasks\n├── graph.jsonl # project tasks (git-tracked)\n└── config.json # connected to central as child\n\n/projects/backend/.opentasks/ # another project\n├── graph.jsonl\n└── config.json\n```\n\n### Central Daemon\n\n- Lives at `~/.multiagent/opentasks/`\n- Auto-started by `createTaskBackend()` when opentasks backend is configured\n- Owns orchestration-level tasks (cross-project coordination)\n- Maintains connections to per-project `.opentasks/` locations\n- Provides federated queries across all connected locations\n- Stopped via `TaskBackendResult.shutdown()` (only if we started it)\n\n### Per-Project Connections\n\n- When an agent is spawned into a cwd that has `.opentasks/`, the central daemon auto-connects to it\n- Connect-only model: macro-agent does **not** auto-init `.opentasks/` in new directories\n- Connections are declared in the central daemon's `config.json` via the opentasks connections API\n- Cross-project task references use URI notation: `opentasks://<project-hash>/t-abc`\n\n## Implementation\n\n### New Module: `src/task/backend/opentasks/daemon-manager.ts`\n\nInternal to the opentasks backend module — not exposed as a standalone service.\n\n```typescript\ninterface DaemonManagerConfig {\n /** Central daemon location (default: ~/.multiagent/opentasks) */\n centralPath?: string;\n /** Whether to auto-connect project .opentasks/ on connectProject() */\n connectOnSpawn?: boolean;\n}\n\ninterface DaemonManagerResult {\n /** Connected OpenTasks client */\n client: OpenTasksClient;\n /** Daemon socket path */\n socketPath: string;\n /** Whether we started the daemon (vs connecting to existing) */\n ownsDaemon: boolean;\n}\n\ninterface DaemonManager {\n /** Start or connect to central daemon */\n ensureDaemon(): Promise<DaemonManagerResult>;\n /** Connect a project's .opentasks/ to the central daemon */\n connectProject(projectPath: string): Promise<void>;\n /** Check if a project is already connected */\n isProjectConnected(projectPath: string): boolean;\n /** Stop the daemon if we started it, disconnect client */\n shutdown(): Promise<void>;\n}\n```\n\n### Updated `TaskBackendResult`\n\n```typescript\ninterface TaskBackendResult {\n backend: TaskBackend;\n openTasksClient?: OpenTasksClient;\n /** Shutdown function — stops daemon if we started it */\n shutdown?: () => Promise<void>;\n}\n```\n\n### Updated `createTaskBackend()` Flow\n\nWhen `backendConfig.type === \"opentasks\"`:\n\n```\n1. Create DaemonManager with config\n2. Call daemonManager.ensureDaemon()\n ├── Determine centralPath: config.centralPath ?? ~/.multiagent/opentasks/\n ├── mkdir -p centralPath (ensure directory exists)\n ├── checkExistingDaemon(centralPath)\n │ ├── running=true → connect client to existing socketPath\n │ └── running=false →\n │ a. createDaemonWithStore({ locationPath: centralPath, version })\n │ b. await daemon.start()\n │ c. connect client to daemon.socketPath\n │ d. Set ownsDaemon=true\n └── Return { client, socketPath, ownsDaemon }\n3. Create OpenTasksTaskBackend with client\n4. Return { backend, openTasksClient, shutdown: () => daemonManager.shutdown() }\n```\n\n### Config Integration\n\nThe `.multiagent/config.json` (layered config system) controls behavior:\n\n```json\n{\n \"task\": {\n \"backend\": \"opentasks\",\n \"opentasks\": {\n \"auto_start\": true,\n \"central_path\": \"~/.multiagent/opentasks\",\n \"connect_on_spawn\": true\n }\n }\n}\n```\n\n| Config Key | Default | Description |\n| --- | --- | --- |\n| `task.opentasks.auto_start` | `true` | Auto-start central daemon in createTaskBackend() |\n| `task.opentasks.central_path` | `~/.multiagent/opentasks` | Central daemon location |\n| `task.opentasks.connect_on_spawn` | `true` | Auto-connect project .opentasks/ on agent spawn |\n\n### CLI Entry Point Changes\n\nMinimal — daemon lifecycle is encapsulated in the backend:\n\n```typescript\n// In acp.ts / index.ts:\nconst result = await createTaskBackend(taskConfig, eventStore);\ntaskBackend = result.backend;\n// ...\nconst cleanup = async () => {\n await result.shutdown?.(); // Stops daemon if we started it\n await eventStore.close();\n};\n```\n\n### Connect-on-Spawn (Phase 2)\n\nStill wired via `agent-manager.ts` but calls into the daemon manager:\n\n```typescript\n// agent-manager.ts\nagentManager.onLifecycleEvent((event) => {\n if (event.type === \"spawned\" && daemonManager) {\n daemonManager.connectProject(event.agent.cwd);\n }\n});\n```\n\n## opentasks Package APIs Used\n\n| Operation | API | Import Path |\n| --- | --- | --- |\n| Check existing daemon | `checkExistingDaemon(locationPath)` | `opentasks` (dynamic) |\n| Create daemon with store | `createDaemonWithStore({ locationPath, version })` | `opentasks` (dynamic) |\n| Start/stop daemon | `daemon.start()` / `daemon.stop()` | Daemon instance |\n| Connect client | `IPCOpenTasksClient({ socketPath })` | local client.ts |\n| Create connection | `createConnection(targetPath, role, basePath)` | `opentasks` (dynamic) |\n| Discover locations | `discoverLocations(startDir, { direction })` | `opentasks` (dynamic) |\n\nAll opentasks imports are dynamic (`await import(\"opentasks\")`) to avoid hard dependencies.\n\n## Edge Cases\n\n### Multiple macro-agent instances on same machine\n\n- `checkExistingDaemon()` detects pre-existing daemon at `~/.multiagent/opentasks/`\n- Second instance connects to existing daemon (shared central graph)\n- Only the instance that started the daemon stops it (tracked via `ownsDaemon` flag)\n\n### opentasks package not installed\n\n- Dynamic import fails → fall back to memory backend (existing behavior in CLI entry points)\n- Log warning: \"opentasks package not available, using memory backend\"\n\n### Daemon crashes mid-session\n\n- Client operations throw `CONNECTION_FAILED`\n- For v1: fall back to memory backend on daemon loss (existing try/catch in CLI entry points)\n- Future: reconnect logic in daemon manager\n\n### Agent spawned in subdirectory of project with .opentasks/\n\n- Walk up from agent cwd to find nearest `.opentasks/`\n- Use `discoverLocations(cwd, { direction: 'up' })` from opentasks API\n- Connect the discovered location, not the agent's exact cwd\n\n## Phases\n\n### Phase 1: Auto-start central daemon (within createTaskBackend)\n\n- Create `DaemonManager` module at `src/task/backend/opentasks/daemon-manager.ts`\n- Integrate into `createTaskBackend()` factory\n- Add `shutdown` to `TaskBackendResult`\n- Update CLI cleanup to call `result.shutdown?.()`\n- Fall back to memory on failure (existing behavior)\n\n### Phase 2: Connect-on-spawn\n\n- Hook into agent spawn lifecycle via agent-manager\n- Auto-discover and connect project `.opentasks/` directories\n- Surface connected projects in API/health endpoint\n\n### Phase 3: Federated queries\n\n- Ensure `query({ ready: {} })` works across connected locations\n- Surface project origin in task metadata\n- Cross-project edge creation via URI references\n\n## Non-Goals\n\n- Auto-initializing `.opentasks/` in new project directories (connect-only model)\n- Running separate daemons per project (single central daemon)\n- Migrating existing EventStore tasks to opentasks (dual persistence continues)\n- Replacing the memory backend fallback (always available as safety net)","priority":1,"archived":0,"archived_at":null,"created_at":"2026-02-18 23:58:49","updated_at":"2026-02-19 00:52:32","parent_id":null,"parent_uuid":null,"relationships":[],"tags":["architecture","config","daemon","opentasks"]}
53
+ {"id":"s-50b3","uuid":"39587db3-652d-4082-bf9b-384f6c869ed6","title":"openteams Migration: Shared Schema + Dependency Integration","file_path":"specs/s-50b3_openteams_migration_shared_schema_dependency_integ.md","content":"\n# openteams Migration: Shared Schema + Dependency Integration\n\nMigrate macro-agent's team template system to consume `openteams` as an external dependency for schema types, template loading, and validation — establishing openteams as the open standard for multi-agent team definitions.\n\n## Goals\n\n1. **openteams becomes the canonical schema** — All team manifest types, role definitions, topology, and communication types are defined in openteams and imported by macro-agent\n2. **Shared wire format** — YAML team.yaml files are interoperable between openteams standalone users and macro-agent\n3. **macro-agent keeps its runtime** — EventStore, MessageRouter, WorkspaceManager, integration strategies, capability enforcement all remain macro-agent's internal concern\n4. **No functionality regression** — All 71 team tests and 3,052 total tests continue passing\n\n## Non-Goals\n\n- Replacing macro-agent's EventStore with openteams' SQLite services (they serve different use cases)\n- Moving macro-agent's runtime enforcement into openteams (enforcement is consumer-specific)\n- Changing the YAML file format (both sides already share ~90% schema compatibility)\n\n## Design Decisions\n\n| ID | Decision | Rationale |\n|----|----------|-----------|\n| **DD1** | openteams defines generic schema types; macro-agent extends with typed `macro_agent` namespace | Clean separation: standard vs. extension |\n| **DD2** | openteams `ResolvedTemplate` is the loader output; macro-agent wraps it with enforcement-enriched state | Keeps manifest pure, resolved state is a separate concern |\n| **DD3** | Capability composition supports both syntaxes (openteams `{add,remove}` AND macro-agent `capabilities_add/remove`) | Backward compatibility for existing team.yaml files |\n| **DD4** | openteams loader accepts optional hooks for consumer-specific post-processing | Extensibility without coupling openteams to macro-agent internals |\n| **DD5** | macro-agent's `RoleDefinition` (with enforcement) stays internal — it maps FROM openteams' `ResolvedRole` | Enforcement is a runtime concern, not a schema concern |\n\n---\n\n## Part A: openteams Library Changes\n\n### A1: Capability Composition Syntax Alignment\n\n**File**: `references/openteams/src/template/loader.ts`, `types.ts`\n\nThe loader already supports `CapabilityComposition` (`{ add, remove }`) inside the `capabilities` field. Add support for the alternate flat syntax used in macro-agent:\n\n```yaml\n# Already supported (openteams style):\ncapabilities:\n add: [task.claim]\n remove: [agent.spawn.integrator]\n\n# Must also support (macro-agent style):\ncapabilities_add:\n - task.claim\ncapabilities_remove:\n - agent.spawn.integrator\n```\n\n**Changes**:\n- Add `capabilities_add?: string[]` and `capabilities_remove?: string[]` to `RoleDefinition` type\n- In `resolveRole()`, normalize: if `capabilities_add`/`capabilities_remove` present AND `capabilities` is not a `CapabilityComposition`, treat as composition\n- Validation: error if both `CapabilityComposition` and flat `capabilities_add/remove` are present simultaneously\n- Update JSON schema (`schema/role.schema.json`)\n\n### A2: RoleRegistry Integration Hook\n\n**File**: `references/openteams/src/template/loader.ts`\n\nCurrently `resolveInheritance()` only resolves against roles within the same template. macro-agent needs to resolve `extends` against an external registry of built-in roles (worker, coordinator, integrator, monitor).\n\n**Changes**:\n- Add optional `LoadOptions` parameter to `TemplateLoader.load()`:\n ```typescript\n interface LoadOptions {\n /** External role resolver for `extends` chains pointing outside the template */\n resolveExternalRole?: (name: string) => ResolvedRole | null;\n /** Post-processing hook called after role resolution */\n postProcessRole?: (role: ResolvedRole, manifest: TeamManifest) => ResolvedRole;\n /** Post-processing hook called after full template resolution */\n postProcess?: (template: ResolvedTemplate) => ResolvedTemplate;\n }\n ```\n- In `resolveInheritance()`: when a role's `extends` target is NOT in the local roles map, call `resolveExternalRole()` if provided — merge parent capabilities from external source\n- In `resolveRole()` post-resolution: call `postProcessRole()` if provided (macro-agent uses this for spawn_rules → capability translation)\n- After full resolution: call `postProcess()` if provided (macro-agent uses this for MCP server loading, enforcement mapping)\n\n### A3: MCP Server Config Support\n\n**File**: `references/openteams/src/template/loader.ts`, `types.ts`\n\nAdd support for loading `tools/mcp-servers.json` — per-role MCP server configurations.\n\n**Changes**:\n- Add `McpServerEntry` type to `types.ts`:\n ```typescript\n export interface McpServerEntry {\n name: string;\n command: string;\n args?: string[];\n env?: Record<string, string>;\n }\n ```\n- Add `mcpServers: Map<string, McpServerEntry[]>` to `ResolvedTemplate`\n- In `TemplateLoader.load()`: after role resolution, load `tools/mcp-servers.json` if it exists, parse as `Record<string, { servers: McpServerEntry[] }>`, populate the map\n- Update exports in `index.ts`\n\n### A4: Routing Status \"none\" Value\n\n**File**: `references/openteams/src/template/types.ts`\n\nAlready present in openteams (`\"upstream\" | \"none\"`). No changes needed on openteams side.\n\nmacro-agent's `CommunicationRouting.status` needs to adopt this (see Part B).\n\n### A5: Async Loader Variant\n\n**File**: `references/openteams/src/template/loader.ts`\n\nmacro-agent's `loadTeam()` is async. While the openteams loader is sync (fine for fs operations), the `LoadOptions` hooks may need to be async (e.g., external role resolution from a database).\n\n**Changes**:\n- Add `TemplateLoader.loadAsync(templateDir, options?)` that accepts async hooks:\n ```typescript\n interface AsyncLoadOptions extends LoadOptions {\n resolveExternalRole?: (name: string) => Promise<ResolvedRole | null> | ResolvedRole | null;\n postProcessRole?: (role: ResolvedRole, manifest: TeamManifest) => Promise<ResolvedRole> | ResolvedRole;\n postProcess?: (template: ResolvedTemplate) => Promise<ResolvedTemplate> | ResolvedTemplate;\n }\n ```\n- Keep sync `load()` for backward compatibility\n- `loadAsync()` internally calls sync file loading, then async hooks\n\n### A6: Export Alignment\n\n**File**: `references/openteams/src/index.ts`\n\nEnsure all types needed by macro-agent are exported:\n\n- `McpServerEntry` (new from A3)\n- `LoadOptions` / `AsyncLoadOptions` (new from A2/A5)\n- All existing template types already exported (verified)\n\n### A7: JSON Schema Updates\n\n**Files**: `references/openteams/schema/role.schema.json`, `references/openteams/schema/team.schema.json`\n\n- Add `capabilities_add` and `capabilities_remove` to role schema (A1)\n- Add `tools` directory convention documentation\n- Ensure `macro_agent` extension namespace is documented as a known extension\n\n---\n\n## Part B: macro-agent Migration Changes\n\n### B1: Add openteams Dependency\n\n**File**: `package.json`\n\n- Add `openteams` as a dependency (local path reference initially, npm package later):\n ```json\n \"dependencies\": {\n \"openteams\": \"file:references/openteams\"\n }\n ```\n- Run `npm install` to link\n\n### B2: Replace Team Types with openteams Imports\n\n**File**: `src/teams/types.ts`\n\nReplace the generic schema types with imports from openteams. Keep macro-agent-specific types local.\n\n**Types to import from openteams**:\n- `TeamManifest` → re-export as-is (or extend)\n- `TopologyConfig` (was `TeamTopology`)\n- `TopologyNode`\n- `TopologyNodeConfig`\n- `CommunicationConfig` (was `TeamCommunication`)\n- `ChannelDefinition`\n- `SubscriptionEntry` (was `ChannelSubscription`)\n- `RoutingConfig` (was `CommunicationRouting`)\n- `PeerRoute` (was `PeerConnection`)\n- `RoleDefinition` as `OpenTeamsRoleDefinition` (was `TeamRoleDefinition`)\n- `CapabilityComposition`\n- `ResolvedTemplate`\n- `ResolvedRole`\n- `ResolvedPrompts`, `PromptSection`\n- `McpServerEntry`\n\n**Types that stay in macro-agent** (internal enforcement layer):\n- `MacroAgentExtensions` (typed interpretation of `macro_agent` field)\n- `TaskAssignmentConfig`, `IntegrationConfig`, `LifecycleConfig`, `ObservabilityConfig`\n- `TeamRoleMacroAgent` (workspace/lifecycle enforcement config)\n- `ResolvedTeamRole` (enriched with macro-agent's `RoleDefinition`)\n- `TeamLoadError`, `TeamLoadErrorCode`\n\n**Naming alignment** — create type aliases for backward compatibility:\n```typescript\n// Re-exports with macro-agent's original names for gradual migration\nexport type TeamTopology = TopologyConfig;\nexport type TeamCommunication = CommunicationConfig;\nexport type ChannelSubscription = SubscriptionEntry;\nexport type CommunicationRouting = RoutingConfig;\nexport type PeerConnection = PeerRoute;\nexport type CommunicationEnforcement = \"strict\" | \"permissive\" | \"audit\";\nexport type TeamRoleDefinition = OpenTeamsRoleDefinition;\n```\n\n### B3: Adopt ResolvedTemplate Architecture\n\n**File**: `src/teams/types.ts`\n\nReplace the current `TeamManifest._resolvedRoles/_loadedPrompts/_mcpServers` pattern with a wrapper around openteams' `ResolvedTemplate`:\n\n```typescript\n/**\n * macro-agent's enriched team resolution result.\n * Wraps openteams' ResolvedTemplate with enforcement-enriched roles.\n */\nexport interface MacroResolvedTemplate {\n /** openteams resolved template (manifest + generic roles + prompts) */\n template: ResolvedTemplate;\n\n /** Enforcement-enriched roles mapped to macro-agent's RoleDefinition */\n resolvedRoles: Map<string, ResolvedTeamRole>;\n\n /** MCP server configs per role */\n mcpServers: Map<string, McpServerEntry[]>;\n\n /** Parsed macro-agent extensions (typed from manifest.macro_agent) */\n macroAgent: MacroAgentExtensions;\n}\n```\n\n### B4: Replace team-loader.ts with openteams TemplateLoader\n\n**File**: `src/teams/team-loader.ts`\n\nReplace the current 434-line `loadTeam()` with a thin wrapper around openteams' `TemplateLoader`:\n\n```typescript\nexport async function loadTeam(\n teamName: string,\n roleRegistry: RoleRegistry,\n basePath?: string\n): Promise<MacroResolvedTemplate> {\n const root = basePath ?? process.cwd();\n const teamDir = path.join(root, TEAMS_DIR, teamName);\n\n // 1. Load via openteams (validates manifest, resolves inheritance, loads prompts)\n const template = await TemplateLoader.loadAsync(teamDir, {\n // Hook: resolve extends against macro-agent's built-in role registry\n resolveExternalRole: (name) => mapRegistryRole(roleRegistry, name),\n // Hook: translate spawn_rules → capabilities, map macro_agent extensions\n postProcessRole: (role, manifest) => enrichRole(role, manifest, roleRegistry),\n });\n\n // 2. Build macro-agent enriched roles (with enforcement)\n const resolvedRoles = buildResolvedRoles(template, roleRegistry);\n\n // 3. Parse macro_agent extensions\n const macroAgent = parseMacroAgentExtensions(template.manifest.macro_agent);\n\n // 4. Validate communication\n validateCommunication(template.manifest.communication, template.manifest.roles, teamName);\n\n return {\n template,\n resolvedRoles,\n mcpServers: template.mcpServers,\n macroAgent,\n };\n}\n```\n\nKey helper functions:\n- `mapRegistryRole()`: Adapts macro-agent `RoleDefinition` → openteams `ResolvedRole`\n- `enrichRole()`: Adds spawn_rules capabilities, inherits enforcement from parent\n- `buildResolvedRoles()`: Maps openteams `ResolvedRole` + enforcement → `ResolvedTeamRole`\n- `parseMacroAgentExtensions()`: Types the opaque `Record<string, unknown>` → `MacroAgentExtensions`\n\n### B5: Adopt Multi-File Prompts\n\n**File**: `src/teams/team-runtime.ts` (spawn interceptor)\n\nCurrently the spawn interceptor reads a single prompt string from `_loadedPrompts`. Adopt openteams' `ResolvedPrompts` model:\n\n**Changes**:\n- In `createSpawnInterceptor()`: read `template.prompts.get(roleName)` which returns `ResolvedPrompts { primary, additional: PromptSection[] }`\n- Assemble the full prompt: primary content + additional sections (SOUL.md first, then others)\n- The spawn interceptor already appends interaction patterns after the role prompt — this stays the same\n- Update prompt assembly to concatenate: `primary + \"\\n\\n\" + additional.map(s => s.content).join(\"\\n\\n\")`\n\n### B6: Update team-runtime.ts to Consume MacroResolvedTemplate\n\n**File**: `src/teams/team-runtime.ts`\n\nUpdate `TeamRuntime` to accept `MacroResolvedTemplate` instead of the current `TeamManifest`:\n\n**Changes**:\n- Constructor: accept `MacroResolvedTemplate`\n- `initialize()`: access `result.template.manifest` for topology, `result.macroAgent` for extensions\n- `bootstrap()`: use `result.template.manifest.topology` for root/companions\n- `createSpawnInterceptor()`: use `result.template.prompts` for multi-file prompts, `result.mcpServers` for MCP configs\n- `installSignalFilter()`: use `result.template.manifest.communication`\n- `installEmissionValidator()`: use `result.template.manifest.communication`\n- Getters: `getManifest()` returns `result.template.manifest`, `getTaskMode()` uses `result.macroAgent`\n- Role registration: iterate `result.resolvedRoles` to register in RoleRegistry\n\n### B7: Update Routing Status Type\n\n**File**: `src/teams/types.ts`\n\nAdopt openteams' `\"upstream\" | \"none\"` for routing status (currently only `\"upstream\"`).\n\nThe `\"none\"` value disables automatic parent→child status propagation. Update the type alias and any runtime handling in `team-runtime.ts` that reads `communication.routing.status`.\n\n### B8: Update Imports Across Codebase\n\nFiles that import from `src/teams/types.ts`:\n- `src/teams/team-runtime.ts`\n- `src/teams/team-loader.ts`\n- `src/teams/index.ts`\n- `src/api/server.ts` (team endpoint)\n- `src/cli/index.ts` (team loading)\n- Test files: `src/teams/__tests__/*.ts`\n\nFor each: update to use the new type aliases (B2 ensures backward-compatible re-exports, so most imports won't break).\n\n### B9: Update Test Fixtures\n\n**Files**: `src/teams/__tests__/team-system.test.ts`, `src/teams/__tests__/cross-subsystem.integration.test.ts`\n\n- Update test manifests to use openteams' `TeamManifest` type (which is slightly different — `communication` is optional, `description` is optional)\n- Update any tests that directly construct `TeamManifest` objects with `_resolvedRoles` etc. to use `MacroResolvedTemplate`\n- Verify all 71 team tests pass\n- Add new tests for:\n - Multi-file prompt loading (ROLE.md + SOUL.md)\n - `capabilities_add`/`capabilities_remove` flat syntax\n - External role registry resolution via hooks\n - `routing.status: \"none\"` handling\n\n---\n\n## Migration Order\n\n### Phase 1: openteams changes (A1-A7)\nNo breaking changes to macro-agent. All changes are additive.\n\n1. A1 (capability syntax) — standalone, no deps\n2. A2 (registry hook) + A5 (async loader) — related, do together\n3. A3 (MCP servers) — standalone\n4. A6 (exports) — depends on A1-A3\n5. A7 (JSON schema) — depends on A1\n\n### Phase 2: macro-agent migration (B1-B9)\nDepends on Phase 1 completion.\n\n1. B1 (add dependency) — first\n2. B2 (type imports) + B7 (routing status) — type layer\n3. B3 (ResolvedTemplate arch) — new types\n4. B4 (replace loader) — core migration\n5. B5 (multi-file prompts) — depends on B4\n6. B6 (update runtime) — depends on B3, B4\n7. B8 (update imports) — depends on B2\n8. B9 (update tests) — last, validates everything\n\n---\n\n## Verification\n\n- All 71 existing team tests pass (no regression)\n- All 3,052 total tests pass\n- Existing team.yaml files load without modification\n- `self-driving` and `structured` templates work end-to-end\n- openteams' own test suite passes with new features\n- Type-check passes with no errors on both codebases\n","priority":1,"archived":0,"archived_at":null,"created_at":"2026-02-20 20:20:07","updated_at":"2026-02-20 20:20:07","parent_id":null,"parent_uuid":null,"relationships":[{"from":"s-50b3","from_type":"spec","to":"s-1z9o","to_type":"spec","type":"related"},{"from":"s-50b3","from_type":"spec","to":"s-8pqr","to_type":"spec","type":"depends-on"}],"tags":["migration","openteams","schema","teams"]}
54
+ {"id":"s-488j","uuid":"80f19236-7b19-4b63-9787-d91d84fa1878","title":"TeamManager: Dynamic Team Loading for multiagent Server","file_path":"specs/s-488j_teammanager_dynamic_team_loading_for_multiagent_se.md","content":"## Goal\n\nAdd dynamic team management to the primary `multiagent` server binary (`src/cli/acp.ts`), replacing the static team loading in the legacy `multiagent-cli start --team` path. Design with a path toward multiple concurrent team instances (Option A) while shipping single-team support first (Option B).\n\n## Design Decisions\n\n1. **Config-driven**: Teams loaded from `.multiagent/config.json` `\"team\"` field on server boot. No `--team` CLI flag.\n2. **API-driven**: REST endpoints for starting/stopping team instances at runtime.\n3. **Server mode only**: No team support in ACP stdio mode (`--acp`). That mode is being deprecated.\n4. **TeamManager module**: New `src/teams/team-manager.ts` owns team instance lifecycle and composite dispatch.\n5. **Composite interceptor**: TeamManager owns the spawn interceptor on AgentManager, dispatching to the correct team instance based on agent-team mapping.\n6. **Agent-to-team mapping**: Stored in EventStore agent records + cached in TeamManager memory.\n7. **REST API**: `POST/GET/DELETE /api/teams` endpoints on CombinedServer.\n8. **Deprecate legacy**: `multiagent-cli start --team` deprecated in favor of `multiagent` with config.\n\n## Architecture\n\n```\nmultiagent (acp.ts)\n ├── EventStore, MessageRouter, AgentManager (existing)\n ├── TeamManager (NEW)\n │ ├── holds Map<instanceId, TeamRuntime>\n │ ├── owns composite spawn interceptor\n │ ├── owns composite signal filter\n │ ├── owns composite emission validator\n │ ├── manages agent→team mapping\n │ └── auto-starts team from config on boot\n ├── CombinedServer (receives TeamManager reference)\n │ └── REST: POST/GET/DELETE /api/teams\n └── Cleanup: teamManager.teardownAll()\n```\n\n## TeamManager Interface\n\n```typescript\nclass TeamManager {\n constructor(services: TeamServices)\n \n // Lifecycle\n async startTeam(templateName: string, basePath?: string): Promise<TeamInstance>\n async stopTeam(instanceId: string): Promise<void>\n async teardownAll(): Promise<void>\n \n // Queries\n getTeam(instanceId: string): TeamInstance | undefined\n listTeams(): TeamInstance[]\n getTeamForAgent(agentId: string): TeamInstance | undefined\n \n // Called once after construction to install composite interceptor/filters\n install(): void\n}\n\ninterface TeamInstance {\n id: string // e.g. \"self-driving-1\"\n templateName: string // e.g. \"self-driving\"\n runtime: TeamRuntime\n rootAgentId?: string\n companionAgentIds: string[]\n}\n```\n\n## TeamRuntime Refactor\n\nTeamRuntime currently installs interceptor/filters directly on services during `initialize()` and `bootstrap()`. Refactor to **expose** them instead:\n\n- `initialize()` — still registers roles, emits team_config, creates strategy. **No longer** calls `setSpawnInterceptor`.\n- `bootstrap()` — still spawns agents, wires peer routes. **No longer** calls `setSignalFilter` or `setEmissionValidator`. Instead populates internal state that the exposed methods use.\n- New methods: `getSpawnInterceptor()`, `getSignalFilter()`, `getEmissionValidator()`\n- TeamManager composes these into composite functions and installs them on the shared services.\n\n## Agent-to-Team Mapping\n\n- **EventStore**: Add optional `team_instance` field to agent records. Set during spawn via interceptor.\n- **In-memory**: TeamManager maintains `Map<AgentId, string>` (agent → instance ID), populated from:\n - Bootstrap (root + companion agents)\n - Spawn interceptor (child agents inherit parent's team)\n - EventStore on restart (rehydrate from persisted agent records)\n\n## REST API Endpoints\n\n```\nPOST /api/teams { template: \"self-driving\" }\n → Loads template, creates TeamRuntime, initializes + bootstraps\n → Returns { id, templateName, rootAgentId, companionAgentIds }\n\nGET /api/teams\n → Returns list of running team instances\n\nGET /api/teams/:id\n → Returns instance details (manifest, agents, strategy, taskMode)\n\nDELETE /api/teams/:id\n → Calls teamManager.stopTeam(id), tears down agents\n → Returns { success: true }\n```\n\nFor Option B: `POST /api/teams` rejects if a team is already running (409 Conflict). This constraint is relaxed for Option A later.\n\n## Config Auto-Start\n\nOn server boot in `acp.ts`:\n```typescript\nconst mergedConfig = loadMergedConfig(defaultCwd);\nconst teamManager = new TeamManager({ agentManager, messageRouter, eventStore });\nteamManager.install(); // composite interceptor/filters\n\nif (mergedConfig.team) {\n await teamManager.startTeam(mergedConfig.team, defaultCwd);\n}\n```\n\n## WebSocket Real-Time\n\nAdd `teams` channel to `/api/ws` for team lifecycle events:\n```json\n{ \"type\": \"team_started\", \"instanceId\": \"sd-1\", \"template\": \"self-driving\" }\n{ \"type\": \"team_stopped\", \"instanceId\": \"sd-1\" }\n```\n\n## Deprecation\n\n- `multiagent-cli start --team` prints deprecation warning, still works\n- `GET /api/team` (singular) redirects to `GET /api/teams/:id` for the active instance\n","priority":1,"archived":0,"archived_at":null,"created_at":"2026-02-21 05:04:13","updated_at":"2026-02-21 05:04:13","parent_id":null,"parent_uuid":null,"relationships":[],"tags":["api","architecture","teams"]}
55
+ {"id":"s-9v71","uuid":"82eef9e0-806c-4d1d-b303-bc9e5201154b","title":"Option A: Multiple Concurrent Teams","file_path":"specs/s-9v71_option_a_multiple_concurrent_teams.md","content":"## Goal\n\nTransition TeamManager from Option B (single team per server) to Option A (multiple concurrent teams). The underlying architecture — composite dispatch, agent-to-team mapping, lifecycle listener, REST API — was designed with this path in mind and is already multi-team capable. This spec lifts the single-team constraint, scopes team_config events for correct MCP subprocess discovery, updates config for multi-team support, and enables cross-team messaging.\n\n## Design Decisions\n\n1. **Cross-team messaging allowed**: Agents from different teams can communicate via explicit addressing. Sender's emission rules and recipient's signal filter both apply.\n2. **Config**: Keep `team: string` for backward-compat default auto-start. Add `teams: Record&lt;string, TeamConfigEntry&gt;` for additional available/auto-start teams.\n3. **team_config scoping**: Each team emits its own team_config event with `team_instance` field. MCP subprocess discovery filters by `MACRO_TEAM_NAME` env var.\n4. **No role namespacing yet**: Role name conflicts between teams are warned but not blocked (deferred hardening).\n\n## What's Already Multi-Team Ready\n\n| Area | Status |\n|------|--------|\n| Composite dispatch (interceptor/filter/validator) | Ready — routes per agent-to-team mapping |\n| Agent-to-team mapping + lifecycle listener | Ready — correctly assigns children to parent's team |\n| REST API `/api/teams` endpoints | Ready — already list/get/delete by instance ID |\n| EventStore `team_instance` field | Ready — persists per-agent team membership |\n| TeamRuntime instance isolation | Ready — strategy, monitoring, peer routes are instance-local |\n\n## Changes Required\n\n### 1. Lift single-team constraint\nRemove the Option B guard in `TeamManager.startTeam()` that rejects when a team is already running.\n\n### 2. Scope team_config events\nAdd `team_instance` to the team_config event payload in `TeamRuntime.initialize()`. Update MCP subprocess discovery (`src/cli/mcp.ts`) to filter by `MACRO_TEAM_NAME` instead of using `.find()` for any team_config.\n\n### 3. Cross-team signal filter verification\nThe current composite signal filter already prioritizes the recipient's team filter for cross-team messages (`const team = recipientTeam ?? senderTeam`). Add test coverage for this behavior.\n\n### 4. Update config schema\n```typescript\nexport interface MultiagentConfig {\n /** Default team auto-started on boot (backward compat) */\n team?: string;\n /** Additional teams available for dynamic or auto-start loading */\n teams?: Record&lt;string, TeamConfigEntry&gt;;\n}\n\nexport interface TeamConfigEntry {\n /** Template name (defaults to the key) */\n template?: string;\n /** Auto-start on server boot (default: false) */\n autoStart?: boolean;\n}\n```\n\n### 5. Update acp.ts startup\nAfter starting the default `team`, iterate `teams` entries with `autoStart: true` and call `teamManager.startTeam()` for each.\n\n### 6. Clean up API 409 handling\nWith multiple teams allowed, the 409 \"already running\" error from `POST /api/teams` is no longer applicable. Remove the special-case 409 mapping.\n\n## Config Example\n\n```json\n{\n \"team\": \"self-driving\",\n \"teams\": {\n \"qa\": { \"autoStart\": false },\n \"monitoring\": { \"template\": \"observer-team\", \"autoStart\": true }\n }\n}\n```\n\nBoot sequence: starts \"self-driving\" (default) + \"monitoring\" (autoStart). \"qa\" available via `POST /api/teams { \"template\": \"qa\" }`.\n","priority":1,"archived":0,"archived_at":null,"created_at":"2026-02-21 07:46:34","updated_at":"2026-02-21 07:46:34","parent_id":null,"parent_uuid":null,"relationships":[],"tags":["architecture","option-a","teams"]}
56
+ {"id":"s-5lao","uuid":"a1d6854b-4303-435b-a2fa-4ca9b9f44c5e","title":"Close Team Capability Gaps","file_path":"specs/s-5lao_close_team_capability_gaps.md","content":"## Goal\n\nClose the gaps between team YAML config and actual runtime behavior. Four gaps identified during self-review after Option A implementation:\n\n1. **Task mode tool gating** — Pull-mode MCP tools register unconditionally (3-line fix)\n2. **Spawn rules defense-in-depth** — Add second enforcement layer in composite interceptor\n3. **Workspace isolation wiring** — Connect WorkspaceManager to server startup chain\n4. **Auto-scaling** — Implement `monitorScaling()` for task-queue-depth-based worker spawning\n\n## Design Decisions\n\n- Gap 1 gates claim tools by `taskMode === \"pull\"` at MCP registration time\n- Gap 2 adds spawn rules check in TeamManager composite interceptor (defense-in-depth, agent-manager already enforces via capabilities)\n- Gap 3 wires existing WorkspaceManager/Pool/MergeQueue through acp.ts → AgentManager → MCP server → done() handler\n- Gap 4 follows `monitorContinuations()` pattern: periodic timer checks queue depth vs active workers, spawns/drains accordingly","priority":1,"archived":0,"archived_at":null,"created_at":"2026-02-21 09:35:27","updated_at":"2026-02-21 09:35:27","parent_id":null,"parent_uuid":null,"relationships":[],"tags":["capabilities","gaps","teams"]}
package/CLAUDE.md CHANGED
@@ -159,6 +159,7 @@ src/
159
159
  │ ├── types.ts # TeamManifest, TeamTopology, TeamCommunication
160
160
  │ ├── team-loader.ts # YAML loading, role resolution, validation
161
161
  │ ├── team-runtime.ts # Initialize, bootstrap, peer routing, signal filtering
162
+ │ ├── team-manager.ts # Multi-team lifecycle, composite dispatch, agent-team mapping
162
163
  │ └── index.ts # Public exports
163
164
 
164
165
  └── workspace/ # Workspace isolation
@@ -180,11 +181,15 @@ src/
180
181
 
181
182
  ### Teams
182
183
 
183
- Teams are declarative YAML configurations that define multi-agent topologies:
184
+ Teams are declarative YAML configurations that define multi-agent topologies. Multiple teams can run concurrently on the same server.
185
+
184
186
  - **TeamLoader** (`team-loader.ts`): Parses `team.yaml`, resolves role inheritance, validates topology
185
- - **TeamRuntime** (`team-runtime.ts`): Wires team config into running services (roles, spawn interceptor, peer routing, signal filtering, emission validation, continuation monitoring)
187
+ - **TeamRuntime** (`team-runtime.ts`): Per-instance runtime registers roles, bootstraps root + companions, wires peer routing, signal filtering, emission validation, continuation monitoring
188
+ - **TeamManager** (`team-manager.ts`): Owns all team instances. Installs composite spawn interceptor, signal filter, and emission validator that route to the correct TeamRuntime per agent-to-team mapping
189
+ - **Agent membership**: Bootstrap agents (root + companions) are spawned as a unit. Dynamic children auto-join the parent's team. Standalone agents (no team parent) are unaffected
190
+ - **Cross-team messaging**: Allowed — sender's emission rules and recipient's signal filter both apply independently
186
191
  - Teams compose on top of existing primitives — no team loaded = identical behavior to pre-team codebase
187
- - Team config is shared across processes via EventStore `team_config` event
192
+ - Team config is shared across processes via scoped EventStore `team_config` events (filtered by `MACRO_TEAM_NAME`)
188
193
 
189
194
  ### Roles
190
195
 
@@ -323,6 +328,7 @@ npm run test:e2e # E2E tests (requires RUN_E2E_TESTS=true)
323
328
  | `OPENTASKS_SOCKET_PATH` | Path to OpenTasks socket | — |
324
329
  | `MACRO_WORKSPACE_POOL_SIZE` | Max concurrent workspaces | `10` |
325
330
  | `MACRO_MERGE_QUEUE_DB` | Merge queue SQLite path | `:memory:` |
331
+ | `MACRO_TEAMS` | Comma-separated team templates to auto-start on boot | — |
326
332
  | `MACRO_TEAM_NAME` | Team name (injected into agent env by team runtime) | — |
327
333
  | `MACRO_TASK_MODE` | Task mode: `push` or `pull` (injected by team runtime) | — |
328
334
  | `MACRO_INTEGRATION_STRATEGY` | Integration strategy name (injected by team runtime) | — |
@@ -1 +1 @@
1
- {"version":3,"file":"agent-manager.d.ts","sourceRoot":"","sources":["../../src/agent/agent-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-manager.d.ts","sourceRoot":"","sources":["../../src/agent/agent-manager.ts"],"names":[],"mappings":"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"}