@openparachute/agent 0.1.0

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 (501) hide show
  1. package/.claude/scheduled_tasks.lock +1 -0
  2. package/.claude/settings.json +5 -0
  3. package/.claude/skills/add-atomic-chat-tool/SKILL.md +243 -0
  4. package/.claude/skills/add-atomic-chat-tool/atomic-chat-mcp-stdio.ts +229 -0
  5. package/.claude/skills/add-codex/SKILL.md +161 -0
  6. package/.claude/skills/add-dashboard/SKILL.md +138 -0
  7. package/.claude/skills/add-dashboard/resources/dashboard-pusher.ts +495 -0
  8. package/.claude/skills/add-emacs/SKILL.md +296 -0
  9. package/.claude/skills/add-gcal-tool/SKILL.md +210 -0
  10. package/.claude/skills/add-gchat/REMOVE.md +6 -0
  11. package/.claude/skills/add-gchat/SKILL.md +92 -0
  12. package/.claude/skills/add-gchat/VERIFY.md +3 -0
  13. package/.claude/skills/add-github/REMOVE.md +6 -0
  14. package/.claude/skills/add-github/SKILL.md +148 -0
  15. package/.claude/skills/add-github/VERIFY.md +3 -0
  16. package/.claude/skills/add-gmail-tool/SKILL.md +229 -0
  17. package/.claude/skills/add-imessage/REMOVE.md +6 -0
  18. package/.claude/skills/add-imessage/SKILL.md +113 -0
  19. package/.claude/skills/add-imessage/VERIFY.md +3 -0
  20. package/.claude/skills/add-karpathy-llm-wiki/SKILL.md +110 -0
  21. package/.claude/skills/add-karpathy-llm-wiki/llm-wiki.md +75 -0
  22. package/.claude/skills/add-linear/REMOVE.md +6 -0
  23. package/.claude/skills/add-linear/SKILL.md +168 -0
  24. package/.claude/skills/add-linear/VERIFY.md +3 -0
  25. package/.claude/skills/add-macos-statusbar/SKILL.md +133 -0
  26. package/.claude/skills/add-macos-statusbar/add/src/statusbar.swift +147 -0
  27. package/.claude/skills/add-matrix/REMOVE.md +6 -0
  28. package/.claude/skills/add-matrix/SKILL.md +148 -0
  29. package/.claude/skills/add-matrix/VERIFY.md +3 -0
  30. package/.claude/skills/add-ollama-provider/SKILL.md +179 -0
  31. package/.claude/skills/add-ollama-tool/SKILL.md +193 -0
  32. package/.claude/skills/add-opencode/SKILL.md +229 -0
  33. package/.claude/skills/add-parallel/SKILL.md +290 -0
  34. package/.claude/skills/add-resend/REMOVE.md +6 -0
  35. package/.claude/skills/add-resend/SKILL.md +93 -0
  36. package/.claude/skills/add-resend/VERIFY.md +3 -0
  37. package/.claude/skills/add-signal/REMOVE.md +13 -0
  38. package/.claude/skills/add-signal/SKILL.md +318 -0
  39. package/.claude/skills/add-signal/VERIFY.md +5 -0
  40. package/.claude/skills/add-slack/REMOVE.md +6 -0
  41. package/.claude/skills/add-slack/SKILL.md +112 -0
  42. package/.claude/skills/add-slack/VERIFY.md +3 -0
  43. package/.claude/skills/add-teams/REMOVE.md +6 -0
  44. package/.claude/skills/add-teams/SKILL.md +207 -0
  45. package/.claude/skills/add-teams/VERIFY.md +3 -0
  46. package/.claude/skills/add-vercel/SKILL.md +147 -0
  47. package/.claude/skills/add-vercel/container-skills/vercel-cli/SKILL.md +103 -0
  48. package/.claude/skills/add-webex/REMOVE.md +6 -0
  49. package/.claude/skills/add-webex/SKILL.md +88 -0
  50. package/.claude/skills/add-webex/VERIFY.md +3 -0
  51. package/.claude/skills/add-wechat/REMOVE.md +49 -0
  52. package/.claude/skills/add-wechat/SKILL.md +170 -0
  53. package/.claude/skills/add-wechat/scripts/wire-dm.ts +172 -0
  54. package/.claude/skills/add-whatsapp/SKILL.md +264 -0
  55. package/.claude/skills/add-whatsapp-cloud/REMOVE.md +6 -0
  56. package/.claude/skills/add-whatsapp-cloud/SKILL.md +95 -0
  57. package/.claude/skills/add-whatsapp-cloud/VERIFY.md +3 -0
  58. package/.claude/skills/claw/SKILL.md +131 -0
  59. package/.claude/skills/claw/scripts/claw +374 -0
  60. package/.claude/skills/convert-to-apple-container/SKILL.md +212 -0
  61. package/.claude/skills/customize/SKILL.md +110 -0
  62. package/.claude/skills/debug/SKILL.md +349 -0
  63. package/.claude/skills/get-qodo-rules/SKILL.md +122 -0
  64. package/.claude/skills/get-qodo-rules/references/output-format.md +41 -0
  65. package/.claude/skills/get-qodo-rules/references/pagination.md +33 -0
  66. package/.claude/skills/get-qodo-rules/references/repository-scope.md +26 -0
  67. package/.claude/skills/init-first-agent/SKILL.md +120 -0
  68. package/.claude/skills/init-onecli/SKILL.md +270 -0
  69. package/.claude/skills/manage-channels/SKILL.md +87 -0
  70. package/.claude/skills/manage-mounts/SKILL.md +47 -0
  71. package/.claude/skills/migrate-from-openclaw/MIGRATE_CRONS.md +100 -0
  72. package/.claude/skills/migrate-from-openclaw/SKILL.md +447 -0
  73. package/.claude/skills/migrate-from-openclaw/scripts/discover-openclaw.ts +734 -0
  74. package/.claude/skills/migrate-from-openclaw/scripts/extract-channel-credentials.ts +476 -0
  75. package/.claude/skills/migrate-nanoclaw/SKILL.md +484 -0
  76. package/.claude/skills/migrate-nanoclaw/diagnostics.md +51 -0
  77. package/.claude/skills/qodo-pr-resolver/SKILL.md +326 -0
  78. package/.claude/skills/qodo-pr-resolver/resources/providers.md +329 -0
  79. package/.claude/skills/update-nanoclaw/SKILL.md +243 -0
  80. package/.claude/skills/update-nanoclaw/diagnostics.md +48 -0
  81. package/.claude/skills/update-skills/SKILL.md +130 -0
  82. package/.claude/skills/use-native-credential-proxy/SKILL.md +167 -0
  83. package/.claude/skills/x-integration/SKILL.md +417 -0
  84. package/.claude/skills/x-integration/agent.ts +243 -0
  85. package/.claude/skills/x-integration/host.ts +155 -0
  86. package/.claude/skills/x-integration/lib/browser.ts +148 -0
  87. package/.claude/skills/x-integration/lib/config.ts +62 -0
  88. package/.claude/skills/x-integration/scripts/like.ts +56 -0
  89. package/.claude/skills/x-integration/scripts/post.ts +66 -0
  90. package/.claude/skills/x-integration/scripts/quote.ts +80 -0
  91. package/.claude/skills/x-integration/scripts/reply.ts +74 -0
  92. package/.claude/skills/x-integration/scripts/retweet.ts +62 -0
  93. package/.claude/skills/x-integration/scripts/setup.ts +87 -0
  94. package/.github/CODEOWNERS +10 -0
  95. package/.github/PULL_REQUEST_TEMPLATE.md +18 -0
  96. package/.github/workflows/bump-version.yml +35 -0
  97. package/.github/workflows/ci.yml +39 -0
  98. package/.github/workflows/label-pr.yml +40 -0
  99. package/.github/workflows/update-tokens.yml +43 -0
  100. package/.husky/pre-commit +1 -0
  101. package/.mcp.json +3 -0
  102. package/.nvmrc +1 -0
  103. package/.parachute/module.json +14 -0
  104. package/.prettierrc +4 -0
  105. package/CHANGELOG.md +215 -0
  106. package/CLAUDE.md +307 -0
  107. package/CODE_OF_CONDUCT.md +128 -0
  108. package/CONTRIBUTING.md +159 -0
  109. package/CONTRIBUTORS.md +26 -0
  110. package/LICENSE +21 -0
  111. package/README.md +190 -0
  112. package/README_ja.md +194 -0
  113. package/README_zh.md +194 -0
  114. package/assets/nanoclaw-favicon.png +0 -0
  115. package/assets/nanoclaw-icon.png +0 -0
  116. package/assets/nanoclaw-logo-dark.png +0 -0
  117. package/assets/nanoclaw-logo.png +0 -0
  118. package/assets/nanoclaw-profile.jpeg +0 -0
  119. package/assets/nanoclaw-sales.png +0 -0
  120. package/assets/social-preview.jpg +0 -0
  121. package/config-examples/mount-allowlist.json +25 -0
  122. package/container/.dockerignore +2 -0
  123. package/container/CLAUDE.md +21 -0
  124. package/container/Dockerfile +121 -0
  125. package/container/agent-runner/bun.lock +243 -0
  126. package/container/agent-runner/package.json +22 -0
  127. package/container/agent-runner/scripts/sdk-signal-probe.ts +169 -0
  128. package/container/agent-runner/src/config.ts +55 -0
  129. package/container/agent-runner/src/db/connection.ts +267 -0
  130. package/container/agent-runner/src/db/index.ts +20 -0
  131. package/container/agent-runner/src/db/messages-in.ts +138 -0
  132. package/container/agent-runner/src/db/messages-out.ts +143 -0
  133. package/container/agent-runner/src/db/session-routing.ts +30 -0
  134. package/container/agent-runner/src/db/session-state.test.ts +100 -0
  135. package/container/agent-runner/src/db/session-state.ts +79 -0
  136. package/container/agent-runner/src/destinations.ts +135 -0
  137. package/container/agent-runner/src/formatter.test.ts +167 -0
  138. package/container/agent-runner/src/formatter.ts +260 -0
  139. package/container/agent-runner/src/index.ts +110 -0
  140. package/container/agent-runner/src/integration.test.ts +121 -0
  141. package/container/agent-runner/src/mcp-tools/agents.instructions.md +26 -0
  142. package/container/agent-runner/src/mcp-tools/agents.ts +66 -0
  143. package/container/agent-runner/src/mcp-tools/core.instructions.md +27 -0
  144. package/container/agent-runner/src/mcp-tools/core.ts +262 -0
  145. package/container/agent-runner/src/mcp-tools/index.ts +22 -0
  146. package/container/agent-runner/src/mcp-tools/interactive.instructions.md +22 -0
  147. package/container/agent-runner/src/mcp-tools/interactive.ts +169 -0
  148. package/container/agent-runner/src/mcp-tools/scheduling.instructions.md +40 -0
  149. package/container/agent-runner/src/mcp-tools/scheduling.ts +299 -0
  150. package/container/agent-runner/src/mcp-tools/self-mod.instructions.md +25 -0
  151. package/container/agent-runner/src/mcp-tools/self-mod.ts +120 -0
  152. package/container/agent-runner/src/mcp-tools/server.ts +54 -0
  153. package/container/agent-runner/src/mcp-tools/types.ts +6 -0
  154. package/container/agent-runner/src/poll-loop.test.ts +248 -0
  155. package/container/agent-runner/src/poll-loop.ts +437 -0
  156. package/container/agent-runner/src/providers/claude.ts +379 -0
  157. package/container/agent-runner/src/providers/factory.test.ts +19 -0
  158. package/container/agent-runner/src/providers/factory.ts +13 -0
  159. package/container/agent-runner/src/providers/index.ts +6 -0
  160. package/container/agent-runner/src/providers/mock.ts +77 -0
  161. package/container/agent-runner/src/providers/provider-registry.ts +33 -0
  162. package/container/agent-runner/src/providers/types.ts +82 -0
  163. package/container/agent-runner/src/scheduling/task-script.ts +121 -0
  164. package/container/agent-runner/src/timezone.test.ts +93 -0
  165. package/container/agent-runner/src/timezone.ts +107 -0
  166. package/container/agent-runner/tsconfig.json +14 -0
  167. package/container/build.sh +48 -0
  168. package/container/entrypoint.sh +16 -0
  169. package/container/skills/agent-browser/SKILL.md +159 -0
  170. package/container/skills/frontend-engineer/SKILL.md +157 -0
  171. package/container/skills/self-customize/SKILL.md +87 -0
  172. package/container/skills/slack-formatting/SKILL.md +94 -0
  173. package/container/skills/vercel-cli/SKILL.md +111 -0
  174. package/container/skills/welcome/SKILL.md +85 -0
  175. package/docs/APPLE-CONTAINER-NETWORKING.md +90 -0
  176. package/docs/BRANCH-FORK-MAINTENANCE.md +81 -0
  177. package/docs/README.md +25 -0
  178. package/docs/SDK_DEEP_DIVE.md +643 -0
  179. package/docs/SECURITY.md +162 -0
  180. package/docs/agent-runner-details.md +749 -0
  181. package/docs/api-details.md +365 -0
  182. package/docs/architecture-diagram.html +422 -0
  183. package/docs/architecture-diagram.md +215 -0
  184. package/docs/architecture.md +751 -0
  185. package/docs/audit/2026-04-30-channel-endpoint-audit.md +36 -0
  186. package/docs/build-and-runtime.md +80 -0
  187. package/docs/cross-mount-stress/README.md +112 -0
  188. package/docs/cross-mount-stress/container-writer-retry.mjs +55 -0
  189. package/docs/cross-mount-stress/container-writer-slow.mjs +42 -0
  190. package/docs/cross-mount-stress/container-writer.mjs +47 -0
  191. package/docs/cross-mount-stress/host-writer-retry.mjs +55 -0
  192. package/docs/cross-mount-stress/host-writer-slow.mjs +43 -0
  193. package/docs/cross-mount-stress/host-writer.mjs +47 -0
  194. package/docs/db-central.md +316 -0
  195. package/docs/db-session.md +183 -0
  196. package/docs/db.md +119 -0
  197. package/docs/design/2026-04-29-vault-management-ui.md +231 -0
  198. package/docs/design/2026-04-30-channel-wiring-rework.md +234 -0
  199. package/docs/design/2026-05-01-channel-wiring-approvals-deep-dive.md +272 -0
  200. package/docs/design/2026-05-02-channel-policy-and-approval-routing.md +250 -0
  201. package/docs/docker-sandboxes.md +359 -0
  202. package/docs/isolation-model.md +88 -0
  203. package/docs/ollama.md +79 -0
  204. package/docs/parachute-integration.md +109 -0
  205. package/docs/post-night-rebirth-reflections.md +151 -0
  206. package/eslint.config.js +32 -0
  207. package/package.json +54 -0
  208. package/pnpm-workspace.yaml +8 -0
  209. package/repo-tokens/README.md +113 -0
  210. package/repo-tokens/action.yml +186 -0
  211. package/repo-tokens/badge.svg +23 -0
  212. package/repo-tokens/examples/green.svg +14 -0
  213. package/repo-tokens/examples/red.svg +14 -0
  214. package/repo-tokens/examples/yellow-green.svg +14 -0
  215. package/repo-tokens/examples/yellow.svg +14 -0
  216. package/scripts/chat.ts +101 -0
  217. package/scripts/cleanup-sessions.sh +150 -0
  218. package/scripts/init-cli-agent.ts +171 -0
  219. package/scripts/init-first-agent.ts +377 -0
  220. package/scripts/parachute.ts +158 -0
  221. package/scripts/run-migrations.ts +105 -0
  222. package/scripts/sanity-live-poll.ts +95 -0
  223. package/scripts/seed-discord.ts +79 -0
  224. package/scripts/test-v2-agent.ts +106 -0
  225. package/scripts/test-v2-channel-e2e.ts +265 -0
  226. package/scripts/test-v2-host.ts +184 -0
  227. package/src/channels/adapter.ts +214 -0
  228. package/src/channels/ask-question.ts +46 -0
  229. package/src/channels/channel-registry.test.ts +421 -0
  230. package/src/channels/channel-registry.ts +313 -0
  231. package/src/channels/chat-sdk-bridge.test.ts +84 -0
  232. package/src/channels/chat-sdk-bridge.ts +652 -0
  233. package/src/channels/cli.ts +276 -0
  234. package/src/channels/discord.ts +90 -0
  235. package/src/channels/index.ts +17 -0
  236. package/src/channels/telegram-markdown-sanitize.test.ts +78 -0
  237. package/src/channels/telegram-markdown-sanitize.ts +55 -0
  238. package/src/channels/telegram-pairing.test.ts +254 -0
  239. package/src/channels/telegram-pairing.ts +339 -0
  240. package/src/channels/telegram.ts +279 -0
  241. package/src/channels/trust-hint.test.ts +48 -0
  242. package/src/channels/trust-hint.ts +75 -0
  243. package/src/claude-md-compose.migrate.test.ts +64 -0
  244. package/src/claude-md-compose.ts +205 -0
  245. package/src/command-gate.ts +63 -0
  246. package/src/config.test.ts +93 -0
  247. package/src/config.ts +108 -0
  248. package/src/container-config.ts +167 -0
  249. package/src/container-runner.test.ts +32 -0
  250. package/src/container-runner.ts +576 -0
  251. package/src/container-runtime.test.ts +169 -0
  252. package/src/container-runtime.ts +92 -0
  253. package/src/db/_bun-sqlite-shim.ts +88 -0
  254. package/src/db/agent-activity.test.ts +155 -0
  255. package/src/db/agent-activity.ts +121 -0
  256. package/src/db/agent-groups.ts +77 -0
  257. package/src/db/connection.migrate.test.ts +143 -0
  258. package/src/db/connection.ts +224 -0
  259. package/src/db/db-v2.test.ts +440 -0
  260. package/src/db/dropped-messages.ts +44 -0
  261. package/src/db/index.ts +40 -0
  262. package/src/db/messaging-groups.ts +252 -0
  263. package/src/db/migrations/001-initial.ts +112 -0
  264. package/src/db/migrations/002-chat-sdk-state.ts +36 -0
  265. package/src/db/migrations/008-dropped-messages.ts +27 -0
  266. package/src/db/migrations/009-drop-pending-credentials.ts +13 -0
  267. package/src/db/migrations/010-engage-modes.ts +103 -0
  268. package/src/db/migrations/011-pending-sender-approvals.ts +40 -0
  269. package/src/db/migrations/012-channel-registration.ts +48 -0
  270. package/src/db/migrations/013-approval-render-metadata.ts +27 -0
  271. package/src/db/migrations/014-secrets.ts +44 -0
  272. package/src/db/migrations/015-secrets-drop-host-pattern.ts +18 -0
  273. package/src/db/migrations/016-secret-assignments.ts +30 -0
  274. package/src/db/migrations/017-agent-activity.ts +40 -0
  275. package/src/db/migrations/018-oauth-app-configs.ts +34 -0
  276. package/src/db/migrations/019-oauth-app-connections.ts +48 -0
  277. package/src/db/migrations/020-agent-app-connections.ts +28 -0
  278. package/src/db/migrations/021-pending-oauth-states.ts +35 -0
  279. package/src/db/migrations/022-app-connections-provider.ts +25 -0
  280. package/src/db/migrations/023-agent-group-secret-mode.test.ts +124 -0
  281. package/src/db/migrations/023-agent-group-secret-mode.ts +65 -0
  282. package/src/db/migrations/024-collapse-approvals.test.ts +249 -0
  283. package/src/db/migrations/024-collapse-approvals.ts +182 -0
  284. package/src/db/migrations/025-secret-mode-check.test.ts +155 -0
  285. package/src/db/migrations/025-secret-mode-check.ts +49 -0
  286. package/src/db/migrations/026-user-dms-bot-id.test.ts +116 -0
  287. package/src/db/migrations/026-user-dms-bot-id.ts +54 -0
  288. package/src/db/migrations/027-provider-credentials.ts +41 -0
  289. package/src/db/migrations/_test-helpers.ts +41 -0
  290. package/src/db/migrations/index.ts +127 -0
  291. package/src/db/migrations/module-agent-to-agent-destinations.ts +84 -0
  292. package/src/db/migrations/module-approvals-pending-approvals.ts +42 -0
  293. package/src/db/migrations/module-approvals-title-options.ts +40 -0
  294. package/src/db/schema.ts +258 -0
  295. package/src/db/session-db.test.ts +93 -0
  296. package/src/db/session-db.ts +325 -0
  297. package/src/db/sessions.ts +241 -0
  298. package/src/delivery.test.ts +148 -0
  299. package/src/delivery.ts +445 -0
  300. package/src/env.ts +74 -0
  301. package/src/group-folder.test.ts +35 -0
  302. package/src/group-folder.ts +44 -0
  303. package/src/group-init.ts +92 -0
  304. package/src/host-core.test.ts +456 -0
  305. package/src/host-sweep.test.ts +146 -0
  306. package/src/host-sweep.ts +287 -0
  307. package/src/index.ts +227 -0
  308. package/src/install-slug.ts +33 -0
  309. package/src/log.test.ts +81 -0
  310. package/src/log.ts +117 -0
  311. package/src/mcp/http.ts +72 -0
  312. package/src/mcp/server.ts +92 -0
  313. package/src/mcp/stdio.ts +51 -0
  314. package/src/mcp/tools/activity.ts +88 -0
  315. package/src/mcp/tools/agent-groups.ts +183 -0
  316. package/src/mcp/tools/approvals.ts +122 -0
  317. package/src/mcp/tools/channels.ts +199 -0
  318. package/src/mcp/tools/index.ts +27 -0
  319. package/src/mcp/tools/oauth.ts +48 -0
  320. package/src/mcp/tools/secrets.ts +169 -0
  321. package/src/mcp/tools/sessions.ts +135 -0
  322. package/src/mcp/types.ts +51 -0
  323. package/src/modules/agent-to-agent/agent-route.test.ts +46 -0
  324. package/src/modules/agent-to-agent/agent-route.ts +223 -0
  325. package/src/modules/agent-to-agent/create-agent.ts +127 -0
  326. package/src/modules/agent-to-agent/db/agent-destinations.ts +135 -0
  327. package/src/modules/agent-to-agent/index.ts +22 -0
  328. package/src/modules/agent-to-agent/write-destinations.ts +59 -0
  329. package/src/modules/approvals/agent.md +45 -0
  330. package/src/modules/approvals/index.ts +21 -0
  331. package/src/modules/approvals/picks.test.ts +291 -0
  332. package/src/modules/approvals/primitive.ts +279 -0
  333. package/src/modules/approvals/project.md +27 -0
  334. package/src/modules/approvals/response-handler.ts +87 -0
  335. package/src/modules/index.ts +24 -0
  336. package/src/modules/interactive/agent.md +21 -0
  337. package/src/modules/interactive/index.ts +69 -0
  338. package/src/modules/interactive/project.md +12 -0
  339. package/src/modules/mount-security/index.ts +448 -0
  340. package/src/modules/mount-security/migrate.test.ts +91 -0
  341. package/src/modules/permissions/access.ts +28 -0
  342. package/src/modules/permissions/channel-approval.test.ts +389 -0
  343. package/src/modules/permissions/channel-approval.ts +188 -0
  344. package/src/modules/permissions/db/agent-group-members.ts +44 -0
  345. package/src/modules/permissions/db/pending-channel-approvals.test.ts +86 -0
  346. package/src/modules/permissions/db/pending-channel-approvals.ts +66 -0
  347. package/src/modules/permissions/db/pending-sender-approvals.ts +60 -0
  348. package/src/modules/permissions/db/user-dms.ts +58 -0
  349. package/src/modules/permissions/db/user-roles.ts +85 -0
  350. package/src/modules/permissions/db/users.ts +38 -0
  351. package/src/modules/permissions/index.ts +421 -0
  352. package/src/modules/permissions/permissions.test.ts +358 -0
  353. package/src/modules/permissions/sender-approval.test.ts +470 -0
  354. package/src/modules/permissions/sender-approval.ts +165 -0
  355. package/src/modules/permissions/user-dm.ts +200 -0
  356. package/src/modules/provider-credentials/db.ts +121 -0
  357. package/src/modules/provider-credentials/index.ts +12 -0
  358. package/src/modules/provider-credentials/spawn.test.ts +206 -0
  359. package/src/modules/provider-credentials/spawn.ts +114 -0
  360. package/src/modules/scheduling/actions.ts +113 -0
  361. package/src/modules/scheduling/db.test.ts +282 -0
  362. package/src/modules/scheduling/db.ts +148 -0
  363. package/src/modules/scheduling/index.ts +34 -0
  364. package/src/modules/scheduling/recurrence.test.ts +98 -0
  365. package/src/modules/scheduling/recurrence.ts +54 -0
  366. package/src/modules/self-mod/agent.md +30 -0
  367. package/src/modules/self-mod/apply.ts +85 -0
  368. package/src/modules/self-mod/index.ts +30 -0
  369. package/src/modules/self-mod/project.md +39 -0
  370. package/src/modules/self-mod/request.ts +91 -0
  371. package/src/modules/typing/index.ts +165 -0
  372. package/src/oauth/agent-app-connections.ts +103 -0
  373. package/src/oauth/app-configs.test.ts +64 -0
  374. package/src/oauth/app-configs.ts +114 -0
  375. package/src/oauth/app-connections.test.ts +109 -0
  376. package/src/oauth/app-connections.ts +178 -0
  377. package/src/oauth/crypto.ts +56 -0
  378. package/src/oauth/flow.ts +104 -0
  379. package/src/oauth/providers/google.test.ts +38 -0
  380. package/src/oauth/providers/google.ts +46 -0
  381. package/src/oauth/providers/index.ts +48 -0
  382. package/src/oauth/state-store.test.ts +54 -0
  383. package/src/oauth/state-store.ts +93 -0
  384. package/src/parachute/README.md +27 -0
  385. package/src/parachute/create-agent.test.ts +83 -0
  386. package/src/parachute/create-agent.ts +122 -0
  387. package/src/parachute/group-status.test.ts +165 -0
  388. package/src/parachute/group-status.ts +136 -0
  389. package/src/parachute/types.ts +41 -0
  390. package/src/parachute/vault-mcp.test.ts +251 -0
  391. package/src/parachute/vault-mcp.ts +232 -0
  392. package/src/platform-id.test.ts +104 -0
  393. package/src/platform-id.ts +109 -0
  394. package/src/providers/index.ts +6 -0
  395. package/src/providers/provider-container-registry.ts +58 -0
  396. package/src/response-registry.ts +45 -0
  397. package/src/router.ts +530 -0
  398. package/src/secrets/crypto.test.ts +45 -0
  399. package/src/secrets/crypto.ts +55 -0
  400. package/src/secrets/index.ts +355 -0
  401. package/src/secrets/master-key.ts +70 -0
  402. package/src/secrets/secrets.test.ts +354 -0
  403. package/src/session-manager.migrate.test.ts +59 -0
  404. package/src/session-manager.ts +433 -0
  405. package/src/startup-bootstrap.test.ts +226 -0
  406. package/src/startup-bootstrap.ts +207 -0
  407. package/src/state-sqlite.ts +182 -0
  408. package/src/timezone.test.ts +64 -0
  409. package/src/timezone.ts +37 -0
  410. package/src/types.ts +230 -0
  411. package/src/web/auth.test.ts +335 -0
  412. package/src/web/auth.ts +214 -0
  413. package/src/web/discord-validate.test.ts +77 -0
  414. package/src/web/discord-validate.ts +88 -0
  415. package/src/web/hub-discovery.test.ts +98 -0
  416. package/src/web/hub-discovery.ts +69 -0
  417. package/src/web/routes/activity.ts +106 -0
  418. package/src/web/routes/agent-provider.test.ts +282 -0
  419. package/src/web/routes/agent-provider.ts +309 -0
  420. package/src/web/routes/approvals.ts +185 -0
  421. package/src/web/routes/apps.ts +434 -0
  422. package/src/web/routes/channels-mg-detail.test.ts +324 -0
  423. package/src/web/routes/channels-mga-detail.test.ts +425 -0
  424. package/src/web/routes/channels.ts +489 -0
  425. package/src/web/routes/oauth-providers.ts +42 -0
  426. package/src/web/routes/secrets.test.ts +175 -0
  427. package/src/web/routes/secrets.ts +282 -0
  428. package/src/web/routes/sessions.ts +123 -0
  429. package/src/web/routes/settings.test.ts +106 -0
  430. package/src/web/routes/settings.ts +247 -0
  431. package/src/web/routes/setup-status.ts +205 -0
  432. package/src/web/routes/vaults.test.ts +389 -0
  433. package/src/web/routes/vaults.ts +225 -0
  434. package/src/web/server-version.test.ts +16 -0
  435. package/src/web/server.ts +1003 -0
  436. package/src/web/services-manifest.test.ts +120 -0
  437. package/src/web/services-manifest.ts +61 -0
  438. package/src/web/static-serve.test.ts +255 -0
  439. package/src/web/static-serve.ts +104 -0
  440. package/src/web/telegram-validate.test.ts +116 -0
  441. package/src/web/telegram-validate.ts +107 -0
  442. package/src/web/vault-proxy.test.ts +214 -0
  443. package/src/web/vault-proxy.ts +120 -0
  444. package/src/web/wire-channel.ts +181 -0
  445. package/src/webhook-server.ts +134 -0
  446. package/tsconfig.json +21 -0
  447. package/vitest.config.ts +18 -0
  448. package/web/README.md +63 -0
  449. package/web/ui/index.html +13 -0
  450. package/web/ui/package.json +35 -0
  451. package/web/ui/pnpm-lock.yaml +2164 -0
  452. package/web/ui/scripts/verify-base.mjs +31 -0
  453. package/web/ui/src/App.tsx +88 -0
  454. package/web/ui/src/components/ActivityFeed.tsx +444 -0
  455. package/web/ui/src/components/AgentGroupPicker.tsx +263 -0
  456. package/web/ui/src/components/AgentProviderCards.tsx +220 -0
  457. package/web/ui/src/components/CredentialForm.tsx +214 -0
  458. package/web/ui/src/components/ScopeGrants.tsx +74 -0
  459. package/web/ui/src/components/StatusDot.tsx +43 -0
  460. package/web/ui/src/components/VaultPicker.tsx +127 -0
  461. package/web/ui/src/components/setup/AdapterInstallStep.tsx +178 -0
  462. package/web/ui/src/components/setup/AgentGroupStep.tsx +43 -0
  463. package/web/ui/src/components/setup/ChannelPickStep.tsx +74 -0
  464. package/web/ui/src/components/setup/DoneStep.tsx +49 -0
  465. package/web/ui/src/components/setup/PrereqStep.tsx +129 -0
  466. package/web/ui/src/components/setup/TestConnectionStep.tsx +108 -0
  467. package/web/ui/src/components/setup/TestMessageStep.tsx +104 -0
  468. package/web/ui/src/components/setup/WireChannelStep.tsx +166 -0
  469. package/web/ui/src/components/setup/types.ts +105 -0
  470. package/web/ui/src/lib/api.test.ts +410 -0
  471. package/web/ui/src/lib/api.ts +1210 -0
  472. package/web/ui/src/lib/auth.test.ts +139 -0
  473. package/web/ui/src/lib/auth.ts +348 -0
  474. package/web/ui/src/lib/channel-adapters.ts +136 -0
  475. package/web/ui/src/main.tsx +19 -0
  476. package/web/ui/src/routes/ApprovalsList.tsx +294 -0
  477. package/web/ui/src/routes/Apps.tsx +613 -0
  478. package/web/ui/src/routes/ChannelWireDetail.test.tsx +233 -0
  479. package/web/ui/src/routes/ChannelWireDetail.tsx +403 -0
  480. package/web/ui/src/routes/ChannelsList.tsx +158 -0
  481. package/web/ui/src/routes/GroupDetail.tsx +755 -0
  482. package/web/ui/src/routes/GroupList.tsx +187 -0
  483. package/web/ui/src/routes/MessagingGroupDetail.test.tsx +233 -0
  484. package/web/ui/src/routes/MessagingGroupDetail.tsx +306 -0
  485. package/web/ui/src/routes/NewGroupWizard.tsx +390 -0
  486. package/web/ui/src/routes/OAuthCallback.tsx +56 -0
  487. package/web/ui/src/routes/SecretsList.tsx +921 -0
  488. package/web/ui/src/routes/SessionsList.tsx +220 -0
  489. package/web/ui/src/routes/SettingsAgentProvider.tsx +109 -0
  490. package/web/ui/src/routes/SettingsApprovals.tsx +234 -0
  491. package/web/ui/src/routes/SetupWizard.tsx +219 -0
  492. package/web/ui/src/routes/VaultDetail.test.tsx +361 -0
  493. package/web/ui/src/routes/VaultDetail.tsx +960 -0
  494. package/web/ui/src/routes/VaultsList.tsx +295 -0
  495. package/web/ui/src/routes/WireChannelPage.tsx +413 -0
  496. package/web/ui/src/styles.css +608 -0
  497. package/web/ui/src/test/setup.ts +23 -0
  498. package/web/ui/src/vite-env.d.ts +10 -0
  499. package/web/ui/tsconfig.json +20 -0
  500. package/web/ui/vite.config.ts +34 -0
  501. package/web/ui/vitest.config.ts +25 -0
