@desplega.ai/agent-swarm 1.150.0 → 1.151.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 (293) hide show
  1. package/README.md +11 -0
  2. package/dist/{acp-adapter-d5mzggyk.js → acp-adapter-ex8hzjfc.js} +5 -5
  3. package/dist/{actions-wn6ew0p7.js → actions-2bgpyhww.js} +38 -11
  4. package/dist/{anthropic-messages-ec35ktvx.js → anthropic-messages-2y8nktar.js} +16 -16
  5. package/dist/{app-dty7p9hg.js → app-1706zhr1.js} +7 -7
  6. package/dist/{assistant-q4vhgjtx.js → assistant-bavke5p7.js} +41 -16
  7. package/dist/{azure-openai-responses-g85jv7m8.js → azure-openai-responses-f38x2avq.js} +13 -13
  8. package/dist/{boot-reembed-92292pgf.js → boot-reembed-3cmrrmpa.js} +8 -8
  9. package/dist/{boot-reembed-n15q6s9x.js → boot-reembed-nafcmmmc.js} +13 -15
  10. package/dist/{boot-scrub-logs-44pc955m.js → boot-scrub-logs-cd6a2sq0.js} +5 -5
  11. package/dist/{claude-adapter-cjegjbje.js → claude-adapter-wfp2gzvz.js} +12 -13
  12. package/dist/{claude-managed-adapter-p3ts5m9m.js → claude-managed-adapter-dsmkcrjy.js} +3 -3
  13. package/dist/{claude-sdk-session-7ywbn12v.js → claude-sdk-session-bht9jjak.js} +12 -13
  14. package/dist/{cli-ceb5y160.js → cli-0qb1z6s2.js} +1 -1
  15. package/dist/{cli-ryz8q8p1.js → cli-2tbvf1z1.js} +40 -40
  16. package/dist/{cli-zthatyrx.js → cli-3v9xhjcn.js} +5 -5
  17. package/dist/{cli-mzb0n642.js → cli-4wppfkcm.js} +350 -20
  18. package/dist/{cli-3ckzxdt1.js → cli-5jd2z7av.js} +90 -81
  19. package/dist/{cli-3mh119qv.js → cli-5tpgq60f.js} +9726 -693
  20. package/dist/{cli-ck1vqzdj.js → cli-7tgcstn2.js} +9 -4
  21. package/dist/{cli-ttje5a4z.js → cli-9004vfdf.js} +105 -56
  22. package/dist/{cli-asvrh7kj.js → cli-9xvdm3bx.js} +1 -1
  23. package/dist/{cli-9gqddmxs.js → cli-a1z3h107.js} +8 -8
  24. package/dist/{cli-72xdszyx.js → cli-czjtgfys.js} +2 -2
  25. package/dist/{cli-5my3bjsd.js → cli-d3p82erb.js} +7 -7
  26. package/dist/{cli-kyysm7m3.js → cli-f1wky6zp.js} +1 -1
  27. package/dist/{cli-a45d5v9b.js → cli-fm4ytsdk.js} +2 -2
  28. package/dist/{cli-111ey3ra.js → cli-frcta2w4.js} +5 -5
  29. package/dist/{cli-h505yhex.js → cli-g69fdc9g.js} +2 -2
  30. package/dist/{cli-cmp8g3sw.js → cli-gbfwcd3k.js} +44 -9
  31. package/dist/{cli-hbagregr.js → cli-gjyvhmmh.js} +88 -13
  32. package/dist/{cli-hmyynq9b.js → cli-ht5rs63n.js} +1 -1
  33. package/dist/{cli-dyx0237s.js → cli-j4nv2wqy.js} +2 -4
  34. package/dist/{cli-vr6qj104.js → cli-j9xczhaq.js} +1 -1
  35. package/dist/cli-pf9q3696.js +172 -0
  36. package/dist/{cli-7fesa1ky.js → cli-pgj4a5fb.js} +1 -1
  37. package/dist/{cli-7kwmt3r5.js → cli-ppm4975n.js} +9 -3
  38. package/dist/{cli-8chp8xab.js → cli-q88st9aj.js} +2 -2
  39. package/dist/{cli-kt7wevqh.js → cli-r2q6pevn.js} +132 -46
  40. package/dist/{cli-07jd68a1.js → cli-re8z5p8p.js} +1 -1
  41. package/dist/{cli-qp69dd5d.js → cli-s14agm5s.js} +105 -12
  42. package/dist/{cli-zd21jrrc.js → cli-sjaae6ff.js} +9872 -424
  43. package/dist/{cli-taym3dmg.js → cli-vwm416m6.js} +13 -13
  44. package/dist/{cli-1mx65de9.js → cli-wbyk465z.js} +1 -1
  45. package/dist/{cli-n75jt793.js → cli-z61ykvam.js} +6 -5
  46. package/dist/{cli-gm0fhz13.js → cli-zkxymas5.js} +2 -1
  47. package/dist/cli.js +22 -21
  48. package/dist/{codex-adapter-rn3aq7jm.js → codex-adapter-jjjk8w4m.js} +8 -9
  49. package/dist/{codex-hook-gthcmm0g.js → codex-hook-8jexc34x.js} +2 -2
  50. package/dist/{codex-session-runner-bge0cbsw.js → codex-session-runner-nd6ayxkx.js} +8 -9
  51. package/dist/{commands-26phw0pc.js → commands-9v4psyq1.js} +5 -5
  52. package/dist/{db-jxjx6s1b.js → db-wnt58tpe.js} +5 -5
  53. package/dist/dispatcher-05jh1aqk.js +74 -0
  54. package/dist/{google-generative-ai-tsskx7te.js → google-generative-ai-ndjmj5fa.js} +7 -7
  55. package/dist/{google-vertex-pkhpkbq9.js → google-vertex-fr665tqs.js} +10 -10
  56. package/dist/handlers-tw90pkh5.js +65 -0
  57. package/dist/{hook-t6fqsggw.js → hook-123e2scb.js} +9 -10
  58. package/dist/{hook-jw0ztn96.js → hook-sxe3r349.js} +9 -10
  59. package/dist/{http-hyc7s57s.js → http-ecsar8ez.js} +1431 -579
  60. package/dist/{index-sfhaq59d.js → index-16js521z.js} +119 -101
  61. package/dist/{index-wtwpthe1.js → index-hw26vj40.js} +25 -19
  62. package/dist/{index-bcyx5djw.js → index-nnrbpcjp.js} +25 -17
  63. package/dist/index-ymn7em0p.js +25 -0
  64. package/dist/{index-1d9r6a74.js → index-zj518gf9.js} +26 -20
  65. package/dist/{keepalive-fbsak4ya.js → keepalive-asqtcm4y.js} +7 -7
  66. package/dist/{lead-rdzdm627.js → lead-xbfr7fvt.js} +41 -49
  67. package/dist/{maintenance-25z1c1vf.js → maintenance-qma55qvw.js} +8 -8
  68. package/dist/{node-209sxmg3.js → node-x1g4v0pq.js} +9 -9
  69. package/dist/{oauth-refresh-sweep-j3d7gtse.js → oauth-refresh-sweep-3s04c6qw.js} +6 -6
  70. package/dist/{onboard-dkcwrc75.js → onboard-drskd386.js} +13 -4
  71. package/dist/{openai-codex-responses-pm5gnyfa.js → openai-codex-responses-wy6a43wd.js} +11 -11
  72. package/dist/{openai-responses-vwvk1taj.js → openai-responses-6xwf7bzg.js} +13 -13
  73. package/dist/{opencode-adapter-dce4wskd.js → opencode-adapter-28axqa09.js} +4 -4
  74. package/dist/{otel-impl-8rgyy3j8.js → otel-impl-943c96er.js} +1 -1
  75. package/dist/{pi-mono-adapter-4s2bbkgq.js → pi-mono-adapter-jcqt71cg.js} +14 -16
  76. package/dist/{pricing-refresh-9cek71nq.js → pricing-refresh-mx51az05.js} +7 -7
  77. package/dist/{rbac-roles-z98s2ypy.js → rbac-roles-78baecqd.js} +13 -9
  78. package/dist/{rbac-roles-vk8mqp9v.js → rbac-roles-wcmrg6sv.js} +7 -7
  79. package/dist/{render-v2-3j26g0qh.js → render-v2-8zjntgf5.js} +7 -7
  80. package/dist/{seed-pricing-7rxhcnzm.js → seed-pricing-jqjs6cws.js} +6 -6
  81. package/dist/{setup-e2t7vz0c.js → setup-4pks0vfk.js} +2 -2
  82. package/dist/{work-objects-8d3nd3x2.js → work-objects-wangt792.js} +38 -14
  83. package/dist/{worker-0x9fn7nq.js → worker-p2mr422x.js} +41 -49
  84. package/openapi.json +1351 -265
  85. package/package.json +2 -1
  86. package/src/agentmail/handlers.ts +95 -71
  87. package/src/be/db-client.ts +5 -0
  88. package/src/be/db.ts +11 -3
  89. package/src/be/extensions/db.ts +461 -0
  90. package/src/be/extensions/validate.ts +107 -0
  91. package/src/be/memory/boot-reembed.ts +17 -12
  92. package/src/be/memory/index.ts +12 -0
  93. package/src/be/memory/providers/openai-embedding.ts +4 -0
  94. package/src/be/memory/types.ts +2 -0
  95. package/src/be/migrations/155_extensions.sql +66 -0
  96. package/src/be/migrations/156_inbox_item_state_read_at.sql +7 -0
  97. package/src/be/rbac-roles.ts +3 -2
  98. package/src/be/scripts/typecheck.ts +52 -38
  99. package/src/be/seed-skills/index.ts +7 -0
  100. package/src/be/swarm-config-guard.ts +3 -1
  101. package/src/commands/onboard/compose-generator.ts +14 -2
  102. package/src/commands/onboard/env-generator.ts +7 -0
  103. package/src/commands/runner.ts +1 -1
  104. package/src/extensions/apply-task-create.ts +135 -0
  105. package/src/extensions/bundle-path.ts +10 -0
  106. package/src/extensions/contract-runtime.ts +7 -0
  107. package/src/extensions/contract-types.generated.ts +4 -0
  108. package/src/extensions/contract.ts +270 -0
  109. package/src/extensions/ctx.ts +186 -0
  110. package/src/extensions/dispatcher.ts +479 -0
  111. package/src/extensions/identity.ts +44 -0
  112. package/src/extensions/lifecycle.ts +281 -0
  113. package/src/extensions/loader.ts +207 -0
  114. package/src/extensions/post-bridge.ts +161 -0
  115. package/src/github/handlers.ts +185 -149
  116. package/src/gitlab/handlers.ts +97 -81
  117. package/src/heartbeat/heartbeat.ts +152 -83
  118. package/src/http/agents.ts +1 -1
  119. package/src/http/all-routes.ts +1 -0
  120. package/src/http/apps.ts +14 -10
  121. package/src/http/core.ts +34 -0
  122. package/src/http/extensions.ts +547 -0
  123. package/src/http/inbox-state.ts +2 -0
  124. package/src/http/index.ts +25 -0
  125. package/src/http/mcp-bridge.ts +96 -62
  126. package/src/http/mcp.ts +1 -1
  127. package/src/http/status.ts +6 -4
  128. package/src/http/tasks.ts +51 -35
  129. package/src/integrations/kapso/inbound.ts +15 -11
  130. package/src/jira/sync.ts +26 -18
  131. package/src/linear/sync.ts +26 -18
  132. package/src/prompts/session-templates.ts +5 -4
  133. package/src/rbac/admission.ts +1 -1
  134. package/src/rbac/elevated-agents.ts +24 -0
  135. package/src/rbac/legacy-policy.ts +35 -6
  136. package/src/rbac/permissions.ts +8 -0
  137. package/src/scheduler/deferred-task-waits.ts +133 -51
  138. package/src/scheduler/schedule-task.ts +50 -24
  139. package/src/scheduler/scheduler.ts +4 -2
  140. package/src/scripts-runtime/executors/native.ts +5 -1
  141. package/src/scripts-runtime/executors/types.ts +5 -0
  142. package/src/scripts-runtime/import-allowlist.ts +79 -19
  143. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  144. package/src/scripts-runtime/swarm-config.ts +8 -0
  145. package/src/scripts-runtime/swarm-sdk.ts +3 -0
  146. package/src/scripts-runtime/types/stdlib.d.ts +9 -0
  147. package/src/scripts-runtime/types/swarm-extension.d.ts +562 -0
  148. package/src/scripts-runtime/types/swarm-sdk.d.ts +9 -0
  149. package/src/server.ts +6 -0
  150. package/src/slack/HEURISTICS.md +1 -1
  151. package/src/slack/actions.ts +21 -17
  152. package/src/slack/blocks.ts +1 -1
  153. package/src/slack/handlers.ts +98 -5
  154. package/src/slack/inbound-files.ts +6 -2
  155. package/src/slack/render-v2.ts +171 -35
  156. package/src/slack/router.ts +13 -3
  157. package/src/slack/steering.ts +3 -3
  158. package/src/tasks/errors.ts +9 -0
  159. package/src/tasks/sibling-awareness.ts +35 -1
  160. package/src/tasks/worker-follow-up.ts +64 -12
  161. package/src/tests/base-prompt.test.ts +1 -0
  162. package/src/tests/deferred-task-wake.test.ts +161 -9
  163. package/src/tests/docs-index-footprint.test.js +3 -3
  164. package/src/tests/env-flag.test.ts +1 -0
  165. package/src/tests/extensions-db.test.ts +216 -0
  166. package/src/tests/extensions-dispatcher.test.ts +275 -0
  167. package/src/tests/extensions-example-heartbeat-remediate.test.ts +69 -0
  168. package/src/tests/extensions-example-mcp-install.test.ts +63 -0
  169. package/src/tests/extensions-example-no-exclamation-marks.test.ts +72 -0
  170. package/src/tests/extensions-example-rewrite-and-suppress.test.ts +70 -0
  171. package/src/tests/extensions-example-route-slack-channel.test.ts +217 -0
  172. package/src/tests/extensions-heartbeat.test.ts +291 -0
  173. package/src/tests/extensions-http.test.ts +431 -0
  174. package/src/tests/extensions-lead-equivalence.test.ts +49 -0
  175. package/src/tests/extensions-lifecycle.test.ts +209 -0
  176. package/src/tests/extensions-loader.test.ts +95 -0
  177. package/src/tests/extensions-mcp-tools.test.ts +245 -0
  178. package/src/tests/extensions-pre-task.test.ts +487 -0
  179. package/src/tests/extensions-run-context.test.ts +41 -0
  180. package/src/tests/extensions-tool-call.test.ts +288 -0
  181. package/src/tests/extensions-validate.test.ts +196 -0
  182. package/src/tests/fixtures/extensions/bad-import/hooks.ts +8 -0
  183. package/src/tests/fixtures/extensions/bad-import/manifest.json +9 -0
  184. package/src/tests/fixtures/extensions/bad-return-shape/hooks.ts +10 -0
  185. package/src/tests/fixtures/extensions/bad-return-shape/manifest.json +9 -0
  186. package/src/tests/fixtures/extensions/block-tasks-from-source/hooks.ts +22 -0
  187. package/src/tests/fixtures/extensions/block-tasks-from-source/manifest.json +9 -0
  188. package/src/tests/fixtures/extensions/ignore-channel/hooks.ts +22 -0
  189. package/src/tests/fixtures/extensions/ignore-channel/manifest.json +9 -0
  190. package/src/tests/fixtures/extensions/load.ts +10 -0
  191. package/src/tests/fixtures/extensions/minimal/hooks.ts +7 -0
  192. package/src/tests/fixtures/extensions/minimal/manifest.json +9 -0
  193. package/src/tests/fixtures/extensions/never-fail-long-tasks/hooks.ts +11 -0
  194. package/src/tests/fixtures/extensions/never-fail-long-tasks/manifest.json +9 -0
  195. package/src/tests/fixtures/extensions/no-exclamation-marks/hooks.ts +23 -0
  196. package/src/tests/fixtures/extensions/no-exclamation-marks/manifest.json +9 -0
  197. package/src/tests/fixtures/extensions/post-logger/hooks.ts +9 -0
  198. package/src/tests/fixtures/extensions/post-logger/manifest.json +9 -0
  199. package/src/tests/fixtures/extensions/priority-a/hooks.ts +7 -0
  200. package/src/tests/fixtures/extensions/priority-a/manifest.json +9 -0
  201. package/src/tests/fixtures/extensions/priority-b/hooks.ts +7 -0
  202. package/src/tests/fixtures/extensions/priority-b/manifest.json +9 -0
  203. package/src/tests/fixtures/extensions/record-only-on-tag/hooks.ts +16 -0
  204. package/src/tests/fixtures/extensions/record-only-on-tag/manifest.json +9 -0
  205. package/src/tests/fixtures/extensions/reserved-assets/hooks.ts +5 -0
  206. package/src/tests/fixtures/extensions/reserved-assets/manifest.json +10 -0
  207. package/src/tests/fixtures/extensions/rewrite-progress-prefix/hooks.ts +22 -0
  208. package/src/tests/fixtures/extensions/rewrite-progress-prefix/manifest.json +9 -0
  209. package/src/tests/fixtures/extensions/rewrite-task-priority/hooks.ts +7 -0
  210. package/src/tests/fixtures/extensions/rewrite-task-priority/manifest.json +9 -0
  211. package/src/tests/fixtures/extensions/route-channel-to-agent/hooks.ts +26 -0
  212. package/src/tests/fixtures/extensions/route-channel-to-agent/manifest.json +9 -0
  213. package/src/tests/fixtures/extensions/slow/hooks.ts +10 -0
  214. package/src/tests/fixtures/extensions/slow/manifest.json +9 -0
  215. package/src/tests/fixtures/extensions/suppress-lead-follow-up/hooks.ts +12 -0
  216. package/src/tests/fixtures/extensions/suppress-lead-follow-up/manifest.json +9 -0
  217. package/src/tests/fixtures/extensions/throws/hooks.ts +12 -0
  218. package/src/tests/fixtures/extensions/throws/manifest.json +9 -0
  219. package/src/tests/fixtures/extensions/worker-runtime/hooks.ts +5 -0
  220. package/src/tests/fixtures/extensions/worker-runtime/manifest.json +9 -0
  221. package/src/tests/memory-edit-authorization.test.ts +32 -0
  222. package/src/tests/multi-runtime-enabled-stats.test.ts +2 -2
  223. package/src/tests/multi-runtime-registration.test.ts +14 -14
  224. package/src/tests/onboard-compose.test.ts +44 -0
  225. package/src/tests/preload.ts +5 -0
  226. package/src/tests/rbac-admission.test.ts +18 -3
  227. package/src/tests/rbac-engine.test.ts +39 -0
  228. package/src/tests/realtime-room-auth.test.ts +1 -1
  229. package/src/tests/reload-config.test.ts +44 -0
  230. package/src/tests/routing-affinity-inventory.test.ts +1 -1
  231. package/src/tests/script-connections.test.ts +2 -0
  232. package/src/tests/scripts-boot-reembed.test.ts +4 -0
  233. package/src/tests/scripts-embeddings.test.ts +4 -0
  234. package/src/tests/scripts-import-allowlist.test.ts +44 -1
  235. package/src/tests/scripts-mcp-e2e.test.ts +80 -0
  236. package/src/tests/scripts-only-gating.test.ts +2 -0
  237. package/src/tests/scripts-runtime-identity.test.ts +1 -1
  238. package/src/tests/slack-blocks.test.ts +12 -1
  239. package/src/tests/slack-render-v2.test.ts +76 -3
  240. package/src/tests/slack-router.test.ts +17 -2
  241. package/src/tests/slack-steering.test.ts +19 -0
  242. package/src/tests/status.test.ts +12 -0
  243. package/src/tests/steering-enabled.test.ts +6 -8
  244. package/src/tests/task-tool-preload-mcp.test.ts +4 -1
  245. package/src/tests/tool-annotations.test.ts +1 -1
  246. package/src/tests/tool-registrar-no-input.test.ts +42 -1
  247. package/src/tools/defer-task.ts +1 -1
  248. package/src/tools/extension-common.ts +84 -0
  249. package/src/tools/extension-install.ts +65 -0
  250. package/src/tools/extension-list.ts +66 -0
  251. package/src/tools/script-common.ts +43 -18
  252. package/src/tools/send-task.ts +69 -107
  253. package/src/tools/task-action.ts +43 -22
  254. package/src/tools/task-tool-ctx.ts +2 -0
  255. package/src/tools/tool-config.ts +3 -1
  256. package/src/tools/utils.ts +140 -16
  257. package/src/types.ts +133 -0
  258. package/src/utils/multi-runtime.ts +2 -2
  259. package/src/utils/steering-enabled.ts +4 -4
  260. package/src/workflows/executors/agent-task.ts +13 -3
  261. package/templates/extensions/README.md +17 -0
  262. package/templates/extensions/notify-on-complete/README.md +11 -0
  263. package/templates/extensions/notify-on-complete/hooks.ts +61 -0
  264. package/templates/extensions/notify-on-complete/manifest.json +7 -0
  265. package/templates/extensions/require-ticket-ref/README.md +11 -0
  266. package/templates/extensions/require-ticket-ref/hooks.ts +30 -0
  267. package/templates/extensions/require-ticket-ref/manifest.json +7 -0
  268. package/templates/extensions/require-verification-note/README.md +11 -0
  269. package/templates/extensions/require-verification-note/hooks.ts +32 -0
  270. package/templates/extensions/require-verification-note/manifest.json +7 -0
  271. package/templates/skills/scheduling/content.md +2 -0
  272. package/templates/skills/swarm-extensions/config.json +14 -0
  273. package/templates/skills/swarm-extensions/content.md +120 -0
  274. package/dist/cli-b8x19vbh.js +0 -823
  275. package/dist/cli-n1yj5fd5.js +0 -164
  276. package/dist/cli-q04q68be.js +0 -3066
  277. package/dist/cli-qgm2pfpq.js +0 -6377
  278. package/dist/cli-rnsr8asm.js +0 -4323
  279. package/dist/cli-rwp3ksm7.js +0 -545
  280. package/dist/cli-xjb9wghj.js +0 -668
  281. package/dist/cli-xvkmedgn.js +0 -332
  282. package/dist/cli-ydk0wjj8.js +0 -338
  283. package/dist/handlers-vr1djg4n.js +0 -41
  284. package/dist/{claude-managed-setup-f5pmsyrp.js → claude-managed-setup-48dwg9bv.js} +3 -3
  285. package/dist/{cli-81r683bv.js → cli-ch38q5z4.js} +0 -0
  286. package/dist/{cli-wk0gjrn3.js → cli-kj76p1ez.js} +6 -6
  287. package/dist/{cli-c71mg51n.js → cli-r2fpe7cx.js} +5 -5
  288. package/dist/{cli-8qx7jnrk.js → cli-y6x0gqtg.js} +16 -16
  289. package/dist/{index-aa3sa6s8.js → index-2wsdsnmm.js} +1 -1
  290. package/dist/{mistral-conversations-4ryk7h83.js → mistral-conversations-qhr84ph3.js} +9 -9
  291. package/dist/{openai-completions-qdcmkfnr.js → openai-completions-32rdwmze.js} +17 -17
  292. package/dist/{openrouter-images-qx18fyp8.js → openrouter-images-9f9ek4rw.js} +3 -3
  293. package/dist/{pi-messages-79jvzz1d.js → pi-messages-b1mbr6gp.js} +4 -4
