@desplega.ai/agent-swarm 1.49.0 → 1.52.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 (547) hide show
  1. package/README.md +1 -1
  2. package/openapi.json +2070 -728
  3. package/package.json +10 -1
  4. package/src/agentmail/handlers.ts +65 -10
  5. package/src/agentmail/templates.ts +111 -0
  6. package/src/be/db.ts +1233 -7
  7. package/src/be/migrations/014_prompt_templates.sql +33 -0
  8. package/src/be/migrations/015_workflow_workspace.sql +3 -0
  9. package/src/be/migrations/016_active_session_runner_session.sql +4 -0
  10. package/src/be/migrations/017_channel_activity_cursors.sql +6 -0
  11. package/src/be/migrations/018_fix_seed_double_version.sql +30 -0
  12. package/src/be/migrations/019_skills.sql +65 -0
  13. package/src/be/migrations/020_approval_requests.sql +41 -0
  14. package/src/be/seed.ts +62 -0
  15. package/src/be/skill-parser.ts +70 -0
  16. package/src/be/skill-sync.ts +106 -0
  17. package/src/commands/runner.ts +320 -132
  18. package/src/commands/templates.ts +172 -0
  19. package/src/github/handlers.ts +292 -77
  20. package/src/github/mentions-aliases.test.ts +73 -0
  21. package/src/github/mentions.test.ts +3 -3
  22. package/src/github/mentions.ts +32 -6
  23. package/src/github/templates.ts +398 -0
  24. package/src/gitlab/handlers.ts +63 -22
  25. package/src/gitlab/templates.ts +140 -0
  26. package/src/heartbeat/heartbeat.ts +19 -10
  27. package/src/heartbeat/templates.ts +30 -0
  28. package/src/http/active-sessions.ts +27 -0
  29. package/src/http/approval-requests.ts +247 -0
  30. package/src/http/config.ts +3 -3
  31. package/src/http/index.ts +9 -2
  32. package/src/http/poll.ts +135 -14
  33. package/src/http/prompt-templates.ts +412 -0
  34. package/src/http/schedules.ts +35 -0
  35. package/src/http/skills.ts +479 -0
  36. package/src/http/workflows.ts +8 -0
  37. package/src/linear/sync.ts +28 -4
  38. package/src/linear/templates.ts +47 -0
  39. package/src/prompts/base-prompt.ts +41 -490
  40. package/src/prompts/registry.ts +57 -0
  41. package/src/prompts/resolver.ts +296 -0
  42. package/src/prompts/session-templates.ts +604 -0
  43. package/src/providers/claude-adapter.ts +15 -2
  44. package/src/providers/pi-mono-extension.ts +5 -1
  45. package/src/scheduler/scheduler.ts +125 -91
  46. package/src/server.ts +44 -0
  47. package/src/slack/assistant.ts +7 -4
  48. package/src/slack/channel-activity.ts +177 -0
  49. package/src/slack/handlers.ts +21 -6
  50. package/src/slack/templates.ts +55 -0
  51. package/src/tests/approval-requests.test.ts +735 -0
  52. package/src/tests/artifact-sdk.test.ts +12 -12
  53. package/src/tests/base-prompt.test.ts +49 -49
  54. package/src/tests/channel-activity.test.ts +363 -0
  55. package/src/tests/heartbeat.test.ts +1 -0
  56. package/src/tests/linear-webhook.test.ts +7 -3
  57. package/src/tests/pool-session-logs.test.ts +199 -0
  58. package/src/tests/prompt-template-github.test.ts +682 -0
  59. package/src/tests/prompt-template-remaining.test.ts +504 -0
  60. package/src/tests/prompt-template-resolver.test.ts +621 -0
  61. package/src/tests/prompt-template-session.test.ts +363 -0
  62. package/src/tests/prompt-templates-db.test.ts +616 -0
  63. package/src/tests/self-improvement.test.ts +8 -7
  64. package/src/tests/skill-parser.test.ts +178 -0
  65. package/src/tests/skill-sync.test.ts +171 -0
  66. package/src/tests/slack-metadata-inheritance.test.ts +1 -1
  67. package/src/tests/slack-thread-followups.test.ts +1 -1
  68. package/src/tests/structured-output.test.ts +0 -4
  69. package/src/tests/tool-annotations.test.ts +2 -1
  70. package/src/tests/update-profile-agentid.test.ts +248 -0
  71. package/src/tests/update-profile-auth.test.ts +195 -0
  72. package/src/tests/workflow-async-v2.test.ts +126 -4
  73. package/src/tests/workflow-definition-validation.test.ts +76 -0
  74. package/src/tests/workflow-executors.test.ts +4 -2
  75. package/src/tests/workflow-retry-v2.test.ts +1 -1
  76. package/src/tests/workflow-schedule-trigger.test.ts +104 -0
  77. package/src/tests/workflow-workspace.test.ts +272 -0
  78. package/src/tools/prompt-templates/delete.ts +86 -0
  79. package/src/tools/prompt-templates/get.ts +89 -0
  80. package/src/tools/prompt-templates/index.ts +5 -0
  81. package/src/tools/prompt-templates/list.ts +95 -0
  82. package/src/tools/prompt-templates/preview.ts +84 -0
  83. package/src/tools/prompt-templates/set.ts +117 -0
  84. package/src/tools/request-human-input.ts +106 -0
  85. package/src/tools/skills/index.ts +11 -0
  86. package/src/tools/skills/skill-create.ts +105 -0
  87. package/src/tools/skills/skill-delete.ts +67 -0
  88. package/src/tools/skills/skill-get.ts +75 -0
  89. package/src/tools/skills/skill-install-remote.ts +152 -0
  90. package/src/tools/skills/skill-install.ts +101 -0
  91. package/src/tools/skills/skill-list.ts +77 -0
  92. package/src/tools/skills/skill-publish.ts +123 -0
  93. package/src/tools/skills/skill-search.ts +43 -0
  94. package/src/tools/skills/skill-sync-remote.ts +128 -0
  95. package/src/tools/skills/skill-uninstall.ts +60 -0
  96. package/src/tools/skills/skill-update.ts +128 -0
  97. package/src/tools/store-progress.ts +22 -4
  98. package/src/tools/task-action.ts +20 -0
  99. package/src/tools/templates.ts +53 -0
  100. package/src/tools/tool-config.ts +23 -0
  101. package/src/tools/update-profile.ts +106 -34
  102. package/src/tools/workflows/create-workflow.ts +19 -1
  103. package/src/tools/workflows/update-workflow.ts +16 -1
  104. package/src/types.ts +109 -2
  105. package/src/workflows/definition.ts +30 -12
  106. package/src/workflows/engine.ts +40 -14
  107. package/src/workflows/executors/agent-task.ts +14 -3
  108. package/src/workflows/executors/human-in-the-loop.ts +160 -0
  109. package/src/workflows/executors/registry.ts +2 -0
  110. package/src/workflows/index.ts +1 -1
  111. package/src/workflows/recovery.ts +72 -0
  112. package/src/workflows/resume.ts +162 -12
  113. package/src/workflows/triggers.ts +31 -2
  114. package/src/workflows/version.ts +2 -0
  115. package/.claude/settings.json +0 -84
  116. package/.claude/settings.local.json +0 -117
  117. package/.dockerignore +0 -61
  118. package/.editorconfig +0 -15
  119. package/.entire/settings.json +0 -4
  120. package/.env.docker.example +0 -56
  121. package/.env.example +0 -78
  122. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -78
  123. package/.github/ISSUE_TEMPLATE/community-template.yml +0 -77
  124. package/.github/ISSUE_TEMPLATE/config.yml +0 -8
  125. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -60
  126. package/.github/PULL_REQUEST_TEMPLATE/community-template.md +0 -29
  127. package/.github/workflows/ci.yml +0 -52
  128. package/.github/workflows/docker-and-deploy.yml +0 -132
  129. package/.github/workflows/merge-gate.yml +0 -233
  130. package/.opencode/plugins/entire.ts +0 -133
  131. package/.superset/config.json +0 -6
  132. package/.wts-config.json +0 -4
  133. package/.wts-setup.ts +0 -171
  134. package/CHANGELOG.md +0 -447
  135. package/CLAUDE.md +0 -521
  136. package/CONTRIBUTING.md +0 -315
  137. package/DEPLOYMENT.md +0 -622
  138. package/Dockerfile +0 -65
  139. package/Dockerfile.worker +0 -189
  140. package/MCP.md +0 -841
  141. package/UI.md +0 -40
  142. package/api-entrypoint.sh +0 -56
  143. package/assets/agent-swarm-logo-orange.png +0 -0
  144. package/assets/agent-swarm-logo.png +0 -0
  145. package/assets/agent-swarm.mp4 +0 -0
  146. package/assets/agent-swarm.png +0 -0
  147. package/biome.json +0 -39
  148. package/deploy/DEPLOY.md +0 -60
  149. package/deploy/agent-swarm.service +0 -17
  150. package/deploy/docker-push.ts +0 -30
  151. package/deploy/install.ts +0 -85
  152. package/deploy/prod-db.ts +0 -42
  153. package/deploy/uninstall.ts +0 -12
  154. package/deploy/update.ts +0 -21
  155. package/depot.json +0 -1
  156. package/docker-compose.example.yml +0 -350
  157. package/docker-compose.local.yml +0 -119
  158. package/docker-entrypoint.sh +0 -632
  159. package/docs-site/app/api/search/route.ts +0 -4
  160. package/docs-site/app/docs/[[...slug]]/page.tsx +0 -87
  161. package/docs-site/app/docs/layout.tsx +0 -12
  162. package/docs-site/app/globals.css +0 -24
  163. package/docs-site/app/layout.config.tsx +0 -34
  164. package/docs-site/app/layout.tsx +0 -119
  165. package/docs-site/app/llms-full.txt/route.ts +0 -11
  166. package/docs-site/app/llms.mdx/docs/[[...slug]]/route.ts +0 -24
  167. package/docs-site/app/llms.txt/route.ts +0 -8
  168. package/docs-site/app/page.tsx +0 -5
  169. package/docs-site/app/robots.ts +0 -13
  170. package/docs-site/app/sitemap.ts +0 -37
  171. package/docs-site/components/api-page.client.tsx +0 -4
  172. package/docs-site/components/api-page.tsx +0 -7
  173. package/docs-site/components/mdx/mermaid.tsx +0 -55
  174. package/docs-site/content/docs/(documentation)/architecture/agents.mdx +0 -117
  175. package/docs-site/content/docs/(documentation)/architecture/hooks.mdx +0 -77
  176. package/docs-site/content/docs/(documentation)/architecture/memory.mdx +0 -96
  177. package/docs-site/content/docs/(documentation)/architecture/meta.json +0 -4
  178. package/docs-site/content/docs/(documentation)/architecture/overview.mdx +0 -172
  179. package/docs-site/content/docs/(documentation)/concepts/epics.mdx +0 -98
  180. package/docs-site/content/docs/(documentation)/concepts/meta.json +0 -4
  181. package/docs-site/content/docs/(documentation)/concepts/scheduling.mdx +0 -136
  182. package/docs-site/content/docs/(documentation)/concepts/services.mdx +0 -104
  183. package/docs-site/content/docs/(documentation)/concepts/task-lifecycle.mdx +0 -148
  184. package/docs-site/content/docs/(documentation)/concepts/workflows.mdx +0 -209
  185. package/docs-site/content/docs/(documentation)/contributing.mdx +0 -158
  186. package/docs-site/content/docs/(documentation)/getting-started.mdx +0 -157
  187. package/docs-site/content/docs/(documentation)/guides/agentmail-integration.mdx +0 -79
  188. package/docs-site/content/docs/(documentation)/guides/deployment.mdx +0 -171
  189. package/docs-site/content/docs/(documentation)/guides/github-integration.mdx +0 -81
  190. package/docs-site/content/docs/(documentation)/guides/gitlab-integration.mdx +0 -93
  191. package/docs-site/content/docs/(documentation)/guides/linear-integration.mdx +0 -98
  192. package/docs-site/content/docs/(documentation)/guides/meta.json +0 -13
  193. package/docs-site/content/docs/(documentation)/guides/sentry-integration.mdx +0 -52
  194. package/docs-site/content/docs/(documentation)/guides/slack-integration.mdx +0 -179
  195. package/docs-site/content/docs/(documentation)/guides/x402-payments.mdx +0 -154
  196. package/docs-site/content/docs/(documentation)/index.mdx +0 -65
  197. package/docs-site/content/docs/(documentation)/meta.json +0 -19
  198. package/docs-site/content/docs/(documentation)/reference/cli.mdx +0 -241
  199. package/docs-site/content/docs/(documentation)/reference/environment-variables.mdx +0 -205
  200. package/docs-site/content/docs/(documentation)/reference/mcp-tools.mdx +0 -449
  201. package/docs-site/content/docs/(documentation)/reference/meta.json +0 -4
  202. package/docs-site/content/docs/api-reference/active-sessions.mdx +0 -9
  203. package/docs-site/content/docs/api-reference/agents.mdx +0 -9
  204. package/docs-site/content/docs/api-reference/channels.mdx +0 -9
  205. package/docs-site/content/docs/api-reference/config.mdx +0 -9
  206. package/docs-site/content/docs/api-reference/debug.mdx +0 -9
  207. package/docs-site/content/docs/api-reference/ecosystem.mdx +0 -9
  208. package/docs-site/content/docs/api-reference/epics.mdx +0 -9
  209. package/docs-site/content/docs/api-reference/index.mdx +0 -32
  210. package/docs-site/content/docs/api-reference/memory.mdx +0 -9
  211. package/docs-site/content/docs/api-reference/meta.json +0 -25
  212. package/docs-site/content/docs/api-reference/poll.mdx +0 -9
  213. package/docs-site/content/docs/api-reference/repos.mdx +0 -9
  214. package/docs-site/content/docs/api-reference/schedules.mdx +0 -9
  215. package/docs-site/content/docs/api-reference/session-data.mdx +0 -9
  216. package/docs-site/content/docs/api-reference/stats.mdx +0 -9
  217. package/docs-site/content/docs/api-reference/tasks.mdx +0 -9
  218. package/docs-site/content/docs/api-reference/trackers.mdx +0 -9
  219. package/docs-site/content/docs/api-reference/webhooks.mdx +0 -9
  220. package/docs-site/content/docs/api-reference/workflows.mdx +0 -9
  221. package/docs-site/content/docs/meta.json +0 -3
  222. package/docs-site/lib/get-llm-text.ts +0 -10
  223. package/docs-site/lib/openapi.ts +0 -23
  224. package/docs-site/lib/source.ts +0 -8
  225. package/docs-site/mdx-components.tsx +0 -13
  226. package/docs-site/next.config.mjs +0 -29
  227. package/docs-site/package.json +0 -35
  228. package/docs-site/pnpm-lock.yaml +0 -5407
  229. package/docs-site/postcss.config.mjs +0 -8
  230. package/docs-site/public/logo.png +0 -0
  231. package/docs-site/scripts/generate-docs.ts +0 -171
  232. package/docs-site/source.config.ts +0 -17
  233. package/docs-site/tsconfig.json +0 -46
  234. package/ecosystem.config.cjs +0 -66
  235. package/landing/next.config.ts +0 -14
  236. package/landing/package.json +0 -31
  237. package/landing/pnpm-lock.yaml +0 -1091
  238. package/landing/postcss.config.mjs +0 -8
  239. package/landing/public/apple-touch-icon.png +0 -0
  240. package/landing/public/favicon.ico +0 -0
  241. package/landing/public/logo.png +0 -0
  242. package/landing/public/og-image.png +0 -0
  243. package/landing/public/omghost-desplega.svg +0 -30
  244. package/landing/public/omghost-openfort.svg +0 -9
  245. package/landing/src/app/actions/waitlist.ts +0 -25
  246. package/landing/src/app/blog/openfort-hackathon/page.tsx +0 -863
  247. package/landing/src/app/blog/page.tsx +0 -162
  248. package/landing/src/app/blog/swarm-metrics/page.tsx +0 -685
  249. package/landing/src/app/examples/page.tsx +0 -174
  250. package/landing/src/app/examples/x402/page.tsx +0 -456
  251. package/landing/src/app/globals.css +0 -122
  252. package/landing/src/app/layout.tsx +0 -134
  253. package/landing/src/app/page.tsx +0 -27
  254. package/landing/src/app/robots.ts +0 -13
  255. package/landing/src/app/sitemap.ts +0 -44
  256. package/landing/src/components/architecture.tsx +0 -163
  257. package/landing/src/components/cta.tsx +0 -52
  258. package/landing/src/components/features.tsx +0 -160
  259. package/landing/src/components/footer.tsx +0 -100
  260. package/landing/src/components/hero.tsx +0 -217
  261. package/landing/src/components/how-it-works.tsx +0 -165
  262. package/landing/src/components/navbar.tsx +0 -147
  263. package/landing/src/components/waitlist.tsx +0 -110
  264. package/landing/src/components/why-choose.tsx +0 -149
  265. package/landing/src/components/workshops.tsx +0 -328
  266. package/landing/src/lib/utils.ts +0 -6
  267. package/landing/tsconfig.json +0 -41
  268. package/misc/transcripts/2026-03-09-pi-mono-e2e-verification.md +0 -154
  269. package/new-ui/CLAUDE.md +0 -92
  270. package/new-ui/README.md +0 -73
  271. package/new-ui/biome.json +0 -42
  272. package/new-ui/components.json +0 -21
  273. package/new-ui/index.html +0 -25
  274. package/new-ui/package.json +0 -49
  275. package/new-ui/pnpm-lock.yaml +0 -4845
  276. package/new-ui/public/logo.png +0 -0
  277. package/new-ui/src/api/client.ts +0 -814
  278. package/new-ui/src/api/hooks/index.ts +0 -64
  279. package/new-ui/src/api/hooks/use-agents.ts +0 -58
  280. package/new-ui/src/api/hooks/use-channels.ts +0 -115
  281. package/new-ui/src/api/hooks/use-config-api.ts +0 -46
  282. package/new-ui/src/api/hooks/use-costs.ts +0 -122
  283. package/new-ui/src/api/hooks/use-db-query.ts +0 -29
  284. package/new-ui/src/api/hooks/use-epics.ts +0 -75
  285. package/new-ui/src/api/hooks/use-repos.ts +0 -61
  286. package/new-ui/src/api/hooks/use-schedules.ts +0 -81
  287. package/new-ui/src/api/hooks/use-services.ts +0 -16
  288. package/new-ui/src/api/hooks/use-stats.ts +0 -27
  289. package/new-ui/src/api/hooks/use-tasks.ts +0 -89
  290. package/new-ui/src/api/hooks/use-workflows.ts +0 -109
  291. package/new-ui/src/api/types.ts +0 -549
  292. package/new-ui/src/app/App.tsx +0 -13
  293. package/new-ui/src/app/providers.tsx +0 -32
  294. package/new-ui/src/app/router.tsx +0 -52
  295. package/new-ui/src/components/layout/app-header.tsx +0 -47
  296. package/new-ui/src/components/layout/app-sidebar.tsx +0 -128
  297. package/new-ui/src/components/layout/breadcrumbs.tsx +0 -57
  298. package/new-ui/src/components/layout/config-guard.tsx +0 -22
  299. package/new-ui/src/components/layout/root-layout.tsx +0 -40
  300. package/new-ui/src/components/layout/swarm-switcher.tsx +0 -85
  301. package/new-ui/src/components/shared/command-menu.tsx +0 -131
  302. package/new-ui/src/components/shared/data-grid.tsx +0 -141
  303. package/new-ui/src/components/shared/empty-state.tsx +0 -24
  304. package/new-ui/src/components/shared/error-boundary.tsx +0 -72
  305. package/new-ui/src/components/shared/json-viewer.tsx +0 -47
  306. package/new-ui/src/components/shared/name-connection-modal.tsx +0 -99
  307. package/new-ui/src/components/shared/page-skeleton.tsx +0 -16
  308. package/new-ui/src/components/shared/session-log-viewer.tsx +0 -364
  309. package/new-ui/src/components/shared/stats-bar.tsx +0 -132
  310. package/new-ui/src/components/shared/status-badge.tsx +0 -131
  311. package/new-ui/src/components/shared/usage-summary.tsx +0 -179
  312. package/new-ui/src/components/ui/alert-dialog.tsx +0 -176
  313. package/new-ui/src/components/ui/alert.tsx +0 -60
  314. package/new-ui/src/components/ui/avatar.tsx +0 -96
  315. package/new-ui/src/components/ui/badge.tsx +0 -46
  316. package/new-ui/src/components/ui/button.tsx +0 -62
  317. package/new-ui/src/components/ui/card.tsx +0 -75
  318. package/new-ui/src/components/ui/command.tsx +0 -160
  319. package/new-ui/src/components/ui/dialog.tsx +0 -143
  320. package/new-ui/src/components/ui/dropdown-menu.tsx +0 -226
  321. package/new-ui/src/components/ui/input.tsx +0 -21
  322. package/new-ui/src/components/ui/label.tsx +0 -19
  323. package/new-ui/src/components/ui/progress.tsx +0 -26
  324. package/new-ui/src/components/ui/scroll-area.tsx +0 -54
  325. package/new-ui/src/components/ui/select.tsx +0 -175
  326. package/new-ui/src/components/ui/separator.tsx +0 -28
  327. package/new-ui/src/components/ui/sheet.tsx +0 -132
  328. package/new-ui/src/components/ui/sidebar.tsx +0 -691
  329. package/new-ui/src/components/ui/skeleton.tsx +0 -13
  330. package/new-ui/src/components/ui/sonner.tsx +0 -35
  331. package/new-ui/src/components/ui/switch.tsx +0 -33
  332. package/new-ui/src/components/ui/table.tsx +0 -92
  333. package/new-ui/src/components/ui/tabs.tsx +0 -79
  334. package/new-ui/src/components/ui/textarea.tsx +0 -18
  335. package/new-ui/src/components/ui/tooltip.tsx +0 -51
  336. package/new-ui/src/components/workflows/action-node.tsx +0 -53
  337. package/new-ui/src/components/workflows/condition-node.tsx +0 -50
  338. package/new-ui/src/components/workflows/graph-utils.ts +0 -124
  339. package/new-ui/src/components/workflows/json-tree.tsx +0 -189
  340. package/new-ui/src/components/workflows/node-styles.ts +0 -10
  341. package/new-ui/src/components/workflows/step-detail-sheet.tsx +0 -87
  342. package/new-ui/src/components/workflows/trigger-node.tsx +0 -41
  343. package/new-ui/src/components/workflows/workflow-graph.tsx +0 -65
  344. package/new-ui/src/hooks/use-auto-scroll.ts +0 -82
  345. package/new-ui/src/hooks/use-config.ts +0 -203
  346. package/new-ui/src/hooks/use-keyboard-shortcuts.ts +0 -41
  347. package/new-ui/src/hooks/use-mobile.ts +0 -19
  348. package/new-ui/src/hooks/use-theme.ts +0 -60
  349. package/new-ui/src/lib/config.ts +0 -188
  350. package/new-ui/src/lib/slugs.ts +0 -71
  351. package/new-ui/src/lib/utils.ts +0 -120
  352. package/new-ui/src/main.tsx +0 -11
  353. package/new-ui/src/pages/agents/[id]/page.tsx +0 -492
  354. package/new-ui/src/pages/agents/page.tsx +0 -134
  355. package/new-ui/src/pages/chat/page.tsx +0 -674
  356. package/new-ui/src/pages/config/page.tsx +0 -1109
  357. package/new-ui/src/pages/dashboard/page.tsx +0 -454
  358. package/new-ui/src/pages/debug/page.tsx +0 -275
  359. package/new-ui/src/pages/epics/[id]/page.tsx +0 -809
  360. package/new-ui/src/pages/epics/page.tsx +0 -321
  361. package/new-ui/src/pages/not-found/page.tsx +0 -18
  362. package/new-ui/src/pages/repos/page.tsx +0 -369
  363. package/new-ui/src/pages/schedules/[id]/page.tsx +0 -664
  364. package/new-ui/src/pages/schedules/page.tsx +0 -477
  365. package/new-ui/src/pages/services/page.tsx +0 -128
  366. package/new-ui/src/pages/tasks/[id]/page.tsx +0 -670
  367. package/new-ui/src/pages/tasks/page.tsx +0 -592
  368. package/new-ui/src/pages/usage/page.tsx +0 -195
  369. package/new-ui/src/pages/workflow-runs/[id]/page.tsx +0 -363
  370. package/new-ui/src/pages/workflows/[id]/page.tsx +0 -417
  371. package/new-ui/src/pages/workflows/page.tsx +0 -266
  372. package/new-ui/src/styles/ag-grid.css +0 -36
  373. package/new-ui/src/styles/globals.css +0 -213
  374. package/new-ui/test-results/.last-run.json +0 -4
  375. package/new-ui/tsconfig.app.json +0 -34
  376. package/new-ui/tsconfig.json +0 -4
  377. package/new-ui/tsconfig.node.json +0 -26
  378. package/new-ui/vercel.json +0 -4
  379. package/new-ui/vite.config.ts +0 -28
  380. package/plugin/README.md +0 -1
  381. package/plugin/build-pi-skills.ts +0 -233
  382. package/plugin/hooks/hooks.json +0 -71
  383. package/prek.toml +0 -75
  384. package/pyproject.toml +0 -9
  385. package/scripts/check-db-boundary.sh +0 -60
  386. package/scripts/e2e-docker-provider.ts +0 -820
  387. package/scripts/e2e-io-schemas-test.ts +0 -807
  388. package/scripts/e2e-provider-test.ts +0 -220
  389. package/scripts/e2e-workflow-redesign.sh +0 -229
  390. package/scripts/e2e-workflow-test.sh +0 -285
  391. package/scripts/e2e-workflow-test.ts +0 -857
  392. package/scripts/generate-mcp-docs.ts +0 -415
  393. package/scripts/generate-openapi.ts +0 -26
  394. package/scripts/measure-tool-tokens.ts +0 -118
  395. package/scripts/x402-e2e-test.ts +0 -195
  396. package/scripts/x402-test-server.ts +0 -236
  397. package/scripts/x402-testnet-e2e.ts +0 -668
  398. package/slack-manifest.json +0 -88
  399. package/templates-ui/README.md +0 -46
  400. package/templates-ui/components.json +0 -17
  401. package/templates-ui/eslint.config.mjs +0 -18
  402. package/templates-ui/next.config.ts +0 -7
  403. package/templates-ui/package.json +0 -35
  404. package/templates-ui/pnpm-lock.yaml +0 -4571
  405. package/templates-ui/postcss.config.mjs +0 -7
  406. package/templates-ui/public/file.svg +0 -1
  407. package/templates-ui/public/globe.svg +0 -1
  408. package/templates-ui/public/logo.png +0 -0
  409. package/templates-ui/public/next.svg +0 -1
  410. package/templates-ui/public/vercel.svg +0 -1
  411. package/templates-ui/public/window.svg +0 -1
  412. package/templates-ui/src/app/[category]/[name]/page.tsx +0 -89
  413. package/templates-ui/src/app/api/templates/[...slug]/route.ts +0 -52
  414. package/templates-ui/src/app/api/templates/route.ts +0 -18
  415. package/templates-ui/src/app/builder/page.tsx +0 -37
  416. package/templates-ui/src/app/globals.css +0 -94
  417. package/templates-ui/src/app/layout.tsx +0 -79
  418. package/templates-ui/src/app/page.tsx +0 -38
  419. package/templates-ui/src/app/robots.ts +0 -11
  420. package/templates-ui/src/app/sitemap.ts +0 -31
  421. package/templates-ui/src/components/compose-builder.tsx +0 -442
  422. package/templates-ui/src/components/compose-preview.tsx +0 -117
  423. package/templates-ui/src/components/file-preview.tsx +0 -77
  424. package/templates-ui/src/components/footer.tsx +0 -40
  425. package/templates-ui/src/components/header.tsx +0 -41
  426. package/templates-ui/src/components/template-card.tsx +0 -87
  427. package/templates-ui/src/components/template-detail.tsx +0 -125
  428. package/templates-ui/src/components/template-gallery.tsx +0 -263
  429. package/templates-ui/src/components/ui/badge.tsx +0 -36
  430. package/templates-ui/src/components/ui/button.tsx +0 -57
  431. package/templates-ui/src/components/ui/card.tsx +0 -76
  432. package/templates-ui/src/components/ui/separator.tsx +0 -31
  433. package/templates-ui/src/components/ui/tooltip.tsx +0 -32
  434. package/templates-ui/src/lib/compose-generator.ts +0 -241
  435. package/templates-ui/src/lib/templates.ts +0 -137
  436. package/templates-ui/src/lib/utils.ts +0 -6
  437. package/templates-ui/tsconfig.json +0 -34
  438. package/thoughts/research/2026-02-28-openfort-viem-x402-research.md +0 -679
  439. package/thoughts/research/2026-02-28-x402-payments-research.md +0 -686
  440. package/thoughts/researcher/plans/2026-02-20-agent-self-improvement-plan.md +0 -282
  441. package/thoughts/researcher/research/2026-02-20-agent-self-improvement.md +0 -492
  442. package/thoughts/shared/plans/.gitkeep +0 -0
  443. package/thoughts/shared/plans/2025-12-18-slack-integration.md +0 -1195
  444. package/thoughts/shared/plans/2025-12-19-agent-log-streaming.md +0 -732
  445. package/thoughts/shared/plans/2025-12-19-role-based-swarm-plugin.md +0 -361
  446. package/thoughts/shared/plans/2025-12-20-mobile-responsive-ui.md +0 -501
  447. package/thoughts/shared/plans/2025-12-20-startup-team-swarm.md +0 -560
  448. package/thoughts/shared/plans/2025-12-23-runner-level-polling.md +0 -934
  449. package/thoughts/shared/plans/2025-12-23-runner-session-logs.md +0 -1000
  450. package/thoughts/shared/plans/2025-12-23-worker-lead-spawn-triggers.md +0 -568
  451. package/thoughts/shared/plans/2026-01-09-inverse-teleport.md +0 -1516
  452. package/thoughts/shared/plans/2026-01-12-agent-rename-pm2-control.md +0 -1133
  453. package/thoughts/shared/plans/2026-01-12-github-app-integration.md +0 -380
  454. package/thoughts/shared/plans/2026-01-12-lead-inbox-model.md +0 -876
  455. package/thoughts/shared/plans/2026-01-12-ralph-wiggum-integration.md +0 -463
  456. package/thoughts/shared/plans/2026-01-13-agent-concurrency.md +0 -691
  457. package/thoughts/shared/plans/2026-01-13-github-assignment-handling.md +0 -690
  458. package/thoughts/shared/plans/2026-01-13-prevent-duplicate-trigger-processing.md +0 -1071
  459. package/thoughts/shared/plans/2026-01-14-fix-slack-thread-context.md +0 -507
  460. package/thoughts/shared/plans/2026-01-15-scheduled-tasks-implementation.md +0 -565
  461. package/thoughts/shared/plans/2026-01-15-usage-cost-tracking-ui.md +0 -1479
  462. package/thoughts/shared/plans/2026-01-16-epics-feature-implementation.md +0 -1230
  463. package/thoughts/shared/plans/2026-02-26-mcp-tool-context-reduction.md +0 -282
  464. package/thoughts/shared/plans/2026-03-02-claude-context-mode-integration.md +0 -328
  465. package/thoughts/shared/plans/2026-03-02-code-level-heartbeat.md +0 -224
  466. package/thoughts/shared/research/.gitkeep +0 -0
  467. package/thoughts/shared/research/2025-01-09-inverse-teleport-plan-review.md +0 -420
  468. package/thoughts/shared/research/2025-12-18-slack-integration.md +0 -442
  469. package/thoughts/shared/research/2025-12-19-agent-log-streaming.md +0 -339
  470. package/thoughts/shared/research/2025-12-19-agent-secrets-cli-research.md +0 -390
  471. package/thoughts/shared/research/2025-12-21-gemini-cli-integration.md +0 -376
  472. package/thoughts/shared/research/2025-12-22-runner-loop-architecture.md +0 -582
  473. package/thoughts/shared/research/2025-12-22-setup-experience-improvements.md +0 -264
  474. package/thoughts/shared/research/2026-01-13-lead-duplicate-trigger-processing.md +0 -223
  475. package/thoughts/shared/research/2026-01-14-lead-slack-thread-context.md +0 -277
  476. package/thoughts/shared/research/2026-01-15-ai-tracker-agent-swarm-integration.md +0 -376
  477. package/thoughts/shared/research/2026-01-15-auto-starting-processes-in-worker-containers.md +0 -787
  478. package/thoughts/shared/research/2026-01-15-scheduled-tasks.md +0 -390
  479. package/thoughts/shared/research/2026-01-16-epics-feature-research.md +0 -437
  480. package/thoughts/shared/research/2026-02-26-cliffy-mcp-tools.md +0 -159
  481. package/thoughts/shared/research/2026-03-03-database-migration-system-refactor.md +0 -337
  482. package/thoughts/swarm-researcher/plans/2026-02-23-openclaw-improvements-plan.md +0 -778
  483. package/thoughts/swarm-researcher/plans/2026-02-26-artifacts-localtunnel-plan.md +0 -1269
  484. package/thoughts/swarm-researcher/research/2026-02-23-openclaw-vs-agent-swarm-comparison.md +0 -411
  485. package/thoughts/swarm-researcher/research/2026-02-26-artifacts-localtunnel.md +0 -724
  486. package/thoughts/taras/brainstorms/2026-03-20-prompt-template-registry.md +0 -443
  487. package/thoughts/taras/brainstorms/2026-03-20-setup-cli-onboarding.md +0 -307
  488. package/thoughts/taras/plans/2026-01-22-agent-swarm-schemas.md +0 -98
  489. package/thoughts/taras/plans/2026-01-28-per-worker-claude-md.md +0 -617
  490. package/thoughts/taras/plans/2026-01-28-sentry-cli-integration.md +0 -214
  491. package/thoughts/taras/plans/2026-02-20-auto-improvement.md +0 -803
  492. package/thoughts/taras/plans/2026-02-20-env-management.md +0 -538
  493. package/thoughts/taras/plans/2026-02-20-memory-system.md +0 -882
  494. package/thoughts/taras/plans/2026-02-20-repos-knowledge.md +0 -806
  495. package/thoughts/taras/plans/2026-02-20-session-attach.md +0 -647
  496. package/thoughts/taras/plans/2026-02-20-worker-identity.md +0 -820
  497. package/thoughts/taras/plans/2026-02-25-feat-new-ui-visual-redesign-plan.md +0 -768
  498. package/thoughts/taras/plans/2026-03-04-fix-buildSystemPrompt-missing-fields.md +0 -77
  499. package/thoughts/taras/plans/2026-03-04-new-ui-missing-actions.md +0 -543
  500. package/thoughts/taras/plans/2026-03-06-one-time-scheduled-tasks.md +0 -373
  501. package/thoughts/taras/plans/2026-03-08-memory-self-improvement-enhancements.md +0 -512
  502. package/thoughts/taras/plans/2026-03-08-pi-mono-provider-implementation.md +0 -919
  503. package/thoughts/taras/plans/2026-03-09-templates-registry.md +0 -723
  504. package/thoughts/taras/plans/2026-03-10-task-working-directory.md +0 -371
  505. package/thoughts/taras/plans/2026-03-11-archil-per-agent-write-strategy.md +0 -621
  506. package/thoughts/taras/plans/2026-03-12-eliminate-inbox-route-to-tasks.md +0 -61
  507. package/thoughts/taras/plans/2026-03-12-slack-thread-followup-additive.md +0 -488
  508. package/thoughts/taras/plans/2026-03-13-slack-ai-improvements.md +0 -644
  509. package/thoughts/taras/plans/2026-03-16-route-wrapper-openapi.md +0 -636
  510. package/thoughts/taras/plans/2026-03-17-multi-api-config.md +0 -444
  511. package/thoughts/taras/plans/2026-03-18-agent-fs-integration.md +0 -591
  512. package/thoughts/taras/plans/2026-03-18-debug-db-explorer.md +0 -446
  513. package/thoughts/taras/plans/2026-03-18-workflow-redesign.md +0 -987
  514. package/thoughts/taras/plans/2026-03-19-compound-learnings.md +0 -403
  515. package/thoughts/taras/plans/2026-03-19-ticket-tracker-linear-integration.md +0 -860
  516. package/thoughts/taras/plans/2026-03-19-workflow-io-schemas-and-bugs.md +0 -899
  517. package/thoughts/taras/plans/2026-03-20-setup-cli-onboarding.md +0 -874
  518. package/thoughts/taras/plans/2026-03-20-workflow-structured-output-validation-workspace.md +0 -723
  519. package/thoughts/taras/research/2026-01-22-vercel-cli-integration.md +0 -287
  520. package/thoughts/taras/research/2026-01-27-excessive-polling-issue.md +0 -311
  521. package/thoughts/taras/research/2026-01-28-per-worker-claude-md.md +0 -383
  522. package/thoughts/taras/research/2026-01-28-sentry-cli-integration.md +0 -240
  523. package/thoughts/taras/research/2026-02-19-agent-native-swarm-architecture.md +0 -390
  524. package/thoughts/taras/research/2026-02-19-swarm-gaps-implementation.md +0 -594
  525. package/thoughts/taras/research/2026-02-25-dashboard-ui-design-best-practices.md +0 -825
  526. package/thoughts/taras/research/2026-02-26-task-detail-page-redesign.md +0 -393
  527. package/thoughts/taras/research/2026-03-03-new-ui-missing-actions.md +0 -168
  528. package/thoughts/taras/research/2026-03-05-pi-mono-provider-research.md +0 -230
  529. package/thoughts/taras/research/2026-03-06-workflow-engine-design.md +0 -445
  530. package/thoughts/taras/research/2026-03-08-drive-loop-concept.md +0 -375
  531. package/thoughts/taras/research/2026-03-08-pi-mono-deep-dive.md +0 -869
  532. package/thoughts/taras/research/2026-03-09-templates-registry.md +0 -373
  533. package/thoughts/taras/research/2026-03-10-agent-working-directory.md +0 -223
  534. package/thoughts/taras/research/2026-03-10-configurable-event-prompts.md +0 -339
  535. package/thoughts/taras/research/2026-03-11-archil-production-setup.md +0 -181
  536. package/thoughts/taras/research/2026-03-11-archil-shared-disk-write-strategies.md +0 -437
  537. package/thoughts/taras/research/2026-03-13-slack-ai-features.md +0 -258
  538. package/thoughts/taras/research/2026-03-16-openapi-docs-generation.md +0 -335
  539. package/thoughts/taras/research/2026-03-16-route-wrapper-openapi.md +0 -670
  540. package/thoughts/taras/research/2026-03-16-slack-thread-followups-e2e.md +0 -54
  541. package/thoughts/taras/research/2026-03-18-agent-fs-integration.md +0 -558
  542. package/thoughts/taras/research/2026-03-18-linear-integration-finalization.md +0 -526
  543. package/thoughts/taras/research/2026-03-18-workflow-redesign.md +0 -797
  544. package/thoughts/taras/research/2026-03-19-workflow-node-io-schemas-and-bugs.md +0 -563
  545. package/thoughts/taras/research/2026-03-19-workflow-structured-output-validation-workspace.md +0 -486
  546. package/thoughts/taras/research/2026-03-20-prompt-template-registry.md +0 -469
  547. package/tsconfig.json +0 -37