@@ -0,0 +1,359 @@
1
+ # Running Paraclaw in Docker Sandboxes (Manual Setup)
2
+
3
+ This guide walks through setting up Paraclaw inside a [Docker Sandbox](https://docs.docker.com/ai/sandboxes/) from scratch — no install script, no pre-built fork. You'll clone the upstream repo, apply the necessary patches, and have agents running in full hypervisor-level isolation.
4
+
5
+ ## Architecture
6
+
7
+ ```
8
+ Host (macOS / Windows WSL)
9
+ └── Docker Sandbox (micro VM with isolated kernel)
10
+ ├── Paraclaw process (Node.js)
11
+ │ ├── Channel adapters (WhatsApp, Telegram, etc.)
12
+ │ └── Container spawner → nested Docker daemon
13
+ └── Docker-in-Docker
14
+ └── paraclaw-agent containers
15
+ └── Claude Agent SDK
16
+ ```
17
+
18
+ Each agent runs in its own container, inside a micro VM that is fully isolated from your host. Two layers of isolation: per-agent containers + the VM boundary.
19
+
20
+ The sandbox provides a MITM proxy at `host.docker.internal:3128` that handles network access and injects your Anthropic API key automatically.
21
+
22
+ > **Note:** This guide is based on a validated setup running on macOS (Apple Silicon) with WhatsApp. Other channels (Telegram, Slack, etc.) and environments (Windows WSL) may require additional proxy patches for their specific HTTP/WebSocket clients. The core patches (container runner, credential proxy, Dockerfile) apply universally — channel-specific proxy configuration varies.
23
+
24
+ ## Prerequisites
25
+
26
+ - **Docker Desktop v4.40+** with Sandbox support
27
+ - **Anthropic API key** (the sandbox proxy manages injection)
28
+ - For **Telegram**: a bot token from [@BotFather](https://t.me/BotFather) and your chat ID
29
+ - For **WhatsApp**: a phone with WhatsApp installed
30
+
31
+ Verify sandbox support:
32
+ ```bash
33
+ docker sandbox version
34
+ ```
35
+
36
+ ## Step 1: Create the Sandbox
37
+
38
+ On your host machine:
39
+
40
+ ```bash
41
+ # Create a workspace directory
42
+ mkdir -p ~/paraclaw-workspace
43
+
44
+ # Create a shell sandbox with the workspace mounted
45
+ docker sandbox create shell ~/paraclaw-workspace
46
+ ```
47
+
48
+ If you're using WhatsApp, configure proxy bypass so WhatsApp's Noise protocol isn't MITM-inspected:
49
+
50
+ ```bash
51
+ docker sandbox network proxy shell-paraclaw-workspace \
52
+ --bypass-host web.whatsapp.com \
53
+ --bypass-host "*.whatsapp.com" \
54
+ --bypass-host "*.whatsapp.net"
55
+ ```
56
+
57
+ Telegram does not need proxy bypass.
58
+
59
+ Enter the sandbox:
60
+ ```bash
61
+ docker sandbox run shell-paraclaw-workspace
62
+ ```
63
+
64
+ ## Step 2: Install Prerequisites
65
+
66
+ Inside the sandbox:
67
+
68
+ ```bash
69
+ sudo apt-get update && sudo apt-get install -y build-essential python3
70
+ npm config set strict-ssl false
71
+ ```
72
+
73
+ ## Step 3: Clone and Install Paraclaw
74
+
75
+ Paraclaw must live inside the workspace directory — Docker-in-Docker can only bind-mount from the shared workspace path.
76
+
77
+ ```bash
78
+ # Clone to home first (virtiofs can corrupt git pack files during clone)
79
+ cd ~
80
+ git clone https://github.com/ParachuteComputer/paraclaw.git
81
+
82
+ # Replace with YOUR workspace path (the host path you passed to `docker sandbox create`)
83
+ WORKSPACE=/Users/you/paraclaw-workspace
84
+
85
+ # Move into workspace so DinD mounts work
86
+ mv paraclaw "$WORKSPACE/paraclaw"
87
+ cd "$WORKSPACE/paraclaw"
88
+
89
+ # Install dependencies
90
+ pnpm install
91
+ pnpm install https-proxy-agent
92
+ ```
93
+
94
+ ## Step 4: Apply Proxy and Sandbox Patches
95
+
96
+ Paraclaw needs several patches to work inside a Docker Sandbox. These handle proxy routing, CA certificates, and Docker-in-Docker mount restrictions.
97
+
98
+ ### 4a. Dockerfile — proxy args for container image build
99
+
100
+ `pnpm install` inside `docker build` fails with `SELF_SIGNED_CERT_IN_CHAIN` because the sandbox's MITM proxy presents its own certificate. Add proxy build args to `container/Dockerfile`:
101
+
102
+ Add these lines after the `FROM` line:
103
+
104
+ ```dockerfile
105
+ # Accept proxy build args
106
+ ARG http_proxy
107
+ ARG https_proxy
108
+ ARG no_proxy
109
+ ARG NODE_EXTRA_CA_CERTS
110
+ ARG npm_config_strict_ssl=true
111
+ RUN npm config set strict-ssl ${npm_config_strict_ssl}
112
+ ```
113
+
114
+ And after the `RUN pnpm install` line:
115
+
116
+ ```dockerfile
117
+ RUN npm config set strict-ssl true
118
+ ```
119
+
120
+ ### 4b. Build script — forward proxy args
121
+
122
+ Patch `container/build.sh` to pass proxy env vars to `docker build`:
123
+
124
+ Add these `--build-arg` flags to the `docker build` command:
125
+
126
+ ```bash
127
+ --build-arg http_proxy="${http_proxy:-$HTTP_PROXY}" \
128
+ --build-arg https_proxy="${https_proxy:-$HTTPS_PROXY}" \
129
+ --build-arg no_proxy="${no_proxy:-$NO_PROXY}" \
130
+ --build-arg npm_config_strict_ssl=false \
131
+ ```
132
+
133
+ ### 4c. Container runner — proxy forwarding, CA cert mount, /dev/null fix
134
+
135
+ Three changes to `src/container-runner.ts`:
136
+
137
+ **Replace `/dev/null` shadow mount.** The sandbox rejects `/dev/null` bind mounts. Find where `.env` is shadow-mounted to `/dev/null` and replace it with an empty file:
138
+
139
+ ```typescript
140
+ // Create an empty file to shadow .env (Docker Sandbox rejects /dev/null mounts)
141
+ const emptyEnvPath = path.join(DATA_DIR, 'empty-env');
142
+ if (!fs.existsSync(emptyEnvPath)) fs.writeFileSync(emptyEnvPath, '');
143
+ // Use emptyEnvPath instead of '/dev/null' in the mount
144
+ ```
145
+
146
+ **Forward proxy env vars** to spawned agent containers. Add `-e` flags for `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` and their lowercase variants.
147
+
148
+ **Mount CA certificate.** If `NODE_EXTRA_CA_CERTS` or `SSL_CERT_FILE` is set, copy the cert into the project directory and mount it into agent containers:
149
+
150
+ ```typescript
151
+ const caCertSrc = process.env.NODE_EXTRA_CA_CERTS || process.env.SSL_CERT_FILE;
152
+ if (caCertSrc) {
153
+ const certDir = path.join(DATA_DIR, 'ca-cert');
154
+ fs.mkdirSync(certDir, { recursive: true });
155
+ fs.copyFileSync(caCertSrc, path.join(certDir, 'proxy-ca.crt'));
156
+ // Mount: certDir -> /workspace/ca-cert (read-only)
157
+ // Set NODE_EXTRA_CA_CERTS=/workspace/ca-cert/proxy-ca.crt in the container
158
+ }
159
+ ```
160
+
161
+ ### 4d. Container runtime — prevent self-termination
162
+
163
+ In `src/container-runtime.ts`, the `cleanupOrphans()` function matches containers by the `paraclaw-install=<slug>` label. Inside a sandbox, the sandbox container itself may match. Filter out the current hostname:
164
+
165
+ ```typescript
166
+ // In cleanupOrphans(), filter out os.hostname() from the list of containers to stop
167
+ ```
168
+
169
+ ### 4e. Credential proxy — route through MITM proxy
170
+
171
+ In `src/credential-proxy.ts`, upstream API requests need to go through the sandbox proxy. Add `HttpsProxyAgent` to outbound requests:
172
+
173
+ ```typescript
174
+ import { HttpsProxyAgent } from 'https-proxy-agent';
175
+
176
+ const proxyUrl = process.env.HTTPS_PROXY || process.env.https_proxy;
177
+ const upstreamAgent = proxyUrl ? new HttpsProxyAgent(proxyUrl) : undefined;
178
+ // Pass upstreamAgent to https.request() options
179
+ ```
180
+
181
+ ### 4f. Setup script — proxy build args
182
+
183
+ Patch `setup/container.ts` to pass the same proxy `--build-arg` flags as `build.sh` (Step 4b).
184
+
185
+ ## Step 5: Build
186
+
187
+ ```bash
188
+ pnpm run build
189
+ bash container/build.sh
190
+ ```
191
+
192
+ ## Step 6: Add a Channel
193
+
194
+ ### Telegram
195
+
196
+ ```bash
197
+ # Apply the Telegram skill
198
+ pnpm exec tsx scripts/apply-skill.ts .claude/skills/add-telegram
199
+
200
+ # Rebuild after applying the skill
201
+ pnpm run build
202
+
203
+ # Configure .env
204
+ cat > .env << EOF
205
+ TELEGRAM_BOT_TOKEN=<your-token-from-botfather>
206
+ ASSISTANT_NAME=paraclaw
207
+ ANTHROPIC_API_KEY=proxy-managed
208
+ EOF
209
+ mkdir -p data/env && cp .env data/env/env
210
+
211
+ # Register your chat
212
+ pnpm exec tsx setup/index.ts --step register \
213
+ --jid "tg:<your-chat-id>" \
214
+ --name "My Chat" \
215
+ --trigger "@paraclaw" \
216
+ --folder "telegram_main" \
217
+ --channel telegram \
218
+ --assistant-name "paraclaw" \
219
+ --is-main \
220
+ --no-trigger-required
221
+ ```
222
+
223
+ **To find your chat ID:** Send any message to your bot, then:
224
+ ```bash
225
+ curl -s --proxy $HTTPS_PROXY "https://api.telegram.org/bot<TOKEN>/getUpdates" | python3 -m json.tool
226
+ ```
227
+
228
+ **Telegram in groups:** Disable Group Privacy in @BotFather (`/mybots` > Bot Settings > Group Privacy > Turn off), then remove and re-add the bot.
229
+
230
+ **Important:** If the Telegram skill creates `src/channels/telegram.ts`, you'll need to patch it for proxy support. Add an `HttpsProxyAgent` and pass it to grammy's `Bot` constructor via `baseFetchConfig.agent`. Then rebuild.
231
+
232
+ ### WhatsApp
233
+
234
+ Make sure you configured proxy bypass in [Step 1](#step-1-create-the-sandbox) first.
235
+
236
+ ```bash
237
+ # Apply the WhatsApp skill
238
+ pnpm exec tsx scripts/apply-skill.ts .claude/skills/add-whatsapp
239
+
240
+ # Rebuild
241
+ pnpm run build
242
+
243
+ # Configure .env
244
+ cat > .env << EOF
245
+ ASSISTANT_NAME=paraclaw
246
+ ANTHROPIC_API_KEY=proxy-managed
247
+ EOF
248
+ mkdir -p data/env && cp .env data/env/env
249
+
250
+ # Authenticate (choose one):
251
+
252
+ # QR code — scan with WhatsApp camera:
253
+ pnpm exec tsx src/whatsapp-auth.ts
254
+
255
+ # OR pairing code — enter code in WhatsApp > Linked Devices > Link with phone number:
256
+ pnpm exec tsx src/whatsapp-auth.ts --pairing-code --phone <phone-number-no-plus>
257
+
258
+ # Register your chat (JID = your phone number + @s.whatsapp.net)
259
+ pnpm exec tsx setup/index.ts --step register \
260
+ --jid "<phone>@s.whatsapp.net" \
261
+ --name "My Chat" \
262
+ --trigger "@paraclaw" \
263
+ --folder "whatsapp_main" \
264
+ --channel whatsapp \
265
+ --assistant-name "paraclaw" \
266
+ --is-main \
267
+ --no-trigger-required
268
+ ```
269
+
270
+ **Important:** The WhatsApp skill files (`src/channels/whatsapp.ts` and `src/whatsapp-auth.ts`) also need proxy patches — add `HttpsProxyAgent` for WebSocket connections and a proxy-aware version fetch. Then rebuild.
271
+
272
+ ### Both Channels
273
+
274
+ Apply both skills, patch both for proxy support, combine the `.env` variables, and register each chat separately.
275
+
276
+ ## Step 7: Run
277
+
278
+ ```bash
279
+ pnpm start
280
+ ```
281
+
282
+ You don't need to set `ANTHROPIC_API_KEY` manually. The sandbox proxy intercepts requests and replaces `proxy-managed` with your real key automatically.
283
+
284
+ ## Networking Details
285
+
286
+ ### How the proxy works
287
+
288
+ All traffic from the sandbox routes through the host proxy at `host.docker.internal:3128`:
289
+
290
+ ```
291
+ Agent container → DinD bridge → Sandbox VM → host.docker.internal:3128 → Host proxy → api.anthropic.com
292
+ ```
293
+
294
+ **"Bypass" does not mean traffic skips the proxy.** It means the proxy passes traffic through without MITM inspection. Node.js doesn't automatically use `HTTP_PROXY` env vars — you need explicit `HttpsProxyAgent` configuration in every HTTP/WebSocket client.
295
+
296
+ ### Shared paths for DinD mounts
297
+
298
+ Only the workspace directory is available for Docker-in-Docker bind mounts. Paths outside the workspace fail with "path not shared":
299
+ - `/dev/null` → replace with an empty file in the project dir
300
+ - `/usr/local/share/ca-certificates/` → copy cert to project dir
301
+ - `/home/agent/` → clone to workspace instead
302
+
303
+ ### Git clone and virtiofs
304
+
305
+ The workspace is mounted via virtiofs. Git's pack file handling can corrupt over virtiofs during clone. Workaround: clone to `/home/agent` first, then `mv` into the workspace.
306
+
307
+ ## Troubleshooting
308
+
309
+ ### pnpm install fails with SELF_SIGNED_CERT_IN_CHAIN
310
+ ```bash
311
+ npm config set strict-ssl false
312
+ ```
313
+
314
+ ### Container build fails with proxy errors
315
+ ```bash
316
+ docker build \
317
+ --build-arg http_proxy=$http_proxy \
318
+ --build-arg https_proxy=$https_proxy \
319
+ -t paraclaw-agent:latest container/
320
+ ```
321
+
322
+ ### Agent containers fail with "path not shared"
323
+ All bind-mounted paths must be under the workspace directory. Check:
324
+ - Is Paraclaw cloned into the workspace? (not `/home/agent/`)
325
+ - Is the CA cert copied to the project root?
326
+ - Has the empty `.env` shadow file been created?
327
+
328
+ ### Agent containers can't reach Anthropic API
329
+ Verify proxy env vars are forwarded to agent containers. Check container logs for `HTTP_PROXY=http://host.docker.internal:3128`.
330
+
331
+ ### WhatsApp error 405
332
+ The version fetch is returning a stale version. Make sure the proxy-aware `fetchWaVersionViaProxy` patch is applied — it fetches `sw.js` through `HttpsProxyAgent` and parses `client_revision`.
333
+
334
+ ### WhatsApp "Connection failed" immediately
335
+ Proxy bypass not configured. From the **host**, run:
336
+ ```bash
337
+ docker sandbox network proxy <sandbox-name> \
338
+ --bypass-host web.whatsapp.com \
339
+ --bypass-host "*.whatsapp.com" \
340
+ --bypass-host "*.whatsapp.net"
341
+ ```
342
+
343
+ ### Telegram bot doesn't receive messages
344
+ 1. Check the grammy proxy patch is applied (look for `HttpsProxyAgent` in `src/channels/telegram.ts`)
345
+ 2. Check Group Privacy is disabled in @BotFather if using in groups
346
+
347
+ ### Git clone fails with "inflate: data stream error"
348
+ Clone to a non-workspace path first, then move:
349
+ ```bash
350
+ cd ~ && git clone https://github.com/ParachuteComputer/paraclaw.git && mv paraclaw /path/to/workspace/paraclaw
351
+ ```
352
+
353
+ ### WhatsApp QR code doesn't display
354
+ Run the auth command interactively inside the sandbox (not piped through `docker sandbox exec`):
355
+ ```bash
356
+ docker sandbox run shell-paraclaw-workspace
357
+ # Then inside:
358
+ pnpm exec tsx src/whatsapp-auth.ts
359
+ ```
@@ -0,0 +1,88 @@
1
+ # Channel Isolation Model
2
+
3
+ Paraclaw decouples messaging channels from agent groups. When you connect a channel (Discord, Telegram, Slack, GitHub, etc.), you decide how it relates to your existing agents. There are three isolation levels.
4
+
5
+ ## The Three Levels
6
+
7
+ ### 1. Shared Session
8
+
9
+ Multiple channels feed into the same conversation. The agent sees all messages from all channels in one thread.
10
+
11
+ **What's shared:** Everything — workspace, memory, CLAUDE.md, and the conversation itself. A GitHub PR comment and a Slack message appear side by side in the agent's context.
12
+
13
+ **Example:** A Slack channel paired with GitHub webhooks. The agent receives PR review requests via GitHub and discusses them in Slack — all in one session. When someone comments on a PR, the agent can reference the earlier Slack discussion about that feature.
14
+
15
+ **When to use:** When one channel feeds context into another. Webhook/notification channels (GitHub, Linear) paired with a chat channel (Slack, Discord) are the classic case.
16
+
17
+ **Technical:** Both messaging groups are wired to the same agent group with `session_mode: 'agent-shared'`. Session resolution looks up by agent group ID only, ignoring the messaging group — so all channels converge on one session.
18
+
19
+ ---
20
+
21
+ ### 2. Same Agent, Separate Sessions
22
+
23
+ Multiple channels share the same agent (same workspace, memory, personality) but have independent conversations.
24
+
25
+ **What's shared:** Workspace, memory, CLAUDE.md, and all persistent state. If you tell the agent something in one session, it can save that to memory and recall it in another. The agent's personality, knowledge, and tools are identical across sessions.
26
+
27
+ **What's separate:** The conversation thread. Messages from one channel don't appear in the other channel's session. Each channel has its own context window and conversation history.
28
+
29
+ **Example:** You have three Telegram chats with your agent — one for a side project, one for personal tasks, one for work. All three share the same agent workspace. If you ask it to remember your API key naming convention in the project chat, it may recall that convention in the work chat too. But the conversations themselves are independent.
30
+
31
+ **When to use:** When you're the primary (or sole) participant across channels and you want a unified agent identity. This is the most common setup for personal use across multiple platforms or multiple groups within one platform.
32
+
33
+ **Technical:** Multiple messaging groups are wired to the same agent group with `session_mode: 'shared'` (or `'per-thread'`). Each messaging group gets its own session, but they all run in the same agent group folder.
34
+
35
+ ---
36
+
37
+ ### 3. Separate Agent Groups
38
+
39
+ Each channel gets its own agent with its own workspace, memory, and personality. Nothing is shared.
40
+
41
+ **What's shared:** Nothing. The agents don't know about each other. Different CLAUDE.md, different memory, different workspace, different conversation history.
42
+
43
+ **Example:** You have a Telegram group with a friend and a Discord server for a team project. The friend shouldn't know what you discuss with your team, and vice versa. Each gets its own agent with its own memory and personality.
44
+
45
+ **When to use:** When different people are involved, or when the information in one channel should never leak to another. This is the right choice whenever there's a privacy or confidentiality boundary between channels.
46
+
47
+ **Technical:** Each channel is wired to a different agent group, each with its own folder under `groups/`. Separate containers, separate session databases, separate everything.
48
+
49
+ ---
50
+
51
+ ## How to Decide
52
+
53
+ The key question: **Are you okay with any and every piece of information from one channel being available in the other?**
54
+
55
+ - **No** → Separate agent groups (level 3)
56
+ - **Yes, and the channels should see each other's messages** → Shared session (level 1)
57
+ - **Yes, but the conversations should be independent** → Same agent, separate sessions (level 2)
58
+
59
+ ### Rules of Thumb
60
+
61
+ | Scenario | Recommended Level |
62
+ |----------|------------------|
63
+ | Just you, multiple platforms (Telegram + Discord + Slack) | Same agent, separate sessions |
64
+ | Just you, multiple groups on one platform (3 Telegram chats) | Same agent, separate sessions |
65
+ | Webhook channel + chat channel (GitHub + Slack) | Shared session |
66
+ | Channel with friend A and channel with friend B | Separate agent groups |
67
+ | Personal channel and work channel | Separate agent groups |
68
+ | Team channel with different access levels | Separate agent groups |
69
+
70
+ ### When in Doubt
71
+
72
+ If the participants are the same across channels → same agent group is usually fine.
73
+
74
+ If different people are involved → separate agent groups. Information will cross-pollinate through agent memory if you don't.
75
+
76
+ ## Entity Model
77
+
78
+ ```
79
+ agent_groups (workspace, memory, CLAUDE.md, personality)
80
+ ↕ many-to-many
81
+ messaging_groups (a specific channel/chat/group on a platform)
82
+ via
83
+ messaging_group_agents (session_mode, trigger_rules, priority)
84
+ ```
85
+
86
+ - **Shared session:** multiple messaging_groups → same agent_group, `session_mode = 'agent-shared'`
87
+ - **Same agent, separate sessions:** multiple messaging_groups → same agent_group, `session_mode = 'shared'`
88
+ - **Separate agents:** each messaging_group → different agent_group
package/docs/ollama.md ADDED
@@ -0,0 +1,79 @@
1
+ # Running Agents on Local Ollama
2
+
3
+ Paraclaw agents can be routed to a local [Ollama](https://ollama.com) instance instead of the Anthropic API. This cuts API costs to zero and keeps all inference on your hardware.
4
+
5
+ ## How It Works
6
+
7
+ Ollama exposes an Anthropic-compatible `/v1/messages` endpoint. The Claude Code CLI (which runs inside agent containers) uses the Anthropic SDK, which reads `ANTHROPIC_BASE_URL` to find the API host. Pointing that variable at Ollama is all that's needed — no new provider code, no changes to the agent runtime.
8
+
9
+ ```
10
+ ┌─────────────────────────────┐
11
+ │ Agent container │
12
+ │ │
13
+ │ Claude Code CLI │
14
+ │ ↓ ANTHROPIC_BASE_URL │
15
+ │ http://host.docker. │ ┌──────────────────┐
16
+ │ internal:11434 ───────┼─────▶│ Ollama :11434 │
17
+ │ │ │ gemma4:latest │
18
+ └─────────────────────────────┘ └──────────────────┘
19
+ ```
20
+
21
+ `host.docker.internal` is Docker's magic hostname that resolves to the host machine from inside a container — so Ollama running on your Mac or Linux box is reachable at that address.
22
+
23
+ ## Network Isolation
24
+
25
+ Setting `ANTHROPIC_BASE_URL` redirects requests but doesn't prevent a misconfigured agent from accidentally reaching `api.anthropic.com` directly. The `blockedHosts` field in `container.json` adds a Docker `--add-host` flag that resolves the domain to `0.0.0.0`, making it physically unreachable from inside the container:
26
+
27
+ ```json
28
+ "blockedHosts": ["api.anthropic.com"]
29
+ ```
30
+
31
+ With this in place, even if the model setting drifts back to a Claude model name, the API call will fail immediately rather than silently billing your account.
32
+
33
+ ## Model Selection
34
+
35
+ The Claude Code CLI reads its model from `~/.claude/settings.json` inside the container, which paraclaw bind-mounts from `data/sessions/<agent-group-id>/.claude-shared/settings.json`. Set `"model": "gemma4:latest"` (or whatever Ollama model you've pulled) there. Use the exact name from `ollama list`.
36
+
37
+ Model selection considerations for Apple Silicon:
38
+
39
+ | Model | Size | Quality | Speed (M4 Pro) |
40
+ |-------|------|---------|----------------|
41
+ | `gemma4:latest` | 12B | Good general-purpose | Fast |
42
+ | `qwen3-coder:latest` | 32B | Excellent for coding tasks | Moderate |
43
+ | `llama3.2:latest` | 3B | Basic | Very fast |
44
+
45
+ The agent uses tool calls extensively (read/write files, shell commands). Models that support tool use reliably work best. Gemma 4 and Qwen 3 Coder both handle structured tool calls well.
46
+
47
+ ## What Changes at the Code Level
48
+
49
+ Three files need to support this feature. See `/add-ollama-provider` for the exact changes.
50
+
51
+ **`src/container-config.ts`** — `ContainerConfig` interface needs `env` and `blockedHosts` fields so the per-group JSON can carry them.
52
+
53
+ **`src/container-runner.ts`** — At container spawn time, `env` entries become `-e KEY=VAL` Docker flags (applied after paraclaw's injected secret env vars so the per-group config wins), and `blockedHosts` entries become `--add-host HOST:0.0.0.0` flags.
54
+
55
+ **`container/Dockerfile`** — The container runs as the host user's uid (e.g. 501 on macOS), not as the `node` user (uid 1000). The home directory must be `chmod 777` so any uid can write `~/.claude.json` and `~/.claude/settings.json`.
56
+
57
+ ## Tradeoffs
58
+
59
+ | | Ollama (local) | Anthropic API |
60
+ |---|---|---|
61
+ | Cost | Free | Pay-per-token |
62
+ | Privacy | Fully local | Data sent to Anthropic |
63
+ | Model quality | Good (open-weight) | Excellent (Claude) |
64
+ | Cold start | 5–30s (model load) | ~1s |
65
+ | Context window | Varies by model | 200k tokens (Sonnet) |
66
+ | Tool use reliability | Good (large models) | Excellent |
67
+ | Hardware req. | 16GB+ RAM | None |
68
+
69
+ For personal automation on capable hardware, the tradeoff favors local. For complex multi-step tasks requiring large context or high reliability, Claude is still ahead.
70
+
71
+ ## Reverting to Claude
72
+
73
+ Remove the `env` and `blockedHosts` keys from `groups/<folder>/container.json`, remove `"model"` from the shared settings file, and restart the service. No rebuild needed.
74
+
75
+ ## See Also
76
+
77
+ - `/add-ollama-provider` — step-by-step skill to configure any agent group for Ollama
78
+ - [Ollama Anthropic compatibility docs](https://ollama.com/blog/openai-compatibility) — upstream docs on the API bridge
79
+ - `docs/architecture.md` — how the container spawn and env injection pipeline works
@@ -0,0 +1,109 @@
1
+ # Parachute integration
2
+
3
+ parachute-agent is a Parachute module: it ships with a `.parachute/module.json` manifest, registers in the hub's services catalog at install, and accepts hub-issued JWTs on every `/api/*` route. This doc covers what gets wired up when you `parachute install parachute-agent`, plus how vault attachments work inside an agent group.
4
+
5
+ ## Module shape
6
+
7
+ `.parachute/module.json` declares the slot:
8
+
9
+ ```json
10
+ {
11
+ "name": "agent",
12
+ "manifestName": "parachute-agent",
13
+ "displayName": "Parachute Agent",
14
+ "kind": "frontend",
15
+ "port": 1944,
16
+ "paths": ["/agent"],
17
+ "health": "/api/health",
18
+ "startCmd": ["bun", "src/index.ts"],
19
+ "scopes": { "defines": ["agent:read", "agent:write", "agent:admin"] }
20
+ }
21
+ ```
22
+
23
+ The hub uses this to:
24
+ - Reserve port 1944 on the operator's tailnet.
25
+ - Mount the SPA at `/agent/`.
26
+ - Add `agent:read|write|admin` to its OAuth scope catalog.
27
+ - Record parachute-agent in `~/.parachute/services.json` so peer modules can discover it.
28
+
29
+ parachute-agent also publishes its own capability card at `/.well-known/parachute.json` (sourced from the manifest) for runtime discovery without hardcoding.
30
+
31
+ ## Auth
32
+
33
+ Every `/api/*` route requires a hub-issued JWT — operator token (CLI/scripts) or user OAuth (browser). Validation is via JWKS against the hub origin (`PARACHUTE_HUB_ORIGIN`, stamped on every spawned module by the hub lifecycle). Two routes stay unauthenticated: `/api/health` (operational probe) and `/api/discovery` (returns hub origin so the SPA can bootstrap OAuth without a baked-in URL).
34
+
35
+ ## Vault attachments
36
+
37
+ An agent group can attach to one or more Parachute vaults. Each attachment grants the in-container Claude Agent SDK a Parachute Vault MCP tool surface (query-notes, create-note, update-note, delete-note, list-tags, update-tag, delete-tag, find-path, vault-info).
38
+
39
+ ### Storage
40
+
41
+ Attachments are filesystem-scoped, not database-scoped. Two files per group:
42
+
43
+ - `groups/<folder>/container.json` — the container's MCP config. The vault attachment lands here as an entry under `mcpServers`:
44
+
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "parachute-vault": {
49
+ "type": "http",
50
+ "url": "http://127.0.0.1:1940/vault/default/mcp",
51
+ "headers": { "Authorization": "Bearer pvt_..." },
52
+ "instructions": "You have access to a Parachute Vault at ..."
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ - `groups/<folder>/parachute.json` — a sibling record holding metadata for the host:
59
+
60
+ ```json
61
+ {
62
+ "vault": {
63
+ "parachute-vault": {
64
+ "vaultBaseUrl": "http://127.0.0.1:1940/vault/default",
65
+ "scope": "vault:read",
66
+ "tokenLabel": "claw-research-bot",
67
+ "attachedAt": "2026-04-28T..."
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ The agent-runner reads `container.json` at spawn and passes `mcpServers` straight through to Claude Agent SDK's `query()`, which supports HTTP-transport MCPs natively.
74
+
75
+ ### Workflow
76
+
77
+ ```sh
78
+ # Mint a scoped token via the hub's vault module.
79
+ parachute vault tokens create --scope vault:read --label claw-research-bot
80
+ # → pvt_...
81
+
82
+ # Attach via parachute-agent's web UI (preferred) or CLI.
83
+ pnpm run parachute attach-vault research-bot --token pvt_... --scope vault:read
84
+
85
+ # Inspect.
86
+ pnpm run parachute status # all groups
87
+ pnpm run parachute status research-bot # one group
88
+
89
+ # Detach (does NOT revoke).
90
+ pnpm run parachute detach-vault research-bot
91
+ parachute vault tokens revoke claw-research-bot
92
+ ```
93
+
94
+ ### What this deliberately does NOT impose
95
+
96
+ - **No prescribed note layout.** The agent group has vault access; how it organizes notes is the agent's business.
97
+ - **No conflation with parachute-agent secrets.** Outbound third-party API keys (Telegram, OpenAI, etc.) live in parachute-agent's local AES-GCM secret store and get injected as container env vars. Vault is for the user's knowledge graph; the secret store is for outbound credentials. Different concerns, different layers.
98
+
99
+ ### Threat model
100
+
101
+ - **Token scope is the boundary.** A `vault:read` agent physically cannot create or delete vault notes. A `vault:write` agent cannot revoke other tokens. A `vault:admin` agent is fully trusted; use sparingly.
102
+ - **Token is plaintext on disk and inside the container.** The bearer lives in `container.json` (host) and at `/workspace/agent/container.json` (container, read-only mount). Anyone with shell access on either side can read it. Same posture as any MCP credential — once inside the container they're plaintext env vars, same as any standard process environment.
103
+ - **Revocation is per-token.** `parachute vault tokens revoke <label>` invalidates the agent's access immediately; the next request will get 401.
104
+
105
+ ## Lifecycle hooks
106
+
107
+ `parachute install`, `parachute start`, `parachute restart`, `parachute stop` — the hub drives lifecycle via the manifest. Install runs migrations, generates the master key if absent, and registers parachute-agent in the services catalog. Start runs `bun src/index.ts`.
108
+
109
+ For the full design of hub-as-issuer OAuth and the services catalog, see `parachute.computer/design/2026-04-20-hub-as-portal-oauth-and-service-catalog.md`.