@@ -0,0 +1,120 @@
1
+ # Swarm Extensions
2
+
3
+ An extension is a trusted TypeScript hook bundle that runs inside the swarm API server. Use one when a rule must apply to the whole swarm: block or rewrite new tasks, route Slack channels, suppress follow-ups, change stalled-task remediation, guard tool calls, or react after a task or tool call finishes.
4
+
5
+ Do not use an extension for work that one task, one script, or one schedule can do.
6
+
7
+ ## Tools
8
+
9
+ `extension-install` and `extension-list`. They are deferred. Load them with your harness tool search before the first call.
10
+
11
+ `extension-install` validates the bundle (manifest, imports, typecheck against the hook contract) and stores it. Only a lead agent, an operator, or a dashboard user may install. A worker gets `Forbidden` from the tool. When you are a worker, write and validate the bundle, then hand it to your lead with `send-task` (include the manifest, the hooks file, and the config) and report that in your output. Do not call the REST install route with the shared API key to get around the role check. The stored extension stays disabled. An operator enables it from the dashboard (Settings, Extensions) or with `POST /api/extensions/{id}/enable`. Say this in your task report and give the extension name.
12
+
13
+ Installing a bundle with the same name and changed files stores a new version. The active version does not change until an operator activates it.
14
+
15
+ ## Get the contract before you write hooks
16
+
17
+ Fetch the generated type definitions and read them. Do not guess event names or field names.
18
+
19
+ ```bash
20
+ curl -s "$MCP_BASE_URL/api/extensions/type-defs" \
21
+ -H "X-Agent-ID: $AGENT_ID" -H "Authorization: Bearer ${AGENT_SWARM_API_KEY:-$API_KEY}"
22
+ ```
23
+
24
+ `$MCP_BASE_URL`, `$AGENT_ID`, and `$AGENT_SWARM_API_KEY` (or `$API_KEY`) are in every worker environment. The response is the `swarm-extension` module declaration: every event, its payload, and what a `modify` result may change.
25
+
26
+ ## Events
27
+
28
+ | Event | When | Result |
29
+ |---|---|---|
30
+ | `pre.task.create` | before any task is stored (REST, MCP, Slack, schedule, workflow, webhook, follow-up) | `block(reason)`, `modify({ priority, agentId, tags, description, ... })`, or nothing |
31
+ | `pre.task.followUp` | before the lead follow-up task for a finished worker task | `block`, `modify({ description, priority, agentId })`, or nothing |
32
+ | `pre.slack.route` | before a Slack message becomes a task | `modify({ target: { kind: "agent", agentId } })`, `{ kind: "lead" }`, `{ kind: "broadcast" }` |
33
+ | `pre.heartbeat.remediate` | after the heartbeat sweep finds a stalled task | `modify({ proposedAction: "record" | "fail" | "supersede-resume" })` |
34
+ | `pre.tool.call` | before an agent MCP tool call runs | `block(reason)` or `modify({ args })` |
35
+ | `post.task.created`, `post.task.completed`, `post.task.failed`, `post.task.cancelled`, `post.task.superseded`, `post.task.progress` | after the change is committed | none |
36
+ | `post.slack.message`, `post.tool.call` | after the message or tool call finished | none |
37
+
38
+ `event.origin` on `pre.task.create` tells where the task comes from: `rest`, `app`, `mcp`, `slack`, `schedule`, `workflow`, `webhook`, `followUp`, or `extension:<name>`.
39
+
40
+ ## Bundle shape
41
+
42
+ The bundle is a manifest plus a files map. Version 1 accepts one file, the `assets.hooks` TypeScript file, and only `runtime: "api"`.
43
+
44
+ ```json
45
+ {
46
+ "manifest": {
47
+ "name": "require-ticket-ref",
48
+ "description": "Blocks REST and MCP tasks that do not name a ticket",
49
+ "version": "1.0.0",
50
+ "runtime": "api",
51
+ "assets": { "hooks": "hooks.ts" }
52
+ },
53
+ "files": { "hooks.ts": "<file content>" },
54
+ "config": { "pattern": "DES-\\d+" }
55
+ }
56
+ ```
57
+
58
+ Rules for `hooks.ts`:
59
+
60
+ - Import only from `swarm-extension`, `zod`, and `stdlib`. Relative imports, other packages, and dynamic imports are rejected.
61
+ - Export the extension as `default`. Export `config` (a Zod schema) when the extension takes configuration. The install validates `config` against it.
62
+ - Return `block(reason)` or `modify(data)` from pre hooks. Return nothing to continue.
63
+ - Keep handlers fast. A handler is cancelled after 5 seconds. Five consecutive failures auto-disable the extension.
64
+ - Handlers run outside database transactions and must not assume ordering with other extensions. Use `priority` in `api.on(event, handler, { priority })` when order matters (lower runs first).
65
+
66
+ ## Minimal hooks file
67
+
68
+ ```ts
69
+ import { block, modify, type SwarmExtension } from "swarm-extension";
70
+ import { z } from "zod";
71
+
72
+ export const config = z.object({ pattern: z.string().default("DES-\\d+") });
73
+
74
+ const manifest = {
75
+ name: "require-ticket-ref",
76
+ description: "Blocks REST and MCP tasks that do not name a ticket",
77
+ version: "1.0.0",
78
+ runtime: "api",
79
+ assets: { hooks: "hooks.ts" },
80
+ config,
81
+ } as const;
82
+
83
+ const extension: SwarmExtension<typeof manifest> = (api) => {
84
+ api.on("pre.task.create", (event, ctx) => {
85
+ if (event.origin !== "rest" && event.origin !== "mcp") return;
86
+ if (new RegExp(ctx.config.pattern).test(event.description)) return;
87
+ return block(`Task must reference a ticket matching ${ctx.config.pattern}`);
88
+ });
89
+
90
+ api.on("post.task.completed", async (event, ctx) => {
91
+ await ctx.state.incr("completed");
92
+ ctx.log.info("task completed", { id: event.task.id });
93
+ });
94
+ };
95
+
96
+ export default extension;
97
+ ```
98
+
99
+ ## Context (`ctx`)
100
+
101
+ - `ctx.config`: the validated configuration.
102
+ - `ctx.state`: per-extension key-value store (`get`, `set`, `incr`, `del`).
103
+ - `ctx.swarm`: the swarm SDK. Call any script-exposed tool by name with underscores, for example `await ctx.swarm.slack_post({ channelId, message })` or `await ctx.swarm.task_send({ ... })`. Calls made from a hook carry the `ext:<name>` identity, which has lead privileges while the extension is enabled. Calls resolve with `{ success, status, data }` and do not throw on a tool error. Check `success` and throw when the hook must fail. The type definitions import `SwarmSdk` from `swarm-sdk`. Call the `script-query-types` tool (or `GET /api/scripts/type-defs`) to get `swarm-sdk.d.ts` with every method name and argument type before you use `ctx.swarm`.
104
+ - `ctx.log`: structured logger. Entries appear in the extension run log on the dashboard.
105
+ - `ctx.signal`: abort signal for the 5-second cap.
106
+
107
+ ## Verify
108
+
109
+ 1. Call `extension-list` and confirm the name, version, and `enabled: false`.
110
+ 2. Report the enable step. After an operator enables it, the dashboard run log shows every dispatch with its result (`continue`, `modify`, `block`, or `error`).
111
+ 3. Trigger the event once and confirm the effect (for example, a blocked REST task returns HTTP 422 with your reason).
112
+
113
+ ## Common mistakes
114
+
115
+ - Guessing event names. Fetch the type definitions.
116
+ - Using `import` from a package other than `swarm-extension`, `zod`, or `stdlib`.
117
+ - Returning a plain object instead of `block(...)` or `modify(...)`.
118
+ - Modifying fields the event does not allow. Read the `*Modify` type for that event.
119
+ - Expecting the extension to run after install. It runs only after an operator enables it.
120
+ - Blocking tasks from every origin. Check `event.origin` so schedules, workflows, and follow-ups keep working unless you mean to block them.