@loompad/cli 0.1.0 → 1.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 (688) hide show
  1. package/ARCHITECTURE.md +96 -11
  2. package/CHANGELOG.md +1054 -0
  3. package/README.md +1473 -44
  4. package/THIRD_PARTY_NOTICES.md +275 -0
  5. package/dist/adapters/antigravity-cli.d.ts +62 -0
  6. package/dist/adapters/antigravity-cli.js +258 -0
  7. package/dist/adapters/antigravity-cli.js.map +1 -0
  8. package/dist/adapters/base.d.ts +61 -9
  9. package/dist/adapters/base.js +266 -15
  10. package/dist/adapters/base.js.map +1 -1
  11. package/dist/adapters/bridges/antigravity.d.ts +9 -12
  12. package/dist/adapters/bridges/antigravity.js +9 -12
  13. package/dist/adapters/bridges/antigravity.js.map +1 -1
  14. package/dist/adapters/echo.d.ts +1 -0
  15. package/dist/adapters/echo.js +59 -3
  16. package/dist/adapters/echo.js.map +1 -1
  17. package/dist/adapters/grok.d.ts +7 -0
  18. package/dist/adapters/grok.js +20 -10
  19. package/dist/adapters/grok.js.map +1 -1
  20. package/dist/adapters/index.d.ts +5 -1
  21. package/dist/adapters/index.js +53 -7
  22. package/dist/adapters/index.js.map +1 -1
  23. package/dist/adapters/model.d.ts +137 -0
  24. package/dist/adapters/model.js +527 -0
  25. package/dist/adapters/model.js.map +1 -0
  26. package/dist/adapters/opencode.d.ts +101 -1
  27. package/dist/adapters/opencode.js +874 -98
  28. package/dist/adapters/opencode.js.map +1 -1
  29. package/dist/cli/doctor.d.ts +32 -0
  30. package/dist/cli/doctor.js +89 -4
  31. package/dist/cli/doctor.js.map +1 -1
  32. package/dist/cli/index.js +2651 -87
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/cli/tui-model.js +3 -1
  35. package/dist/cli/tui-model.js.map +1 -1
  36. package/dist/cli/tui.js +44 -1
  37. package/dist/cli/tui.js.map +1 -1
  38. package/dist/cli/ui.d.ts +2 -0
  39. package/dist/cli/ui.js +13 -0
  40. package/dist/cli/ui.js.map +1 -1
  41. package/dist/core/ades.d.ts +32 -16
  42. package/dist/core/ades.js +57 -20
  43. package/dist/core/ades.js.map +1 -1
  44. package/dist/core/agent-state.d.ts +14 -0
  45. package/dist/core/agent-state.js +32 -0
  46. package/dist/core/agent-state.js.map +1 -0
  47. package/dist/core/approvals.d.ts +33 -0
  48. package/dist/core/approvals.js +29 -0
  49. package/dist/core/approvals.js.map +1 -0
  50. package/dist/core/backup.d.ts +19 -0
  51. package/dist/core/backup.js +86 -0
  52. package/dist/core/backup.js.map +1 -0
  53. package/dist/core/baton.d.ts +2 -2
  54. package/dist/core/baton.js.map +1 -1
  55. package/dist/core/brain-extract.d.ts +17 -0
  56. package/dist/core/brain-extract.js +28 -2
  57. package/dist/core/brain-extract.js.map +1 -1
  58. package/dist/core/brain-index.d.ts +71 -0
  59. package/dist/core/brain-index.js +204 -5
  60. package/dist/core/brain-index.js.map +1 -1
  61. package/dist/core/brain.d.ts +58 -2
  62. package/dist/core/brain.js +79 -1
  63. package/dist/core/brain.js.map +1 -1
  64. package/dist/core/chat-import.d.ts +71 -0
  65. package/dist/core/chat-import.js +419 -0
  66. package/dist/core/chat-import.js.map +1 -0
  67. package/dist/core/checkpoint.d.ts +107 -0
  68. package/dist/core/checkpoint.js +259 -0
  69. package/dist/core/checkpoint.js.map +1 -0
  70. package/dist/core/claude-cli.js +1 -1
  71. package/dist/core/claude-cli.js.map +1 -1
  72. package/dist/core/continuity/artifacts.d.ts +14 -0
  73. package/dist/core/continuity/artifacts.js +118 -0
  74. package/dist/core/continuity/artifacts.js.map +1 -0
  75. package/dist/core/continuity/capabilities.d.ts +65 -0
  76. package/dist/core/continuity/capabilities.js +129 -0
  77. package/dist/core/continuity/capabilities.js.map +1 -0
  78. package/dist/core/continuity/contracts.d.ts +352 -0
  79. package/dist/core/continuity/contracts.js +117 -0
  80. package/dist/core/continuity/contracts.js.map +1 -0
  81. package/dist/core/continuity/engine.d.ts +55 -0
  82. package/dist/core/continuity/engine.js +504 -0
  83. package/dist/core/continuity/engine.js.map +1 -0
  84. package/dist/core/continuity/store.d.ts +73 -0
  85. package/dist/core/continuity/store.js +438 -0
  86. package/dist/core/continuity/store.js.map +1 -0
  87. package/dist/core/conversations.d.ts +19 -0
  88. package/dist/core/conversations.js +87 -0
  89. package/dist/core/conversations.js.map +1 -0
  90. package/dist/core/crew-coordination.d.ts +6 -0
  91. package/dist/core/crew-coordination.js +24 -0
  92. package/dist/core/crew-coordination.js.map +1 -0
  93. package/dist/core/crew-policy.d.ts +18 -0
  94. package/dist/core/crew-policy.js +40 -0
  95. package/dist/core/crew-policy.js.map +1 -0
  96. package/dist/core/crew-protocol.d.ts +64 -0
  97. package/dist/core/crew-protocol.js +146 -0
  98. package/dist/core/crew-protocol.js.map +1 -0
  99. package/dist/core/crew-requests.d.ts +14 -0
  100. package/dist/core/crew-requests.js +22 -0
  101. package/dist/core/crew-requests.js.map +1 -0
  102. package/dist/core/crew.d.ts +395 -0
  103. package/dist/core/crew.js +1857 -0
  104. package/dist/core/crew.js.map +1 -0
  105. package/dist/core/digest.d.ts +40 -0
  106. package/dist/core/digest.js +94 -0
  107. package/dist/core/digest.js.map +1 -0
  108. package/dist/core/distill.js +3 -5
  109. package/dist/core/distill.js.map +1 -1
  110. package/dist/core/eventlog.d.ts +27 -25
  111. package/dist/core/eventlog.js +97 -150
  112. package/dist/core/eventlog.js.map +1 -1
  113. package/dist/core/events/contracts.d.ts +51 -0
  114. package/dist/core/events/contracts.js +2 -0
  115. package/dist/core/events/contracts.js.map +1 -0
  116. package/dist/core/events/jsonl-store.d.ts +23 -0
  117. package/dist/core/events/jsonl-store.js +90 -0
  118. package/dist/core/events/jsonl-store.js.map +1 -0
  119. package/dist/core/events/sqlite-store.d.ts +37 -0
  120. package/dist/core/events/sqlite-store.js +215 -0
  121. package/dist/core/events/sqlite-store.js.map +1 -0
  122. package/dist/core/forecast.d.ts +44 -0
  123. package/dist/core/forecast.js +46 -0
  124. package/dist/core/forecast.js.map +1 -0
  125. package/dist/core/free-pool.d.ts +65 -0
  126. package/dist/core/free-pool.js +171 -0
  127. package/dist/core/free-pool.js.map +1 -0
  128. package/dist/core/git.d.ts +30 -0
  129. package/dist/core/git.js +50 -2
  130. package/dist/core/git.js.map +1 -1
  131. package/dist/core/github-events.d.ts +53 -0
  132. package/dist/core/github-events.js +227 -0
  133. package/dist/core/github-events.js.map +1 -0
  134. package/dist/core/goal-lanes.d.ts +53 -0
  135. package/dist/core/goal-lanes.js +99 -0
  136. package/dist/core/goal-lanes.js.map +1 -0
  137. package/dist/core/hosted.d.ts +27 -0
  138. package/dist/core/hosted.js +50 -0
  139. package/dist/core/hosted.js.map +1 -0
  140. package/dist/core/http-server.d.ts +5 -0
  141. package/dist/core/http-server.js +8 -0
  142. package/dist/core/http-server.js.map +1 -0
  143. package/dist/core/invite-link.d.ts +31 -0
  144. package/dist/core/invite-link.js +45 -0
  145. package/dist/core/invite-link.js.map +1 -0
  146. package/dist/core/loops.d.ts +37 -0
  147. package/dist/core/loops.js +81 -0
  148. package/dist/core/loops.js.map +1 -0
  149. package/dist/core/mcp-catalog.d.ts +182 -0
  150. package/dist/core/mcp-catalog.js +431 -0
  151. package/dist/core/mcp-catalog.js.map +1 -0
  152. package/dist/core/mcp.d.ts +87 -0
  153. package/dist/core/mcp.js +181 -0
  154. package/dist/core/mcp.js.map +1 -0
  155. package/dist/core/memory.d.ts +1 -0
  156. package/dist/core/memory.js +5 -2
  157. package/dist/core/memory.js.map +1 -1
  158. package/dist/core/model-tools.d.ts +97 -0
  159. package/dist/core/model-tools.js +388 -0
  160. package/dist/core/model-tools.js.map +1 -0
  161. package/dist/core/notify.js +19 -1
  162. package/dist/core/notify.js.map +1 -1
  163. package/dist/core/orchestra.d.ts +635 -0
  164. package/dist/core/orchestra.js +2120 -0
  165. package/dist/core/orchestra.js.map +1 -0
  166. package/dist/core/permissions.d.ts +56 -0
  167. package/dist/core/permissions.js +122 -0
  168. package/dist/core/permissions.js.map +1 -0
  169. package/dist/core/preview-proxy.d.ts +70 -0
  170. package/dist/core/preview-proxy.js +563 -0
  171. package/dist/core/preview-proxy.js.map +1 -0
  172. package/dist/core/preview-shot.d.ts +46 -0
  173. package/dist/core/preview-shot.js +109 -0
  174. package/dist/core/preview-shot.js.map +1 -0
  175. package/dist/core/process.d.ts +36 -0
  176. package/dist/core/process.js +168 -0
  177. package/dist/core/process.js.map +1 -0
  178. package/dist/core/prompt-queue.d.ts +136 -0
  179. package/dist/core/prompt-queue.js +269 -0
  180. package/dist/core/prompt-queue.js.map +1 -0
  181. package/dist/core/prompts.d.ts +53 -0
  182. package/dist/core/prompts.js +127 -0
  183. package/dist/core/prompts.js.map +1 -0
  184. package/dist/core/proof.d.ts +82 -0
  185. package/dist/core/proof.js +216 -0
  186. package/dist/core/proof.js.map +1 -0
  187. package/dist/core/provider-text.d.ts +23 -0
  188. package/dist/core/provider-text.js +66 -0
  189. package/dist/core/provider-text.js.map +1 -0
  190. package/dist/core/providers.d.ts +152 -0
  191. package/dist/core/providers.js +343 -0
  192. package/dist/core/providers.js.map +1 -0
  193. package/dist/core/quota.d.ts +33 -0
  194. package/dist/core/quota.js +74 -0
  195. package/dist/core/quota.js.map +1 -0
  196. package/dist/core/recipes.d.ts +50 -0
  197. package/dist/core/recipes.js +99 -0
  198. package/dist/core/recipes.js.map +1 -0
  199. package/dist/core/registry.d.ts +54 -0
  200. package/dist/core/registry.js +62 -5
  201. package/dist/core/registry.js.map +1 -1
  202. package/dist/core/relay-client.d.ts +67 -0
  203. package/dist/core/relay-client.js +184 -0
  204. package/dist/core/relay-client.js.map +1 -0
  205. package/dist/core/relay-protocol.d.ts +140 -0
  206. package/dist/core/relay-protocol.js +189 -0
  207. package/dist/core/relay-protocol.js.map +1 -0
  208. package/dist/core/replay.d.ts +18 -0
  209. package/dist/core/replay.js +191 -0
  210. package/dist/core/replay.js.map +1 -0
  211. package/dist/core/review-triage.d.ts +41 -0
  212. package/dist/core/review-triage.js +124 -0
  213. package/dist/core/review-triage.js.map +1 -0
  214. package/dist/core/router.js +2 -2
  215. package/dist/core/router.js.map +1 -1
  216. package/dist/core/routes.d.ts +39 -3
  217. package/dist/core/routes.js +137 -4
  218. package/dist/core/routes.js.map +1 -1
  219. package/dist/core/run-command.d.ts +14 -0
  220. package/dist/core/run-command.js +45 -0
  221. package/dist/core/run-command.js.map +1 -0
  222. package/dist/core/runner-setup.d.ts +36 -0
  223. package/dist/core/runner-setup.js +114 -0
  224. package/dist/core/runner-setup.js.map +1 -0
  225. package/dist/core/search.js +0 -0
  226. package/dist/core/search.js.map +1 -1
  227. package/dist/core/semantic.d.ts +92 -0
  228. package/dist/core/semantic.js +227 -0
  229. package/dist/core/semantic.js.map +1 -0
  230. package/dist/core/servers.d.ts +115 -0
  231. package/dist/core/servers.js +305 -0
  232. package/dist/core/servers.js.map +1 -0
  233. package/dist/core/setup.js +64 -6
  234. package/dist/core/setup.js.map +1 -1
  235. package/dist/core/shield.d.ts +17 -0
  236. package/dist/core/shield.js +81 -0
  237. package/dist/core/shield.js.map +1 -0
  238. package/dist/core/shift.d.ts +69 -0
  239. package/dist/core/shift.js +120 -0
  240. package/dist/core/shift.js.map +1 -0
  241. package/dist/core/skill-install.d.ts +125 -0
  242. package/dist/core/skill-install.js +328 -0
  243. package/dist/core/skill-install.js.map +1 -0
  244. package/dist/core/skills.d.ts +116 -0
  245. package/dist/core/skills.js +223 -0
  246. package/dist/core/skills.js.map +1 -0
  247. package/dist/core/step-conditions.d.ts +65 -0
  248. package/dist/core/step-conditions.js +102 -0
  249. package/dist/core/step-conditions.js.map +1 -0
  250. package/dist/core/subagents.d.ts +45 -0
  251. package/dist/core/subagents.js +90 -0
  252. package/dist/core/subagents.js.map +1 -0
  253. package/dist/core/team-canon.d.ts +42 -0
  254. package/dist/core/team-canon.js +121 -0
  255. package/dist/core/team-canon.js.map +1 -0
  256. package/dist/core/team-crypto.d.ts +97 -0
  257. package/dist/core/team-crypto.js +175 -0
  258. package/dist/core/team-crypto.js.map +1 -0
  259. package/dist/core/team-hub.d.ts +514 -0
  260. package/dist/core/team-hub.js +964 -0
  261. package/dist/core/team-hub.js.map +1 -0
  262. package/dist/core/team-landing.d.ts +239 -0
  263. package/dist/core/team-landing.js +504 -0
  264. package/dist/core/team-landing.js.map +1 -0
  265. package/dist/core/team-leases.d.ts +44 -0
  266. package/dist/core/team-leases.js +145 -0
  267. package/dist/core/team-leases.js.map +1 -0
  268. package/dist/core/team-memory.d.ts +42 -0
  269. package/dist/core/team-memory.js +84 -0
  270. package/dist/core/team-memory.js.map +1 -0
  271. package/dist/core/team-policy.d.ts +85 -0
  272. package/dist/core/team-policy.js +191 -0
  273. package/dist/core/team-policy.js.map +1 -0
  274. package/dist/core/thread-md.d.ts +6 -0
  275. package/dist/core/thread-md.js +42 -0
  276. package/dist/core/thread-md.js.map +1 -0
  277. package/dist/core/turn-stats.d.ts +61 -0
  278. package/dist/core/turn-stats.js +124 -0
  279. package/dist/core/turn-stats.js.map +1 -0
  280. package/dist/core/updater.d.ts +73 -0
  281. package/dist/core/updater.js +153 -0
  282. package/dist/core/updater.js.map +1 -0
  283. package/dist/core/usage.d.ts +75 -0
  284. package/dist/core/usage.js +163 -0
  285. package/dist/core/usage.js.map +1 -0
  286. package/dist/core/windows-jobs.d.ts +15 -0
  287. package/dist/core/windows-jobs.js +170 -0
  288. package/dist/core/windows-jobs.js.map +1 -0
  289. package/dist/core/worktree-merge.d.ts +57 -0
  290. package/dist/core/worktree-merge.js +123 -0
  291. package/dist/core/worktree-merge.js.map +1 -0
  292. package/dist/core/worktree.d.ts +5 -0
  293. package/dist/core/worktree.js +45 -5
  294. package/dist/core/worktree.js.map +1 -1
  295. package/dist/core/worktrees.d.ts +6 -0
  296. package/dist/core/worktrees.js +21 -0
  297. package/dist/core/worktrees.js.map +1 -0
  298. package/dist/daemon/app-page.d.ts +0 -17
  299. package/dist/daemon/app-page.js +10 -6346
  300. package/dist/daemon/app-page.js.map +1 -1
  301. package/dist/daemon/auth.d.ts +24 -3
  302. package/dist/daemon/auth.js +66 -7
  303. package/dist/daemon/auth.js.map +1 -1
  304. package/dist/daemon/board.d.ts +7 -0
  305. package/dist/daemon/board.js +12 -1
  306. package/dist/daemon/board.js.map +1 -1
  307. package/dist/daemon/brand-icons.d.ts +6 -1
  308. package/dist/daemon/brand-icons.js +11 -3
  309. package/dist/daemon/brand-icons.js.map +1 -1
  310. package/dist/daemon/client.d.ts +665 -1
  311. package/dist/daemon/client.js +381 -3
  312. package/dist/daemon/client.js.map +1 -1
  313. package/dist/daemon/delivery.d.ts +34 -0
  314. package/dist/daemon/delivery.js +63 -0
  315. package/dist/daemon/delivery.js.map +1 -0
  316. package/dist/daemon/deploys.d.ts +62 -0
  317. package/dist/daemon/deploys.js +159 -0
  318. package/dist/daemon/deploys.js.map +1 -0
  319. package/dist/daemon/landing.d.ts +192 -0
  320. package/dist/daemon/landing.js +992 -0
  321. package/dist/daemon/landing.js.map +1 -0
  322. package/dist/daemon/onboard.d.ts +150 -0
  323. package/dist/daemon/onboard.js +390 -0
  324. package/dist/daemon/onboard.js.map +1 -0
  325. package/dist/daemon/proof.d.ts +70 -0
  326. package/dist/daemon/proof.js +172 -0
  327. package/dist/daemon/proof.js.map +1 -0
  328. package/dist/daemon/push.d.ts +19 -1
  329. package/dist/daemon/push.js +90 -3
  330. package/dist/daemon/push.js.map +1 -1
  331. package/dist/daemon/relay.d.ts +82 -0
  332. package/dist/daemon/relay.js +351 -0
  333. package/dist/daemon/relay.js.map +1 -0
  334. package/dist/daemon/routes/agent-discovery.d.ts +4 -0
  335. package/dist/daemon/routes/agent-discovery.js +29 -0
  336. package/dist/daemon/routes/agent-discovery.js.map +1 -0
  337. package/dist/daemon/routes/agent-settings.d.ts +4 -0
  338. package/dist/daemon/routes/agent-settings.js +94 -0
  339. package/dist/daemon/routes/agent-settings.js.map +1 -0
  340. package/dist/daemon/routes/agents.d.ts +4 -0
  341. package/dist/daemon/routes/agents.js +105 -0
  342. package/dist/daemon/routes/agents.js.map +1 -0
  343. package/dist/daemon/routes/alerts.d.ts +4 -0
  344. package/dist/daemon/routes/alerts.js +137 -0
  345. package/dist/daemon/routes/alerts.js.map +1 -0
  346. package/dist/daemon/routes/approvals.d.ts +4 -0
  347. package/dist/daemon/routes/approvals.js +40 -0
  348. package/dist/daemon/routes/approvals.js.map +1 -0
  349. package/dist/daemon/routes/assets.d.ts +3 -0
  350. package/dist/daemon/routes/assets.js +64 -0
  351. package/dist/daemon/routes/assets.js.map +1 -0
  352. package/dist/daemon/routes/board.d.ts +4 -0
  353. package/dist/daemon/routes/board.js +147 -0
  354. package/dist/daemon/routes/board.js.map +1 -0
  355. package/dist/daemon/routes/brain.d.ts +4 -0
  356. package/dist/daemon/routes/brain.js +270 -0
  357. package/dist/daemon/routes/brain.js.map +1 -0
  358. package/dist/daemon/routes/chats.d.ts +4 -0
  359. package/dist/daemon/routes/chats.js +249 -0
  360. package/dist/daemon/routes/chats.js.map +1 -0
  361. package/dist/daemon/routes/clients.d.ts +4 -0
  362. package/dist/daemon/routes/clients.js +49 -0
  363. package/dist/daemon/routes/clients.js.map +1 -0
  364. package/dist/daemon/routes/cloud.d.ts +4 -0
  365. package/dist/daemon/routes/cloud.js +46 -0
  366. package/dist/daemon/routes/cloud.js.map +1 -0
  367. package/dist/daemon/routes/config.d.ts +4 -0
  368. package/dist/daemon/routes/config.js +35 -0
  369. package/dist/daemon/routes/config.js.map +1 -0
  370. package/dist/daemon/routes/context.d.ts +51 -0
  371. package/dist/daemon/routes/context.js +2 -0
  372. package/dist/daemon/routes/context.js.map +1 -0
  373. package/dist/daemon/routes/crews.d.ts +4 -0
  374. package/dist/daemon/routes/crews.js +149 -0
  375. package/dist/daemon/routes/crews.js.map +1 -0
  376. package/dist/daemon/routes/files.d.ts +3 -0
  377. package/dist/daemon/routes/files.js +253 -0
  378. package/dist/daemon/routes/files.js.map +1 -0
  379. package/dist/daemon/routes/git.d.ts +4 -0
  380. package/dist/daemon/routes/git.js +96 -0
  381. package/dist/daemon/routes/git.js.map +1 -0
  382. package/dist/daemon/routes/history.d.ts +4 -0
  383. package/dist/daemon/routes/history.js +101 -0
  384. package/dist/daemon/routes/history.js.map +1 -0
  385. package/dist/daemon/routes/integrations-project.d.ts +3 -0
  386. package/dist/daemon/routes/integrations-project.js +103 -0
  387. package/dist/daemon/routes/integrations-project.js.map +1 -0
  388. package/dist/daemon/routes/integrations.d.ts +3 -0
  389. package/dist/daemon/routes/integrations.js +111 -0
  390. package/dist/daemon/routes/integrations.js.map +1 -0
  391. package/dist/daemon/routes/logs.d.ts +3 -0
  392. package/dist/daemon/routes/logs.js +40 -0
  393. package/dist/daemon/routes/logs.js.map +1 -0
  394. package/dist/daemon/routes/messages.d.ts +4 -0
  395. package/dist/daemon/routes/messages.js +60 -0
  396. package/dist/daemon/routes/messages.js.map +1 -0
  397. package/dist/daemon/routes/observability.d.ts +4 -0
  398. package/dist/daemon/routes/observability.js +247 -0
  399. package/dist/daemon/routes/observability.js.map +1 -0
  400. package/dist/daemon/routes/onboard.d.ts +12 -0
  401. package/dist/daemon/routes/onboard.js +67 -0
  402. package/dist/daemon/routes/onboard.js.map +1 -0
  403. package/dist/daemon/routes/orchestra.d.ts +4 -0
  404. package/dist/daemon/routes/orchestra.js +110 -0
  405. package/dist/daemon/routes/orchestra.js.map +1 -0
  406. package/dist/daemon/routes/pairing.d.ts +4 -0
  407. package/dist/daemon/routes/pairing.js +155 -0
  408. package/dist/daemon/routes/pairing.js.map +1 -0
  409. package/dist/daemon/routes/preview.d.ts +24 -0
  410. package/dist/daemon/routes/preview.js +122 -0
  411. package/dist/daemon/routes/preview.js.map +1 -0
  412. package/dist/daemon/routes/project-actions.d.ts +4 -0
  413. package/dist/daemon/routes/project-actions.js +53 -0
  414. package/dist/daemon/routes/project-actions.js.map +1 -0
  415. package/dist/daemon/routes/project-team.d.ts +4 -0
  416. package/dist/daemon/routes/project-team.js +201 -0
  417. package/dist/daemon/routes/project-team.js.map +1 -0
  418. package/dist/daemon/routes/projects.d.ts +14 -0
  419. package/dist/daemon/routes/projects.js +138 -0
  420. package/dist/daemon/routes/projects.js.map +1 -0
  421. package/dist/daemon/routes/prompts.d.ts +4 -0
  422. package/dist/daemon/routes/prompts.js +44 -0
  423. package/dist/daemon/routes/prompts.js.map +1 -0
  424. package/dist/daemon/routes/proof.d.ts +4 -0
  425. package/dist/daemon/routes/proof.js +22 -0
  426. package/dist/daemon/routes/proof.js.map +1 -0
  427. package/dist/daemon/routes/providers.d.ts +3 -0
  428. package/dist/daemon/routes/providers.js +60 -0
  429. package/dist/daemon/routes/providers.js.map +1 -0
  430. package/dist/daemon/routes/public.d.ts +4 -0
  431. package/dist/daemon/routes/public.js +64 -0
  432. package/dist/daemon/routes/public.js.map +1 -0
  433. package/dist/daemon/routes/queue.d.ts +4 -0
  434. package/dist/daemon/routes/queue.js +140 -0
  435. package/dist/daemon/routes/queue.js.map +1 -0
  436. package/dist/daemon/routes/routing.d.ts +4 -0
  437. package/dist/daemon/routes/routing.js +61 -0
  438. package/dist/daemon/routes/routing.js.map +1 -0
  439. package/dist/daemon/routes/runtime-handler.d.ts +2 -0
  440. package/dist/daemon/routes/runtime-handler.js +63 -0
  441. package/dist/daemon/routes/runtime-handler.js.map +1 -0
  442. package/dist/daemon/routes/search.d.ts +4 -0
  443. package/dist/daemon/routes/search.js +17 -0
  444. package/dist/daemon/routes/search.js.map +1 -0
  445. package/dist/daemon/routes/servers.d.ts +4 -0
  446. package/dist/daemon/routes/servers.js +133 -0
  447. package/dist/daemon/routes/servers.js.map +1 -0
  448. package/dist/daemon/routes/setup.d.ts +3 -0
  449. package/dist/daemon/routes/setup.js +50 -0
  450. package/dist/daemon/routes/setup.js.map +1 -0
  451. package/dist/daemon/routes/shift.d.ts +4 -0
  452. package/dist/daemon/routes/shift.js +30 -0
  453. package/dist/daemon/routes/shift.js.map +1 -0
  454. package/dist/daemon/routes/specs.d.ts +4 -0
  455. package/dist/daemon/routes/specs.js +57 -0
  456. package/dist/daemon/routes/specs.js.map +1 -0
  457. package/dist/daemon/routes/task-delivery.d.ts +4 -0
  458. package/dist/daemon/routes/task-delivery.js +38 -0
  459. package/dist/daemon/routes/task-delivery.js.map +1 -0
  460. package/dist/daemon/routes/team.d.ts +4 -0
  461. package/dist/daemon/routes/team.js +193 -0
  462. package/dist/daemon/routes/team.js.map +1 -0
  463. package/dist/daemon/routes/terminals.d.ts +4 -0
  464. package/dist/daemon/routes/terminals.js +87 -0
  465. package/dist/daemon/routes/terminals.js.map +1 -0
  466. package/dist/daemon/routes/tools.d.ts +4 -0
  467. package/dist/daemon/routes/tools.js +180 -0
  468. package/dist/daemon/routes/tools.js.map +1 -0
  469. package/dist/daemon/routes/updates.d.ts +4 -0
  470. package/dist/daemon/routes/updates.js +89 -0
  471. package/dist/daemon/routes/updates.js.map +1 -0
  472. package/dist/daemon/routes/voice.d.ts +4 -0
  473. package/dist/daemon/routes/voice.js +53 -0
  474. package/dist/daemon/routes/voice.js.map +1 -0
  475. package/dist/daemon/runner.d.ts +186 -0
  476. package/dist/daemon/runner.js +612 -0
  477. package/dist/daemon/runner.js.map +1 -0
  478. package/dist/daemon/runtime/accounting.d.ts +130 -0
  479. package/dist/daemon/runtime/accounting.js +303 -0
  480. package/dist/daemon/runtime/accounting.js.map +1 -0
  481. package/dist/daemon/runtime/agents.d.ts +16 -0
  482. package/dist/daemon/runtime/agents.js +71 -0
  483. package/dist/daemon/runtime/agents.js.map +1 -0
  484. package/dist/daemon/runtime/briefings.d.ts +134 -0
  485. package/dist/daemon/runtime/briefings.js +329 -0
  486. package/dist/daemon/runtime/briefings.js.map +1 -0
  487. package/dist/daemon/runtime/native-usage.d.ts +21 -0
  488. package/dist/daemon/runtime/native-usage.js +71 -0
  489. package/dist/daemon/runtime/native-usage.js.map +1 -0
  490. package/dist/daemon/runtime/queue.d.ts +94 -0
  491. package/dist/daemon/runtime/queue.js +222 -0
  492. package/dist/daemon/runtime/queue.js.map +1 -0
  493. package/dist/daemon/runtime/relay.d.ts +93 -0
  494. package/dist/daemon/runtime/relay.js +240 -0
  495. package/dist/daemon/runtime/relay.js.map +1 -0
  496. package/dist/daemon/runtime/turns.d.ts +202 -0
  497. package/dist/daemon/runtime/turns.js +663 -0
  498. package/dist/daemon/runtime/turns.js.map +1 -0
  499. package/dist/daemon/runtime-support.d.ts +76 -0
  500. package/dist/daemon/runtime-support.js +134 -0
  501. package/dist/daemon/runtime-support.js.map +1 -0
  502. package/dist/daemon/runtime.d.ts +739 -70
  503. package/dist/daemon/runtime.js +2751 -470
  504. package/dist/daemon/runtime.js.map +1 -1
  505. package/dist/daemon/server.d.ts +82 -55
  506. package/dist/daemon/server.js +674 -1435
  507. package/dist/daemon/server.js.map +1 -1
  508. package/dist/daemon/shift.d.ts +70 -0
  509. package/dist/daemon/shift.js +170 -0
  510. package/dist/daemon/shift.js.map +1 -0
  511. package/dist/daemon/specs.d.ts +92 -0
  512. package/dist/daemon/specs.js +285 -0
  513. package/dist/daemon/specs.js.map +1 -0
  514. package/dist/daemon/system.d.ts +208 -0
  515. package/dist/daemon/system.js +557 -0
  516. package/dist/daemon/system.js.map +1 -0
  517. package/dist/daemon/tasks.js +1 -1
  518. package/dist/daemon/team-brain.d.ts +136 -0
  519. package/dist/daemon/team-brain.js +659 -0
  520. package/dist/daemon/team-brain.js.map +1 -0
  521. package/dist/daemon/team-coordinator.d.ts +78 -0
  522. package/dist/daemon/team-coordinator.js +408 -0
  523. package/dist/daemon/team-coordinator.js.map +1 -0
  524. package/dist/daemon/team.d.ts +339 -0
  525. package/dist/daemon/team.js +1433 -0
  526. package/dist/daemon/team.js.map +1 -0
  527. package/dist/daemon/terminals.d.ts +22 -3
  528. package/dist/daemon/terminals.js +236 -16
  529. package/dist/daemon/terminals.js.map +1 -1
  530. package/dist/hub/client.d.ts +120 -0
  531. package/dist/hub/client.js +228 -0
  532. package/dist/hub/client.js.map +1 -0
  533. package/dist/hub/server.d.ts +32 -0
  534. package/dist/hub/server.js +180 -0
  535. package/dist/hub/server.js.map +1 -0
  536. package/dist/hub/supabase-client.d.ts +220 -0
  537. package/dist/hub/supabase-client.js +843 -0
  538. package/dist/hub/supabase-client.js.map +1 -0
  539. package/dist/observability/ask.d.ts +91 -0
  540. package/dist/observability/ask.js +179 -0
  541. package/dist/observability/ask.js.map +1 -0
  542. package/dist/observability/clickhouse.d.ts +33 -0
  543. package/dist/observability/clickhouse.js +48 -0
  544. package/dist/observability/clickhouse.js.map +1 -0
  545. package/dist/observability/decisions.d.ts +176 -0
  546. package/dist/observability/decisions.js +377 -0
  547. package/dist/observability/decisions.js.map +1 -0
  548. package/dist/observability/index.d.ts +89 -0
  549. package/dist/observability/index.js +348 -0
  550. package/dist/observability/index.js.map +1 -0
  551. package/dist/observability/insights.d.ts +151 -0
  552. package/dist/observability/insights.js +319 -0
  553. package/dist/observability/insights.js.map +1 -0
  554. package/dist/observability/logs-query.d.ts +82 -0
  555. package/dist/observability/logs-query.js +102 -0
  556. package/dist/observability/logs-query.js.map +1 -0
  557. package/dist/observability/logs.d.ts +72 -0
  558. package/dist/observability/logs.js +295 -0
  559. package/dist/observability/logs.js.map +1 -0
  560. package/dist/observability/metrics.d.ts +86 -0
  561. package/dist/observability/metrics.js +303 -0
  562. package/dist/observability/metrics.js.map +1 -0
  563. package/dist/observability/otlp.d.ts +127 -0
  564. package/dist/observability/otlp.js +242 -0
  565. package/dist/observability/otlp.js.map +1 -0
  566. package/dist/observability/snapshots.d.ts +43 -0
  567. package/dist/observability/snapshots.js +129 -0
  568. package/dist/observability/snapshots.js.map +1 -0
  569. package/dist/observability/triage.d.ts +49 -0
  570. package/dist/observability/triage.js +284 -0
  571. package/dist/observability/triage.js.map +1 -0
  572. package/dist/providers/adapter.d.ts +50 -0
  573. package/dist/providers/adapter.js +38 -0
  574. package/dist/providers/adapter.js.map +1 -0
  575. package/dist/providers/agent.d.ts +110 -0
  576. package/dist/providers/agent.js +487 -0
  577. package/dist/providers/agent.js.map +1 -0
  578. package/dist/providers/approvals.d.ts +24 -0
  579. package/dist/providers/approvals.js +78 -0
  580. package/dist/providers/approvals.js.map +1 -0
  581. package/dist/providers/attachments.d.ts +20 -0
  582. package/dist/providers/attachments.js +51 -0
  583. package/dist/providers/attachments.js.map +1 -0
  584. package/dist/providers/claude/adapter.d.ts +99 -0
  585. package/dist/providers/claude/adapter.js +790 -0
  586. package/dist/providers/claude/adapter.js.map +1 -0
  587. package/dist/providers/codex/adapter.d.ts +113 -0
  588. package/dist/providers/codex/adapter.js +881 -0
  589. package/dist/providers/codex/adapter.js.map +1 -0
  590. package/dist/providers/codex/instructions.d.ts +11 -0
  591. package/dist/providers/codex/instructions.js +154 -0
  592. package/dist/providers/codex/instructions.js.map +1 -0
  593. package/dist/providers/codex/rpc.d.ts +36 -0
  594. package/dist/providers/codex/rpc.js +104 -0
  595. package/dist/providers/codex/rpc.js.map +1 -0
  596. package/dist/providers/contracts.d.ts +339 -0
  597. package/dist/providers/contracts.js +19 -0
  598. package/dist/providers/contracts.js.map +1 -0
  599. package/dist/providers/directory.d.ts +70 -0
  600. package/dist/providers/directory.js +95 -0
  601. package/dist/providers/directory.js.map +1 -0
  602. package/dist/providers/errors.d.ts +47 -0
  603. package/dist/providers/errors.js +24 -0
  604. package/dist/providers/errors.js.map +1 -0
  605. package/dist/providers/index.d.ts +18 -0
  606. package/dist/providers/index.js +19 -0
  607. package/dist/providers/index.js.map +1 -0
  608. package/dist/providers/ingestion.d.ts +80 -0
  609. package/dist/providers/ingestion.js +330 -0
  610. package/dist/providers/ingestion.js.map +1 -0
  611. package/dist/providers/live.d.ts +22 -0
  612. package/dist/providers/live.js +56 -0
  613. package/dist/providers/live.js.map +1 -0
  614. package/dist/providers/process.d.ts +29 -0
  615. package/dist/providers/process.js +71 -0
  616. package/dist/providers/process.js.map +1 -0
  617. package/dist/providers/reaper.d.ts +33 -0
  618. package/dist/providers/reaper.js +65 -0
  619. package/dist/providers/reaper.js.map +1 -0
  620. package/dist/providers/service.d.ts +87 -0
  621. package/dist/providers/service.js +256 -0
  622. package/dist/providers/service.js.map +1 -0
  623. package/dist/sdk.d.ts +1 -1
  624. package/dist/sdk.js +1 -1
  625. package/dist/sdk.js.map +1 -1
  626. package/dist/types.d.ts +385 -6
  627. package/dist/types.js +1 -0
  628. package/dist/types.js.map +1 -1
  629. package/dist/version.d.ts +7 -0
  630. package/dist/version.js +16 -0
  631. package/dist/version.js.map +1 -0
  632. package/dist/web/app.css +4646 -0
  633. package/dist/web/app.js +22640 -0
  634. package/dist/web/app.js.map +7 -0
  635. package/dist/web/shell.html +39 -0
  636. package/docs/README.md +21 -0
  637. package/docs/SETUP.md +10 -0
  638. package/docs/adapters.md +21 -8
  639. package/docs/brain-continuity.md +186 -0
  640. package/docs/cloud.md +108 -0
  641. package/docs/crews.md +62 -0
  642. package/docs/design-system.md +31 -2
  643. package/docs/integration-notes.md +128 -20
  644. package/docs/loompad.md +105 -0
  645. package/docs/observability.md +220 -0
  646. package/docs/play-store.md +123 -0
  647. package/docs/proposals/agent-teams.md +249 -0
  648. package/docs/proposals/brain-continuity-implementation.md +468 -0
  649. package/docs/proposals/brain-session-continuity.md +623 -0
  650. package/docs/proposals/t3code-port.md +81 -0
  651. package/docs/proposals/t3code-reference.md +95 -0
  652. package/docs/refactoring/AGENT-TEAMS-PROGRESS.md +88 -0
  653. package/docs/refactoring/BOUNDARIES.md +120 -0
  654. package/docs/refactoring/BRAIN-AUDIT.md +176 -0
  655. package/docs/refactoring/BRAIN-NOTES.md +390 -0
  656. package/docs/refactoring/BRAIN-TODO.md +214 -0
  657. package/docs/refactoring/NOTES.md +129 -0
  658. package/docs/refactoring/T3-PORT-NOTES.md +165 -0
  659. package/docs/refactoring/T3-PORT-TODO.md +123 -0
  660. package/docs/refactoring/TODO.md +46 -0
  661. package/docs/refactoring/brain-benchmark-2026-09-28.json +48 -0
  662. package/docs/refactoring/brain-benchmark-audit-2026-09-28.json +48 -0
  663. package/docs/release-notes/v0.2.0.md +35 -0
  664. package/docs/release-notes/v0.2.1.md +59 -0
  665. package/docs/release-notes/v0.2.3.md +77 -0
  666. package/docs/release-notes/v0.2.4.md +128 -0
  667. package/docs/release-notes/v0.2.5.md +153 -0
  668. package/docs/release-notes/v0.2.6.md +62 -0
  669. package/docs/release-notes/v1.0.0.md +120 -0
  670. package/docs/release-notes/v1.0.1.md +77 -0
  671. package/docs/release-notes/v1.1.0.md +71 -0
  672. package/docs/release-notes/v1.1.1.md +38 -0
  673. package/docs/release-notes/v1.1.2.md +21 -0
  674. package/docs/teams-architecture.md +697 -0
  675. package/docs/teams.md +171 -0
  676. package/docs/windows.md +85 -0
  677. package/package.json +22 -9
  678. package/dist/adapters/claude-code.d.ts +0 -26
  679. package/dist/adapters/claude-code.js +0 -209
  680. package/dist/adapters/claude-code.js.map +0 -1
  681. package/dist/adapters/codex.d.ts +0 -51
  682. package/dist/adapters/codex.js +0 -291
  683. package/dist/adapters/codex.js.map +0 -1
  684. package/docs/img/board-linear.png +0 -0
  685. package/docs/img/board-projects.png +0 -0
  686. package/docs/img/brain.png +0 -0
  687. package/docs/img/settings.png +0 -0
  688. package/docs/img/workspace.png +0 -0