@@ -1,724 +0,0 @@
1
- ---
2
- date: 2026-02-26T18:38:00Z
3
- topic: "Agent Artifacts: Concept & Localtunnel Research"
4
- author: "Researcher (Swarm Agent)"
5
- status: "complete"
6
- ---
7
-
8
- # Agent Artifacts: Concept & Localtunnel Research
9
-
10
- ## TL;DR
11
-
12
- **Artifacts** are a way for swarm agents to serve HTML pages, interactive apps, and rich content via public URLs. By combining dynamically allocated local ports with our localtunnel infrastructure (`lt.desplega.ai`), agents can publish multiple artifacts simultaneously — each on its own port and subdomain — that anyone with credentials can access from a browser.
13
-
14
- Our localtunnel forks already have the two key features needed: **deterministic subdomains** (with 409 conflict handling) and **HTTP Basic Auth** (per-tunnel, timing-safe). The infrastructure is ready to use today.
15
-
16
- ---
17
-
18
- ## Part 1: The Artifacts Concept
19
-
20
- ### What Are Artifacts?
21
-
22
- Artifacts are publicly accessible web content served by swarm agents. Instead of agents only communicating through Slack messages and task outputs (text), artifacts let agents produce rich, interactive deliverables:
23
-
24
- ```
25
- Agent Container (dynamic port per artifact)
26
- |
27
- | localtunnel client
28
- v
29
- lt.desplega.ai (localtunnel server)
30
- |
31
- | HTTPS + Basic Auth
32
- v
33
- Public URL: https://{agentId}.lt.desplega.ai
34
- |
35
- v
36
- Browser (human or another agent)
37
- ```
38
-
39
- ### Use Cases
40
-
41
- | Use Case | Description | Example |
42
- |----------|-------------|---------|
43
- | **Interactive reports** | Rich HTML dashboards with charts, tables, and drill-downs | PR review summary with file diffs, test coverage heatmap, dependency graph |
44
- | **Approval flows** | Forms that let humans approve/reject agent proposals | "Agent wants to merge PR #42 — Approve / Reject / Request Changes" with a button that calls the swarm API |
45
- | **Visual diffs** | Side-by-side visual comparisons | Before/after screenshots of UI changes, rendered markdown diffs |
46
- | **Forms that create tasks** | Structured input that agents can parse | "Create a new feature request" form that submits a task to the swarm |
47
- | **Live dashboards** | Real-time status pages | Swarm health dashboard, build pipeline status, Sentry issue tracker |
48
- | **Documentation previews** | Rendered docs before merge | Preview of documentation changes with live navigation |
49
- | **Data exploration** | Interactive data viewers | Log viewer, database query results with sorting/filtering |
50
-
51
- ### CLI Design — Detailed
52
-
53
- The artifact system adds a new command to the `agent-swarm` CLI (`src/cli.tsx`). It follows the existing pattern where commands like `worker`, `lead`, and `hook` dispatch to their own modules.
54
-
55
- #### `artifact serve` — Start serving content
56
-
57
- ```bash
58
- # Serve a static directory
59
- artifact serve ./dist --name "pr-review-42"
60
-
61
- # Serve a custom server script (auto-assigns a free port)
62
- artifact serve ./server.js --name "approval-flow"
63
-
64
- # Serve with explicit port (otherwise auto-assigned)
65
- artifact serve ./app.js --name "dashboard" --port 8080
66
-
67
- # Serve without auth (for public content)
68
- artifact serve ./dist --name "docs-preview" --no-auth
69
- ```
70
-
71
- | Flag | Default | Description |
72
- |------|---------|-------------|
73
- | `--name` | Required | Human-readable name for the artifact |
74
- | `--port` | auto | Local port (default: auto-assign a free port) |
75
- | `--no-auth` | `false` | Disable Basic Auth on the tunnel |
76
- | `--subdomain` | Agent UUID | Custom subdomain (overrides default) |
77
-
78
- **What happens under the hood:**
79
-
80
- 1. If path points to a directory → starts a static file server (e.g., `sirv` or `serve-handler`) on an auto-assigned free port
81
- 2. If path points to a `.js`/`.ts` file → starts it via PM2 (`pm2 start <script> --name artifact-<name>`)
82
- 3. Creates a localtunnel: `localtunnel({ port, subdomain: '${agentId}-${name}', auth: API_KEY })`
83
- - Each artifact gets its own subdomain: `{agentId}-{name}.lt.desplega.ai`
84
- - A single worker can serve multiple artifacts simultaneously on different ports/subdomains
85
- 4. Registers in service registry via `register-service` MCP tool with metadata:
86
- ```json
87
- {
88
- "type": "artifact",
89
- "artifactName": "pr-review-42",
90
- "port": 49152,
91
- "publicUrl": "https://{agentId}-pr-review-42.lt.desplega.ai",
92
- "auth": { "username": "swarm", "password": "***" }
93
- }
94
- ```
95
- 5. Posts to `#general` channel: "Artifact `pr-review-42` is live at <url>"
96
-
97
- #### `artifact list` — List active artifacts
98
-
99
- ```bash
100
- $ artifact list
101
- NAME AGENT PORT URL STATUS
102
- pr-review-42 researcher 49152 https://1699...cf73-pr-review-42.lt.desplega.ai healthy
103
- approval-flow lead 49153 https://d454...f9c3-approval-flow.lt.desplega.ai healthy
104
- dashboard picateclas 49200 https://a8b2...80f-dashboard.lt.desplega.ai unhealthy
105
- ```
106
-
107
- Queries `list-services` MCP tool, filtering for services with `metadata.type === "artifact"`.
108
-
109
- #### `artifact stop <name>` — Stop an artifact
110
-
111
- ```bash
112
- $ artifact stop pr-review-42
113
- # Stops PM2 process, closes localtunnel, unregisters service
114
- ```
115
-
116
- 1. Finds the artifact in service registry
117
- 2. `pm2 delete artifact-<name>`
118
- 3. Closes the localtunnel connection
119
- 4. `unregister-service`
120
-
121
- #### `artifact open <name>` — Open in browser
122
-
123
- ```bash
124
- $ artifact open pr-review-42
125
- # Opens https://swarm:<apikey>@1699...cf73.lt.desplega.ai in default browser
126
- ```
127
-
128
- Looks up the artifact URL from the service registry, embeds credentials, and opens via `xdg-open` (Linux) or `open` (macOS).
129
-
130
- ### Agent SDK — Detailed Design
131
-
132
- The SDK has two sides: a **server-side TypeScript API** (used by agents to create artifacts programmatically) and a **browser-side JS SDK** (injected into served HTML for interactivity).
133
-
134
- #### Server-Side SDK (`src/artifact-sdk/`)
135
-
136
- This is a TypeScript module that lives **inside the agent-swarm repo** — no npm publishing required. Since agents already run inside agent-swarm's Docker container, the SDK is available as a direct import.
137
-
138
- ```typescript
139
- import { createArtifactServer } from '../artifact-sdk';
140
-
141
- // Minimal example — serve static HTML
142
- const server = createArtifactServer({
143
- name: 'pr-review-42',
144
- // Serves files from this directory
145
- static: './dist',
146
- });
147
-
148
- await server.start();
149
- // → Finds a free port, starts server, creates tunnel, registers service
150
- // → Logs: "Artifact live at https://{agentId}-pr-review-42.lt.desplega.ai"
151
- ```
152
-
153
- ```typescript
154
- // Advanced example — custom Hono app with swarm API proxy
155
- import { createArtifactServer } from '../artifact-sdk';
156
- import { Hono } from 'hono';
157
-
158
- const app = new Hono();
159
-
160
- app.get('/', (c) => c.html(`
161
- <h1>PR Review #42</h1>
162
- <button id="approve">Approve</button>
163
- <script src="/@swarm/sdk.js"></script>
164
- <script>
165
- const swarm = new SwarmSDK();
166
- document.getElementById('approve').onclick = () =>
167
- swarm.createTask({ task: 'Merge PR #42 — approved' });
168
- </script>
169
- `));
170
-
171
- // Custom API routes (agent-specific logic)
172
- app.post('/api/approve', async (c) => {
173
- const { prNumber, comment } = await c.req.json();
174
- // Agent logic here...
175
- return c.json({ ok: true });
176
- });
177
-
178
- const server = createArtifactServer({
179
- name: 'pr-review',
180
- app, // Pass Hono app instead of static dir
181
- });
182
-
183
- await server.start();
184
- ```
185
-
186
- **`createArtifactServer(options)` internals:**
187
-
188
- ```typescript
189
- interface ArtifactServerOptions {
190
- name: string; // Artifact name (used in subdomain + registry)
191
- static?: string; // Path to static directory (mutually exclusive with app)
192
- app?: HonoApp; // Custom Hono application
193
- port?: number; // Local port (default: 0 = auto-assign free port)
194
- auth?: boolean; // Enable Basic Auth (default: true)
195
- subdomain?: string; // Custom subdomain (default: `${AGENT_ID}-${name}`)
196
- }
197
-
198
- interface ArtifactServer {
199
- start(): Promise<void>; // Start server + tunnel + register
200
- stop(): Promise<void>; // Stop everything + unregister
201
- url: string; // Public URL (available after start)
202
- port: number; // Actual port the server is listening on
203
- tunnel: LocaltunnelInstance; // Raw tunnel object
204
- }
205
- ```
206
-
207
- **What `start()` does:**
208
-
209
- 1. Creates a Hono app wrapping the user's app or static handler
210
- 2. Injects middleware:
211
- - `/@swarm/sdk.js` → serves the browser SDK bundle
212
- - `/@swarm/api/*` → proxies to the swarm MCP server HTTP API (`$MCP_BASE_URL`)
213
- - `/@swarm/config` → returns `{ agentId, artifactName }` as JSON
214
- 3. Starts HTTP server on port 0 (OS picks a free port) — or a user-specified port
215
- 4. Creates localtunnel with `{ port: server.port, subdomain: '${AGENT_ID}-${name}', auth: API_KEY }`
216
- 5. Registers via `POST $MCP_BASE_URL/api/services` (or `register-service` tool)
217
- 6. Sets up SIGTERM handler for graceful shutdown
218
-
219
- #### Browser-Side SDK (`/@swarm/sdk.js`)
220
-
221
- Auto-served by the artifact server. Provides a clean API for HTML pages to interact with the swarm.
222
-
223
- ```html
224
- <script src="/@swarm/sdk.js"></script>
225
- <script>
226
- const swarm = new SwarmSDK();
227
-
228
- // Task management
229
- await swarm.createTask({ task: 'Do something', tags: ['from-artifact'] });
230
- const tasks = await swarm.getTasks({ status: 'in_progress', limit: 10 });
231
- const detail = await swarm.getTaskDetails(taskId);
232
-
233
- // Messaging
234
- await swarm.postMessage({ channel: 'general', content: 'Hello from artifact!' });
235
- const messages = await swarm.readMessages({ channel: 'general', limit: 20 });
236
-
237
- // Agent info
238
- const agents = await swarm.getSwarm();
239
- const myAgent = await swarm.getMyAgent();
240
-
241
- // Epics
242
- const epics = await swarm.listEpics({ status: 'active' });
243
-
244
- // Services
245
- const services = await swarm.listServices();
246
- </script>
247
- ```
248
-
249
- **How it works internally:**
250
-
251
- ```javascript
252
- class SwarmSDK {
253
- constructor() {
254
- // Config is fetched from the artifact server on init
255
- this._configPromise = fetch('/@swarm/config').then(r => r.json());
256
- }
257
-
258
- async createTask(opts) {
259
- // Proxied through the artifact server to avoid CORS
260
- return this._post('/@swarm/api/tasks', opts);
261
- }
262
-
263
- async getTasks(filters) {
264
- const params = new URLSearchParams(filters);
265
- return this._get(`/@swarm/api/tasks?${params}`);
266
- }
267
-
268
- async postMessage(opts) {
269
- return this._post('/@swarm/api/messages', opts);
270
- }
271
-
272
- // ... other methods map to swarm HTTP API endpoints
273
-
274
- async _post(url, body) {
275
- const res = await fetch(url, {
276
- method: 'POST',
277
- headers: { 'Content-Type': 'application/json' },
278
- body: JSON.stringify(body),
279
- });
280
- return res.json();
281
- }
282
-
283
- async _get(url) {
284
- const res = await fetch(url);
285
- return res.json();
286
- }
287
- }
288
- ```
289
-
290
- **Security model:**
291
- - The tunnel's Basic Auth gates access to the artifact (only credentialed users can reach it)
292
- - The SDK calls go through the artifact server (`/@swarm/api/*`), which proxies to `$MCP_BASE_URL` with the agent's `Authorization` and `X-Agent-ID` headers
293
- - The browser never has direct swarm API access — the artifact server is the proxy
294
- - The agent can add middleware to filter/validate SDK requests before forwarding
295
-
296
- ### Agent Developer Experience — Step by Step
297
-
298
- Here's how an agent (e.g., Researcher) would create and serve an artifact:
299
-
300
- #### Step 1: Write the artifact content
301
-
302
- ```javascript
303
- // /workspace/personal/artifacts/pr-review/index.html
304
- // or
305
- // /workspace/personal/artifacts/pr-review/server.js
306
- ```
307
-
308
- The agent generates HTML/JS as part of its normal task work. For example, after analyzing PRs, it generates a review dashboard.
309
-
310
- #### Step 2: Serve it
311
-
312
- **Option A — Static content (simplest):**
313
- ```bash
314
- # Agent runs this via Bash tool
315
- cd /workspace/personal/artifacts/pr-review
316
- artifact serve . --name "pr-review-42"
317
- ```
318
-
319
- **Option B — Programmatic (inside a task script):**
320
- ```javascript
321
- // The agent writes and runs this script
322
- import { createArtifactServer } from '../artifact-sdk';
323
-
324
- const server = createArtifactServer({
325
- name: 'pr-review-42',
326
- static: '/workspace/personal/artifacts/pr-review',
327
- });
328
-
329
- await server.start();
330
- console.log(`Live at: ${server.url}`);
331
- ```
332
-
333
- **Option C — Custom server with interactivity:**
334
- ```javascript
335
- import { createArtifactServer } from '../artifact-sdk';
336
- import { Hono } from 'hono';
337
-
338
- const app = new Hono();
339
- app.get('/', (c) => c.html(myGeneratedHtml));
340
- app.post('/api/approve', async (c) => { /* handle approval */ });
341
-
342
- // Each artifact auto-assigns a free port and gets its own subdomain
343
- const server = createArtifactServer({ name: 'approval-flow', app });
344
- await server.start();
345
- // → Listening on port 49153, tunnel at https://{agentId}-approval-flow.lt.desplega.ai
346
-
347
- // Workers can serve multiple artifacts simultaneously:
348
- const dashboard = createArtifactServer({ name: 'dashboard', static: './dashboard-dist' });
349
- await dashboard.start();
350
- // → Listening on port 49154, tunnel at https://{agentId}-dashboard.lt.desplega.ai
351
- ```
352
-
353
- #### Step 3: Share the URL
354
-
355
- The agent posts the URL to Slack or includes it in task output:
356
-
357
- ```javascript
358
- await swarm.slackReply({
359
- taskId: currentTaskId,
360
- message: `PR review artifact ready: ${server.url}`,
361
- });
362
- ```
363
-
364
- #### Step 4: Automatic cleanup
365
-
366
- When the agent's task completes or the container restarts:
367
- - PM2 manages the artifact server process
368
- - The `Stop` hook in `src/hooks/hook.ts` could auto-close tunnels
369
- - The service registry entry is cleaned up
370
- - On container restart, PM2 auto-restarts via `ecosystem.config.cjs` from `/ecosystem` endpoint
371
-
372
- ### Integration with agent-swarm Project
373
-
374
- Here's where artifacts hooks into the existing codebase:
375
-
376
- ```
377
- src/
378
- ├── cli.tsx # Add `artifact` command dispatch
379
- ├── commands/
380
- │ ├── artifact.ts # NEW: artifact serve/list/stop/open
381
- │ └── runner.ts # No changes (artifacts are independent processes)
382
- ├── artifact-sdk/ # NEW: in-repo SDK (no npm publishing needed)
383
- │ ├── index.ts # Public exports
384
- │ ├── server.ts # createArtifactServer() — auto-assigns free port
385
- │ ├── tunnel.ts # Localtunnel wrapper — per-artifact subdomains
386
- │ ├── port.ts # Dynamic port allocation (getPort())
387
- │ ├── proxy.ts # /@swarm/api/* proxy middleware
388
- │ └── browser-sdk.ts # Browser SDK (bundled to sdk.js)
389
- ├── hooks/
390
- │ └── hook.ts # Add tunnel cleanup to Stop hook
391
- ├── tools/
392
- │ └── register-service.ts # Already handles service registration (no changes)
393
- ├── prompts/
394
- │ └── base-prompt.ts # Add BASE_PROMPT_ARTIFACTS section
395
- ├── server.ts # Add 'artifacts' capability gate
396
- └── http.ts # Add /@swarm/api proxy routes (or separate server)
397
-
398
- Dockerfile.worker # Install @desplega.ai/localtunnel globally
399
- docker-entrypoint.sh # Optional: auto-start tunnel on container boot
400
- ```
401
-
402
- > **Why in-repo?** Agents run inside agent-swarm's Docker container, so the SDK code is already available at runtime. No npm publishing, no version drift, no extra install step. Agents import directly: `import { createArtifactServer } from '../artifact-sdk'`.
403
-
404
- #### Specific integration points:
405
-
406
- | Component | File | Change |
407
- |-----------|------|--------|
408
- | **CLI command** | `src/cli.tsx` | Add `case "artifact":` dispatch to `src/commands/artifact.ts` |
409
- | **Capability** | `src/server.ts:72` | Add `"artifacts"` to default capabilities string |
410
- | **Artifact SDK** | `src/artifact-sdk/` | In-repo module — no npm publishing needed. Direct import by agents |
411
- | **Base prompt** | `src/prompts/base-prompt.ts` | Add `BASE_PROMPT_ARTIFACTS` with usage instructions, gated by `hasCapability("artifacts")` |
412
- | **Stop hook** | `src/hooks/hook.ts` (Stop case) | Call `tunnel.close()` for all running artifact tunnels (multiple per worker) |
413
- | **Service registry** | `src/tools/register-service.ts` | No changes — already supports metadata for custom service types |
414
- | **Docker** | `Dockerfile.worker` | `npm install -g @desplega.ai/localtunnel` (client binary only) |
415
- | **Entrypoint** | `docker-entrypoint.sh` | Optional: auto-create tunnel when PM2 starts a registered artifact service |
416
- | **PM2 ecosystem** | `src/http.ts` (`/ecosystem`) | Already generates PM2 config from registered services — artifacts auto-restart on container boot |
417
-
418
- ---
419
-
420
- ## Part 2: Localtunnel Research
421
-
422
- ### Deterministic Subdomains
423
-
424
- The client requests a specific subdomain by appending it as a URL path segment during tunnel negotiation:
425
-
426
- ```
427
- # Without subdomain: GET https://lt.desplega.ai/?new
428
- # With subdomain: GET https://lt.desplega.ai/my-agent-name
429
- ```
430
-
431
- **CLI:**
432
- ```bash
433
- lt --port 3000 --subdomain my-agent-name
434
- # Result: https://my-agent-name.lt.desplega.ai
435
- ```
436
-
437
- **Programmatic API:**
438
- ```javascript
439
- const localtunnel = require('@desplega.ai/localtunnel');
440
-
441
- const tunnel = await localtunnel({
442
- port: 3000,
443
- subdomain: 'my-agent-name',
444
- // host defaults to 'https://lt.desplega.ai'
445
- });
446
-
447
- console.log(tunnel.url);
448
- // https://my-agent-name.lt.desplega.ai
449
- ```
450
-
451
- #### Subdomain Validation Rules (Server-Side)
452
-
453
- The server validates subdomains with this regex:
454
-
455
- ```
456
- /^(?:[a-z0-9][a-z0-9\-]{2,61}[a-z0-9]|[a-z0-9]{4,63})$/
457
- ```
458
-
459
- | Rule | Detail |
460
- |------|--------|
461
- | Length | 4-63 characters |
462
- | Allowed chars | Lowercase alphanumeric (`a-z`, `0-9`) and hyphens (`-`) |
463
- | Start/end | Cannot start or end with a hyphen |
464
- | Case | Must be lowercase |
465
-
466
- #### Conflict Handling (409)
467
-
468
- **Our fork differs from upstream here.** In upstream localtunnel, if a requested subdomain is taken, the server silently assigns a random one. Our fork returns a proper 409 Conflict:
469
-
470
- **Server (`ClientManager.js`):**
471
- ```javascript
472
- if (clients[id]) {
473
- const err = new Error(`Subdomain '${id}' is already in use.`);
474
- err.code = 'SUBDOMAIN_IN_USE';
475
- throw err;
476
- }
477
- ```
478
-
479
- **Client (`Tunnel.js`):**
480
- ```javascript
481
- if (err.response?.status === 409) {
482
- const message = err.response.data?.message || 'Subdomain is already in use';
483
- return cb(new Error(message)); // Fails immediately, no retry
484
- }
485
- ```
486
-
487
- #### Agent IDs as Subdomains — Tested
488
-
489
- Agent IDs are UUIDs like `16990304-76e4-4017-b991-f3e37b34cf73`. These are 36 characters, contain only hex digits and hyphens, and are lowercase — they pass the subdomain validation regex.
490
-
491
- **Tested against `lt.desplega.ai` on 2026-02-26:**
492
-
493
- | Format | Example | Length | Result |
494
- |--------|---------|--------|--------|
495
- | Full UUID with hyphens | `16990304-76e4-4017-b991-f3e37b34cf73` | 36 | **Works** — tunnel created, HTTP 200 confirmed |
496
- | Short UUID prefix | `16990304` | 8 | **Works** — tunnel created |
497
- | UUID without hyphens | `1699030476e44017b991f3e37b34cf73` | 32 | **Works** — tunnel created |
498
-
499
- ```bash
500
- # Actual test output:
501
- $ lt --port 8787 --subdomain 16990304-76e4-4017-b991-f3e37b34cf73 --host https://lt.desplega.ai
502
- your url is: https://16990304-76e4-4017-b991-f3e37b34cf73.lt.desplega.ai
503
-
504
- $ curl -H "Bypass-Tunnel-Reminder: true" https://16990304-76e4-4017-b991-f3e37b34cf73.lt.desplega.ai
505
- Hello from UUID subdomain test! # HTTP 200
506
- ```
507
-
508
- No issues with UUID length, hyphens, or character set. The server validates and accepts all three formats.
509
-
510
- **Recommendation:** Use full UUID. The URL is primarily for programmatic access, not for humans typing into browsers. The service registry provides a human-friendly lookup. This also matches the existing URL pattern: `https://{agentId}.{SWARM_URL}` (see `src/tools/register-service.ts:76`).
511
-
512
- ### HTTP Basic Auth
513
-
514
- Auth is a feature **added by our fork** — it does not exist in upstream localtunnel.
515
-
516
- **CLI (two modes):**
517
- ```bash
518
- # Mode 1: Server generates an 18-char hex password
519
- lt --port 3000 --subdomain my-agent --auth
520
- # Username: "hi", Password: auto-generated
521
-
522
- # Mode 2: Custom password
523
- lt --port 3000 --subdomain my-agent --auth "my-secret-password"
524
- # Username: "hi", Password: "my-secret-password"
525
- ```
526
-
527
- **Programmatic API:**
528
- ```javascript
529
- const tunnel = await localtunnel({
530
- port: 3000,
531
- subdomain: 'my-agent',
532
- auth: true, // server generates password
533
- // OR
534
- auth: 'my-password', // custom password
535
- });
536
-
537
- // tunnel.url includes embedded credentials:
538
- // https://hi:a1b2c3d4e5f6g7h8i9@my-agent.lt.desplega.ai
539
- ```
540
-
541
- #### Auth Flow
542
-
543
- 1. **Client → Server (tunnel registration):** Query params `username=hi` and optionally `password=<value>` appended to the registration URL
544
- 2. **Server stores credentials:** If no password given, auto-generates 18-char hex string via `crypto.randomBytes(9).toString('hex')`
545
- 3. **Server → Client (registration response):** Credentials returned in response body and embedded in URL
546
- 4. **Browser/client → Server (accessing tunnel):** Standard HTTP Basic Auth — browser shows login prompt, or `Authorization: Basic <base64>` header
547
- 5. **Server validates:** Timing-safe comparison via `crypto.timingSafeEqual()`, returns `401 Unauthorized` with `WWW-Authenticate: Basic realm="Localtunnel"` on failure
548
- 6. **WebSocket auth:** Also enforced
549
-
550
- #### Security Properties
551
-
552
- | Property | Status |
553
- |----------|--------|
554
- | Timing-safe comparison | Yes (`crypto.timingSafeEqual`) |
555
- | Per-tunnel isolation | Yes (each tunnel has its own credentials) |
556
- | Credentials in URL | Yes (embedded in the response URL) — note: not ideal for logging |
557
- | HTTPS | Yes (`lt.desplega.ai` uses TLS via Caddy) |
558
- | WebSocket support | Yes (auth checked on upgrade) |
559
-
560
- ### Connection Management
561
-
562
- | Parameter | Value | Source |
563
- |-----------|-------|--------|
564
- | Max TCP sockets per tunnel | 10 (hardcoded) | `TunnelAgent.js` — `--max-sockets` flag has a property name mismatch bug |
565
- | Socket idle timeout | 10 minutes (default) | `TunnelAgent.js` — configurable via `SOCKET_TIMEOUT` env var (seconds) |
566
- | Grace period (no connections) | 1 second | `Client.js` — tunnel removed if no client connects within 1s |
567
- | WebSocket timeout | Disabled (0) | `Client.js` — WebSocket connections exempt from idle timeout |
568
-
569
- **Auto-Reconnection (Client-Side):**
570
- - Dead tunnel socket → immediately reopened
571
- - Server unavailable → retry every 1s
572
- - Local server refused → retry every 1s
573
- - 409 subdomain conflict → immediate failure (no retry)
574
-
575
- **Graceful Shutdown (fork addition):**
576
- - `tunnel.close()` is async, destroys all resources
577
- - CLI handles `SIGINT`/`SIGTERM`
578
-
579
- **Env var configuration:** All CLI flags can be set via environment variables (yargs `.env(true)`).
580
-
581
- ---
582
-
583
- ## Part 3: Fork Modifications vs Upstream
584
-
585
- ### Client (`desplega-ai/localtunnel` v2.2.0)
586
-
587
- | Modification | Description |
588
- |-------------|-------------|
589
- | **Default host** | Changed from `localtunnel.me` to `lt.desplega.ai` |
590
- | **`--auth` flag** | New: HTTP Basic Auth support (boolean or string) |
591
- | **409 handling** | New: subdomain conflict returns immediate error instead of retrying |
592
- | **Graceful shutdown** | New: async `close()` with full resource cleanup |
593
- | **Test suite** | Migrated from Mocha (JS) to Bun (TypeScript) |
594
- | **Package name** | `@desplega.ai/localtunnel` (scoped) |
595
-
596
- ### Server (`desplega-ai/localtunnel-server` v0.1.3)
597
-
598
- | Modification | Description |
599
- |-------------|-------------|
600
- | **HTTP Basic Auth** | Full implementation: `authUtils.js` + per-tunnel credential storage + timing-safe validation |
601
- | **409 Conflict** | Returns proper 409 for subdomain collisions |
602
- | **Socket timeout** | Increased from 60s to 10 minutes, configurable via `SOCKET_TIMEOUT` env var |
603
- | **X-Forwarded-Proto/Host** | Sets forwarded headers for HTTPS-aware apps |
604
- | **X-Robots-Tag** | All tunnel responses include `noindex, nofollow` |
605
- | **Agent IP tracking** | `X-Localtunnel-Agent-Ips` header on responses |
606
- | **ESM** | Converted to ES modules |
607
- | **Docker** | Dockerfile + compose config, GHCR publishing |
608
- | **CI/CD** | Test, E2E, and Docker publish workflows |
609
-
610
- ---
611
-
612
- ## Part 4: Design Decisions
613
-
614
- ### Auth Strategy
615
-
616
- | Option | Description | Pros | Cons |
617
- |--------|-------------|------|------|
618
- | Per-tunnel random password | `auth: true` (server generates) | Zero config | Need to store/share the generated password |
619
- | **user=`swarm`, pass=API key** | Use existing API key as tunnel password | Simple, no new secrets, already available in env | API key shared across all tunnels |
620
- | Per-agent HMAC-derived password | `auth: hash(agentId + swarmSecret)` | Per-agent isolation, deterministic | Requires separate secret management |
621
-
622
- **Recommendation:** Use `username=swarm`, `password=API_KEY` as the default. The API key (`API_KEY` env var) is already available in every worker container — it's set in `docker-entrypoint.sh` and used for MCP server auth. This means zero additional configuration.
623
-
624
- For enhanced security in production, an HMAC-derived per-agent password (`crypto.createHmac('sha256', API_KEY).update(agentId).digest('hex')`) would provide per-agent isolation — if one tunnel's password leaks, others aren't compromised. But for MVP, the API key approach is simpler and sufficient.
625
-
626
- > **Note:** The localtunnel client currently hardcodes `username="hi"`. To use `username="swarm"`, the client's `Tunnel.js` needs a minor patch to accept a custom username option. Alternatively, the server could be configured to only check the password (since the username is less important for security).
627
-
628
- ### Lifecycle Management
629
-
630
- 1. **Container restart:** Server frees subdomain after 1s grace. Agent reconnects with same subdomain immediately.
631
- 2. **Server restart:** All tunnels lost. Client retry loop handles reconnection (1s interval).
632
- 3. **Stale subdomains:** Held up to 10 minutes (socket timeout). Acceptable for MVP.
633
-
634
- ### Implementation Sketch
635
-
636
- ```typescript
637
- // src/commands/artifact.ts — core artifact serve logic
638
- import localtunnel from '@desplega.ai/localtunnel';
639
-
640
- const AGENT_ID = process.env.AGENT_ID;
641
- const API_KEY = process.env.API_KEY;
642
- const MCP_BASE_URL = process.env.MCP_BASE_URL;
643
-
644
- // Create tunnel with swarm auth
645
- const tunnel = await localtunnel({
646
- port: 3000,
647
- subdomain: AGENT_ID,
648
- auth: API_KEY, // username defaults to "hi", password = API key
649
- // TODO: patch client to support username: 'swarm'
650
- });
651
-
652
- console.log(`Artifact URL: ${tunnel.url}`);
653
- // https://hi:<API_KEY>@<agentId>.lt.desplega.ai
654
-
655
- // Register in service registry via HTTP API
656
- await fetch(`${MCP_BASE_URL}/api/services`, {
657
- method: 'POST',
658
- headers: {
659
- 'Authorization': `Bearer ${API_KEY}`,
660
- 'X-Agent-ID': AGENT_ID,
661
- 'Content-Type': 'application/json',
662
- },
663
- body: JSON.stringify({
664
- script: '/workspace/personal/artifacts/server.js',
665
- metadata: {
666
- type: 'artifact',
667
- artifactName: 'pr-review-42',
668
- publicUrl: tunnel.url,
669
- },
670
- }),
671
- });
672
-
673
- // Graceful shutdown
674
- process.on('SIGTERM', async () => {
675
- await tunnel.close();
676
- // Service unregistered via Stop hook
677
- });
678
- ```
679
-
680
- ---
681
-
682
- ## Part 5: Known Issues & Risks
683
-
684
- | Issue | Severity | Mitigation |
685
- |-------|----------|------------|
686
- | **10 max TCP sockets per tunnel** | Medium | Fine for artifacts. Fix the property name bug (`maxSockets` → `maxTcpSockets`). |
687
- | **1-second grace period** | Low | Good for subdomain reuse, no overlap possible. |
688
- | **No heartbeat mechanism** | Medium | Stale subdomains held up to 10 minutes. Acceptable for MVP. |
689
- | **Hardcoded username "hi"** | Medium | Need to patch client to support `username: 'swarm'` for cleaner auth. Alternatively, server could validate password only. |
690
- | **HTTP only (no raw TCP/UDP)** | Low | Artifacts are HTTP-served. Fine. |
691
- | **No wildcard DNS guarantee** | Medium | Requires `*.lt.desplega.ai` DNS via Caddy. |
692
-
693
- ### `maxSockets` Bug Fix Needed
694
-
695
- In `desplega-ai/localtunnel-server`, `ClientManager.js:43-46`:
696
-
697
- ```javascript
698
- // Current (buggy):
699
- const agent = new TunnelAgent({ clientId: id, maxSockets: 10 });
700
-
701
- // Fix:
702
- const agent = new TunnelAgent({ clientId: id, maxTcpSockets: maxSockets });
703
- ```
704
-
705
- ---
706
-
707
- ## Part 6: Next Steps
708
-
709
- ### Phase 1: Foundation (MVP)
710
- 1. **Patch localtunnel client** — add `username` option to `@desplega.ai/localtunnel` so we can use `swarm` instead of `hi`
711
- 2. **Fix the `maxSockets` property name bug** in `desplega-ai/localtunnel-server`
712
- 3. **Create `src/artifact-sdk/`** in-repo module with `createArtifactServer()`, dynamic port allocation, static serving, and tunnel management
713
- 4. **Add `artifact` CLI command** to `src/cli.tsx` with `serve`, `list`, `stop` subcommands
714
-
715
- ### Phase 2: Interactivity
716
- 5. **Build the browser SDK** (`/@swarm/sdk.js`) for HTML → swarm API calls
717
- 6. **Add `/@swarm/api/*` proxy** middleware in the artifact server
718
- 7. **Add `BASE_PROMPT_ARTIFACTS`** section to `src/prompts/base-prompt.ts`
719
-
720
- ### Phase 3: Polish
721
- 8. **Add tunnel cleanup to Stop hook** in `src/hooks/hook.ts`
722
- 9. **Add `artifact open`** command that opens URL with embedded credentials
723
- 10. **Install `@desplega.ai/localtunnel`** globally in `Dockerfile.worker`
724
- 11. **Health check endpoint** — `/health` on each artifact for monitoring