@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.
- package/ARCHITECTURE.md +96 -11
- package/CHANGELOG.md +1042 -0
- package/README.md +1473 -44
- package/THIRD_PARTY_NOTICES.md +275 -0
- package/dist/adapters/antigravity-cli.d.ts +62 -0
- package/dist/adapters/antigravity-cli.js +258 -0
- package/dist/adapters/antigravity-cli.js.map +1 -0
- package/dist/adapters/base.d.ts +61 -9
- package/dist/adapters/base.js +266 -15
- package/dist/adapters/base.js.map +1 -1
- package/dist/adapters/bridges/antigravity.d.ts +9 -12
- package/dist/adapters/bridges/antigravity.js +9 -12
- package/dist/adapters/bridges/antigravity.js.map +1 -1
- package/dist/adapters/echo.d.ts +1 -0
- package/dist/adapters/echo.js +59 -3
- package/dist/adapters/echo.js.map +1 -1
- package/dist/adapters/grok.d.ts +7 -0
- package/dist/adapters/grok.js +20 -10
- package/dist/adapters/grok.js.map +1 -1
- package/dist/adapters/index.d.ts +5 -1
- package/dist/adapters/index.js +53 -7
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/model.d.ts +137 -0
- package/dist/adapters/model.js +527 -0
- package/dist/adapters/model.js.map +1 -0
- package/dist/adapters/opencode.d.ts +101 -1
- package/dist/adapters/opencode.js +874 -98
- package/dist/adapters/opencode.js.map +1 -1
- package/dist/cli/doctor.d.ts +32 -0
- package/dist/cli/doctor.js +89 -4
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.js +2651 -87
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/tui-model.js +3 -1
- package/dist/cli/tui-model.js.map +1 -1
- package/dist/cli/tui.js +44 -1
- package/dist/cli/tui.js.map +1 -1
- package/dist/cli/ui.d.ts +2 -0
- package/dist/cli/ui.js +13 -0
- package/dist/cli/ui.js.map +1 -1
- package/dist/core/ades.d.ts +32 -16
- package/dist/core/ades.js +57 -20
- package/dist/core/ades.js.map +1 -1
- package/dist/core/agent-state.d.ts +14 -0
- package/dist/core/agent-state.js +32 -0
- package/dist/core/agent-state.js.map +1 -0
- package/dist/core/approvals.d.ts +33 -0
- package/dist/core/approvals.js +29 -0
- package/dist/core/approvals.js.map +1 -0
- package/dist/core/backup.d.ts +19 -0
- package/dist/core/backup.js +86 -0
- package/dist/core/backup.js.map +1 -0
- package/dist/core/baton.d.ts +2 -2
- package/dist/core/baton.js.map +1 -1
- package/dist/core/brain-extract.d.ts +17 -0
- package/dist/core/brain-extract.js +28 -2
- package/dist/core/brain-extract.js.map +1 -1
- package/dist/core/brain-index.d.ts +71 -0
- package/dist/core/brain-index.js +204 -5
- package/dist/core/brain-index.js.map +1 -1
- package/dist/core/brain.d.ts +58 -2
- package/dist/core/brain.js +79 -1
- package/dist/core/brain.js.map +1 -1
- package/dist/core/chat-import.d.ts +71 -0
- package/dist/core/chat-import.js +419 -0
- package/dist/core/chat-import.js.map +1 -0
- package/dist/core/checkpoint.d.ts +107 -0
- package/dist/core/checkpoint.js +259 -0
- package/dist/core/checkpoint.js.map +1 -0
- package/dist/core/claude-cli.js +1 -1
- package/dist/core/claude-cli.js.map +1 -1
- package/dist/core/continuity/artifacts.d.ts +14 -0
- package/dist/core/continuity/artifacts.js +118 -0
- package/dist/core/continuity/artifacts.js.map +1 -0
- package/dist/core/continuity/capabilities.d.ts +65 -0
- package/dist/core/continuity/capabilities.js +129 -0
- package/dist/core/continuity/capabilities.js.map +1 -0
- package/dist/core/continuity/contracts.d.ts +352 -0
- package/dist/core/continuity/contracts.js +117 -0
- package/dist/core/continuity/contracts.js.map +1 -0
- package/dist/core/continuity/engine.d.ts +55 -0
- package/dist/core/continuity/engine.js +504 -0
- package/dist/core/continuity/engine.js.map +1 -0
- package/dist/core/continuity/store.d.ts +73 -0
- package/dist/core/continuity/store.js +438 -0
- package/dist/core/continuity/store.js.map +1 -0
- package/dist/core/conversations.d.ts +19 -0
- package/dist/core/conversations.js +87 -0
- package/dist/core/conversations.js.map +1 -0
- package/dist/core/crew-coordination.d.ts +6 -0
- package/dist/core/crew-coordination.js +24 -0
- package/dist/core/crew-coordination.js.map +1 -0
- package/dist/core/crew-policy.d.ts +18 -0
- package/dist/core/crew-policy.js +40 -0
- package/dist/core/crew-policy.js.map +1 -0
- package/dist/core/crew-protocol.d.ts +64 -0
- package/dist/core/crew-protocol.js +146 -0
- package/dist/core/crew-protocol.js.map +1 -0
- package/dist/core/crew-requests.d.ts +14 -0
- package/dist/core/crew-requests.js +22 -0
- package/dist/core/crew-requests.js.map +1 -0
- package/dist/core/crew.d.ts +395 -0
- package/dist/core/crew.js +1857 -0
- package/dist/core/crew.js.map +1 -0
- package/dist/core/digest.d.ts +40 -0
- package/dist/core/digest.js +94 -0
- package/dist/core/digest.js.map +1 -0
- package/dist/core/distill.js +3 -5
- package/dist/core/distill.js.map +1 -1
- package/dist/core/eventlog.d.ts +27 -25
- package/dist/core/eventlog.js +97 -150
- package/dist/core/eventlog.js.map +1 -1
- package/dist/core/events/contracts.d.ts +51 -0
- package/dist/core/events/contracts.js +2 -0
- package/dist/core/events/contracts.js.map +1 -0
- package/dist/core/events/jsonl-store.d.ts +23 -0
- package/dist/core/events/jsonl-store.js +90 -0
- package/dist/core/events/jsonl-store.js.map +1 -0
- package/dist/core/events/sqlite-store.d.ts +37 -0
- package/dist/core/events/sqlite-store.js +215 -0
- package/dist/core/events/sqlite-store.js.map +1 -0
- package/dist/core/forecast.d.ts +44 -0
- package/dist/core/forecast.js +46 -0
- package/dist/core/forecast.js.map +1 -0
- package/dist/core/free-pool.d.ts +65 -0
- package/dist/core/free-pool.js +171 -0
- package/dist/core/free-pool.js.map +1 -0
- package/dist/core/git.d.ts +30 -0
- package/dist/core/git.js +50 -2
- package/dist/core/git.js.map +1 -1
- package/dist/core/github-events.d.ts +53 -0
- package/dist/core/github-events.js +227 -0
- package/dist/core/github-events.js.map +1 -0
- package/dist/core/goal-lanes.d.ts +53 -0
- package/dist/core/goal-lanes.js +99 -0
- package/dist/core/goal-lanes.js.map +1 -0
- package/dist/core/hosted.d.ts +27 -0
- package/dist/core/hosted.js +50 -0
- package/dist/core/hosted.js.map +1 -0
- package/dist/core/http-server.d.ts +5 -0
- package/dist/core/http-server.js +8 -0
- package/dist/core/http-server.js.map +1 -0
- package/dist/core/invite-link.d.ts +31 -0
- package/dist/core/invite-link.js +45 -0
- package/dist/core/invite-link.js.map +1 -0
- package/dist/core/loops.d.ts +37 -0
- package/dist/core/loops.js +81 -0
- package/dist/core/loops.js.map +1 -0
- package/dist/core/mcp-catalog.d.ts +182 -0
- package/dist/core/mcp-catalog.js +431 -0
- package/dist/core/mcp-catalog.js.map +1 -0
- package/dist/core/mcp.d.ts +87 -0
- package/dist/core/mcp.js +181 -0
- package/dist/core/mcp.js.map +1 -0
- package/dist/core/memory.d.ts +1 -0
- package/dist/core/memory.js +5 -2
- package/dist/core/memory.js.map +1 -1
- package/dist/core/model-tools.d.ts +97 -0
- package/dist/core/model-tools.js +388 -0
- package/dist/core/model-tools.js.map +1 -0
- package/dist/core/notify.js +19 -1
- package/dist/core/notify.js.map +1 -1
- package/dist/core/orchestra.d.ts +635 -0
- package/dist/core/orchestra.js +2120 -0
- package/dist/core/orchestra.js.map +1 -0
- package/dist/core/permissions.d.ts +56 -0
- package/dist/core/permissions.js +122 -0
- package/dist/core/permissions.js.map +1 -0
- package/dist/core/preview-proxy.d.ts +70 -0
- package/dist/core/preview-proxy.js +563 -0
- package/dist/core/preview-proxy.js.map +1 -0
- package/dist/core/preview-shot.d.ts +46 -0
- package/dist/core/preview-shot.js +109 -0
- package/dist/core/preview-shot.js.map +1 -0
- package/dist/core/process.d.ts +36 -0
- package/dist/core/process.js +168 -0
- package/dist/core/process.js.map +1 -0
- package/dist/core/prompt-queue.d.ts +136 -0
- package/dist/core/prompt-queue.js +269 -0
- package/dist/core/prompt-queue.js.map +1 -0
- package/dist/core/prompts.d.ts +53 -0
- package/dist/core/prompts.js +127 -0
- package/dist/core/prompts.js.map +1 -0
- package/dist/core/proof.d.ts +82 -0
- package/dist/core/proof.js +216 -0
- package/dist/core/proof.js.map +1 -0
- package/dist/core/provider-text.d.ts +23 -0
- package/dist/core/provider-text.js +66 -0
- package/dist/core/provider-text.js.map +1 -0
- package/dist/core/providers.d.ts +152 -0
- package/dist/core/providers.js +343 -0
- package/dist/core/providers.js.map +1 -0
- package/dist/core/quota.d.ts +33 -0
- package/dist/core/quota.js +74 -0
- package/dist/core/quota.js.map +1 -0
- package/dist/core/recipes.d.ts +50 -0
- package/dist/core/recipes.js +99 -0
- package/dist/core/recipes.js.map +1 -0
- package/dist/core/registry.d.ts +54 -0
- package/dist/core/registry.js +62 -5
- package/dist/core/registry.js.map +1 -1
- package/dist/core/relay-client.d.ts +67 -0
- package/dist/core/relay-client.js +184 -0
- package/dist/core/relay-client.js.map +1 -0
- package/dist/core/relay-protocol.d.ts +140 -0
- package/dist/core/relay-protocol.js +189 -0
- package/dist/core/relay-protocol.js.map +1 -0
- package/dist/core/replay.d.ts +18 -0
- package/dist/core/replay.js +191 -0
- package/dist/core/replay.js.map +1 -0
- package/dist/core/review-triage.d.ts +41 -0
- package/dist/core/review-triage.js +124 -0
- package/dist/core/review-triage.js.map +1 -0
- package/dist/core/router.js +2 -2
- package/dist/core/router.js.map +1 -1
- package/dist/core/routes.d.ts +39 -3
- package/dist/core/routes.js +137 -4
- package/dist/core/routes.js.map +1 -1
- package/dist/core/run-command.d.ts +14 -0
- package/dist/core/run-command.js +45 -0
- package/dist/core/run-command.js.map +1 -0
- package/dist/core/runner-setup.d.ts +36 -0
- package/dist/core/runner-setup.js +114 -0
- package/dist/core/runner-setup.js.map +1 -0
- package/dist/core/search.js +0 -0
- package/dist/core/search.js.map +1 -1
- package/dist/core/semantic.d.ts +92 -0
- package/dist/core/semantic.js +227 -0
- package/dist/core/semantic.js.map +1 -0
- package/dist/core/servers.d.ts +115 -0
- package/dist/core/servers.js +305 -0
- package/dist/core/servers.js.map +1 -0
- package/dist/core/setup.js +64 -6
- package/dist/core/setup.js.map +1 -1
- package/dist/core/shield.d.ts +17 -0
- package/dist/core/shield.js +81 -0
- package/dist/core/shield.js.map +1 -0
- package/dist/core/shift.d.ts +69 -0
- package/dist/core/shift.js +120 -0
- package/dist/core/shift.js.map +1 -0
- package/dist/core/skill-install.d.ts +125 -0
- package/dist/core/skill-install.js +328 -0
- package/dist/core/skill-install.js.map +1 -0
- package/dist/core/skills.d.ts +116 -0
- package/dist/core/skills.js +223 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/step-conditions.d.ts +65 -0
- package/dist/core/step-conditions.js +102 -0
- package/dist/core/step-conditions.js.map +1 -0
- package/dist/core/subagents.d.ts +45 -0
- package/dist/core/subagents.js +90 -0
- package/dist/core/subagents.js.map +1 -0
- package/dist/core/team-canon.d.ts +42 -0
- package/dist/core/team-canon.js +121 -0
- package/dist/core/team-canon.js.map +1 -0
- package/dist/core/team-crypto.d.ts +97 -0
- package/dist/core/team-crypto.js +175 -0
- package/dist/core/team-crypto.js.map +1 -0
- package/dist/core/team-hub.d.ts +514 -0
- package/dist/core/team-hub.js +964 -0
- package/dist/core/team-hub.js.map +1 -0
- package/dist/core/team-landing.d.ts +239 -0
- package/dist/core/team-landing.js +504 -0
- package/dist/core/team-landing.js.map +1 -0
- package/dist/core/team-leases.d.ts +44 -0
- package/dist/core/team-leases.js +145 -0
- package/dist/core/team-leases.js.map +1 -0
- package/dist/core/team-memory.d.ts +42 -0
- package/dist/core/team-memory.js +84 -0
- package/dist/core/team-memory.js.map +1 -0
- package/dist/core/team-policy.d.ts +85 -0
- package/dist/core/team-policy.js +191 -0
- package/dist/core/team-policy.js.map +1 -0
- package/dist/core/thread-md.d.ts +6 -0
- package/dist/core/thread-md.js +42 -0
- package/dist/core/thread-md.js.map +1 -0
- package/dist/core/turn-stats.d.ts +61 -0
- package/dist/core/turn-stats.js +124 -0
- package/dist/core/turn-stats.js.map +1 -0
- package/dist/core/updater.d.ts +73 -0
- package/dist/core/updater.js +153 -0
- package/dist/core/updater.js.map +1 -0
- package/dist/core/usage.d.ts +75 -0
- package/dist/core/usage.js +163 -0
- package/dist/core/usage.js.map +1 -0
- package/dist/core/windows-jobs.d.ts +15 -0
- package/dist/core/windows-jobs.js +170 -0
- package/dist/core/windows-jobs.js.map +1 -0
- package/dist/core/worktree-merge.d.ts +57 -0
- package/dist/core/worktree-merge.js +123 -0
- package/dist/core/worktree-merge.js.map +1 -0
- package/dist/core/worktree.d.ts +5 -0
- package/dist/core/worktree.js +45 -5
- package/dist/core/worktree.js.map +1 -1
- package/dist/core/worktrees.d.ts +6 -0
- package/dist/core/worktrees.js +21 -0
- package/dist/core/worktrees.js.map +1 -0
- package/dist/daemon/app-page.d.ts +0 -17
- package/dist/daemon/app-page.js +10 -6346
- package/dist/daemon/app-page.js.map +1 -1
- package/dist/daemon/auth.d.ts +24 -3
- package/dist/daemon/auth.js +66 -7
- package/dist/daemon/auth.js.map +1 -1
- package/dist/daemon/board.d.ts +7 -0
- package/dist/daemon/board.js +12 -1
- package/dist/daemon/board.js.map +1 -1
- package/dist/daemon/brand-icons.d.ts +6 -1
- package/dist/daemon/brand-icons.js +11 -3
- package/dist/daemon/brand-icons.js.map +1 -1
- package/dist/daemon/client.d.ts +665 -1
- package/dist/daemon/client.js +381 -3
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/delivery.d.ts +34 -0
- package/dist/daemon/delivery.js +63 -0
- package/dist/daemon/delivery.js.map +1 -0
- package/dist/daemon/deploys.d.ts +62 -0
- package/dist/daemon/deploys.js +159 -0
- package/dist/daemon/deploys.js.map +1 -0
- package/dist/daemon/landing.d.ts +192 -0
- package/dist/daemon/landing.js +992 -0
- package/dist/daemon/landing.js.map +1 -0
- package/dist/daemon/onboard.d.ts +150 -0
- package/dist/daemon/onboard.js +390 -0
- package/dist/daemon/onboard.js.map +1 -0
- package/dist/daemon/proof.d.ts +70 -0
- package/dist/daemon/proof.js +172 -0
- package/dist/daemon/proof.js.map +1 -0
- package/dist/daemon/push.d.ts +19 -1
- package/dist/daemon/push.js +90 -3
- package/dist/daemon/push.js.map +1 -1
- package/dist/daemon/relay.d.ts +82 -0
- package/dist/daemon/relay.js +351 -0
- package/dist/daemon/relay.js.map +1 -0
- package/dist/daemon/routes/agent-discovery.d.ts +4 -0
- package/dist/daemon/routes/agent-discovery.js +29 -0
- package/dist/daemon/routes/agent-discovery.js.map +1 -0
- package/dist/daemon/routes/agent-settings.d.ts +4 -0
- package/dist/daemon/routes/agent-settings.js +94 -0
- package/dist/daemon/routes/agent-settings.js.map +1 -0
- package/dist/daemon/routes/agents.d.ts +4 -0
- package/dist/daemon/routes/agents.js +105 -0
- package/dist/daemon/routes/agents.js.map +1 -0
- package/dist/daemon/routes/alerts.d.ts +4 -0
- package/dist/daemon/routes/alerts.js +137 -0
- package/dist/daemon/routes/alerts.js.map +1 -0
- package/dist/daemon/routes/approvals.d.ts +4 -0
- package/dist/daemon/routes/approvals.js +40 -0
- package/dist/daemon/routes/approvals.js.map +1 -0
- package/dist/daemon/routes/assets.d.ts +3 -0
- package/dist/daemon/routes/assets.js +64 -0
- package/dist/daemon/routes/assets.js.map +1 -0
- package/dist/daemon/routes/board.d.ts +4 -0
- package/dist/daemon/routes/board.js +147 -0
- package/dist/daemon/routes/board.js.map +1 -0
- package/dist/daemon/routes/brain.d.ts +4 -0
- package/dist/daemon/routes/brain.js +270 -0
- package/dist/daemon/routes/brain.js.map +1 -0
- package/dist/daemon/routes/chats.d.ts +4 -0
- package/dist/daemon/routes/chats.js +249 -0
- package/dist/daemon/routes/chats.js.map +1 -0
- package/dist/daemon/routes/clients.d.ts +4 -0
- package/dist/daemon/routes/clients.js +49 -0
- package/dist/daemon/routes/clients.js.map +1 -0
- package/dist/daemon/routes/cloud.d.ts +4 -0
- package/dist/daemon/routes/cloud.js +46 -0
- package/dist/daemon/routes/cloud.js.map +1 -0
- package/dist/daemon/routes/config.d.ts +4 -0
- package/dist/daemon/routes/config.js +35 -0
- package/dist/daemon/routes/config.js.map +1 -0
- package/dist/daemon/routes/context.d.ts +51 -0
- package/dist/daemon/routes/context.js +2 -0
- package/dist/daemon/routes/context.js.map +1 -0
- package/dist/daemon/routes/crews.d.ts +4 -0
- package/dist/daemon/routes/crews.js +149 -0
- package/dist/daemon/routes/crews.js.map +1 -0
- package/dist/daemon/routes/files.d.ts +3 -0
- package/dist/daemon/routes/files.js +253 -0
- package/dist/daemon/routes/files.js.map +1 -0
- package/dist/daemon/routes/git.d.ts +4 -0
- package/dist/daemon/routes/git.js +96 -0
- package/dist/daemon/routes/git.js.map +1 -0
- package/dist/daemon/routes/history.d.ts +4 -0
- package/dist/daemon/routes/history.js +101 -0
- package/dist/daemon/routes/history.js.map +1 -0
- package/dist/daemon/routes/integrations-project.d.ts +3 -0
- package/dist/daemon/routes/integrations-project.js +103 -0
- package/dist/daemon/routes/integrations-project.js.map +1 -0
- package/dist/daemon/routes/integrations.d.ts +3 -0
- package/dist/daemon/routes/integrations.js +111 -0
- package/dist/daemon/routes/integrations.js.map +1 -0
- package/dist/daemon/routes/logs.d.ts +3 -0
- package/dist/daemon/routes/logs.js +40 -0
- package/dist/daemon/routes/logs.js.map +1 -0
- package/dist/daemon/routes/messages.d.ts +4 -0
- package/dist/daemon/routes/messages.js +60 -0
- package/dist/daemon/routes/messages.js.map +1 -0
- package/dist/daemon/routes/observability.d.ts +4 -0
- package/dist/daemon/routes/observability.js +247 -0
- package/dist/daemon/routes/observability.js.map +1 -0
- package/dist/daemon/routes/onboard.d.ts +12 -0
- package/dist/daemon/routes/onboard.js +67 -0
- package/dist/daemon/routes/onboard.js.map +1 -0
- package/dist/daemon/routes/orchestra.d.ts +4 -0
- package/dist/daemon/routes/orchestra.js +110 -0
- package/dist/daemon/routes/orchestra.js.map +1 -0
- package/dist/daemon/routes/pairing.d.ts +4 -0
- package/dist/daemon/routes/pairing.js +155 -0
- package/dist/daemon/routes/pairing.js.map +1 -0
- package/dist/daemon/routes/preview.d.ts +24 -0
- package/dist/daemon/routes/preview.js +122 -0
- package/dist/daemon/routes/preview.js.map +1 -0
- package/dist/daemon/routes/project-actions.d.ts +4 -0
- package/dist/daemon/routes/project-actions.js +53 -0
- package/dist/daemon/routes/project-actions.js.map +1 -0
- package/dist/daemon/routes/project-team.d.ts +4 -0
- package/dist/daemon/routes/project-team.js +201 -0
- package/dist/daemon/routes/project-team.js.map +1 -0
- package/dist/daemon/routes/projects.d.ts +14 -0
- package/dist/daemon/routes/projects.js +138 -0
- package/dist/daemon/routes/projects.js.map +1 -0
- package/dist/daemon/routes/prompts.d.ts +4 -0
- package/dist/daemon/routes/prompts.js +44 -0
- package/dist/daemon/routes/prompts.js.map +1 -0
- package/dist/daemon/routes/proof.d.ts +4 -0
- package/dist/daemon/routes/proof.js +22 -0
- package/dist/daemon/routes/proof.js.map +1 -0
- package/dist/daemon/routes/providers.d.ts +3 -0
- package/dist/daemon/routes/providers.js +60 -0
- package/dist/daemon/routes/providers.js.map +1 -0
- package/dist/daemon/routes/public.d.ts +4 -0
- package/dist/daemon/routes/public.js +64 -0
- package/dist/daemon/routes/public.js.map +1 -0
- package/dist/daemon/routes/queue.d.ts +4 -0
- package/dist/daemon/routes/queue.js +140 -0
- package/dist/daemon/routes/queue.js.map +1 -0
- package/dist/daemon/routes/routing.d.ts +4 -0
- package/dist/daemon/routes/routing.js +61 -0
- package/dist/daemon/routes/routing.js.map +1 -0
- package/dist/daemon/routes/runtime-handler.d.ts +2 -0
- package/dist/daemon/routes/runtime-handler.js +63 -0
- package/dist/daemon/routes/runtime-handler.js.map +1 -0
- package/dist/daemon/routes/search.d.ts +4 -0
- package/dist/daemon/routes/search.js +17 -0
- package/dist/daemon/routes/search.js.map +1 -0
- package/dist/daemon/routes/servers.d.ts +4 -0
- package/dist/daemon/routes/servers.js +133 -0
- package/dist/daemon/routes/servers.js.map +1 -0
- package/dist/daemon/routes/setup.d.ts +3 -0
- package/dist/daemon/routes/setup.js +50 -0
- package/dist/daemon/routes/setup.js.map +1 -0
- package/dist/daemon/routes/shift.d.ts +4 -0
- package/dist/daemon/routes/shift.js +30 -0
- package/dist/daemon/routes/shift.js.map +1 -0
- package/dist/daemon/routes/specs.d.ts +4 -0
- package/dist/daemon/routes/specs.js +57 -0
- package/dist/daemon/routes/specs.js.map +1 -0
- package/dist/daemon/routes/task-delivery.d.ts +4 -0
- package/dist/daemon/routes/task-delivery.js +38 -0
- package/dist/daemon/routes/task-delivery.js.map +1 -0
- package/dist/daemon/routes/team.d.ts +4 -0
- package/dist/daemon/routes/team.js +193 -0
- package/dist/daemon/routes/team.js.map +1 -0
- package/dist/daemon/routes/terminals.d.ts +4 -0
- package/dist/daemon/routes/terminals.js +87 -0
- package/dist/daemon/routes/terminals.js.map +1 -0
- package/dist/daemon/routes/tools.d.ts +4 -0
- package/dist/daemon/routes/tools.js +180 -0
- package/dist/daemon/routes/tools.js.map +1 -0
- package/dist/daemon/routes/updates.d.ts +4 -0
- package/dist/daemon/routes/updates.js +89 -0
- package/dist/daemon/routes/updates.js.map +1 -0
- package/dist/daemon/routes/voice.d.ts +4 -0
- package/dist/daemon/routes/voice.js +53 -0
- package/dist/daemon/routes/voice.js.map +1 -0
- package/dist/daemon/runner.d.ts +186 -0
- package/dist/daemon/runner.js +612 -0
- package/dist/daemon/runner.js.map +1 -0
- package/dist/daemon/runtime/accounting.d.ts +130 -0
- package/dist/daemon/runtime/accounting.js +303 -0
- package/dist/daemon/runtime/accounting.js.map +1 -0
- package/dist/daemon/runtime/agents.d.ts +16 -0
- package/dist/daemon/runtime/agents.js +71 -0
- package/dist/daemon/runtime/agents.js.map +1 -0
- package/dist/daemon/runtime/briefings.d.ts +134 -0
- package/dist/daemon/runtime/briefings.js +329 -0
- package/dist/daemon/runtime/briefings.js.map +1 -0
- package/dist/daemon/runtime/native-usage.d.ts +21 -0
- package/dist/daemon/runtime/native-usage.js +71 -0
- package/dist/daemon/runtime/native-usage.js.map +1 -0
- package/dist/daemon/runtime/queue.d.ts +94 -0
- package/dist/daemon/runtime/queue.js +222 -0
- package/dist/daemon/runtime/queue.js.map +1 -0
- package/dist/daemon/runtime/relay.d.ts +93 -0
- package/dist/daemon/runtime/relay.js +240 -0
- package/dist/daemon/runtime/relay.js.map +1 -0
- package/dist/daemon/runtime/turns.d.ts +202 -0
- package/dist/daemon/runtime/turns.js +663 -0
- package/dist/daemon/runtime/turns.js.map +1 -0
- package/dist/daemon/runtime-support.d.ts +76 -0
- package/dist/daemon/runtime-support.js +134 -0
- package/dist/daemon/runtime-support.js.map +1 -0
- package/dist/daemon/runtime.d.ts +739 -70
- package/dist/daemon/runtime.js +2751 -470
- package/dist/daemon/runtime.js.map +1 -1
- package/dist/daemon/server.d.ts +82 -55
- package/dist/daemon/server.js +674 -1435
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/shift.d.ts +70 -0
- package/dist/daemon/shift.js +170 -0
- package/dist/daemon/shift.js.map +1 -0
- package/dist/daemon/specs.d.ts +92 -0
- package/dist/daemon/specs.js +285 -0
- package/dist/daemon/specs.js.map +1 -0
- package/dist/daemon/system.d.ts +208 -0
- package/dist/daemon/system.js +557 -0
- package/dist/daemon/system.js.map +1 -0
- package/dist/daemon/tasks.js +1 -1
- package/dist/daemon/team-brain.d.ts +136 -0
- package/dist/daemon/team-brain.js +659 -0
- package/dist/daemon/team-brain.js.map +1 -0
- package/dist/daemon/team-coordinator.d.ts +78 -0
- package/dist/daemon/team-coordinator.js +408 -0
- package/dist/daemon/team-coordinator.js.map +1 -0
- package/dist/daemon/team.d.ts +339 -0
- package/dist/daemon/team.js +1433 -0
- package/dist/daemon/team.js.map +1 -0
- package/dist/daemon/terminals.d.ts +22 -3
- package/dist/daemon/terminals.js +236 -16
- package/dist/daemon/terminals.js.map +1 -1
- package/dist/hub/client.d.ts +120 -0
- package/dist/hub/client.js +228 -0
- package/dist/hub/client.js.map +1 -0
- package/dist/hub/server.d.ts +32 -0
- package/dist/hub/server.js +180 -0
- package/dist/hub/server.js.map +1 -0
- package/dist/hub/supabase-client.d.ts +220 -0
- package/dist/hub/supabase-client.js +843 -0
- package/dist/hub/supabase-client.js.map +1 -0
- package/dist/observability/ask.d.ts +91 -0
- package/dist/observability/ask.js +179 -0
- package/dist/observability/ask.js.map +1 -0
- package/dist/observability/clickhouse.d.ts +33 -0
- package/dist/observability/clickhouse.js +48 -0
- package/dist/observability/clickhouse.js.map +1 -0
- package/dist/observability/decisions.d.ts +176 -0
- package/dist/observability/decisions.js +377 -0
- package/dist/observability/decisions.js.map +1 -0
- package/dist/observability/index.d.ts +89 -0
- package/dist/observability/index.js +348 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/insights.d.ts +151 -0
- package/dist/observability/insights.js +319 -0
- package/dist/observability/insights.js.map +1 -0
- package/dist/observability/logs-query.d.ts +82 -0
- package/dist/observability/logs-query.js +102 -0
- package/dist/observability/logs-query.js.map +1 -0
- package/dist/observability/logs.d.ts +72 -0
- package/dist/observability/logs.js +295 -0
- package/dist/observability/logs.js.map +1 -0
- package/dist/observability/metrics.d.ts +86 -0
- package/dist/observability/metrics.js +303 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/observability/otlp.d.ts +127 -0
- package/dist/observability/otlp.js +242 -0
- package/dist/observability/otlp.js.map +1 -0
- package/dist/observability/snapshots.d.ts +43 -0
- package/dist/observability/snapshots.js +129 -0
- package/dist/observability/snapshots.js.map +1 -0
- package/dist/observability/triage.d.ts +49 -0
- package/dist/observability/triage.js +284 -0
- package/dist/observability/triage.js.map +1 -0
- package/dist/providers/adapter.d.ts +50 -0
- package/dist/providers/adapter.js +38 -0
- package/dist/providers/adapter.js.map +1 -0
- package/dist/providers/agent.d.ts +110 -0
- package/dist/providers/agent.js +487 -0
- package/dist/providers/agent.js.map +1 -0
- package/dist/providers/approvals.d.ts +24 -0
- package/dist/providers/approvals.js +78 -0
- package/dist/providers/approvals.js.map +1 -0
- package/dist/providers/attachments.d.ts +20 -0
- package/dist/providers/attachments.js +51 -0
- package/dist/providers/attachments.js.map +1 -0
- package/dist/providers/claude/adapter.d.ts +99 -0
- package/dist/providers/claude/adapter.js +790 -0
- package/dist/providers/claude/adapter.js.map +1 -0
- package/dist/providers/codex/adapter.d.ts +113 -0
- package/dist/providers/codex/adapter.js +881 -0
- package/dist/providers/codex/adapter.js.map +1 -0
- package/dist/providers/codex/instructions.d.ts +11 -0
- package/dist/providers/codex/instructions.js +154 -0
- package/dist/providers/codex/instructions.js.map +1 -0
- package/dist/providers/codex/rpc.d.ts +36 -0
- package/dist/providers/codex/rpc.js +104 -0
- package/dist/providers/codex/rpc.js.map +1 -0
- package/dist/providers/contracts.d.ts +339 -0
- package/dist/providers/contracts.js +19 -0
- package/dist/providers/contracts.js.map +1 -0
- package/dist/providers/directory.d.ts +70 -0
- package/dist/providers/directory.js +95 -0
- package/dist/providers/directory.js.map +1 -0
- package/dist/providers/errors.d.ts +47 -0
- package/dist/providers/errors.js +24 -0
- package/dist/providers/errors.js.map +1 -0
- package/dist/providers/index.d.ts +18 -0
- package/dist/providers/index.js +19 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/ingestion.d.ts +80 -0
- package/dist/providers/ingestion.js +330 -0
- package/dist/providers/ingestion.js.map +1 -0
- package/dist/providers/live.d.ts +22 -0
- package/dist/providers/live.js +56 -0
- package/dist/providers/live.js.map +1 -0
- package/dist/providers/process.d.ts +29 -0
- package/dist/providers/process.js +71 -0
- package/dist/providers/process.js.map +1 -0
- package/dist/providers/reaper.d.ts +33 -0
- package/dist/providers/reaper.js +65 -0
- package/dist/providers/reaper.js.map +1 -0
- package/dist/providers/service.d.ts +87 -0
- package/dist/providers/service.js +256 -0
- package/dist/providers/service.js.map +1 -0
- package/dist/sdk.d.ts +1 -1
- package/dist/sdk.js +1 -1
- package/dist/sdk.js.map +1 -1
- package/dist/types.d.ts +385 -6
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +7 -0
- package/dist/version.js +16 -0
- package/dist/version.js.map +1 -0
- package/dist/web/app.css +4643 -0
- package/dist/web/app.js +22640 -0
- package/dist/web/app.js.map +7 -0
- package/dist/web/shell.html +39 -0
- package/docs/README.md +21 -0
- package/docs/SETUP.md +10 -0
- package/docs/adapters.md +21 -8
- package/docs/brain-continuity.md +186 -0
- package/docs/cloud.md +108 -0
- package/docs/crews.md +62 -0
- package/docs/design-system.md +31 -2
- package/docs/integration-notes.md +128 -20
- package/docs/loompad.md +105 -0
- package/docs/observability.md +220 -0
- package/docs/play-store.md +123 -0
- package/docs/proposals/agent-teams.md +249 -0
- package/docs/proposals/brain-continuity-implementation.md +468 -0
- package/docs/proposals/brain-session-continuity.md +623 -0
- package/docs/proposals/t3code-port.md +81 -0
- package/docs/proposals/t3code-reference.md +95 -0
- package/docs/refactoring/AGENT-TEAMS-PROGRESS.md +88 -0
- package/docs/refactoring/BOUNDARIES.md +120 -0
- package/docs/refactoring/BRAIN-AUDIT.md +176 -0
- package/docs/refactoring/BRAIN-NOTES.md +390 -0
- package/docs/refactoring/BRAIN-TODO.md +214 -0
- package/docs/refactoring/NOTES.md +129 -0
- package/docs/refactoring/T3-PORT-NOTES.md +165 -0
- package/docs/refactoring/T3-PORT-TODO.md +123 -0
- package/docs/refactoring/TODO.md +46 -0
- package/docs/refactoring/brain-benchmark-2026-09-28.json +48 -0
- package/docs/refactoring/brain-benchmark-audit-2026-09-28.json +48 -0
- package/docs/release-notes/v0.2.0.md +35 -0
- package/docs/release-notes/v0.2.1.md +59 -0
- package/docs/release-notes/v0.2.3.md +77 -0
- package/docs/release-notes/v0.2.4.md +128 -0
- package/docs/release-notes/v0.2.5.md +153 -0
- package/docs/release-notes/v0.2.6.md +62 -0
- package/docs/release-notes/v1.0.0.md +120 -0
- package/docs/release-notes/v1.0.1.md +77 -0
- package/docs/release-notes/v1.1.0.md +71 -0
- package/docs/release-notes/v1.1.1.md +38 -0
- package/docs/teams-architecture.md +697 -0
- package/docs/teams.md +171 -0
- package/docs/windows.md +85 -0
- package/package.json +22 -9
- package/dist/adapters/claude-code.d.ts +0 -26
- package/dist/adapters/claude-code.js +0 -209
- package/dist/adapters/claude-code.js.map +0 -1
- package/dist/adapters/codex.d.ts +0 -51
- package/dist/adapters/codex.js +0 -291
- package/dist/adapters/codex.js.map +0 -1
- package/docs/img/board-linear.png +0 -0
- package/docs/img/board-projects.png +0 -0
- package/docs/img/brain.png +0 -0
- package/docs/img/settings.png +0 -0
- 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.
|
|
6
|
+
## Claude Code (verified: v2.1.278, Agent SDK 0.3.283)
|
|
7
7
|
|
|
8
|
-
|
|
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 -
|
|
12
|
-
--
|
|
13
|
-
|
|
14
|
-
[--
|
|
15
|
-
|
|
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
|
-
-
|
|
19
|
-
- `
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
|
|
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
|
|
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
|
-
|
|
76
|
-
|
|
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**.
|
package/docs/loompad.md
ADDED
|
@@ -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).
|