@loompad/cli 0.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (687) hide show
  1. package/ARCHITECTURE.md +96 -11
  2. package/CHANGELOG.md +1042 -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 +4643 -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/teams-architecture.md +697 -0
  674. package/docs/teams.md +171 -0
  675. package/docs/windows.md +85 -0
  676. package/package.json +22 -9
  677. package/dist/adapters/claude-code.d.ts +0 -26
  678. package/dist/adapters/claude-code.js +0 -209
  679. package/dist/adapters/claude-code.js.map +0 -1
  680. package/dist/adapters/codex.d.ts +0 -51
  681. package/dist/adapters/codex.js +0 -291
  682. package/dist/adapters/codex.js.map +0 -1
  683. package/docs/img/board-linear.png +0 -0
  684. package/docs/img/board-projects.png +0 -0
  685. package/docs/img/brain.png +0 -0
  686. package/docs/img/settings.png +0 -0
  687. package/docs/img/workspace.png +0 -0
@@ -3,27 +3,102 @@
3
3
  These are not guesses: each surface below was verified against the locally installed
4
4
  tool before the adapter was written. Re-verify when versions move.
5
5
 
6
- ## Claude Code (verified: v2.1.83)
6
+ ## Claude Code (verified: v2.1.278, Agent SDK 0.3.283)
7
7
 
8
- Headless invocation per turn:
8
+ Loom drives the user's installed `claude` through the Claude Agent SDK
9
+ (`@anthropic-ai/claude-agent-sdk`), one warm streaming-input `query()` per chat
10
+ session, the way t3code does (`src/providers/claude/adapter.ts`). Each turn is one
11
+ more user message on the open stream. The SDK speaks the CLI's stream-json control
12
+ protocol over stdio:
9
13
 
10
14
  ```
11
- claude -p "<prompt>" \
12
- --output-format stream-json --verbose \
13
- [--resume <session-id>] \
14
- [--append-system-prompt "<loom briefing>"] \
15
- --permission-mode acceptEdits
15
+ claude --output-format stream-json --verbose --input-format stream-json \
16
+ --permission-prompt-tool stdio --setting-sources=user,project,local \
17
+ --permission-mode <mode> (--session-id=<uuid> | --resume=<uuid>) [--model <m>]
18
+ [--include-partial-messages] [--mcp-config <json>]
19
+ stdin: control_request {subtype: "initialize"} → control_response
20
+ {type: "user", message: {content: [{type: "text", text}]}, uuid: <turn id>} (per turn)
21
+ control_request {subtype: "set_model", model} (model switch)
22
+ stdout: system/init (session_id) · system/status (requesting | compacting) ·
23
+ stream_event (message_start, content_block_delta text/thinking) ·
24
+ system/compact_boundary {pre_tokens, post_tokens} · assistant (content, usage) ·
25
+ rate_limit_event {utilization 0–1, rateLimitType, resetsAt s} ·
26
+ result (usage, total_cost_usd, modelUsage[*].contextWindow)
16
27
  ```
17
28
 