@@ -0,0 +1,697 @@
1
+ # Loom Teams — architecture for many people, many agents, one repo
2
+
3
+ > Status: **design, researched and decided 2026-09-18.** The decision record in
4
+ > [§1a](#1a-decision-record) was settled in a design interview with the owner, and it
5
+ > overrides anything below that disagrees with it. Nothing here is built yet except
6
+ > where a section says "exists today". It is the plan for taking Loom from one developer's
7
+ > fleet to a team of 2–10 people, each running their own agents against the same
8
+ > GitHub repository. Sources for every claim about other tools are in
9
+ > [§12](#12-sources).
10
+
11
+ ## 0. The problem in one paragraph
12
+
13
+ Put five people on one repo, each with an orchestrator and four workers, and you
14
+ have ~25 agents writing code at once. The failures that follow are well-documented,
15
+ not hypothetical:
16
+
17
+ - **Reviewers drown first.** Code generation outruns review. DORA 2025 ties more AI
18
+ adoption to higher throughput *and* higher instability.
19
+ - **AI-authored PRs carry more defects.** One study of 470 PRs found ~1.7× more
20
+ issues than human PRs.
21
+ - **Parallel agents collide.** When two concurrent agent PRs from *different* agent
22
+ vendors touch the same files, they conflict **41.7%** of the time. The rate for
23
+ the same vendor is 19.8% (33,596 agent PRs, 2,807 repos). A Loom team is exactly
24
+ that mixed-vendor case.
25
+ - Beyond that: duplicated work nobody noticed, semantic conflicts that merge cleanly
26
+ and break main, flaky CI multiplied through merge queues, secrets leaking through
27
+ prompt-injected PR text, and shared memory that drifts or gets poisoned.
28
+
29
+ **Worktrees give agents isolated checkouts. They do nothing about who should work
30
+ on what.** Loom Teams is the answer to that second question.
31
+
32
+ ## 1. Principles
33
+
34
+ 1. **Code stays on members' machines; GitHub stays the source of truth for code.**
35
+ Loom never hosts repositories. It coordinates *intent* (who is doing what, and
36
+ where), and it moves *memory*.
37
+ 2. **Memory is the product.** Every agent on the team should start its turn knowing
38
+ what the team has decided, what failed, what's in flight, and what a teammate's
39
+ agent learned an hour ago. Getting this right, with provenance and without
40
+ poisoning, is the core of the design.
41
+ 3. **One reviewable unit per goal.** Worker branches never become PRs. A goal
42
+ produces one PR, or a short stack. Agents never approve or merge.
43
+ 4. **Coordinate before you collide.** Leases are taken at planning time, and
44
+ conflicts are detected while the work is still in progress, not at merge time.
45
+ 5. **Test the merged result, not the branch.** A merge queue is not optional at team
46
+ scale.
47
+ 6. **Least privilege and a signed audit trail.** Every action is traceable to a
48
+ member, an agent, a goal and a task.
49
+ 7. **Private by default.** Content (code, prompts, memory) is end-to-end encrypted
50
+ to the team. The coordination plane sees only what it must.
51
+
52
+ ## 1a. Decision record
53
+
54
+ These were settled one at a time, root first, in the order the design tree depends
55
+ on them. Later sections implement them.
56
+
57
+ | # | Decision | Chosen | Why it matters downstream |
58
+ |---|---|---|---|
59
+ | **Foundations** |||
60
+ | D1 | Who runs the Team Hub | **Hosted by Loom *and* self-hostable from day one** | One schema, migrations and Edge Functions deploy to any Supabase. `LOOM_TEAM_HUB_URL` picks the hub. |
61
+ | D2 | Privacy from the hub operator | **Content E2E, metadata plain** | Prompts, memory text, plans, goal/task titles and snippets are team-key encrypted. Member, agent, state, branch and **file paths/globs are plaintext**, so the hub arbitrates leases itself. |
62
+ | D3 | What a team is | **People; projects are GitHub repos** | Invite-based membership. One team spans many repos. A person can be in several teams. |
63
+ | D4 | Identity | **GitHub required, Google optional** | Every member maps to a GitHub login, for commit trailers, CODEOWNERS and reviewer routing. |
64
+ | **Keys, joining, scope** |||
65
+ | D5 | How a new member gets the team key | **The key rides the invite link's `#fragment`** | Same pattern as phone pairing. Invites are one-time and expire in 24h. |
66
+ | D6 | Offboarding | **Rotate forward** | The new key is sealed to each remaining **device key** (Ed25519/X25519). Invites cover joining; device keys cover rotation. History stays under the old key. |
67
+ | D7 | GitHub App for self-hosters | **One-click manifest App; `gh` polling fallback** | Hosted teams use Loom's App. Self-hosted teams generate their own, pointed at their hub. With no App, daemons poll with the member's `gh`. |
68
+ | D8 | Which projects are shared | **Opt-in per project** | Explicit "Share with team", or auto when the git remote matches a repo the team connected. Nothing else leaves the machine. |
69
+ | **Coordination** |||
70
+ | D9 | Where "touches" come from | **Declared by the orchestrator, corrected by reality** | `touches` globs are required in team mode. Leases widen on any edit outside them: live for Claude and Codex (they emit `file_edit`), at task end for Grok and Antigravity. |
71
+ | D10 | Lease strength | **Advisory, plus hard zones** | `loom.team.json` `hardZones` (e.g. `db/migrations/**`) refuse a second claim. Everything else is planning context. |
72
+ | D11 | Where WIP code is shared | **Hidden refs on GitHub** | `refs/loom/wip/<member>/<run>` hold WIP; `git merge-tree` predicts conflicts; the refs are deleted when the goal lands. |
73
+ | D12 | Lease lifetime | **Heartbeat TTL (~10 min) + reclaim on wake** | A sleeping laptop's leases go stale. On wake, the goal reclaims and gets a report of what moved. |
74
+ | **Memory** |||
75
+ | D13 | What auto-shares | **Durable kinds above the confidence floor** | Constraint, decision, convention, fact and failure memories at ≥0.6 become *proposed*. Task memories stay personal. Any memory can be marked private. |
76
+ | D14 | Who promotes to canon | **Anyone proposes; the PR decides** | Promotion opens a PR on the canon section. The repo's review rules (CODEOWNERS on AGENTS.md) gate it, so there's no separate ACL. |
77
+ | D15 | Where canon lives | **A managed section in `AGENTS.md`** | Between `<!-- loom:canon -->` markers. `CLAUDE.md` gets `@AGENTS.md`. One source of truth. |
78
+ | D16 | Aging | **Failures and facts decay (~90d) unless re-confirmed; rules persist** | A resolved contradiction marks the loser *superseded*, never deleted. |
79
+ | **Landing** |||
80
+ | D17 | Reviewable unit | **One PR per goal; auto-stack when big** | Over ~400 changed lines or 3 independent task clusters → a stack of 2–4 PRs cut along the plan graph. |
81
+ | D18 | Review | **A cross-vendor agent review is a required status check, *plus* a human CODEOWNER approval** | The reviewer agent is from a different vendor than the authors. It blocks on high-severity findings and comments on the rest. It never clicks Approve. |
82
+ | D19 | Who runs CI auto-fix | **The owner's machine; teammates can Adopt** | At most 2 attempts. After 15+ min with the owner offline, the goal shows "needs someone" and any member can Adopt it onto their daemon. |
83
+ | D20 | Testing the merged result | **GitHub merge queue if the repo has it; otherwise a Loom landing lease** | The fallback serializes landing through a hub lease on `main`: rebase on fresh main, fast tests, merge. It's the same lease machinery. |
84
+ | **Business and UX** |||
85
+ | D21 | Pricing (hosted) | **Per seat, free up to 3 members** | The hub counts members and nothing else. Model costs stay on each member's own agent subscriptions; Loom never resells tokens. |
86
+ | D22 | Who sees whose spend | **Owners see everything; members see team totals + their own** | No leaderboard of colleagues. |
87
+ | D23 | Policy enforcement | **Enforced for team-shared projects** | The daemon refuses a mode looser than `loom.team.json` allows and says why. Members can go stricter. Side projects are untouched. |
88
+ | D24 | Visibility into teammates' work | **Intent, not transcripts** | Goal and task titles, agents, file globs, state and PR/CI status (decrypted client-side). Prompts and agent output only when a thread is explicitly shared. |
89
+ | D25 | Phone alerts | **Only what needs you** | A review requested from you; your CI failed after auto-fix; a predicted conflict with your goal; an approval your agent needs; an adopt request. Everything else goes to the feed and a daily digest. |
90
+ | D26 | Where teammates show up | **A Team section in Fleet, plus a lease map** | Desktop and phone. The same data feeds orchestrators' planning context. |
91
+ | **Phase 2: stop colliding** (settled 2026-09-19) |||
92
+ | D28 | When leases overlap | **Expand globs to real files, then compare sets** | Each daemon sends the globs, the concrete files (`git ls-files` matches, capped) and literal directory prefixes (for files not yet created). Overlap is a shared file or a prefix containment. |
93
+ | D29 | What an orchestrator must do on overlap | **Declare how it handles it** | Loom won't spawn an overlapping task until the task carries `overlap: "wait:<goal>" \| "narrow" \| "proceed:<reason>"`. The refusal returns to its planning turn with the holder and their intent. The choice is posted to the feed. |
94
+ | D30 | When a `wait:` task starts | **When the other goal's PR merges to main** | Seen through the feed (`pr_merged` on `loom/orchestra/<run>/main`). The waiting goal's integration branch is then rebased onto fresh main before the task starts. |
95
+ | D31 | A claimed hard zone | **Queue the task; it starts on its own when the zone is released** | The goal's other tasks keep running. The feed and the holder are told someone is waiting. |
96
+ | D32 | A waited-on goal that never merges | **Unblock when it ends without a PR, or on "Stop waiting"** | It unblocks when that goal is aborted or failed, or 24h after it finishes with no PR, or when the waiting goal's owner clicks "Stop waiting". Every unblock is logged with its reason. |
97
+ | D33 | Drift outside declared touches | **Extend the lease and flag it; stop only in hard zones** | The lease widens, and the holder of the area plus the feed are told. Drift into someone else's hard zone interrupts the task until the zone frees up. |
98
+ | D34 | A predicted conflict | **Tell both owners and both orchestrators** | A feed item plus a phone alert to both owners with the files. Orchestrators see it at their next review. Nothing replans mid-task on its own. |
99
+ | D35 | Cadence | **On every task merge, plus every 5 min** | Push `refs/loom/wip/<member>/<run>` and run `git merge-tree --write-tree --name-only` against teammates' refs. Verified: GitHub accepts these refs and they trigger no CI. |
100
+ | D36 | When a lease is released | **When the goal's PR merges** (or the goal is abandoned) | After a task finishes, its leases are held as *landing*. D12's staleness still applies while the owner's laptop sleeps. |
101
+ | D37 | Where policy comes from | **`loom.team.json` on the default branch at origin** | Read with `git show origin/HEAD:loom.team.json`, so policy changes need a reviewed PR. A local copy can only make rules stricter. |
102
+ | D38 | What policy enforces in Phase 2 | **Hard zones, a permission ceiling (+ `bypassRequiresPlan`), an agent allowlist, protected-branch delivery, concurrency caps** | Caps: `maxParallelPerMember`, and `teamMaxConcurrentAgents` counted from hub presence. |
103
+ | D39 | A policy change mid-run | **Applies to new actions only** | Running tasks finish under the old rules; spawns, mode changes and deliveries use the new ones. Violations are noted in the feed. |
104
+ | **Phase 3: one brain** (settled 2026-09-19) |||
105
+ | D40 | Who changes a teammate's memory | **The author edits; others supersede** | Only the author's daemon updates or forgets its own memories. A teammate records a correction linked to the original, and both stay visible until a human resolves it. |
106
+ | D41 | Duplicates | **Exact matches merge and count; near-duplicates are flagged** | An identical memory from another member becomes "confirmed by N" (the hub matches an HMAC of the normalized text, so it never reads the text). A near-paraphrase goes to the inbox for a one-click merge. |
107
+ | D42 | Trust in briefings | **Canon > confirmed > own > a teammate's proposal** | Each briefed memory is labelled with its tier ("team canon" / "confirmed by 3" / "proposed by bob"). |
108
+ | D43 | Untrusted memories | **Learned while reading external content** | A turn that read web pages, issue or PR text, or fetched docs tags its memories untrusted. They stay personal until a human marks them trusted. |
109
+ | D44 | Canon's source of truth | **The managed `AGENTS.md` section on main** | Lines carry hidden `<!-- loom:m:<id> -->` markers so they round-trip. Hand edits in any PR are real canon changes. Native-memory import skips the section (no feedback loop). |
110
+ | D45 | How promotion reaches the repo | **One rolling canon PR per repo** | Branch `loom/canon`. Later promotions, from anyone, append to the open PR until it merges through the normal review rules. |
111
+ | D46 | Claude Code outside Loom | **Add `@AGENTS.md` to CLAUDE.md in the canon PR** | Only if CLAUDE.md exists and lacks it. A one-time change, reviewed in the PR. |
112
+ | D47 | Resolving a contradiction | **The loser is superseded, kept with a link** | It leaves briefings but stays in history, with who resolved it and why. A canon loser is removed in the canon PR. |
113
+ | D48 | Live team context in briefings | **Nearby leases, PRs and failures, capped at ~1.5k chars** | Covers the files a task touches: teammates' overlapping or adjacent leases, open PRs that changed those paths, recent failed checks on them, and predicted conflicts. |
114
+ | D49 | Where people review | **A Team view in the Brain tab, plus the phone** | Tiers (Canon · Confirmed · Proposed · Mine · Untrusted) plus an Inbox: contradictions, likely duplicates, untrusted. Actions: Promote, Supersede, Merge, Mark trusted, Make private. |
115
+ | D50 | Backfill for a new member or device | **All live memories as a snapshot, then the stream** | Superseded and forgotten memories load only when someone opens history. |
116
+ | D51 | Scope | **Per repo, never across** | Side projects never enter a team brain, and a team brain never leaks into unrelated projects. |
117
+ | **Phase 4: land safely** (settled 2026-09-19) |||
118
+ | D52 | How CI results reach the owner | **The owner's daemon polls its own goal PRs** | Every 30s, `gh pr checks --required` on open goal PRs. No GitHub App needed; the existing feed poll still tells teammates. |
119
+ | D53 | A failing check | **Rerun once, then fix** | `gh run rerun --failed` first; a pass on rerun is labelled flaky, never "fixed" by an agent. A second failure sends the `--log-failed` tail (~200 lines, fenced as untrusted) to the orchestrator, which reopens the goal and routes a fix to the worker owning the files. |
120
+ | D54 | Which checks count | **Required checks only** | Branch-protection-required checks; every failing check when the repo requires none. Optional ones only reach the feed. |
121
+ | D55 | Fix budget | **2 attempts per goal, shared with review findings** | Then the goal waits on a human and the owner's phone is alerted (D25). |
122
+ | D56 | Landing | **The owner clicks Land** | Pushrebase-lite (merge fresh main into the goal branch, fast tests, push), then `gh pr merge --auto --squash`: the queue or GitHub merges when approvals and checks pass. A human triggers it; GitHub enforces the rules. |
123
+ | D57 | Fast tests | **`landing.fastTest` in loom.team.json, else skipped** | With `timeoutMin`. No guessing at commands; CI stays the source of truth. |
124
+ | D58 | A conflict with fresh main | **One agent attempt, then a human** | A merge task for the worker owning the conflicted files; always a human in a hard zone. |
125
+ | D59 | Stacks | **Opt-in: `delivery.stack: "auto"`** | Cut along the integration branch's merge commits in landing order (D17's thresholds), each PR based on the one below; stacks land with the merge method and the next PR is retargeted. |
126
+ | D60 | Who runs the review agent | **The owner's daemon** | A different vendor than the goal's authors, on the diff and PLAN.md, read-only. Posts a COMMENT review (never Approve) and a `loom/review` commit status. |
127
+ | D61 | Review cadence and blocking | **On open and after each fix push, at most 3 per goal** | Only high findings (bug, security, data loss) fail `loom/review`; they go to the orchestrator like a failed check. The owner can override with a logged reason. |
128
+ | D62 | Repo setup | **`loom team doctor` reports and offers a fix PR** | Checks rules (merge queue, required checks, `loom/review`) and `merge_group` triggers; the PR adds `merge_group:`. It never changes repo settings. |
129
+ | D63 | Adopt | **A takeover run on the adopter's machine, handed back when green** | "Make PR #n green" pushes to the same branch; `goal_adopted` / `goal_returned` on the feed make the owner's daemon back off. Offered after the owner is offline 15+ min and the goal needs someone. |
130
+ | D64 | Budgets | **Per-goal cap and per-member daily cap, plus rollups** | `budgets: {perGoalUsd, perMemberDailyUsd}`. A goal over its cap pauses for a human; a member over the daily cap can't start goals. Rollups per member/day, per goal and per landed PR (abandoned goals count), from feed costs. |
131
+ | D65 | Hosted hub sign-in | **GitHub OAuth through Supabase, loopback redirect** | `loom team signin` with no URL uses the hosted hub (its URL and publishable key ship in the build); a URL still means a self-hosted hub. |
132
+ | D66 | Deploys and release notes | **Deferred to Phase 5** | GitHub Environments stay the deploy gate. |
133
+ | **Phase 5: runners** (settled 2026-09-19) |||
134
+ | D67 | Where cloud sandboxes run | **`loom runner`, hosted by the team** | A headless Loom daemon in runner mode on any always-on machine (VPS, home server, Railway, Fly, Docker). Code never touches Loom's servers; it reuses the daemon, orchestra and landing. |
135
+ | D68 | Whose credentials and goals | **Personal first, shared opt-in** | A runner is one member's: their agent logins and keys, their goals (and goals they adopt). A runner marked shared (allowed by `runners.shared` in loom.team.json) takes any member's goals, billed to its owner, visible in the feed. |
136
+ | D69 | How goals reach a runner | **Explicit, plus automatic CI fixes** | "Start on runner" and "Continue on runner" (desktop and phone). A goal needing a CI fix while its owner has been offline 15+ min is taken by the owner's runner, like an Adopt (D63). Goals travel as pushed branches plus a sealed run record, never local-only state. |
137
+ | D70 | The trust tier | **A container per goal, minimal secrets** | Docker when available, else a fresh clone and a scrubbed environment per goal. Agents may bypass inside, capped by `runners.permissions`. It holds only agent logins and a fine-grained GitHub token; no production secrets; destroyed after the goal. |
138
+ | D71 | Job transport | **A hub job table with claim leases** | Runners register (owner, installed kinds, shared). Jobs (start / continue / fix / return) carry sealed payloads; a runner claims one atomically and heartbeats it; silence for 10 min makes it claimable again (D12). |
139
+ | D72 | Deploys and release notes | **Both, read-only** | Deployment statuses from `gh api` go to the feed (`deploy_started/succeeded/failed`), and a failed deploy containing your merged goal alerts your phone. `loom team release-notes --since <tag>` writes notes from merged goals. GitHub Environments stay the gate; Loom never deploys. |
140
+ | D73 | The phone and runners | **Start, continue, watch** | Start a goal on your runner, move a running goal there, and watch runner goals through the hub. Tapping an alert opens its project and goal. |
141
+ | D74 | Runner identity | **Paired like a device** | `loom runner pair` prints a one-time link carrying the team keys; `loom runner join <link>` signs in as the member (loopback or paste-the-URL OAuth on a headless box) and registers a device marked runner. Revoking it removes the device and rotates the team key (D6). |
142
+ | D75 | Moving a running goal | **Pause at a safe point** | Stop new work, let running turns finish (interrupt after 2 min), commit, push the integration and task branches to `refs/loom/run/<id>/*`. The runner rebuilds the run and its orchestrator carries on; the local run becomes "moved", read-only. |
143
+ | D76 | After the owner is back | **The runner finishes the goal** | No ping-pong. "Bring back" moves it home the same way, when the owner chooses. |
144
+ | D77 | The runner's GitHub access | **A fine-grained token, checked** | `loom runner join` takes a fine-grained PAT or uses `gh auth`; `loom runner doctor` warns when it can do more than contents and pull requests on the shared repos. Stored 0600 on the runner, never sent through the hub. |
145
+ | D78 | Packaging | **A Docker image and an installer** | `Dockerfile.runner` and `loom runner install` (a systemd or launchd unit). Nothing is deployed to anyone's cloud account by Loom. |
146
+ | **Phase 6: land in turn, hear it now** (settled 2026-09-20) |||
147
+ | D79 | The landing slot (D20's missing half) | **A hub lease per lane on `.loom/landing/<lane>`, that path its own hard zone** | Every hub (MemoryHub, `loom hub`, the SQL) refuses a second claimer atomically through D31's machinery, with no new hub API. Claimed under the run id `<run>:land`, so releasing the slot never drops the goal's task leases (D36). Stale after 10 minutes like any lease (D12). One zone per lane: a shared `.loom/landing/**` zone would make every lane one lane. |
148
+ | D80 | When Land takes the train | **The base branch has no merge queue, on a team repo** | Read from `gh api repos/{r}/rules/branches/{base}` (cached 10 min per repo). A merge queue keeps Phase 4's path (`gh pr merge --auto`). No team hub, or a stack (D59), keeps auto-merge. |
149
+ | D81 | Lanes | **`landing.lanes` path scopes, Aviator-style** | A goal takes every lane whose globs match a file in its PR's diff (`gh pr diff --name-only`); none configured or none matching is the lane `main`. Lanes are taken in sorted order, all or none (look first, roll back a lost race). Only the reviewed `loom.team.json` can split lanes. A diff Loom can't read waits for every lane. |
150
+ | D82 | A turn | **Fresh base, fast tests, push, green on that head, then `gh pr merge --squash`** | The holder merges fresh base in (D58's conflict handling), runs `landing.fastTest`, pushes, and waits for the PR's required checks on the new head. A red check, or a blocking review, gives the lane back and goes to the fix loop; the goal requeues itself once green (`landRequested` stays). Waiters show `queued` ("waiting behind bob's goal in lane api") and retry each tick and at once on `lease_released` / `goal_landed`. A PR still waiting for an approval doesn't take a turn. Feed: `land_queued`, `land_turn`. |
151
+ | D83 | GitHub events without an App | **Repo webhooks with a per-team secret, into `loom hub` or the hosted Edge Function** | Owners create and rotate the secret (`webhookSecret`). `POST /github/webhook/:teamId` (self-hosted) and the `github-webhook` Edge Function (hosted) check `X-Hub-Signature-256` (HMAC-SHA256, constant time): unknown team 404, bad or missing signature 401, `ping` acknowledged. Events for shared repos land as system events. `loom team webhook [--install]` prints the URL and secret, or makes the webhook with `gh`. |
152
+ | D84 | Webhooks and polling together | **One mapping, the same dedupe keys, and an immediate poll** | `core/github-events.ts` maps both `gh` polling and webhook deliveries, keyed per fact (a failing check is per check, per commit), so running both never posts a fact twice. A `check_failed`, `check_passed` or `pr_merged` on a goal's PR polls that goal now instead of at the next 30s tick. Polling stays as the fallback. |
153
+ | **Build approach** |||
154
+ | D27 | Build before a live Supabase exists | **In-memory hub + real migrations** | The hub protocol is tested against an in-memory hub with two real daemons as two members; SQL, RLS and Edge Functions ship ready to deploy. |
155
+
156
+ ## 2. The shape
157
+
158
+ ```
159
+ member A's Mac member B's Mac … members C–E
160
+ ┌─────────────────────────┐ ┌─────────────────────────┐
161
+ │ loom daemon │ │ loom daemon │
162
+ │ orchestra · workers │ │ orchestra · workers │
163
+ │ local brain (log) │ │ local brain (log) │
164
+ │ Team Link ──────────────┼──┐ ┌──┼── Team Link │
165
+ └───────────┬─────────────┘ │ │ └───────────┬─────────────┘
166
+ │ git push/PR │ │ │ git push/PR
167
+ ▼ ▼ ▼ ▼
168
+ ┌─────────────┐ ┌──────────────────────────────┐
169
+ │ GitHub │──▶│ Loom Team Hub (Supabase) │
170
+ │ repo · PRs │ │ Realtime: presence + feed │
171
+ │ merge queue │ │ Postgres: teams, members, │
172
+ │ Actions CI │ │ leases, goals, brain log │
173
+ │ GitHub App ─┼──▶│ (ciphertext), cost rollups │
174
+ └─────────────┘ │ Edge fn: GitHub webhooks │
175
+ ▲ └──────────────────────────────┘
176
+ │ merge_group checks ▲
177
+ └──── CI/CD ──── deploy ──────┘ status fan-out
178
+ ```
179
+
180
+ - **Member daemon** (exists today) keeps doing all agent execution, worktrees,
181
+ credentials and fast tests. A new **Team Link** module speaks to the hub.
182
+ - **Team Hub** is a thin Supabase project, the same stack Loom Cloud already uses:
183
+ - Postgres with row-level security per team;
184
+ - Realtime Presence for liveness;
185
+ - Realtime broadcast for the activity feed;
186
+ - one Edge Function that receives GitHub App webhooks.
187
+ - **GitHub App**, one per team, with short-lived installation tokens. It is the
188
+ only thing that talks to GitHub on the team's behalf; there are no shared PATs.
189
+
190
+ ## 3. Identity, roles and policy
191
+
192
+ **Identity**
193
+ - Members sign in with **GitHub** (required, D4), or with Google plus a linked GitHub
194
+ account, through Supabase Auth. Google sign-in exists today in the phone app.
195
+ - Each device generates an Ed25519 key. The hub stores the public key per
196
+ `(member, device)`.
197
+ - Every event a daemon publishes is signed with it.
198
+
199
+ **The team key**
200
+ - A 32-byte **team key** encrypts content.
201
+ - **Joining (D5):** a one-time invite link (24h) carries the key in its `#fragment`,
202
+ which is never sent to a server. It's the same pattern as phone pairing.
203
+ - **Rotation (D6):** removing a member mints a new key, sealed to each remaining
204
+ device's public key (X25519 sealed box). Rotation is forward-only; history keeps
205
+ its old key.
206
+
207
+ **Roles**
208
+
209
+ | Role | Can |
210
+ |---|---|
211
+ | owner | edit team policy, add/remove members, rotate the team key |
212
+ | member | run agents, take leases, open goal PRs, promote memory to canon |
213
+ | viewer | watch the feed and fleet, read canon |
214
+
215
+ **Policy lives in the repo**, as `loom.team.json`, so it's reviewed like code. An
216
+ optional org-level override sits above it that members can't loosen. This is the
217
+ committed-settings-plus-managed-overrides model Claude Code uses.
218
+
219
+ ```jsonc
220
+ {
221
+ "agents": { "allow": ["claude-code", "codex", "antigravity-cli", "grok-code"] },
222
+ "permissions": { "ceiling": "auto", "bypassRequiresPlan": true }, // no bypass on main work without a plan
223
+ "delivery": { "default": "pr", "protected": ["main"] }, // orchestras open PRs, never push main
224
+ "orchestra": { "maxParallelPerMember": 6, "teamMaxConcurrentAgents": 20 },
225
+ "memory": { "canonRequiresReview": true },
226
+ "ci": { "autoFixAttempts": 2, "flakeRetries": 1 }
227
+ }
228
+ ```
229
+
230
+ **Exists today, single-player:** per-agent permission modes (bypass, auto, ask),
231
+ real "always ask" approvals for Claude Code, the delivery policy (none, commit,
232
+ push, pr), and budgets with quarantine. Teams add a *ceiling* on top of these.
233
+
234
+ ## 4. Presence and the team activity feed
235
+
236
+ Each daemon publishes a **heartbeat** every 15 seconds per active session, over
237
+ Realtime Presence:
238
+
239
+ ```ts
240
+ { member, device, project, goal?, task?, agent, kind, branch,
241
+ touches: ["src/auth/**"], // globs the task declared (§5)
242
+ state: "planning" | "running" | "ci" | "review" | "waiting_human",
243
+ intent: "add OAuth callback handler", since }
244
+ ```
245
+
246
+ **Durable events** go to the feed as a broadcast plus a Postgres append:
247
+ - goal started or finished;
248
+ - plan written;
249
+ - lease taken or released;
250
+ - PR opened;
251
+ - check failed;
252
+ - memory proposed or promoted.
253
+
254
+ The GitHub App merges PR, check, review and merge events into the same feed, so
255
+ every member (and every orchestrator) reads **one timeline** for the team.
256
+
257
+ **UI.** The existing **Fleet** view, which shows every agent in every local project
258
+ with its thread and last step, grows a **Team** section:
259
+ - teammates' agents, read-only: who, which agent, which goal and task, which files,
260
+ and state;
261
+ - their open goal PRs with check status;
262
+ - the lease map.
263
+
264
+ On the phone it's the same Fleet screen.
265
+
266
+ **Encryption.** Heartbeat content such as `intent` and `touches` is encrypted with
267
+ the team key. The hub relays it and cannot read it. Every client does its own
268
+ reasoning over the decrypted feed.
269
+
270
+ ## 5. Work claiming: leases, not locks
271
+
272
+ Research is thin on the right lease size for a small team. The design therefore
273
+ leans on *advisory* leases plus *continuous* conflict detection, rather than hard
274
+ locks that deadlock.
275
+
276
+ **Taking a lease**
277
+ - When an orchestrator plans, each task declares what it will touch. This extends
278
+ the existing `loom` action protocol:
279
+ ```json
280
+ {"type":"spawn","id":"t1","agent":"codex","prompt":"…","touches":["src/auth/**","test/auth/**"],"issue":"#212"}
281
+ ```
282
+ - Before spawning, Team Link claims a **lease** per glob and per issue: a row with
283
+ a unique constraint, a TTL of about 10 minutes, and renewal by heartbeat.
284
+ - File globs are **plaintext metadata** (D2), so the hub settles overlaps itself, in
285
+ one Postgres transaction per claim. Glob overlap uses a normalized prefix match,
286
+ with a conservative "may overlap" for wildcards. **Hard zones** (D10) are refused
287
+ there. Everything else is returned as context.
288
+
289
+ **When a new plan overlaps someone else's lease**, the orchestrator gets it as
290
+ context in its planning turn: *"src/auth/** is leased by Priya's run o7x (claude,
291
+ 'rotate session keys'), expires in 6 min."* It then does one of four things:
292
+ - **reorders:** depends on the other goal's PR and starts after it merges;
293
+ - **narrows** its tasks to avoid the area;
294
+ - **proceeds** (the overlap is small and it says why in the plan);
295
+ - **asks** the human. This uses the existing `ask` action and the waiting_human state.
296
+
297
+ **Continuous conflict detection.** Every running integration branch is pushed as
298
+ a work-in-progress ref, `refs/loom/wip/<member>/<run>`. Every few minutes each
299
+ daemon runs `git merge-tree` of its integration branch against teammates' WIP refs
300
+ and main.
301
+ - Predicted conflicts go to the feed and to the owning orchestrator, *while there
302
+ is still time to coordinate*.
303
+ - This is the defence the 41.7% cross-agent conflict rate calls for.
304
+
305
+ **Hotspot affinity.** When one vendor's agent already owns a hot area, the
306
+ orchestrator is nudged to assign follow-up work there to the same vendor. Same-
307
+ vendor pairs conflict half as often.
308
+
309
+ ## 6. Memory: one team brain, three tiers
310
+
311
+ **Exists today:** an append-only event log per project; memory units folded from
312
+ `memory_*` events with provenance (author agent); retrieval scoped by query; a
313
+ contradictions finder; memory import from each agent's native files (CLAUDE.md,
314
+ AGENTS.md, …); and projection back into them on handoff.
315
+
316
+ **Teams: the log becomes many logs**
317
+ - Each member's daemon owns a **signed, append-only stream**, encrypted with the
318
+ team key and replicated through the hub, in a Postgres table of ciphertext rows.
319
+ - The team log is the **union** of the streams, ordered by hybrid logical clocks.
320
+ - A union of append-only streams can't conflict. Conflicts exist only in the
321
+ *derived* memory, which is where they belong.
322
+
323
+ **Three tiers, with promotion as the safety valve.** This follows Devin's
324
+ suggest-and-approve flow.
325
+
326
+ | Tier | Written by | Read by | Durable home |
327
+ |---|---|---|---|
328
+ | **personal** | your agents | your agents | your stream |
329
+ | **proposed** | any member's agents | everyone's agents, trust-weighted | team log |
330
+ | **canon** | a *human* promotion | everyone's agents, first | **git**: `AGENTS.md` / `CLAUDE.md` Loom sections + `.loom/brain/canon.md` |
331
+
332
+ - **Canon lives in git.** Promotion opens a small PR, so team memory is
333
+ code-reviewed and versioned. Agents outside Loom see it too, because AGENTS.md is
334
+ the cross-vendor convention. Rolling back a bad memory is `git revert`.
335
+ - **Provenance on every unit:** member, agent, goal, task, and the source text it
336
+ came from. Retrieval weights by tier, trust and recency.
337
+ - **Poisoning defence.** Units derived from *untrusted* input (issue or PR text,
338
+ web pages, third-party code comments) are tagged. They are never auto-promoted,
339
+ and they rank below team-authored units. Memory-poisoning attacks exceed 95%
340
+ injection success in research, so this is not paranoia.
341
+ - **Contradictions surface; they don't win silently.** When two members' units
342
+ disagree (for example "use zod for validation" against "use valibot"), the
343
+ contradictions finder puts both in the feed with their provenance. A human picks
344
+ one, and the loser is recorded as superseded, not deleted.
345
+ - **What every agent is briefed with**, in order:
346
+ 1. relevant canon;
347
+ 2. the **live team context** for the files its task touches: who else is working
348
+ nearby, which PRs are open against those paths, and what failed recently;
349
+ 3. proposed units ranked by trust;
350
+ 4. personal units.
351
+
352
+ Item 2 is what "agents see other teams' work" means in practice.
353
+
354
+ ## 7. Branches, PRs and the merge path
355
+
356
+ ```
357
+ worker branches (local only) goal branch (pushed) main
358
+ loom/orchestra/<run>/t1 ─┐
359
+ loom/orchestra/<run>/t2 ─┼─ merge ─▶ loom/orchestra/<run>/main ─▶ PR ─▶ merge queue ─▶ main
360
+ loom/orchestra/<run>/t3 ─┘ (exists today) (delivery=pr exists today)
361
+ ```
362
+
363
+ - **One PR per goal.** A goal too big for one review becomes a **stack** of 2–4 PRs
364
+ cut along the plan's dependency graph (Graphite's model), each with its task spec
365
+ files attached. The PR body is generated from `plans/<run>/PLAN.md` (exists
366
+ today). Reviewers get the *why*, not just the diff.
367
+ - **Pre-queue pushrebase-lite.** Before a goal PR enters the queue, the daemon:
368
+ 1. rebases the integration branch onto fresh main;
369
+ 2. re-runs the fast local test set;
370
+ 3. pushes.
371
+
372
+ This is Meta's server-side pushrebase idea, done client-side.
373
+ - **GitHub merge queue by default**, with required checks on `merge_group`. A queue
374
+ whose checks don't run on `merge_group` waits forever; Loom's setup doctor checks
375
+ for this. Teams that outgrow it can use Mergify scopes or Aviator affected-targets
376
+ to split the queue by path, so a failure in `web/` doesn't stall `api/`.
377
+ - **Agents never approve or merge.** They can *review*: a teammate's configured
378
+ reviewer agent posts a pre-review on every goal PR (AO's auto-reviewer). The human
379
+ CODEOWNER still approves, and merging is the queue's job.
380
+ - **Commit trailers make every line traceable:**
381
+ ```
382
+ Co-Authored-By: codex <codex@loom.local>
383
+ Loom-Member: priya
384
+ Loom-Goal: o7x2k
385
+ Loom-Task: t3
386
+ ```
387
+
388
+ ## 8. CI/CD
389
+
390
+ 1. **Checks come back to the owner.** The GitHub App relays check runs to the hub.
391
+ The daemon that owns the goal (identified by the branch) receives the failure,
392
+ and its orchestrator starts a **bounded auto-fix loop**: the failing check's log
393
+ tail goes to the worker that owns the files, as a follow-up with the `send`
394
+ action (exists today).
395
+ - At most `autoFixAttempts` tries (default 2), each a new commit.
396
+ - After that, the goal waits on a human.
397
+ 2. **Flakes are classified before they are blamed.** Re-run once. Check the test's
398
+ pass rate on main over the last N runs. A likely flake is labelled rather than
399
+ "fixed" by an agent rewriting a test. Trunk's pending-failure-depth idea applies
400
+ to the queue itself.
401
+ 3. **No agents in CI with secrets.** Fix loops run on the member's machine, where
402
+ credentials already are. Any CI-side agent gets read-only permissions, OIDC
403
+ tokens instead of stored secrets, and sanitized input. "Comment and Control"
404
+ (2026) exfiltrated keys through a PR *title*.
405
+ 4. **Workflow runs on agent branches need a trusted member identity.** Otherwise a
406
+ human approves them, as GitHub does for its Copilot agent.
407
+ 5. **Deployments.** GitHub Environments with required reviewers stay the gate. Loom
408
+ shows deploy status in the feed and on the phone, and writes release notes from
409
+ the merged goals' PLAN.md results.
410
+ 6. **CI cost is attributed to the goal** through its PR's check runs (§10).
411
+
412
+ ## 9. A day with five people
413
+
414
+ **09:10** Aisha starts a goal from her phone: *"add Google sign-in to the web app"*.
415
+ Plan mode is on.
416
+ - Her orchestrator (Claude) plans 4 tasks.
417
+ - Team Link leases `web/src/auth/**`, `api/routes/session.ts` and issue #212.
418
+ - `plans/o1/PLAN.md` lands on her goal branch.
419
+
420
+ **09:12** Ben asks his orchestrator (Codex) to *"refactor the session store to
421
+ Redis"*.
422
+ - His plan wants `api/routes/session.ts`.
423
+ - The planning turn is told the file is leased by Aisha's o1 until about 09:22,
424
+ with her intent line.
425
+ - Codex makes its task depend on o1's PR, starts the unrelated tasks now, and says
426
+ so in its plan.
427
+ - Ben sees the decision in his thread. Aisha sees "Ben's o2 is waiting on your o1"
428
+ in the feed.
429
+
430
+ **09:40** The merge-tree check predicts a conflict between Aisha's
431
+ `web/src/auth/button.tsx` and Chen's design-system goal (o3).
432
+ - Both orchestrators are told.
433
+ - Chen's orchestrator narrows its task to leave `button.tsx` alone and adds a
434
+ follow-up task that depends on o1.
435
+
436
+ **10:05** Aisha's goal PR opens with the PLAN.md-derived description.
437
+ - Dev's reviewer agent (Grok) posts a pre-review.
438
+ - Aisha's CODEOWNER, Emma, approves on her phone.
439
+ - The PR enters the merge queue.
440
+
441
+ **10:20** `merge_group` CI fails in `api/`.
442
+ - The check is relayed to Aisha's daemon.
443
+ - Her orchestrator sends the log to the worker that owned `api/routes/session.ts`.
444
+ - Attempt 1 fixes it, and the queue retries.
445
+ - Merged at 10:31.
446
+ - Ben's o2 was waiting on it. Its dependent task starts on its own, on top of
447
+ fresh main.
448
+
449
+ **10:35** Aisha's agents learned *"session cookies must be SameSite=Lax because of
450
+ the OAuth redirect"*.
451
+ - It's a proposed unit with full provenance, so everyone's agents working near
452
+ `auth/` see it in their briefings immediately.
453
+ - Emma promotes it to canon. A one-line PR to `AGENTS.md` merges, and now every
454
+ agent, in or out of Loom, knows it.
455
+
456
+ ## 10. Cost, budgets and fairness
457
+
458
+ - Every agent event already carries tokens, and cost where the vendor reports it.
459
+ Teams tag each event with member, goal and task, then roll up:
460
+ - per member and day;
461
+ - per goal;
462
+ - per *landed PR*, which counts the real cost including abandoned goals;
463
+ - CI minutes per goal.
464
+ - Budgets exist today per agent and per day. Teams add per-member caps, a team-wide
465
+ **concurrent-agent cap** (Jules-style concurrency tiers), and a per-goal ceiling
466
+ that pauses a run before it overspends.
467
+
468
+ ## 11. What runs where
469
+
470
+ | Local (member daemon) | Hub (Supabase) | GitHub |
471
+ |---|---|---|
472
+ | all agent execution, worktrees, code | presence, feed relay | code, PRs, reviews |
473
+ | credentials, secrets | lease table (HMAC keys) | merge queue |
474
+ | fast tests, pushrebase-lite | encrypted brain streams | Actions CI/CD, environments |
475
+ | brain folding, retrieval, briefing | goal index, cost rollups (metadata) | CODEOWNERS |
476
+ | conflict prediction (`merge-tree`) | GitHub webhook receiver | the team's GitHub App |
477
+ | approvals UI (desktop and phone) | auth, device keys | |
478
+
479
+ Optional later: **cloud sandboxes** per goal, so a goal can keep going while its
480
+ owner's laptop is closed, or so CI-triggered fix jobs run without a member online.
481
+ This is a separate trust tier with its own secrets model, which is how AO cloud,
482
+ Cursor background agents and Codex cloud do it. Not in v1.
483
+
484
+ ## 12. Failure modes → mitigations
485
+
486
+ | Failure | Mitigation |
487
+ |---|---|
488
+ | PR flood / review bottleneck | one PR per goal; stacks for big goals; reviewer-agent pre-review; PLAN.md as the PR description |
489
+ | cross-vendor merge conflicts | leases at plan time; continuous `merge-tree` prediction; hotspot vendor affinity |
490
+ | duplicated work | issue leases; team feed in planning context |
491
+ | semantic conflicts (clean merge, broken main) | merge queue tests the merged result; pushrebase-lite before queueing |
492
+ | flaky CI stalling the queue | flake classification; one retry; failure-depth tolerance; queue scopes |
493
+ | secrets exfiltrated via prompt injection | no agents with secrets in CI; OIDC; untrusted-input tagging; "ask" mode for risky tools |
494
+ | poisoned or stale memory | tiers; human promotion; provenance; canon in git behind review |
495
+ | runaway cost | per-member, per-goal and team caps; concurrency cap; cost per landed PR |
496
+ | "who did this?" | signed event log; commit trailers; approvals recorded as events |
497
+ | an orchestrator deadlocked on someone else's lease | leases expire; the orchestrator can reorder, narrow, proceed-with-reason or ask |
498
+
499
+ ## 13. Build plan
500
+
501
+ **Phase 1: see each other.** Built per D27. Status on 2026-09-18:
502
+
503
+ | Piece | Status |
504
+ |---|---|
505
+ | Team crypto: team key, sealed boxes, Ed25519 signatures, invite fragments (`src/core/team-crypto.ts`) | ✅ built, tested |
506
+ | Hub protocol plus reference hub (`src/core/team-hub.ts`: `HubClient`, `MemoryHub`) | ✅ built, tested |
507
+ | Self-hosted hub: `loom hub` server plus `HttpHubClient` (`src/hub/`) | ✅ built, tested over real HTTP + WebSocket |
508
+ | Team Link in the daemon (`src/daemon/team.ts`): sign-in, create, invite and join, forward rotation, opt-in sharing plus remote auto-match, heartbeats (intent only), goal feed, `gh` polling fallback | ✅ built; two members tested end to end |
509
+ | Hosted-hub SQL (`supabase/migrations/0002_teams.sql`): tables, RLS, rule functions, Realtime | ✅ built; tested against a real Postgres 16 as the `authenticated` role |
510
+ | Commit trailers on worker commits (`Loom-Goal`, `Loom-Task`, `Loom-Agent`, `Loom-Member`) | ✅ built, tested |
511
+ | CLI: `loom hub`, `loom team [signin/create/invite/join/share/unshare/remove/leave]`; REST `/api/team/*` | ✅ built, tested |
512
+ | Team section in Fleet (desktop and phone), Team settings | 🔨 in progress |
513
+ | Hosted client: `SupabaseHubClient` + GitHub OAuth loopback sign-in | ⏳ waits for a live Supabase project, so it's tested for real rather than written blind |
514
+ | GitHub App manifest flow + webhook Edge Function (D7) | ⏳ with the hosted client; until then the `gh` polling fallback covers PRs and checks |
515
+
516
+ The original Phase 1 plan:
517
+ - Team Hub schema:
518
+ - `teams`, `members`, `devices` and `team_keys`;
519
+ - `presence` over Realtime;
520
+ - `feed` in Postgres plus broadcast.
521
+ - Team Link: sign in, join a team by invite, publish heartbeats, subscribe to the feed.
522
+ - Team section in the Fleet view, desktop and phone.
523
+ - GitHub App: webhook to Edge Function to feed (PRs, checks, reviews).
524
+ - `delivery: "pr"` as the team default (exists today), plus commit trailers.
525
+
526
+ **Phase 2: stop colliding.** Built per D28–D39. Status on 2026-09-19:
527
+
528
+ | Piece | Status |
529
+ |---|---|
530
+ | Lease scopes, overlap and hard zones (`src/core/team-leases.ts`) | ✅ built, tested (including `**/*.test.ts` vs `src/auth/**`) |
531
+ | Team policy `loom.team.json` from origin, local-only-stricter (`src/core/team-policy.ts`) | ✅ built, tested |
532
+ | Hub leases: claim, extend, renew, landing, release; atomic hard-zone arbitration | ✅ MemoryHub + `loom hub` + SQL (`0003_team_leases.sql`, tested on Postgres 16) |
533
+ | Orchestra holds (decide, wait, zone, capacity), `overlap` decisions, rebase before a wait, pause on drift, "Stop waiting" | ✅ built, tested |
534
+ | Team coordinator (`src/daemon/team-coordinator.ts`): admission, drift, WIP refs, `merge-tree` prediction, lease lifecycle | ✅ built; two members tested end to end on a real bare origin |
535
+ | Policy enforced: permission ceiling, agent allowlist, protected-branch delivery, concurrency caps | ✅ built, tested |
536
+ | UI: holds on task cards, lease list, new feed sentences, policy panel (desktop and phone) | 🔨 in progress |
537
+
538
+ The original Phase 2 plan:
539
+ - `touches` in the orchestra protocol; lease claims and renewals; lease context in
540
+ planning turns.
541
+ - WIP refs and periodic `merge-tree` prediction, reported into the feed and to
542
+ orchestrators.
543
+ - `loom.team.json` policy: agent allowlist, permission ceiling, delivery rules,
544
+ concurrency caps.
545
+
546
+ **Phase 3: one brain.** Built per D40–D51. Status on 2026-09-19:
547
+
548
+ | Piece | Status |
549
+ |---|---|
550
+ | Canon in a managed `AGENTS.md` section: parse, render, upsert; hand-added lines honoured; native import skips it; `@AGENTS.md` for CLAUDE.md (`src/core/team-canon.ts`) | ✅ built, tested |
551
+ | Tiered retrieval and labelled briefs, canon first; failures/facts age out after ~90 days (`src/core/team-memory.ts`) | ✅ built, tested |
552
+ | Untrusted tagging: a turn that read the web, `gh issue/pr` text or fetched URLs marks what it taught as untrusted (`readExternalContent`) | ✅ built, tested |
553
+ | Memory HMAC under the team key (`memoryHmac`), so the hub merges exact twins without reading them | ✅ built, tested |
554
+ | Hub team memories: publish (twin → confirmation), author-only edit/forget, resolve (loser kept and linked, winner inherits confirmations), history | ✅ MemoryHub + `loom hub` + SQL (`0004_team_memories.sql`, tested on Postgres 16) |
555
+ | Team Brain in the daemon (`src/daemon/team-brain.ts`): snapshot-then-stream backfill, stateless publish, canon from `origin/HEAD:AGENTS.md`, the tiered pool in every briefing (orchestra workers, subtasks, handoffs), inbox, corrections, resolution | ✅ built; two members tested end to end |
556
+ | Promotion: one rolling `loom/canon` PR, rebuilt from the default branch each time (its canon + what's pending + the new entries) | ✅ built; tested on a real bare origin with a stub `gh` |
557
+ | Live team context (≤1.5k chars): teammates' leases on these paths, open PRs changing them (`files` now in PR feed metadata), failing checks, predicted conflicts | ✅ built, tested |
558
+ | REST `GET/POST /api/projects/:id/team/brain[/:action]`; CLI `loom team brain [inbox\|sync\|promote\|resolve\|merge\|correct\|trust\|private]` | ✅ built |
559
+ | Team view in the Brain tab with the inbox (desktop and phone) | 🔨 in progress |
560
+
561
+ How it differs from the original sketch below: no per-member signed streams or
562
+ HLC union. The hub already orders writes and enforces who may change what (D40),
563
+ so memories replicate as sealed rows with an HMAC handle, not as merged logs.
564
+ One less protocol to get wrong, and the same guarantees for five people.
565
+
566
+ The original Phase 3 plan:
567
+ - Signed per-member streams, encrypted replication, HLC union.
568
+ - Personal, proposed and canon tiers; promotion flow; canon export to AGENTS.md
569
+ through a PR.
570
+ - Untrusted-input tagging; trust-weighted retrieval; the team-context block in
571
+ briefings.
572
+
573
+ **Phase 4: land safely.** Built per D52–D66. Status on 2026-09-19:
574
+
575
+ | Piece | Status |
576
+ |---|---|
577
+ | Pure decisions (`src/core/team-landing.ts`): check buckets, rerun-then-fix, fenced log tails, cross-vendor reviewer pick, review prompt/parse/verdict, stack cuts, `merge_group` doctor and fixer, cost rollups | ✅ built, tested |
578
+ | Orchestra: landing state per goal, `reopen` for fixes, fixes pushed to the existing PR, stacked delivery along merge commits, adopted runs from a teammate's branch, per-goal budget pause, daily cap at start | ✅ built, tested (budget and a real two-slice stack on a bare origin) |
579
+ | Landing in the daemon (`src/daemon/landing.ts`): 30s poll of own goal PRs, rerun once, flaky label, fix loop (2 attempts), cross-vendor review with `loom/review`, Land (fresh main, fast tests, push, auto-merge), hard-zone conflicts to a human, needs-someone, Adopt and hand-back, doctor + fix PR, phone alerts | ✅ built; two members tested end to end with a fake GitHub |
580
+ | Policy: `landing`, `review`, `delivery.stack`, `budgets` in `loom.team.json` | ✅ built, tested |
581
+ | Feed: `goal_landed`, `goal_needs_someone`, `goal_adopted`, `goal_returned`, `check_flaky`; goal costs on `goal_finished`; rollups in the team view (SQL `0006_landing.sql`) | ✅ built; SQL tested on Postgres and applied to the hosted project |
582
+ | Hosted hub: `SupabaseHubClient` (RPC + Realtime), `extend_lease` (`0005_hosted_hub.sql`), session refresh, `loom team signin` defaults to hosted | ✅ built; live two-member test against the real project passes |
583
+ | GitHub sign-in to the hosted hub (OAuth loopback) | 🔨 built and unit-tested; needs the GitHub OAuth App configured on the project |
584
+ | REST `/api/projects/:id/team/landing[/:action]`, `/team/doctor[/fix]`; CLI `loom land`, `loom team landing \| doctor [fix] \| adopt <pr>` | ✅ built |
585
+ | UI: landing on goal cards, Land, Adopt, doctor, costs (desktop and phone) | 🔨 in progress |
586
+
587
+ Deferred: deploy status and release notes (D66), CI minutes per goal (needs the
588
+ GitHub App), auto-fix for lower PRs of a stack (a failing lower slice waits on a
589
+ human).
590
+
591
+ The original Phase 4 plan:
592
+ - Merge-queue integration (`merge_group` doctor check); pushrebase-lite; stacked
593
+ goal PRs.
594
+ - The check relay drives the orchestrator's bounded auto-fix loop; flake
595
+ classification.
596
+ - Cost rollups per member, goal and landed PR; team budgets.
597
+
598
+ **Phase 5: runners.** Built per D67–D78. Status on 2026-09-19:
599
+
600
+ | Piece | Status |
601
+ |---|---|
602
+ | Hub protocol: runners (a member's device marked runner) and a job queue (start / continue / fix / return / land) with atomic claims, heartbeats and stale reclaim; `revokeDevice` | ✅ MemoryHub + `loom hub` + SQL (`0007_runners.sql`) |
603
+ | Orchestra: `moveOut` (safe point, branches to `refs/loom/run/<id>/*`, status "moved") and `importRun` (worktrees rebuilt, orchestrator resumes) | ✅ built, tested |
604
+ | Runner in the daemon (`src/daemon/runner.ts`): register, claim, a fresh clone per goal as its own project, progress heartbeats, finish when the goal lands / fails / moves, cleanup; Land and Bring back as jobs; takes the owner's stuck goal when they're away | ✅ built; tested end to end (laptop + runner + teammate on a real hub and bare origin) |
605
+ | Trust tier: scrubbed environment, runner permission ceiling (`runners.permissions`), shared runners only when `runners.shared` allows, fine-grained token stored 0600 and checked by `loom runner doctor` | ✅ built, tested |
606
+ | Docker per goal (`loom runner exec` in a container) | 🔨 built; command tested, not run here (no Docker daemon on the build machine) |
607
+ | Pairing (`loom runner pair` / `join`), revoke with key rotation, `loom runner install` (launchd / systemd), `Dockerfile.runner` | ✅ built; service files tested |
608
+ | Deploys to the feed (+ an alert when a failed deploy contains your goal) and `loom team release-notes --since <tag>` | ✅ built, tested |
609
+ | REST `/api/projects/:id/team/runners[/:action]`, `/api/runner[/:action]`, `/team/deploys`, `/team/release-notes`; CLI `loom runner …`, `loom team deploys \| release-notes` | ✅ built |
610
+ | UI: runners, jobs, Continue on runner / Bring back, runner settings, deploys, release notes (desktop); runners and notification-tap deep links (phone) | 🔨 in progress |
611
+
612
+ Not done: headless sign-in to the hosted hub on a runner box needs the GitHub
613
+ OAuth App (then `loom runner join` takes the session from the paste-the-URL
614
+ flow); CI minutes per goal and auto-fixing lower stack PRs stay open.
615
+
616
+ **Phase 6: land in turn, hear it now.** Built per D79–D84. Status on 2026-09-20:
617
+
618
+ | Piece | Status |
619
+ |---|---|
620
+ | Pure decisions (`src/core/team-landing.ts`): lanes from a diff, lane claims, routing (queue / train / auto), a turn's next step | ✅ built, tested |
621
+ | The landing train in the daemon (`src/daemon/landing.ts`): the slot as a lease per lane, queued waiters woken by the feed, a turn (fresh base, fast tests, push, green, `gh pr merge --squash`), a red check gives the lane back and requeues when green | ✅ built; two members tested end to end on a real hub, a bare origin and a fake GitHub that squash-merges for real |
622
+ | Policy: `landing.lanes` in `loom.team.json` | ✅ built, tested |
623
+ | Feed: `land_queued`, `land_turn` (SQL `0009_phase6.sql`) | ✅ built; SQL tested on Postgres 16, not yet applied to the hosted project |
624
+ | GitHub mapping (`src/core/github-events.ts`): webhook deliveries and `gh` polling produce the same dedupe keys; signature checks | ✅ built, tested (key equality included) |
625
+ | `loom hub`: `POST /github/webhook/:teamId`, owner-only webhook secrets | ✅ built; tested over real HTTP (404, 401, ping, 202, heard by subscribers) |
626
+ | Hosted: webhook secrets and ingest in SQL (`0009_phase6.sql`), the `github-webhook` Edge Function (`supabase/functions/`) | 🔨 built; SQL and the handler tested, not deployed (needs a Supabase access token: `supabase functions deploy github-webhook --no-verify-jwt`) |
627
+ | Landing polls a goal the moment a check result or merge for its PR reaches the feed | ✅ built, tested end to end with a signed webhook |
628
+ | CLI `loom team webhook [--repo] [--install] [--rotate]`; REST `POST /api/team/webhook` | ✅ built |
629
+ | UI: `queued` landing chip (desktop and phone), feed lines for the train and for webhook reviews | ✅ built |
630
+
631
+ Known gaps: a pull request's changed files (used by the live team context,
632
+ D48) only come from polling, so a `pr_opened` that a webhook posts first has
633
+ none. Stacks keep landing through auto-merge even without a merge queue.
634
+
635
+ ## 14. What Loom already has that this builds on
636
+
637
+ - **Orchestra** (`src/core/orchestra.ts`): one orchestrator and many parallel
638
+ workers, a task graph, worktrees, an integration branch, review rounds, `send` for
639
+ follow-ups.
640
+ - **Plan mode:** `plans/<run>/PLAN.md` plus one spec per task that any agent can
641
+ execute.
642
+ - **Git delivery:** none / commit / push / pr, with PRs opened through `gh`.
643
+ - **Permissions and approvals:** bypass / auto / ask per agent, with real approval
644
+ routing for Claude Code, all verified against the real CLIs.
645
+ - **Fleet view:** every agent's thread, task and last step.
646
+ - **Brain:** event log, memory units, contradictions, and import/projection into
647
+ each agent's native memory files.
648
+ - **Loom Cloud:** a Supabase Realtime relay, end-to-end encrypted, and Google
649
+ sign-in. The hub reuses the same project and keys model.
650
+
651
+ ## 15. Sources
652
+
653
+ **Reviews, AI-authored code and PR volume**
654
+ - DORA 2025: https://cloud.google.com/blog/products/ai-machine-learning/announcing-the-2025-dora-report
655
+ and https://redmonk.com/rstephens/2025/12/18/dora2025/
656
+ - AI vs human PR defects (CodeRabbit): https://www.coderabbit.ai/blog/state-of-ai-vs-human-code-generation-report
657
+ - Agent PR volume (secondary sources): https://www.danilchenko.dev/posts/2026-04-11-github-ai-agents-pull-requests/
658
+
659
+ **Conflicts and keeping main green**
660
+ - Concurrent agent PR conflicts: https://arxiv.org/abs/2607.04697
661
+ - Semantic conflicts: https://dl.acm.org/doi/10.1145/3546944 and https://arxiv.org/pdf/2310.02395
662
+ - Uber SubmitQueue: https://www.uber.com/blog/research/keeping-master-green-at-scale/
663
+ - Meta Sapling (pushrebase): https://github.com/facebook/sapling
664
+
665
+ **Merge queues**
666
+ - GitHub merge queue: https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue
667
+ - Graphite stack-aware queue: https://graphite.com/blog/the-first-stack-aware-merge-queue
668
+ - Mergify scopes: https://docs.mergify.com/merge-queue/scopes/
669
+ - Aviator affected targets: https://docs.aviator.co/mergequeue/affected-targets
670
+ - Trunk anti-flake protection: https://docs.trunk.io/merge-queue/concepts-and-optimizations/anti-flake-protection
671
+
672
+ **Agent platforms**
673
+ - Copilot coding agent: https://docs.github.com/en/copilot/concepts/agents/coding-agent/about-coding-agent
674
+ and https://github.blog/news-insights/company-news/welcome-home-agents/
675
+ - Codex cloud environments: https://developers.openai.com/codex/cloud/environments
676
+ - Jules: https://jules.google/
677
+ - Cursor cloud agents and rules: https://cursor.com/docs/cloud-agent and https://cursor.com/docs/rules
678
+ - Factory audit: https://docs.factory.ai/enterprise/compliance-audit-and-monitoring
679
+ - Claude Code settings and GitHub Actions: https://code.claude.com/docs/en/settings
680
+ and https://code.claude.com/docs/en/github-actions
681
+ - Agent Orchestrator: https://github.com/Untrivial-ai/agent-orchestrator
682
+
683
+ **Memory**
684
+ - Devin Knowledge: https://docs.devin.ai/product-guides/knowledge
685
+ - AGENTS.md: https://agents.md/
686
+ - Cline Memory Bank: https://docs.cline.bot/best-practices/memory-bank
687
+ - Memory poisoning: https://arxiv.org/html/2601.05504v2
688
+
689
+ **Security**
690
+ - Comment and Control / prompt injection in CI: https://venturebeat.com/security/ai-agent-runtime-security-system-card-audit-comment-and-control-2026
691
+
692
+ **Where the evidence is thin:** there is no rigorous data on duplicated work or on
693
+ the right lease size for 2–10 people. Vendor speed-up figures (Graphite, Jules,
694
+ Mergify) are self-reported. The PR-volume figures come from secondary blogs.
695
+ Memory-poisoning is demonstrated in research, not in reported team incidents.
696
+ Agent Orchestrator's cloud internals are inferred from its issue titles. The lease
697
+ design above is deliberately advisory and cheap to tune for exactly this reason.