@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,797 +0,0 @@
1
- ---
2
- date: 2026-03-18T14:30:00Z
3
- topic: "Workflow Engine Redesign"
4
- status: reviewed
5
- researcher: taras+claude
6
- ---
7
-
8
- # Workflow Engine Redesign — Research
9
-
10
- **Status**: v2 — incorporates Taras review feedback + Temporal research
11
- **Prior art**: [Content-Agent Workflow Engine Mechanics](/Users/taras/Documents/code/content-agent/thoughts/shared/research/2026-03-18-workflow-engine-mechanics.md)
12
- **Supersedes**: [2026-03-06-workflow-engine-design.md](./2026-03-06-workflow-engine-design.md) (original design that led to current implementation)
13
-
14
- ---
15
-
16
- ## 1. Motivation
17
-
18
- The current workflow engine (shipped from the March 6 design) works but has architectural issues:
19
-
20
- 1. **Cyclical triggers** — Event-based triggers (task.created, task.completed) fire workflows that create tasks, creating infinite loops. Guard logic is fragile.
21
- 2. **No executor abstraction** — Node executors are scattered across files with no unified contract. Adding a new step type means touching engine code.
22
- 3. **No validation/quality gates** — No built-in way to validate step outputs, retry on failure, or gate workflow progression.
23
- 4. **No durability guarantees** — If the process crashes mid-workflow, recovery depends on detecting "stuck" runs after the fact.
24
- 5. **No versioning** — Workflow definitions are mutable JSON in the DB with no history.
25
- 6. **No workflow templates** — Can't share reusable workflow patterns (e.g., content-agent daily docs update, weekly blog post generator, QA weekly bug bash). Templates should be first-class: define once, instantiate many times with different inputs.
26
-
27
- The goal: redesign the workflow engine to adopt the **executor registry pattern** from content-agent, add **checkpoint-based durability**, and clean up the execution model — while preserving DAG support and the multi-agent task delegation model.
28
-
29
- ---
30
-
31
- ## 2. Design Decisions (from Q&A with Taras)
32
-
33
- | Decision | Choice | Rationale |
34
- |----------|--------|-----------|
35
- | **Core pattern** | Executor registry (class-based) + validation model | Clean `execute(input) → output`, quality gates, retry. Extensible via class inheritance. |
36
- | **Execution model** | Directed graph with event-loop style executor | Idle until step ready → execute → checkpoint → next. Cycles allowed with max-iterations guard. See §4.8. |
37
- | **Durability** | Checkpoint-based | Persist after each step, resume from last success. Aspire to deterministic replay later. |
38
- | **Definitions** | Keep in database (JSON) | UI-friendly, API-driven. Add version history table. |
39
- | **Triggers** | Simplify: webhook (HMAC) + schedule (via scheduleId ref). Manual always available (UI or agent MCP tool). | Event-based triggers deferred — too cyclical. |
40
- | **Step types (initial)** | script, agent-task, raw-llm, vcs, property-match, code-match, send-message, validate | Start lean, extend via registry. |
41
- | **LLM execution** | Agent tasks (primary) + raw AI SDK/OpenRouter (secondary) | Complex work = agent task. Simple structured ops = direct LLM call. |
42
- | **Validation** | Executor `fn(output) → {pass, reasoning, confidence}` per-step | Reusable RetryPolicy type. Global final validation deferred. |
43
- | **Context chain** | Node IDs (current style) | Machine-friendly, avoids naming conflicts in DAG. |
44
- | **Schedules** | Triggers array on workflow, schedule ID reference to `scheduled_tasks` | SOT in schedules table, atomic removal. |
45
- | **Schema format** | Nodes with `next` references, edges auto-generated for UI | Compact authoring, nodes are the key structure, edges purely visual. |
46
- | **Migration** | Rip and replace | Clean break on `feat/workflow-redesign` branch. Nobody uses current workflows. |
47
- | **Templates** | First-class workflow templates, instantiable with custom inputs | Enable reusable patterns across domains. |
48
-
49
- **Future direction**: Agent-defined reusable "tools" as first-class citizens — think little lambdas that agents can define and then reference in workflow steps. Not in scope for this redesign but the class-based executor pattern should make this extensible.
50
-
51
- ---
52
-
53
- ## 3. Current System Inventory
54
-
55
- ### 3.1 What Exists Today
56
-
57
- **Database tables** (from `003_workflows.sql`, `004_workflow_source.sql`):
58
- - `workflows` — DAG definitions (JSON: `{nodes, edges}`)
59
- - `workflow_runs` — Execution instances (status, context, error)
60
- - `workflow_run_steps` — Per-node execution history
61
- - `agent_tasks` extensions — `workflowRunId`, `workflowRunStepId` columns
62
-
63
- **Engine** (`src/workflows/`):
64
- - `engine.ts` — BFS DAG walker, `startWorkflowExecution()`, `walkGraph()`, `executeNode()`
65
- - `resume.ts` — Event bus listeners for task.completed/failed/cancelled → resume waiting runs
66
- - `recovery.ts` — Detect stuck runs (waiting + task already done), re-trigger resume
67
- - `triggers.ts` — Match events → fire workflows
68
- - `event-bus.ts` — Simple in-process EventEmitter
69
- - `template.ts` — `{{path.to.value}}` interpolation
70
- - `llm-provider.ts` — OpenRouter or Claude CLI for `llm-classify` node
71
- - `index.ts` — `initWorkflows()` wires up event listeners
72
-
73
- **Node executors** (`src/workflows/nodes/`):
74
- - `create-task.ts` — Async: creates agent task, pauses workflow
75
- - `delegate-to-agent.ts` — Async: assigns/offers task to agent
76
- - `send-message.ts` — Instant: posts to channel
77
- - `property-match.ts` — Instant: JSONPath condition evaluation
78
- - `code-match.ts` — Instant: sandboxed JS evaluation
79
- - `llm-classify.ts` — Instant (awaited): AI SDK structured output for classification
80
-
81
- **Trigger nodes** (7 types): `trigger-new-task`, `trigger-task-completed`, `trigger-webhook`, `trigger-email`, `trigger-slack-message`, `trigger-github-event`, `trigger-gitlab-event`
82
-
83
- **MCP tools** (`src/tools/workflows/`): 9 tools (CRUD + trigger + runs + retry)
84
- **HTTP API** (`src/http/workflows.ts`): Full REST for workflows, runs, steps, retry, webhook trigger
85
- **Tests**: ~2,500 lines across 9 test files + E2E script
86
-
87
- ### 3.2 What Gets Replaced
88
-
89
- | Component | Action |
90
- |-----------|--------|
91
- | `src/workflows/engine.ts` | **Replace** — New engine with executor registry + checkpoint durability |
92
- | `src/workflows/nodes/*` | **Replace** — Rewrite as executor classes registered in registry |
93
- | `src/workflows/triggers.ts` | **Replace** — Simplify to webhook + schedule + manual |
94
- | `src/workflows/resume.ts` | **Refactor** — Keep event-driven resume for async executors but integrate into new engine |
95
- | `src/workflows/recovery.ts` | **Refactor** — Checkpoint-based recovery replaces stuck-run detection |
96
- | `src/workflows/event-bus.ts` | **Keep** — Still needed for async task completion events |
97
- | `src/workflows/template.ts` | **Keep** — Template interpolation is fine |
98
- | `src/workflows/llm-provider.ts` | **Refactor** — Becomes part of `raw-llm` executor |
99
- | DB schema | **Migrate** — New migration for schema changes |
100
- | MCP tools | **Update** — Same tools, updated to new engine |
101
- | HTTP API | **Update** — Same endpoints, updated to new engine |
102
- | Tests | **Rewrite** — New tests for new engine |
103
-
104
- ---
105
-
106
- ## 4. Proposed Architecture
107
-
108
- ### 4.1 Executor Registry (Class-Based)
109
-
110
- The core abstraction: every step is an **executor class** registered by type name. The class-based approach enables:
111
- - Typed configs and outputs via Zod schemas
112
- - Constructor-injected dependencies (DB, event bus, etc.)
113
- - Extensibility through inheritance
114
- - Future: agent-defined custom executors
115
-
116
- ```typescript
117
- import { z, type ZodType } from "zod";
118
-
119
- // ─── Shared Types ───────────────────────────────────────────
120
-
121
- /** Reusable retry policy — used by validation, steps, etc. */
122
- const RetryPolicySchema = z.object({
123
- maxRetries: z.number().int().min(0).default(3),
124
- strategy: z.enum(["exponential", "static", "linear"]).default("exponential"),
125
- baseDelayMs: z.number().int().min(0).default(1000),
126
- maxDelayMs: z.number().int().min(0).default(60000),
127
- });
128
- type RetryPolicy = z.infer<typeof RetryPolicySchema>;
129
-
130
- /** Execution metadata passed to every executor */
131
- const ExecutorMetaSchema = z.object({
132
- runId: z.string().uuid(),
133
- stepId: z.string().uuid(),
134
- nodeId: z.string(),
135
- workflowId: z.string().uuid(),
136
- dryRun: z.boolean().default(false),
137
- });
138
- type ExecutorMeta = z.infer<typeof ExecutorMetaSchema>;
139
-
140
- // ─── Executor Base Class ────────────────────────────────────
141
-
142
- abstract class BaseExecutor<
143
- TConfig extends ZodType = ZodType,
144
- TOutput extends ZodType = ZodType,
145
- > {
146
- abstract readonly type: string;
147
- abstract readonly mode: "instant" | "async";
148
- abstract readonly configSchema: TConfig;
149
- abstract readonly outputSchema: TOutput;
150
-
151
- /** Optional retry policy — override per executor type */
152
- readonly retryPolicy?: RetryPolicy;
153
-
154
- constructor(protected readonly deps: ExecutorDependencies) {}
155
-
156
- /** Validate config, execute, validate output — catches Zod errors at both boundaries */
157
- async run(input: ExecutorInput): Promise<ExecutorResult<z.infer<TOutput>>> {
158
- // Validate input config
159
- const configResult = this.configSchema.safeParse(input.config);
160
- if (!configResult.success) {
161
- return { status: "failed", error: `Input validation failed: ${configResult.error.message}` };
162
- }
163
-
164
- const result = await this.execute(configResult.data, input.context, input.meta);
165
-
166
- // Validate output
167
- if (result.status === "success" && result.output !== undefined) {
168
- const outputResult = this.outputSchema.safeParse(result.output);
169
- if (!outputResult.success) {
170
- return { status: "failed", error: `Output validation failed: ${outputResult.error.message}` };
171
- }
172
- }
173
- return result;
174
- }
175
-
176
- /** Implement this in each executor */
177
- protected abstract execute(
178
- config: z.infer<TConfig>,
179
- context: Readonly<Record<string, unknown>>,
180
- meta: ExecutorMeta,
181
- ): Promise<ExecutorResult<z.infer<TOutput>>>;
182
- }
183
-
184
- interface ExecutorDependencies {
185
- db: typeof import("../be/db");
186
- eventBus: WorkflowEventBus;
187
- interpolate: (template: string, ctx: Record<string, unknown>) => string;
188
- }
189
-
190
- interface ExecutorInput {
191
- config: Record<string, unknown>;
192
- context: Readonly<Record<string, unknown>>;
193
- meta: ExecutorMeta;
194
- }
195
-
196
- interface ExecutorResult<TOutput = unknown> {
197
- status: "success" | "failed" | "skipped";
198
- output?: TOutput;
199
- nextPort?: string; // default: "default"
200
- error?: string;
201
- }
202
-
203
- /** Async executors signal the engine to pause */
204
- interface AsyncExecutorResult<TOutput = unknown> extends ExecutorResult<TOutput> {
205
- async: true;
206
- waitFor: string; // e.g., "task.completed"
207
- correlationId: string; // e.g., taskId
208
- }
209
-
210
- // ─── Registry ───────────────────────────────────────────────
211
-
212
- class ExecutorRegistry {
213
- private executors = new Map<string, BaseExecutor>();
214
-
215
- register(executor: BaseExecutor): void {
216
- this.executors.set(executor.type, executor);
217
- }
218
-
219
- get(type: string): BaseExecutor {
220
- const executor = this.executors.get(type);
221
- if (!executor) throw new Error(`Unknown executor type: ${type}`);
222
- return executor;
223
- }
224
-
225
- has(type: string): boolean {
226
- return this.executors.has(type);
227
- }
228
-
229
- types(): string[] {
230
- return [...this.executors.keys()];
231
- }
232
- }
233
- ```
234
-
235
- **Example: notify executor implementation**
236
-
237
- ```typescript
238
- class NotifyExecutor extends BaseExecutor<typeof NotifyConfigSchema, typeof NotifyOutputSchema> {
239
- readonly type = "notify";
240
- readonly mode = "instant" as const;
241
-
242
- readonly configSchema = z.object({
243
- channel: z.enum(["swarm", "slack", "email"]),
244
- target: z.string().optional(),
245
- template: z.string(),
246
- });
247
-
248
- readonly outputSchema = z.object({
249
- sent: z.boolean(),
250
- messageId: z.string().optional(),
251
- });
252
-
253
- protected async execute(
254
- config: z.infer<typeof this.configSchema>,
255
- context: Readonly<Record<string, unknown>>,
256
- meta: ExecutorMeta,
257
- ): Promise<ExecutorResult<z.infer<typeof this.outputSchema>>> {
258
- const message = this.deps.interpolate(config.template, context);
259
-
260
- if (meta.dryRun) {
261
- return { status: "success", output: { sent: false } };
262
- }
263
-
264
- switch (config.channel) {
265
- case "swarm":
266
- const msgId = this.deps.db.postMessage(config.target ?? "general", message);
267
- return { status: "success", output: { sent: true, messageId: msgId } };
268
- case "slack":
269
- // ... slack posting logic
270
- case "email":
271
- // ... email sending logic
272
- }
273
- }
274
- }
275
-
276
- // Registration
277
- registry.register(new NotifyExecutor(deps));
278
- ```
279
-
280
- ### 4.2 Initial Executor Set
281
-
282
- | Executor | Type | Mode | What it does |
283
- |----------|------|------|-------------|
284
- | **script** | `script` | Instant | Run bash/TS(bun)/Python script. Config: `{runtime, script, args, timeout, cwd?, workerId? (future)}`. Scripts can be scoped to run on a specific worker machine via `workerId` (future — dispatch mechanism TBD). |
285
- | **agent-task** | `agent-task` | **Async** | Create task for worker agent. Config: `{template, agentId?, tags?, priority?}`. Pauses workflow until task completes. |
286
- | **raw-llm** | `raw-llm` | Instant | Direct AI SDK + OpenRouter call. Config: `{prompt, model?, schema?}`. Returns structured output via Zod. |
287
- | **vcs** | `vcs` | Instant | Version control operations. Config: `{action: "create-issue" \| "create-pr" \| "comment", provider: "github" \| "gitlab", repo, ...}`. |
288
- | **property-match** | `property-match` | Instant | JSONPath condition evaluation. Returns `nextPort: "true" \| "false"`. |
289
- | **code-match** | `code-match` | Instant | Sandboxed JS evaluation. Returns `nextPort` based on result. |
290
- | **notify** | `notify` | Instant | Multi-channel notification. Config: `{channel: "swarm" \| "slack" \| "email", target?, template}`. |
291
- | **validate** | `validate` | Instant | Quality gate. Config: `{targetNodeId, prompt?, schema?}`. Returns `{pass, reasoning, confidence}`. |
292
-
293
- ### 4.3 Validation System
294
-
295
- Validation is an executor with a special relationship to the engine.
296
-
297
- ```typescript
298
- const ValidationResultSchema = z.object({
299
- pass: z.boolean(),
300
- reasoning: z.string(),
301
- confidence: z.number().min(0).max(1),
302
- });
303
- type ValidationResult = z.infer<typeof ValidationResultSchema>;
304
-
305
- const StepValidationConfigSchema = z.object({
306
- /** Executor type for validation (default: "validate") */
307
- executor: z.string().default("validate"),
308
- /** Config passed to the validation executor */
309
- config: z.record(z.unknown()),
310
- /** If true, a failed validation halts the workflow */
311
- mustPass: z.boolean().default(false),
312
- /** Retry policy on validation failure */
313
- retry: RetryPolicySchema.optional(),
314
- });
315
- type StepValidationConfig = z.infer<typeof StepValidationConfigSchema>;
316
- ```
317
-
318
- Per-step: any node can have a `validation` field. After the step executes, the engine runs the validation executor. If `retry` is set, re-runs the step with `{previousOutput, validationResult}` injected into context, following the retry policy (exponential, static, or linear backoff).
319
-
320
- ### 4.4 Checkpoint-Based Durability
321
-
322
- After each step completes:
323
- 1. Write step result to `workflow_run_steps`
324
- 2. Write accumulated context to `workflow_runs.context`
325
- 3. Both in a single SQLite transaction (atomic checkpoint)
326
-
327
- Key features:
328
- - **Step-level retry** — Each executor can declare a `RetryPolicy`. The engine handles retry scheduling.
329
- - **Idempotency keys** — Steps get a deterministic key `${runId}:${nodeId}` to prevent double execution.
330
- - **Context snapshots** — Context written atomically with step completion.
331
- - **Recovery on startup** — Scan for `status: 'running'` runs, find last completed step, resume from successors.
332
- - **All JSON parsed via Zod** — No raw `JSON.parse`. Every DB read validates through schemas.
333
-
334
- ```typescript
335
- // Recovery — Zod-validated, type-safe
336
- async function recoverIncompleteRuns(): Promise<void> {
337
- const incompleteRuns = db.getWorkflowRunsByStatus(["running", "waiting"]);
338
-
339
- for (const run of incompleteRuns) {
340
- const completedStepNodeIds = db.getCompletedStepNodeIds(run.id);
341
- const context = WorkflowContextSchema.parse(JSON.parse(run.context));
342
- const def = WorkflowDefinitionSchema.parse(JSON.parse(run.workflow.definition));
343
-
344
- const readyNodes = findReadyNodes(def, completedStepNodeIds);
345
-
346
- if (readyNodes.length > 0) {
347
- await walkGraph(def, run.id, context, readyNodes);
348
- }
349
- }
350
- }
351
- ```
352
-
353
- **Retry with backoff** — Applied per-step when execution fails:
354
-
355
- ```typescript
356
- function calculateDelay(policy: RetryPolicy, attempt: number): number {
357
- switch (policy.strategy) {
358
- case "exponential": {
359
- const delay = Math.min(policy.baseDelayMs * 2 ** (attempt - 1), policy.maxDelayMs);
360
- return Math.floor(Math.random() * delay); // full jitter
361
- }
362
- case "linear":
363
- return Math.min(policy.baseDelayMs * attempt, policy.maxDelayMs);
364
- case "static":
365
- return policy.baseDelayMs;
366
- }
367
- }
368
- ```
369
-
370
- A retry poller runs on `setInterval` (e.g., every 5s), picks up failed steps past their `nextRetryAt`, and re-executes them. This same poller mechanism doubles as the executor for durable timer nodes (future).
371
-
372
- ### 4.5 Workflow Definition Schema
373
-
374
- **Decision: Nodes with `next` references (Option B)**. Edges are auto-generated for UI rendering.
375
-
376
- Nodes are the canonical structure. When `next` is absent → the workflow terminates at that node. No special "input" or "output" node types — any node can be an entry point (no incoming references) or a terminal (no `next`).
377
-
378
- ```typescript
379
- const WorkflowNodeSchema = z.object({
380
- id: z.string(),
381
- type: z.string(), // executor type name
382
- label: z.string().optional(),
383
- config: z.record(z.unknown()),
384
- /** Next node(s) — string for single, object for port-based branching */
385
- next: z.union([
386
- z.string(), // single next: "nodeId"
387
- z.record(z.string(), z.string()), // port-based: { "true": "n3", "false": "n4" }
388
- ]).optional(),
389
- /** Per-step validation config */
390
- validation: StepValidationConfigSchema.optional(),
391
- /** Per-step retry policy (overrides executor default) */
392
- retry: RetryPolicySchema.optional(),
393
- });
394
- type WorkflowNode = z.infer<typeof WorkflowNodeSchema>;
395
-
396
- const WorkflowDefinitionSchema = z.object({
397
- nodes: z.array(WorkflowNodeSchema).min(1),
398
- });
399
- type WorkflowDefinition = z.infer<typeof WorkflowDefinitionSchema>;
400
-
401
- /** Auto-generate edges from `next` references — for UI graph rendering */
402
- function generateEdges(def: WorkflowDefinition): WorkflowEdge[] {
403
- const edges: WorkflowEdge[] = [];
404
- for (const node of def.nodes) {
405
- if (!node.next) continue;
406
- if (typeof node.next === "string") {
407
- edges.push({ id: `${node.id}→${node.next}`, source: node.id, target: node.next, sourcePort: "default" });
408
- } else {
409
- for (const [port, targetId] of Object.entries(node.next)) {
410
- edges.push({ id: `${node.id}→${targetId}:${port}`, source: node.id, target: targetId, sourcePort: port });
411
- }
412
- }
413
- }
414
- return edges;
415
- }
416
- ```
417
-
418
- **Consistency validation** — Before a workflow can run, validate:
419
- 1. All `next` references point to existing node IDs
420
- 2. Exactly **one entry node** (a node with no incoming `next` references). Multiple triggers can invoke the same workflow, but execution always starts at the single entry node. The trigger payload is injected into `context.trigger` before the entry node runs.
421
- 3. No orphaned nodes (every non-entry node must be reachable from the entry node)
422
- 4. Cycles are explicitly allowed — the graph is a **directed graph** (not strictly a DAG). The engine must enforce a `maxIterations` guard per node (default: 100) to prevent infinite loops. When a node exceeds `maxIterations`, the run fails with `error: "max iterations exceeded on node <id>"`
423
-
424
- **Example: linear workflow**
425
- ```json
426
- {
427
- "nodes": [
428
- { "id": "extract", "type": "script", "config": { "runtime": "bash", "script": "scripts/extract.sh" }, "next": "check" },
429
- { "id": "check", "type": "property-match", "config": { "property": "{{extract.exitCode}}", "operator": "eq", "value": 0 }, "next": { "true": "process", "false": "notify-fail" } },
430
- { "id": "process", "type": "agent-task", "config": { "template": "Process: {{extract.output}}" } },
431
- { "id": "notify-fail", "type": "notify", "config": { "channel": "slack", "template": "Extract failed: {{extract.error}}" } }
432
- ]
433
- }
434
- ```
435
-
436
- > **Convention**: Nodes without a `next` field are **terminal nodes** — execution ends when they complete. In this example, both `process` and `notify-fail` are terminal nodes (the workflow ends at whichever branch is taken).
437
-
438
- ### 4.6 Trigger System
439
-
440
- Workflows have a `triggers` array in their definition. Each trigger is typed.
441
-
442
- > **Note**: All workflows can always be triggered manually (via `POST /api/workflows/:id/trigger` from the UI or an agent using the `trigger-workflow` MCP tool). The `triggers` array only declares **additional** trigger mechanisms beyond manual. If `triggers` is empty or absent, the workflow is manual-only.
443
-
444
- ```typescript
445
- const TriggerConfigSchema = z.discriminatedUnion("type", [
446
- z.object({
447
- type: z.literal("webhook"),
448
- hmacSecret: z.string().optional(), // HMAC-SHA256 signature verification
449
- hmacHeader: z.string().default("X-Hub-Signature-256"),
450
- }),
451
- z.object({
452
- type: z.literal("schedule"),
453
- scheduleId: z.string().uuid(), // Reference to scheduled_tasks row
454
- }),
455
- ]);
456
- type TriggerConfig = z.infer<typeof TriggerConfigSchema>;
457
- ```
458
-
459
- **Manual trigger** (always available): `POST /api/workflows/:id/trigger` — requires API auth (Bearer token). Callable from the dashboard UI or by agents via the `trigger-workflow` MCP tool. Payload passed as `context.trigger`.
460
-
461
- **Webhook trigger**: `POST /api/webhooks/:workflowId` — optionally verified via HMAC-SHA256 signature. The workflow's `hmacSecret` is used to verify the `X-Hub-Signature-256` header (or custom header).
462
-
463
- **Schedule trigger**: The workflow references a `scheduleId` from the existing `scheduled_tasks` table. The schedule's SOT is in `scheduled_tasks` — the workflow just links to it. Creating/removing a schedule atomically updates both the `scheduled_tasks` row and the workflow's `triggers` array.
464
-
465
- Event-based triggers (task.created, github.*, slack.*) deferred to a later phase.
466
-
467
- ### 4.7 Version History
468
-
469
- Simple JSON snapshot table:
470
-
471
- ```sql
472
- CREATE TABLE IF NOT EXISTS workflow_versions (
473
- id TEXT PRIMARY KEY,
474
- workflowId TEXT NOT NULL REFERENCES workflows(id) ON DELETE CASCADE,
475
- version INTEGER NOT NULL,
476
- snapshot TEXT NOT NULL, -- JSON: WorkflowSnapshot (see below)
477
- changedByAgentId TEXT,
478
- createdAt TEXT DEFAULT (datetime('now')),
479
- UNIQUE(workflowId, version)
480
- );
481
- ```
482
-
483
- **Snapshot contents** — the `snapshot` column stores the full workflow record as it existed before the update:
484
-
485
- ```typescript
486
- const WorkflowSnapshotSchema = z.object({
487
- name: z.string(),
488
- description: z.string().optional(),
489
- definition: WorkflowDefinitionSchema, // { nodes: [...] }
490
- triggers: z.array(TriggerConfigSchema),
491
- cooldown: CooldownConfigSchema.optional(),
492
- input: z.record(InputValueSchema).optional(),
493
- enabled: z.boolean(),
494
- });
495
- ```
496
-
497
- On every `UPDATE` to a workflow, insert a version record with the **previous** state. The current state is always in the `workflows` table.
498
-
499
- ### 4.8 Execution Model (Event-Loop Style)
500
-
501
- The workflow executor runs **in-process in the API server**. It follows an event-loop approach:
502
-
503
- ```
504
- ┌─────────────────────────────────────────────────────────────┐
505
- │ WORKFLOW EXECUTOR (in API process) │
506
- │ │
507
- │ State: IDLE │
508
- │ ┌────────────────────────────────────────────────────────┐ │
509
- │ │ Event arrives (trigger, task completion, retry timer) │ │
510
- │ └──────────────┬─────────────────────────────────────────┘ │
511
- │ ▼ │
512
- │ ┌────────────────────────────────────────────────────────┐ │
513
- │ │ Find ready steps (predecessors all completed) │ │
514
- │ │ For each ready step: │ │
515
- │ │ │ │
516
- │ │ ┌─ Instant (script, llm, condition, notify, vcs) ──┐ │ │
517
- │ │ │ Execute in-process │ │ │
518
- │ │ │ Checkpoint result to DB (atomic transaction) │ │ │
519
- │ │ │ Add output to context │ │ │
520
- │ │ │ Find next ready steps → continue loop │ │ │
521
- │ │ └────────────────────────────────────────────────────┘ │ │
522
- │ │ │ │
523
- │ │ ┌─ Async (agent-task) ───────────────────────────────┐ │ │
524
- │ │ │ Create task, store correlation ID │ │ │
525
- │ │ │ Mark step as "waiting", checkpoint to DB │ │ │
526
- │ │ │ → Return to IDLE (don't block) │ │ │
527
- │ │ │ → When task completes, event bus fires │ │ │
528
- │ │ │ → Executor wakes up, resumes from next step │ │ │
529
- │ │ └────────────────────────────────────────────────────┘ │ │
530
- │ │ │ │
531
- │ │ When no more ready steps → workflow complete │ │
532
- │ └────────────────────────────────────────────────────────┘ │
533
- │ │
534
- │ Retry Poller (setInterval ~5s) │
535
- │ ┌────────────────────────────────────────────────────────┐ │
536
- │ │ Query: steps WHERE status='failed' AND nextRetryAt≤now│ │
537
- │ │ Re-execute each via the same loop │ │
538
- │ └────────────────────────────────────────────────────────┘ │
539
- │ │
540
- │ Startup Recovery │
541
- │ ┌────────────────────────────────────────────────────────┐ │
542
- │ │ Find runs with status='running' but no active steps │ │
543
- │ │ Resume from last checkpoint │ │
544
- │ └────────────────────────────────────────────────────────┘ │
545
- └─────────────────────────────────────────────────────────────┘
546
- ```
547
-
548
- > **Event-based execution**: Yes — the executor loop is purely event-driven. It only moves forward when an event arrives (trigger invocation, task completion callback, or retry poller tick). Between events, the executor is idle and holds no resources.
549
-
550
- > **Execution timeout**: Each instant executor should declare a `timeoutMs` in its config (e.g., script executor defaults to 30s, raw-llm to 60s). The engine wraps `execute()` in a `Promise.race` with a timeout. If the timeout fires, the step is marked `failed` with `error: “timeout”` and follows the retry policy. For async executors (agent-task), the timeout is handled by the task system itself (task-level TTL), not the workflow engine.
551
-
552
- **Key principle**: The executor is **never blocked**. Instant steps execute and immediately checkpoint. Async steps mark as waiting and return control. The event bus / retry poller re-enters the loop when work becomes available.
553
-
554
- **Parallel step execution**: When the graph has nodes whose predecessors are all completed, they can execute concurrently via `Promise.all()`. This is a natural consequence of the "find ready steps" approach.
555
-
556
- **Where things run**:
557
- - The executor loop itself runs in the API server process
558
- - Instant steps (script, LLM, conditions) run in-process or as subprocesses
559
- - Async steps (agent-task) create tasks that run on worker machines
560
- - Scripts with a `workerId` config are dispatched to that specific worker (future: via task with script payload)
561
-
562
- ### 4.9 Input Resolution
563
-
564
- Workflow-level `input` supports variable resolution:
565
-
566
- ```typescript
567
- const EnvVarSchema = z.string().regex(/^\$\{.+\}$/); // env var: ${MY_VAR}
568
- const SecretRefSchema = z.string().regex(/^secret\..+$/); // swarm secret: secret.OPENAI_KEY
569
- const LiteralSchema = z.string(); // literal value
570
-
571
- const InputValueSchema = z.union([EnvVarSchema, SecretRefSchema, LiteralSchema]);
572
- ```
573
-
574
- Resolution at workflow start:
575
- - `${ENV_VAR}` → `process.env.ENV_VAR`
576
- - `secret.NAME` → fetched from swarm secrets store
577
- - Literal strings → passed through
578
-
579
- ### 4.10 Workflow Templates
580
-
581
- Templates are workflow definitions designed for reuse:
582
-
583
- ```typescript
584
- const WorkflowTemplateSchema = z.object({
585
- id: z.string().uuid(),
586
- name: z.string(),
587
- description: z.string(),
588
- category: z.string(), // e.g., "content", "qa", "devops"
589
- /** Template variables — must be provided when instantiating */
590
- variables: z.array(z.object({
591
- name: z.string(),
592
- description: z.string(),
593
- type: z.enum(["string", "number", "boolean"]),
594
- default: z.unknown().optional(),
595
- required: z.boolean().default(true),
596
- })),
597
- /** The workflow definition with {{variable}} placeholders */
598
- definition: WorkflowDefinitionSchema,
599
- });
600
- ```
601
-
602
- **Examples**:
603
- - "Daily Blog Generator" template — variables: `{repo, branch, topic_source}`
604
- - "Weekly QA Bug Bash" template — variables: `{test_suite, notify_channel}`
605
- - "PR Review Pipeline" template — variables: `{repo, reviewers, auto_merge}`
606
-
607
- Templates can be stored alongside regular workflows or in the existing templates registry.
608
-
609
- ### 4.11 Cooldown System
610
-
611
- Simple pre-execution check:
612
-
613
- ```typescript
614
- const CooldownConfigSchema = z.object({
615
- hours: z.number().min(0),
616
- });
617
-
618
- /** Check before starting a workflow */
619
- async function shouldSkipCooldown(workflowId: string, cooldown: CooldownConfig): Promise<boolean> {
620
- const lastSuccess = db.getLastSuccessfulRun(workflowId);
621
- if (!lastSuccess) return false;
622
- const hoursSince = (Date.now() - new Date(lastSuccess.finishedAt).getTime()) / 3600000;
623
- return hoursSince < cooldown.hours;
624
- }
625
- ```
626
-
627
- Defined at workflow level: `cooldown: { hours: 24 }`. Checked before execution starts. If within cooldown, the run is skipped with `status: "skipped"`, `error: "cooldown"`.
628
-
629
- ---
630
-
631
- ## 5. Comparison: Content-Agent vs Proposed Design
632
-
633
- | Aspect | Content-Agent | Proposed Agent-Swarm |
634
- |--------|--------------|---------------------|
635
- | Format | YAML files | JSON in DB + version history |
636
- | Execution | Linear sequential | Directed graph (event-loop BFS walk, supports loops + branches) |
637
- | Executors | 4 (prompt, bash, git_pr, imgflip) | 8 initial (script, agent-task, raw-llm, vcs, property-match, code-match, notify, validate) |
638
- | Registry | Hardcoded if/elif | Class-based `ExecutorRegistry` with typed config/output (Zod) |
639
- | Context | `steps.<name>.output` | `ctx[nodeId]` |
640
- | Async | None — runs to completion | Async executors pause/resume via event bus |
641
- | Validation | Litmus test config block + retry | Validation executor with reusable `RetryPolicy` type |
642
- | Durability | None (re-run from start) | Checkpoint-based (resume from last completed step) |
643
- | Scheduling | Inline YAML, APScheduler | `triggers[]` with `scheduleId` ref to `scheduled_tasks` |
644
- | Cooldowns | Built-in per-workflow | Pre-execution check, workflow-level config |
645
- | Triggers | Cron + CLI + programmatic | Manual always available (UI/agent) + webhook (HMAC) + schedule |
646
- | Templates | YAML files = implicit templates | First-class template system with variables |
647
- | Input resolution | `${ENV_VAR}`, `data/file.json` | `${ENV_VAR}`, `secret.NAME` |
648
- | Typing | Python, untyped | Full Zod schemas for config, output, context |
649
-
650
- ---
651
-
652
- ## 6. Resolved Questions
653
-
654
- | # | Question | Resolution |
655
- |---|----------|-----------|
656
- | 6.1 | Schema format | **Nodes with `next`**, edges auto-generated for UI. Support loops + branches. No special input/output nodes. |
657
- | 6.2 | Cooldowns | **Yes** — part of initial execution logic, pre-execution check. |
658
- | 6.3 | Input resolution | **Yes** — `${ENV_VAR}` and `secret.NAME` supported. |
659
- | 6.4 | Retry policy | **Reusable `RetryPolicy` type** with strategy: exponential/static/linear. Used by validation and step-level retry. |
660
- | 6.5 | Parallel execution | **Yes** — natural consequence of "find ready steps" in directed graph. Nodes with all predecessors completed run via `Promise.all()`. |
661
- | 6.6 | Global final validation | **Deferred** — not in initial scope. |
662
- | 6.7 | Existing workflow migration | **Not needed** — nobody uses current workflows. Clean slate. |
663
-
664
- ---
665
-
666
- ## 7. Key Files to Change
667
-
668
- ```
669
- src/workflows/
670
- engine.ts → Full rewrite (executor registry + checkpoint + event-loop)
671
- nodes/ → Delete, replaced by executors/
672
- resume.ts → Refactor for new engine
673
- recovery.ts → Replace with checkpoint-based recovery
674
- triggers.ts → Simplify to webhook + schedule + manual
675
- event-bus.ts → Keep
676
- template.ts → Keep, add secret.NAME support
677
- llm-provider.ts → Move into raw-llm executor
678
- index.ts → Update initialization
679
-
680
- src/be/
681
- migrations/
682
- NNN_workflow_redesign.sql → Schema changes (version history, retry columns, triggers)
683
- db.ts → Update workflow query functions
684
-
685
- src/tools/workflows/ → Update MCP tools for new types
686
- src/http/workflows.ts → Update HTTP handlers, HMAC verification
687
- src/types.ts → Update workflow type definitions (Zod schemas)
688
-
689
- NEW files:
690
- src/workflows/executors/ → Executor implementations
691
- base.ts → BaseExecutor class
692
- registry.ts → ExecutorRegistry
693
- script.ts → Script executor (bash/ts/python)
694
- agent-task.ts → Async task creation executor
695
- raw-llm.ts → Direct LLM call executor
696
- vcs.ts → Version control executor (GitHub/GitLab)
697
- notify.ts → Multi-channel notification executor
698
- validate.ts → Validation executor
699
- src/workflows/checkpoint.ts → Checkpoint persistence logic
700
- src/workflows/version.ts → Version history logic
701
- src/workflows/retry-poller.ts → Retry poller (setInterval)
702
- src/workflows/validation.ts → Validation engine (wraps validate executor)
703
- src/workflows/templates.ts → Template instantiation logic
704
- ```
705
-
706
- ---
707
-
708
- ## 8. Temporal-Like Patterns — Research Findings
709
-
710
- Background research investigated Temporal, Inngest, Restate, DBOS, Hatchet, @hazeljs/flow, and a SQLite-based proof-of-concept. Key findings:
711
-
712
- ### 8.1 We Don't Need Full Temporal
713
-
714
- Our workflows are **declarative directed graphs**, not arbitrary code. The graph structure itself is the replay mechanism — we don't need deterministic replay. What we need is **step result memoization** (skip completed steps on resume).
715
-
716
- ### 8.2 Minimum Viable Durable Execution
717
-
718
- The existing `walkGraph` (currently named `walkDag` — to be renamed) + `workflow_run_steps` is **80% there**. Four concrete additions:
719
-
720
- 1. **Context checkpoint after every step** (currently only done on `waiting` — also do it on each `completed`)
721
- 2. **Retry columns** on `workflow_run_steps`: `retryCount`, `maxRetries`, `nextRetryAt` + a poller
722
- 3. **Step memoization** in `walkGraph`: before executing, check if step already completed → skip and inject stored output
723
- 4. **Startup recovery**: extend to handle "process crashed mid-walk" (runs in `running` status with no active steps)
724
-
725
- ### 8.3 DB Schema Additions
726
-
727
- ```sql
728
- ALTER TABLE workflow_run_steps ADD COLUMN retryCount INTEGER NOT NULL DEFAULT 0;
729
- ALTER TABLE workflow_run_steps ADD COLUMN maxRetries INTEGER NOT NULL DEFAULT 3;
730
- ALTER TABLE workflow_run_steps ADD COLUMN nextRetryAt TEXT; -- ISO timestamp
731
- ALTER TABLE workflow_run_steps ADD COLUMN idempotencyKey TEXT; -- runId:nodeId
732
-
733
- CREATE INDEX IF NOT EXISTS idx_wrs_retry
734
- ON workflow_run_steps(status, nextRetryAt)
735
- WHERE status = 'failed' AND nextRetryAt IS NOT NULL;
736
- ```
737
-
738
- ### 8.4 Signals, Timers, Child Workflows
739
-
740
- - **Signals**: Already implemented via `status: 'waiting'` + event bus resume. No changes needed.
741
- - **Timers**: A future `timer` node type that writes `nextRetryAt` and returns `mode: "async"`. The retry poller doubles as the timer executor.
742
- - **Child workflows**: A node type that calls `startWorkflowExecution()` for another workflow and returns `mode: "async"`. Store `parentRunId`/`parentStepId` for the callback.
743
-
744
- ### 8.5 What We Explicitly Skip
745
-
746
- - **Full deterministic replay** — graphs are declarative, structure = replay
747
- - **Event sourcing** — step log is sufficient
748
- - **Separate worker processes** — single-process SQLite
749
- - **Distributed locking** — SQLite WAL mode, no contention
750
- - **External dependencies** — no Temporal, Inngest, or other infra. Pure bun:sqlite.
751
-
752
- ### 8.6 Idempotency Gap
753
-
754
- If a `create-task` step succeeds but the process crashes before recording the step as `completed`, retrying will create a duplicate task.
755
-
756
- **Mitigation**: The engine enforces idempotency at the executor level. Before executing any step, the engine checks for an existing completed step with the same idempotency key (`${runId}:${nodeId}`). If found, it skips execution and injects the stored output into context. For async executors specifically, the executor itself must also check — e.g., the `agent-task` executor queries for an existing task with the matching idempotency key before creating a new one. This is a **mandatory contract** for all async executor implementations.
757
-
758
- ---
759
-
760
- ## 9. Next Steps
761
-
762
- 1. ~~Finalize schema format~~ → **Decided: nodes with `next`, edges auto-generated**
763
- 2. ~~Finalize open questions~~ → **All resolved (§6)**
764
- 3. **Write implementation plan** — phase by phase with verification at each step
765
- 4. **Implement** — rip-and-replace on this branch
766
-
767
- ---
768
-
769
- ## Review Errata
770
-
771
- _Reviewed: 2026-03-18 by Claude (automated review + codebase verification)_
772
- _File review: 2026-03-18 by Taras (14 inline comments processed)_
773
-
774
- ### Pending
775
-
776
- - [ ] **Code References table** — Add a structured table of key `file:line` references for the implementer. To be added during plan creation.
777
-
778
- ### Resolved
779
-
780
- - [x] **DAG → directed graph terminology** — Standardized to "directed graph" throughout. Renamed `walkDag` → `walkGraph`. Added `maxIterations` guard (default: 100) to §4.5.
781
- - [x] **Missing Research Question/Summary** — Dismissed by Taras: motivation section is sufficient.
782
- - [x] **Unhandled ZodError in `BaseExecutor.run()`** — Updated pseudocode to use `safeParse()` for both input config and output validation.
783
- - [x] **Single entry node constraint** — Added to §4.5: exactly one entry node, trigger payload in `context.trigger`.
784
- - [x] **script executor `workerId`** — Marked as "(future)" in config and description.
785
- - [x] **InputValueSchema invalid Zod** — Fixed to use `z.string().regex()`.
786
- - [x] **Idempotency gap** — Resolved in §8.6 with engine-level memoization + mandatory async executor idempotency key check.
787
- - [x] **Webhook HMAC upgrade** — Dismissed: nobody uses current workflows, clean slate.
788
- - [x] **Manual trigger redundancy** — Removed from `TriggerConfigSchema`. All workflows always manually triggerable (UI or agent MCP tool).
789
- - [x] **Executor implementation example** — Added notify executor example after §4.1.
790
- - [x] **"No next = end" clarification** — Added convention note after linear workflow example.
791
- - [x] **Snapshot type** — Added `WorkflowSnapshotSchema` type definition to §4.7.
792
- - [x] **Execution timeout** — Added to §4.8: `Promise.race` for instant executors, task-level TTL for async.
793
- - [x] **Event-based executor loop** — Confirmed in §4.8: purely event-driven, idle between events.
794
- - [x] Frontmatter field `author` → `researcher` — auto-fixed
795
- - [x] Test count corrected to ~2,500 lines across 9 test files — auto-fixed
796
- - [x] All prior art, tables, files, tools verified against codebase
797
- - [x] Context checkpoint gap claim (§8.2) verified accurate