18
- - `--output-format stream-json` — newline-delimited JSON events on stdout:
19
- - `{"type":"system","subtype":"init","session_id":...}` → capture session id
20
- - `{"type":"assistant","message":{"content":[{"type":"text"|"tool_use",...}]}}`
21
- - `{"type":"result","subtype":"success","total_cost_usd":...}` → run complete
22
- - `--resume <session-id>` — continue the same conversation across turns.
23
- - `--append-system-prompt` — **this is how Loom injects the handoff briefing** without
24
- touching user files.
25
- - `--permission-mode` — `acceptEdits` default for baton holders (configurable).
26
- - Interrupt = SIGINT to the child process (escalate SIGKILL).
29
+ - `pathToClaudeCodeExecutable` points the SDK at the user's `claude`, so the
30
+ signed-in version runs. `spawnClaudeCodeProcess` lets Loom spawn it in its own
31
+ process group (quiescence for Brain), and capture stderr.
32
+ - `systemPrompt: {type: "preset", preset: "claude_code"}` and
33
+ `settingSources: ["user", "project", "local"]` reproduce an interactive
34
+ `claude`; the SDK loads neither by default. A warm session's system prompt is
35
+ fixed when it starts, so a handoff briefing rides in front of the turn's text.
36
+ - The session id is chosen up front (`--session-id`, a UUID) and is the resume
37
+ cursor; `initializationResult()` proves the session opened before any prompt.
38
+ - Permissions: "ask" is `permissionMode: default` with `canUseTool` answered
39
+ in-process by Loom's approval broker (no MCP shim); "auto" is `acceptEdits`;
40
+ "bypass" is `bypassPermissions` with `allowDangerouslySkipPermissions`.
41
+ - Interrupt closes the session (query and process group), as t3code does:
42
+ `interrupt()` can acknowledge while background tasks keep the CLI alive. Loom
43
+ reports `interrupted`; the next turn resumes the same session.
44
+ - A resumed session that no longer exists: the CLI prints `No conversation found`
45
+ and exits before reading the prompt; `initializationResult()` rejects with it
46
+ (verified live, 2.1.x). Loom starts a new session, or with Brain continuity
47
+ reports `NativeSessionMissing` so Brain rebuilds into a new epoch.
48
+ - Context in use is the main thread's last response usage (input + cache read +
49
+ cache creation + output); the window comes from the result's `modelUsage`.
50
+ - The SDK package pulls a platform binary as an optional dependency (~228 MB);
51
+ Loom never runs it because `pathToClaudeCodeExecutable` is always set.
52
+
53
+ ## Codex (verified: codex-cli 0.153.4)
54
+
55
+ Loom keeps one warm `codex app-server` per chat session
56
+ (`src/providers/codex/adapter.ts`): newline-delimited JSON-RPC (`{id, method,
57
+ params}`, no `jsonrpc` field), the protocol t3code uses. The thread stays open, so
58
+ each turn is one `turn/start` on the same connection.
59
+
60
+ ```
61
+ initialize {clientInfo, capabilities: {experimentalApi: true}} → initialized
62
+ thread/start {cwd, sandbox, approvalPolicy, model?, config?}
63
+ | thread/resume {threadId, excludeTurns: true, …same}
64
+ turn/start {threadId, input: [{type: "text", text, text_elements: []}], model?, effort?,
65
+ clientUserMessageId?}
66
+ … item/agentMessage/delta · item/reasoning/textDelta · item/reasoning/summaryTextDelta ·
67
+ item/commandExecution/outputDelta · turn/plan/updated · turn/diff/updated · model/rerouted
68
+ … item/started · item/completed (agentMessage, reasoning, commandExecution, fileChange,
69
+ mcpToolCall, webSearch, contextCompaction) · thread/tokenUsage/updated
70
+ {total, last, modelContextWindow} · account/rateLimits/updated · error {willRetry}
71
+ turn/completed {turn: {id, status: completed | interrupted | failed, error}}
72
+ turn/interrupt {threadId, turnId}
73
+ ```
74
+
75
+ - Sandbox and approvals per Loom mode: bypass → `danger-full-access` + `never`;
76
+ auto → `workspace-write` + `never`; ask → `read-only` + `untrusted`, and each
77
+ `item/commandExecution/requestApproval` / `item/fileChange/requestApproval` is
78
+ answered by Loom's approval broker. Requests Loom can't put to a person
79
+ (elicitations, extra permissions) are declined rather than left waiting.
80
+ - Project MCP servers go in `thread/start` config as `mcp_servers.<key>`.
81
+ - Context in use is `last.totalTokens`; `inputTokens` already includes cached
82
+ tokens and `outputTokens` includes reasoning, so neither is added twice.
83
+ - A missing thread on resume is an error response; Loom starts a new thread, or
84
+ with Brain continuity reports `NativeSessionMissing`.
85
+ - The account's own default model comes from `~/.codex/config.toml`. A model the
86
+ account can't use fails the turn with Codex's 400; `model/list` says which
87
+ models the account offers.
88
+
89
+ ### Warm sessions and Brain continuity
90
+
91
+ A session per (chat, agent) stays up between turns and is reaped after 30 minutes
92
+ idle (its binding keeps the resume cursor). A turn — Brain continuity turns included
93
+ — settles at turn level: the provider reported it complete and no command it started
94
+ (`commandExecution` / Bash item) is still running.
95
+
96
+ Plan mode: Codex `turn/start.collaborationMode {mode: "plan" | "default", settings:
97
+ {model, reasoning_effort, developer_instructions}}`; Claude `setPermissionMode("plan")`,
98
+ and the plan arrives as the `ExitPlanMode` tool's input (Claude first writes it to
99
+ `~/.claude/plans/`). Questions: Codex `item/tool/requestUserInput` → `{answers: {id:
100
+ {answers: [..]}}}`; Claude `AskUserQuestion` through `canUseTool` → `updatedInput:
101
+ {questions, answers: {<question text>: <label>}}`.
27
102
 
28
103
  ## OpenCode (verified: v1.17.20)
29
104
 
@@ -66,11 +141,44 @@ Dogfood findings (verified live on 1.17.20):
66
141
  spawning agents — running `loom` from inside a Claude Code terminal otherwise poisons
67
142
  nested agent auth.
68
143
 
69
- ## Antigravity (bridge, best-effort)
144
+ ## Antigravity — the CDP bridge, and what replaced it (verified: `agy` 1.1.6)
145
+
146
+ **The bridge is withdrawn.** It is kept here because the spike is worth the record, not
147
+ because it is on offer.
148
+
149
+ The original integration drove the Antigravity IDE. Launched with a debug port, the app
150
+ exposes a Chromium DevTools endpoint:
70
151
 
71
- Launched with a debug port it exposes a Chromium DevTools endpoint:
72
152
  - `GET http://127.0.0.1:{port}/json/version` — presence check
73
153
  - `GET http://127.0.0.1:{port}/json` — target list (read-only visibility)
74
154
 
75
- No stable send/interrupt/memory surface → **Bridge tier** (never holds the baton),
76
- receives projections via `.loom/memory/antigravity.md`.
155
+ There was no stable send/interrupt/memory surface behind it, so it could only watch, which
156
+ put it in the **Bridge tier** — never the baton, projections delivered as a file the human
157
+ driving the GUI reads (`.loom/memory/antigravity.md`).
158
+
159
+ Google then shipped a headless CLI, and it graduated: `antigravity-cli` is a real adapter
160
+ that holds the baton and runs a turn to completion with no GUI in the loop
161
+ (`src/adapters/antigravity-cli.ts`). One process per turn:
162
+
163
+ ```
164
+ agy -p "<text>" --dangerously-skip-permissions --add-dir <dir> \
165
+ --model <model> --print-timeout <dur>
166
+ agy -p "<text>" --conversation <id> … (follow-up turns)
167
+ ```
168
+
169
+ - `-p/--print` runs one prompt non-interactively and prints **only** the final assistant
170
+ message (markdown) to stdout, then exits 0. There is no JSON event stream — so the
171
+ adapter reports the final message plus the files it touched, parsed from the
172
+ `[name](file://…)` links `agy` emits.
173
+ - No tokens and no cost come back, so turns report a model and a duration and nothing
174
+ else. A price table would only produce a fabricated number rendered as fact.
175
+ - Conversations are keyed by working directory in
176
+ `~/.gemini/antigravity-cli/cache/last_conversations.json`. The adapter reads the id back
177
+ after a fresh turn and resumes it explicitly with `--conversation` from then on, so
178
+ continuity survives another tool rewriting that mapping.
179
+ - `agy` leaves a language server holding the stdout pipe after it exits, so anything
180
+ reading it must key off process exit rather than EOF.
181
+
182
+ The bridge's registration still exists — deleting it would stop any project that still
183
+ names `kind: "antigravity"` from opening at all — but it is in `WITHDRAWN_KINDS` and no
184
+ surface offers it (`src/adapters/index.ts`). The one remaining bridge is **Kiro**.
@@ -0,0 +1,105 @@
1
+ # LoomPad
2
+
3
+ LoomPad is the physical companion for Loom: a printable ESP32-S3 desk pad that
4
+ selects an agent, sets effort, captures hold-to-talk audio, and sends work to
5
+ the Loom stack. The current repository ships the v0.1 enclosure, keycaps, CAD
6
+ sources, and the daemon-side connectivity surface. Firmware and the voice
7
+ backend are not yet included, so the flashing and voice sections below define
8
+ the intended integration contract rather than a ready-to-run build.
9
+
10
+ See [`hardware/orchestrator-pad/README.md`](../hardware/orchestrator-pad/README.md)
11
+ for CAD regeneration and [`hardware/orchestrator-pad/SPEC.md`](../hardware/orchestrator-pad/SPEC.md)
12
+ for the dimensional source of truth.
13
+
14
+ ## Parts
15
+
16
+ | Qty. | Part | Notes |
17
+ | ---: | --- | --- |
18
+ | 1 | ESP32-S3 DevKitC-1 | Use a board without factory headers, or trim the headers flush; the tray has no clearance below the PCB. |
19
+ | 14 | MX-style switches | 13 1u switches plus one switch under the 2u voice bar. |
20
+ | 1 | EC11 rotary encoder | M7 threaded bush; the printed knob fits its D-shaft. |
21
+ | 1 | INMP441 I2S microphone | Mount behind the front three-hole mic grille. |
22
+ | 4 | M3 heat-set inserts | Fit the tray's corner bosses. |
23
+ | 4 | M3×8 button-head screws | M3×10 screws bottom out before clamping the plate. |
24
+ | 4 | Rubber feet, about Ø8 mm | Fit the tray's recessed feet pockets. |
25
+ | Optional | WS2812 LEDs | Intended for the three preset/status keys. |
26
+
27
+ Print `tray.stl`, `plate.stl`, `caps-all.stl`, and `knob.stl` from
28
+ `hardware/orchestrator-pad/exports/`. Use a 0.4 mm nozzle and 0.2 mm layers in
29
+ PLA or PETG. Print the tray and plate flat without supports, the knob upright,
30
+ and the caps face-down or with tree supports.
31
+
32
+ The v0.1 electrical build is hand-wired. The matrix row/column GPIO assignment
33
+ and I2S pin mapping are firmware-owned and are not defined in this repository;
34
+ do not infer them from the mechanical 4×4 layout.
35
+
36
+ ## 4×4 keymap
37
+
38
+ The grid is viewed from the user, with row 0 at the back of the pad. The voice
39
+ bar spans columns 1 and 2 but is one 2u key/switch position for matrix purposes.
40
+
41
+ | Row \ Column | 0 | 1 | 2 | 3 |
42
+ | --- | --- | --- | --- | --- |
43
+ | 0 | Effort encoder | Preset/status: dot | Preset/status: ring | Preset/status: target |
44
+ | 1 | Codex (`X`) | Claude (`C`) | Antigravity (`A`) | OpenCode (`O`) |
45
+ | 2 | Kiro (`K`) | Run (`⚡`) | Approve (`✓`) | Reject (`✕`) |
46
+ | 3 | Prompt/terminal | Voice hold (`🎤`, 2u) | Voice hold (`🎤`, 2u) | Send/dispatch (`➤`) |
47
+
48
+ Agent keys lock the target agent. The encoder maps its detents to effort:
49
+ `low`, `medium`, `high`, `xhigh`, `max`, and `ultracode`. Run, approve, reject,
50
+ prompt, and send are command actions; their exact daemon mapping belongs in the
51
+ firmware once implemented.
52
+
53
+ ## Flashing with `arduino-cli`
54
+
55
+ There is currently no `firmware/` sketch in this repository, so these commands
56
+ are the expected flow after a LoomPad sketch is added or checked out locally.
57
+ They intentionally do not name a serial port or dependencies that the missing
58
+ sketch has not declared.
59
+
60
+ ```bash
61
+ # Install the ESP32 board support once.
62
+ arduino-cli core update-index
63
+ arduino-cli core install esp32:esp32
64
+
65
+ # Identify the DevKitC-1's serial port.
66
+ arduino-cli board list
67
+
68
+ # From the directory containing the future LoomPad sketch.
69
+ arduino-cli compile --fqbn esp32:esp32:esp32s3 firmware/loompad
70
+ arduino-cli upload --fqbn esp32:esp32:esp32s3 --port /dev/cu.usbmodemXXXX firmware/loompad
71
+
72
+ # Inspect boot and Wi-Fi logs.
73
+ arduino-cli monitor --port /dev/cu.usbmodemXXXX --config baudrate=115200
74
+ ```
75
+
76
+ Replace `/dev/cu.usbmodemXXXX` with the port from `arduino-cli board list`
77
+ (`COM…` on Windows or `/dev/ttyACM…` on Linux). If upload cannot enter the
78
+ bootloader, hold the board's **BOOT** button while starting upload, then release
79
+ it when the tool connects.
80
+
81
+ ## Voice loop
82
+
83
+ The intended hold-to-talk flow is:
84
+
85
+ 1. Press an agent key to lock the recipient, and turn the encoder to choose
86
+ effort.
87
+ 2. Hold the voice bar. Firmware samples the INMP441 and buffers/streams audio.
88
+ 3. On release, firmware sends the selected agent, action, effort, and audio to
89
+ the voice service. The planned envelope is `{ "agent", "action", "effort",
90
+ "audio" }`.
91
+ 4. The voice service performs speech-to-text, asks Loom to route the text to
92
+ the locked agent, and waits for that agent's reply.
93
+ 5. The service synthesizes the reply and returns audio for playback on the pad.
94
+
95
+ Loom exposes a best-effort proxy for the service at `/api/loompad/health` and
96
+ `/api/loompad/connect`. It reads `LOOMPAD_BACKEND_URL`, defaulting to
97
+ `http://127.0.0.1:8080`; the desktop UI uses it to report whether the backend
98
+ is reachable. The expected backend is responsible for STT → agent dispatch →
99
+ TTS. Its implementation, audio codec, authentication, Wi-Fi provisioning, and
100
+ speaker/amplifier wiring are not yet shipped here.
101
+
102
+ For local operation, run Loom and the voice backend on the same trusted machine
103
+ or tailnet, keep pairing credentials out of firmware source, and require a
104
+ deliberate press-and-hold before recording. The microphone should be visibly
105
+ indicated as active by firmware or LEDs before audio leaves the device.
@@ -0,0 +1,220 @@
1
+ # Observability — Loom over OpenTelemetry
2
+
3
+ Loom ships its agent activity as **all three OpenTelemetry signals — traces,
4
+ metrics and logs**. Every turn, tool call, baton handoff, route step and memory
5
+ fold your agents produce becomes a span; the same events are folded into
6
+ counters and histograms; and every agent message, tool call, edit, decision and
7
+ error is also emitted as a log record correlated to the span it happened inside.
8
+ You get the whole fleet in one place: latency, cost, token usage, error rates,
9
+ the critical path across agents — and, from a slow span, the log lines saying
10
+ what the agent was actually doing while it was slow.
11
+
12
+ **Backend-agnostic by construction.** Loom speaks OTLP/HTTP and nothing else, so
13
+ it works against anything with a `/v1/{traces,metrics,logs}` endpoint: the
14
+ OpenTelemetry Collector, Grafana/Tempo, Jaeger, SigNoz, Honeycomb, Datadog's
15
+ OTLP intake. Loom has no vendor SDK and no vendor-specific code path — point
16
+ `OTEL_EXPORTER_OTLP_ENDPOINT` at your collector and it works.
17
+
18
+ ## How it works
19
+
20
+ Loom's daemon is already a stream of `LoomEvent`s. The observability layer
21
+ (`src/observability/`) folds the notable ones into each signal and exports them
22
+ over **OTLP/HTTP (JSON)** — no OpenTelemetry SDK dependency, just `fetch`.
23
+ Egress is best-effort: if no collector is reachable the POST fails silently and
24
+ never touches the agent loop.
25
+
26
+ | Signal | Endpoint | Module |
27
+ |---|---|---|
28
+ | Traces | `/v1/traces` | `src/observability/otlp.ts` |
29
+ | Metrics | `/v1/metrics` | `src/observability/metrics.ts` |
30
+ | Logs | `/v1/logs` | `src/observability/logs.ts` |
31
+
32
+ All three carry the same `service.name`, `service.namespace = loom` resource
33
+ block — a backend keys a service off `service.name`, and a mismatch is what
34
+ makes a trace and its own logs look like two different apps.
35
+
36
+ Event → span mapping (using the OpenTelemetry [GenAI semantic
37
+ conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/) where they
38
+ apply):
39
+
40
+ | LoomEvent | Span | Key attributes |
41
+ |---|---|---|
42
+ | `run_complete` | `gen_ai.agent.turn` | `gen_ai.agent.id`, `gen_ai.request.model`, `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`, `gen_ai.usage.cost_usd`, duration |
43
+ | `tool_call` | `gen_ai.tool.call` | `gen_ai.tool.name` |
44
+ | `handoff` | `loom.baton.handoff` | `loom.handoff.from`, `loom.handoff.to` |
45
+ | `route_*` | `loom.route.<phase>` | `loom.route.id` |
46
+ | `memory_add/update/forget` | `loom.memory.<op>` | `loom.memory.kind`, `loom.memory.scope` |
47
+ | `error` | `loom.error` (ERROR status) | message |
48
+
49
+ Every span carries `service.name = loom`, plus `loom.project` and `loom.chat`
50
+ so you can slice by project and conversation. One trace per turn: it is minted
51
+ at the turn boundary rather than off a `turn_started` status only some adapters
52
+ emit, so the span tree is right for the whole roster.
53
+
54
+ ### Metrics emitted
55
+
56
+ Six, all delta temporality — the daemon restarts whenever you edit a config or
57
+ upgrade the CLI, which is the case cumulative handles worst.
58
+
59
+ | Metric | Unit | What it counts |
60
+ |---|---|---|
61
+ | `gen_ai.client.token.usage` | `{token}` | Tokens an agent turn consumed, split by `gen_ai.token.type` (`input`/`output`) |
62
+ | `gen_ai.client.operation.duration` | `s` | Turn duration (histogram, as the convention specifies) |
63
+ | `loom.turns` | `{turn}` | Turns that reached completion, by outcome |
64
+ | `loom.cost.usd` | `USD` | Money an adapter *reported* spending on a turn |
65
+ | `loom.agents.active` | `{agent}` | Agents currently executing a turn |
66
+ | `loom.handoffs` | `{handoff}` | Baton handoffs between agents |
67
+
68
+ These same six names are the default set the Observatory's metric explorer
69
+ queries when a caller names none (`LOOM_METRIC_NAMES` in
70
+ `src/observability/insights.ts` — a constant in the code, not a knob).
71
+
72
+ `gen_ai.client.token.usage` deviates from the convention on purpose: it is a
73
+ monotonic sum rather than a histogram, because Loom reports exactly one
74
+ input/output pair per turn and the question anyone asks is "how many tokens did
75
+ this agent burn today", which a sum answers exactly.
76
+
77
+ **Nothing emits a zero to keep a chart's line alive.** A flat zero and "nothing
78
+ happened" look identical on a graph and only one of them is true. The same rule
79
+ governs cost: an adapter that reports tokens but no dollar figure (codex does
80
+ exactly this) produces token datapoints and *no* cost datapoint, rather than a
81
+ cost of 0 — zeros are indistinguishable from real cheap turns once summed, and
82
+ the total then reads as authoritative.
83
+
84
+ ### Logs emitted
85
+
86
+ Every agent message, tool call, file edit, decision, route step, budget pause
87
+ and error becomes one OTLP log record. When the event happened inside a turn it
88
+ carries that turn's `traceId`/`spanId`, so the trace view gets a working
89
+ "related logs" tab. Severity is mapped without inflation: an agent speaking is
90
+ INFO, a failed turn is ERROR, something a human must look at but that isn't a
91
+ failure (blocked on input, over budget, a suggested handoff) is WARN, adapter
92
+ lifecycle chatter is DEBUG. Nothing is FATAL.
93
+
94
+ ## Point it at your collector
95
+
96
+ Nothing to configure for a local collector — Loom exports to
97
+ `http://localhost:4318` out of the box. To target another one, set environment
98
+ variables before starting the daemon:
99
+
100
+ ```bash
101
+ # a collector on another host
102
+ export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-collector:4318"
103
+
104
+ # a hosted backend that wants an ingestion key — any header name it asks for
105
+ export OTEL_EXPORTER_OTLP_HEADERS="signoz-access-token=<key>"
106
+ # or, for a different vendor:
107
+ export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=<key>"
108
+
109
+ # optional: rename the service
110
+ export LOOM_SERVICE_NAME="loom"
111
+ ```
112
+
113
+ The ingestion key rides in through the standard `OTEL_EXPORTER_OTLP_HEADERS`
114
+ (`k=v,k2=v2`) rather than a per-vendor variable, so a new destination is a
115
+ config change and never a code change.
116
+
117
+ ## Turn it off
118
+
119
+ Consent is not per-signal — any of these kills all three:
120
+
121
+ ```bash
122
+ export DO_NOT_TRACK=1 # or
123
+ export LOOM_TELEMETRY_DISABLED=1 # or
124
+ export LOOM_OTEL=0
125
+ ```
126
+
127
+ ## Every environment variable
128
+
129
+ Resolved in `resolveTelemetryConfig` (`src/observability/otlp.ts`) unless noted.
130
+
131
+ | Variable | Default | What it does |
132
+ |---|---|---|
133
+ | `LOOM_OTEL_ENDPOINT` | `http://localhost:4318` | Collector base URL. `OTEL_EXPORTER_OTLP_ENDPOINT` is the fallback. |
134
+ | `OTEL_EXPORTER_OTLP_HEADERS` | — | Standard `k=v,k2=v2` headers, for whatever ingestion key your backend wants. |
135
+ | `LOOM_SERVICE_NAME` | `loom` | `service.name` on all three signals. `OTEL_SERVICE_NAME` is the fallback. Also what the read-back queries filter on, so emit and read-back can't disagree. |
136
+ | `DO_NOT_TRACK` | — | Any truthy value disables **all** telemetry. |
137
+ | `LOOM_TELEMETRY_DISABLED` | — | Same, Loom-specific. |
138
+ | `LOOM_OTEL` | — | `0` disables all telemetry. |
139
+ | `LOOM_OTEL_METRICS` | on | `0` turns off the metrics exporter only; traces and logs keep going. |
140
+ | `LOOM_OTEL_LOGS` | on | `0` turns off the logs exporter only. Volume control — Loom ships every agent message as a log record, which is the point, and also a lot of bytes. |
141
+
142
+ ### Reading telemetry back
143
+
144
+ The Observatory reads spans, metrics and logs back out of the backend's store to
145
+ render Span Replay, the trace waterfall, burn rate and the Logs view. That
146
+ requires a ClickHouse-backed store; the physical table names default to the
147
+ layout an OTLP collector writes and are overridable for a backend that lays them
148
+ out differently.
149
+
150
+ | Variable | Default | What it does |
151
+ |---|---|---|
152
+ | `LOOM_CLICKHOUSE_URL` | `http://localhost:8123` | Where to query the telemetry store. |
153
+ | `LOOM_SPAN_TABLE` | `signoz_traces.distributed_signoz_index_v3` | The span index. |
154
+ | `LOOM_LOG_TABLE` | *(collector default)* | The log table. |
155
+ | `LOOM_METRIC_SAMPLES_TABLE` / `LOOM_METRIC_SERIES_TABLE` | *(collector defaults)* | The metric tables. |
156
+ | `LOOM_TRACE_UI_URL` | — | Your backend's own UI, for the trace deep links. Unset means the links hide themselves rather than pointing at a guessed port. |
157
+
158
+ Read-back is optional. With no store reachable, the panels that can fall back to
159
+ the local event log do (Span Replay, triage, burn rate); the Logs view says so
160
+ instead, because a log record's severity and trace correlation only exist once
161
+ it has been shipped, and reconstructing something log-shaped from the event log
162
+ would be inventing the correlation that is the whole point.
163
+
164
+ These steer the LLM-backed read-back features, and exist so those paths can be
165
+ made deterministic:
166
+
167
+ | Variable | Default | What it does |
168
+ |---|---|---|
169
+ | `LOOM_TRIAGE_NO_LLM` | — | `1` makes triage skip the model entirely and return the deterministic heuristic. `src/observability/triage.ts` |
170
+ | `LOOM_DECISION_MODEL` | `claude-haiku-4-5-20251001` | The model used to extract decisions from a turn's output. `src/observability/decisions.ts` |
171
+ | `LOOM_DECISIONS_NO_CLI` | — | `1` stops decision extraction from shelling out to a signed-in CLI when there's no `ANTHROPIC_API_KEY`; it falls through to the regex extractor. `src/observability/decisions.ts` |
172
+
173
+ The classification and evidence behind triage are deterministic either way; only
174
+ the prose is model-written.
175
+
176
+ ## Self-heal
177
+
178
+ Loom accepts alerts back from your monitoring at `POST /api/webhooks/alerts`, in
179
+ the Alertmanager-shaped payload SigNoz, Prometheus and Grafana all send. A
180
+ firing alert takes the named agent out of rotation — it is refused the baton
181
+ until the alert resolves — and a resolved one puts it back.
182
+
183
+ This is the part a dashboard cannot show you: it knows the alert fired, only
184
+ Loom knows the fleet reacted. The Observatory's Self-heal view is built from
185
+ Loom's own event log rather than the backend's API, so it still answers when the
186
+ backend is down — which is exactly the moment you want to know which agents are
187
+ still paused.
188
+
189
+ | Variable | Default | What it does |
190
+ |---|---|---|
191
+ | `LOOM_WEBHOOK_SECRET` | — | Shared secret the webhook requires, when set. |
192
+ | `LOOM_HEAL_DISABLED` | — | `1` accepts alerts but never acts on them. |
193
+ | `LOOM_HEAL_MAX_RETRIES` | — | How many times a recovered agent is retried. |
194
+ | `LOOM_HEAL_RECHECK_MS` | — | How long before a quarantined agent is re-examined. |
195
+
196
+ ## Verify it's flowing
197
+
198
+ Run a turn, then look for the `loom` service in your backend, or query the
199
+ store directly:
200
+
201
+ ```sql
202
+ SELECT name, count()
203
+ FROM signoz_traces.distributed_signoz_index_v3
204
+ WHERE serviceName = 'loom' AND timestamp > now() - INTERVAL 15 MINUTE
205
+ GROUP BY name;
206
+ ```
207
+
208
+ ## Test it
209
+
210
+ The exporter and the event→span mapping are covered end to end:
211
+
212
+ ```bash
213
+ npm test -- observability # unit: config, mapper, OTLP payload shape
214
+ npm test -- observability-export # integration: a stand-in OTLP collector
215
+ # receives real spans from daemon turns
216
+ ```
217
+
218
+ The integration test stands up a real HTTP server, points the daemon at it, runs
219
+ real turns and asserts on the OTLP payloads that arrive — so "it exports" is a
220
+ measured claim rather than a mocked one.
@@ -0,0 +1,123 @@
1
+ # Loom on Google Play
2
+
3
+ What the Play Console asks for, and Loom's answers. The app is `tech.loompad.app`.
4
+
5
+ ## Build the bundle
6
+
7
+ ```bash
8
+ LOOM_KEYSTORE_PROPS=/path/to/keystore.properties app/scripts/build-aab.sh
9
+ ```
10
+
11
+ It writes `app/dist/loom-<version>-<versionCode>.aab`, signed with your **upload key**.
12
+ Google re-signs it with the app signing key it keeps (Play App Signing — accept it when
13
+ you create the app). Before each new upload, raise `expo.android.versionCode` in
14
+ `app/app.json` (Play refuses a code it has seen). Raise `expo.version` when users should
15
+ see a new version number.
16
+
17
+ Keep the keystore and its `keystore.properties` backed up somewhere safe and out of git.
18
+ If the upload key is lost, Play support can reset it, which takes a few days.
19
+
20
+ The APK on GitHub Releases is signed with a different key (the `ANDROID_KEYSTORE_*`
21
+ secrets). Android won't install the Play build over that APK, so anyone moving from the
22
+ APK to the Play build uninstalls the APK first. To avoid that, choose "use my own key"
23
+ under Play App Signing and upload that same keystore as the app signing key.
24
+
25
+ ### Push notifications in the Play build
26
+
27
+ Expo Go gets push for free. A store build needs two things that only you can set up:
28
+
29
+ 1. **Firebase:** create a project at console.firebase.google.com, add an Android app with
30
+ package `tech.loompad.app`, and download `google-services.json` into `app/`. It's
31
+ gitignored, and `app.config.js` picks it up.
32
+ 2. **Expo:** run `npx eas-cli login`, then `npx eas-cli init` in `app/`. It prints a
33
+ project id. Build with `EAS_PROJECT_ID=<that id>` set. Then upload the Firebase
34
+ service-account key in expo.dev → the project → Credentials → Android → FCM V1.
35
+
36
+ Without them, the app works and its account sheet says this build can't get push.
37
+
38
+ ## Store listing
39
+
40
+ - **App name:** Loom
41
+ - **Short description (80):** Watch, steer and approve your coding agents from your phone.
42
+ - **Full description:**
43
+
44
+ > Loom is the remote for Loom, the free and open-source workspace where your coding
45
+ > agents (Claude Code, Codex, OpenCode, Grok, Antigravity and plain models) work side by
46
+ > side and share one memory of your project.
47
+ >
48
+ > Loom runs on your computer. This app pairs with it by QR code and lets you:
49
+ > • follow every agent live and send them messages, pictures or voice
50
+ > • answer their questions and Allow or Deny tool calls
51
+ > • run Orchestra goals and races, and crews of agents with roles
52
+ > • review diffs, rewind to a checkpoint, commit and push
53
+ > • see what each agent cost, in dollars and tokens
54
+ > • get notified when an agent asks something, finishes, or a goal is done
55
+ >
56
+ > You'll need Loom on a Mac, Linux or Windows computer: see
57
+ > loompad.tech. Nothing goes through Loom's servers. The phone
58
+ > talks to your computer over your network, your tailnet, or an encrypted relay.
59
+
60
+ - **Category:** Tools (or Productivity) · **Tags:** developer tools
61
+ - **Contact email:** required, use one you read.
62
+ - **Website:** https://loompad.tech
63
+ - **Privacy policy:** https://loompad.tech/privacy (the landing site,
64
+ nickthelegend/loompad-landing)
65
+ - **Graphics:** a 512×512 icon (`app/assets/icon.png` scaled down), a 1024×500 feature
66
+ graphic, and at least 2 phone screenshots (Board, a chat, the Orchestra tab, the
67
+ account sheet).
68
+
69
+ ## App content (the questionnaires)
70
+
71
+ - **Privacy policy:** the URL above.
72
+ - **Ads:** no ads.
73
+ - **App access:** "All or some functionality is restricted." Reviewers can't pair without
74
+ a computer running Loom, so give them instructions: "Loom is the companion app for a
75
+ desktop tool. Install Loom on a computer (loompad.tech), run
76
+ `loom up` then `loom pair`, and scan the QR code." Better still, link a short screen
77
+ recording of pairing and use.
78
+ - **Content rating:** answer the IARC questionnaire as a utility/productivity app. No
79
+ violence, sexual content, gambling or drugs. It does show text written by AI models.
80
+ It doesn't let users message other people.
81
+ - **Target audience:** 18+ (a developer tool); not designed for children.
82
+ - **News app:** no. **COVID / government:** no. **Financial features:** none.
83
+ - **Data safety** (for the Play build, which has no sign-in or analytics):
84
+ - Data collected: **none** (nothing is sent to the developer).
85
+ - Data shared: **none**. What goes to Firebase/Expo for push, and to the speech
86
+ recognizer, is processed for you by a service provider. Google's guidance doesn't
87
+ count that as sharing.
88
+ - Data is encrypted in transit: **yes** (HTTPS / the relay); over a plain LAN or tailnet
89
+ address the transport is your own network's.
90
+ - Users can request deletion: **yes**, by unpairing or uninstalling. The data lives on
91
+ their own computer.
92
+ - If a later build turns on Google sign-in or usage stats, update this form: name,
93
+ email and user id for the account, and approximate location (region) for analytics.
94
+ - **Permissions:** camera (QR pairing, attaching a photo), microphone (dictation),
95
+ notifications. Nothing in the background. Storage and media-library permissions are
96
+ blocked in `app.json`.
97
+
98
+ ## Testing tracks, and the 12-tester rule
99
+
100
+ Personal developer accounts created after November 2023 can't publish to production
101
+ straight away. You need a **closed test with at least 12 testers who stay opted in for 14
102
+ days in a row**; then "Apply for production" unlocks. It can't be skipped. (Organisation
103
+ accounts are exempt.)
104
+
105
+ 1. **Internal testing** (up to 100 testers, no review, live in minutes): create a release,
106
+ upload the `.aab`, add your own Google accounts as testers, and install from the opt-in
107
+ link. Use this to check the build on real phones.
108
+ 2. **Closed testing:** create a track, upload the same `.aab` (or promote it), add testers
109
+ by email list or a Google Group, and share the opt-in link. You need **12+ people who
110
+ accept and keep it installed for 14 days**. Friends, a Discord or the repo's community
111
+ all work; a Google Group makes adding people easy.
112
+ 3. After 14 days, **Apply for production** in the dashboard. You'll answer questions about
113
+ the test and the app. Review usually takes a few days.
114
+ 4. **Production:** promote the release, choose countries, roll out (a staged rollout
115
+ such as 20% first is a good habit).
116
+
117
+ ## Updates
118
+
119
+ - Each Play update needs a higher `versionCode`. Build, upload to a track, and promote.
120
+ - Users get updates through Play. The app's account sheet also shows whether the
121
+ *computer's* Loom is behind the newest GitHub release. The computer pushes an "update
122
+ available" notification once per release (the "Loom updates" switch).
123
+ - The account sheet's **Rate Loom** opens the Play listing (Android only).