@desplega.ai/agent-swarm 1.87.0 → 1.89.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 (102) hide show
  1. package/README.md +5 -1
  2. package/openapi.json +53 -1
  3. package/package.json +6 -5
  4. package/plugin/skills/composio/SKILL.md +98 -0
  5. package/src/be/db.ts +374 -9
  6. package/src/be/migrations/080_skill_system_defaults.sql +8 -0
  7. package/src/be/migrations/081_metrics.sql +39 -0
  8. package/src/be/migrations/082_user_audit_fields.sql +120 -0
  9. package/src/be/modelsdev-cache.json +3825 -2417
  10. package/src/be/seed/registry.ts +3 -2
  11. package/src/be/seed-skills/index.ts +179 -0
  12. package/src/cli.tsx +51 -4
  13. package/src/commands/e2b-stack-wizard.tsx +394 -0
  14. package/src/commands/e2b.ts +1352 -53
  15. package/src/commands/onboard/dashboard-url.ts +29 -0
  16. package/src/commands/onboard/steps/post-dashboard.tsx +3 -1
  17. package/src/commands/onboard.tsx +3 -1
  18. package/src/commands/runner.ts +154 -22
  19. package/src/commands/x.ts +118 -0
  20. package/src/e2b/dispatch.ts +234 -18
  21. package/src/github/handlers.ts +40 -1
  22. package/src/heartbeat/heartbeat.ts +26 -5
  23. package/src/http/active-sessions.ts +32 -1
  24. package/src/http/auth.ts +36 -0
  25. package/src/http/core.ts +20 -16
  26. package/src/http/db-query.ts +20 -0
  27. package/src/http/index.ts +2 -0
  28. package/src/http/memory.ts +13 -1
  29. package/src/http/metrics.ts +447 -0
  30. package/src/http/operator-actor.ts +9 -0
  31. package/src/http/poll.ts +11 -1
  32. package/src/http/skills.ts +53 -0
  33. package/src/http/tasks.ts +4 -1
  34. package/src/http/webhooks.ts +75 -0
  35. package/src/http/workflows.ts +5 -1
  36. package/src/integrations/kapso/client.ts +82 -0
  37. package/src/memory/automatic-task-gate.ts +47 -0
  38. package/src/metrics/version.ts +26 -0
  39. package/src/prompts/base-prompt.ts +24 -1
  40. package/src/prompts/session-templates.ts +74 -0
  41. package/src/providers/claude-adapter.ts +19 -0
  42. package/src/providers/codex-adapter.ts +22 -0
  43. package/src/providers/ctx-mode-env.ts +10 -0
  44. package/src/providers/opencode-adapter.ts +72 -7
  45. package/src/server.ts +10 -1
  46. package/src/slack/blocks.ts +12 -4
  47. package/src/slack/watcher.ts +3 -3
  48. package/src/telemetry.ts +14 -1
  49. package/src/templates.d.ts +4 -0
  50. package/src/tests/base-prompt.test.ts +76 -0
  51. package/src/tests/budget-claim-gate.test.ts +26 -0
  52. package/src/tests/claude-adapter.test.ts +86 -1
  53. package/src/tests/codex-adapter.test.ts +89 -0
  54. package/src/tests/core-auth.test.ts +8 -1
  55. package/src/tests/e2b-dispatch.test.ts +603 -11
  56. package/src/tests/events-http.test.ts +6 -2
  57. package/src/tests/github-handlers-cancel-config.test.ts +262 -0
  58. package/src/tests/heartbeat.test.ts +84 -3
  59. package/src/tests/http-api-integration.test.ts +116 -1
  60. package/src/tests/kapso-client.test.ts +74 -1
  61. package/src/tests/kapso-inbound.test.ts +60 -2
  62. package/src/tests/metrics-http.test.ts +247 -0
  63. package/src/tests/opencode-adapter.test.ts +185 -30
  64. package/src/tests/prompt-template-session.test.ts +4 -2
  65. package/src/tests/runner-repo-autostash.test.ts +117 -0
  66. package/src/tests/runner-requester-profile.test.ts +25 -0
  67. package/src/tests/runner-skills-refresh.test.ts +1 -1
  68. package/src/tests/self-improvement.test.ts +89 -0
  69. package/src/tests/skill-update-scope.test.ts +88 -1
  70. package/src/tests/slack-blocks.test.ts +15 -0
  71. package/src/tests/swarm-x-tool.test.ts +90 -0
  72. package/src/tests/system-default-skills.test.ts +122 -0
  73. package/src/tests/telemetry-init.test.ts +86 -0
  74. package/src/tests/ui-logs-parser.test.ts +271 -0
  75. package/src/tests/user-token-rest-auth.test.ts +129 -0
  76. package/src/tests/workflow-async-v2.test.ts +23 -0
  77. package/src/tests/x-composio.test.ts +122 -0
  78. package/src/tools/create-metric.ts +191 -0
  79. package/src/tools/skills/skill-delete.ts +14 -0
  80. package/src/tools/skills/skill-update.ts +14 -0
  81. package/src/tools/store-progress.ts +19 -5
  82. package/src/tools/swarm-x.ts +116 -0
  83. package/src/tools/tool-config.ts +6 -0
  84. package/src/types.ts +121 -0
  85. package/src/utils/request-auth-context.ts +28 -0
  86. package/src/utils/skills-refresh.ts +2 -2
  87. package/src/workflows/engine.ts +24 -2
  88. package/src/workflows/executors/agent-task.ts +2 -0
  89. package/src/x/composio.ts +295 -0
  90. package/templates/skills/artifacts/config.json +1 -0
  91. package/templates/skills/attio-interaction/SKILL.md +279 -0
  92. package/templates/skills/attio-interaction/config.json +14 -0
  93. package/templates/skills/attio-interaction/content.md +272 -0
  94. package/templates/skills/kv-storage/config.json +1 -0
  95. package/templates/skills/pages/config.json +1 -0
  96. package/templates/skills/scheduled-task-resilience/config.json +1 -0
  97. package/templates/skills/swarm-scripts/SKILL.md +91 -0
  98. package/templates/skills/swarm-scripts/config.json +14 -0
  99. package/templates/skills/swarm-scripts/content.md +86 -0
  100. package/templates/skills/workflow-iterate/config.json +1 -0
  101. package/templates/skills/workflow-structured-output/config.json +1 -0
  102. package/tsconfig.json +2 -1
@@ -0,0 +1,14 @@
1
+ {
2
+ "kind": "skill",
3
+ "name": "attio-interaction",
4
+ "displayName": "Attio Interaction",
5
+ "slug": "attio-interaction",
6
+ "title": "Attio Interaction",
7
+ "description": "Generic Attio CRM REST API v2 recipes for querying records, upserting companies/people/deals, writing notes/tasks/comments, managing lists, and handling webhooks.",
8
+ "version": "1.0.0",
9
+ "category": "skills",
10
+ "placeholders": ["ATTIO_API_KEY"],
11
+ "runAllSeedersCandidate": true,
12
+ "systemDefault": true,
13
+ "tags": ["attio", "crm", "sales"]
14
+ }
@@ -0,0 +1,272 @@
1
+ # Attio Interaction (Read + Write)
2
+
3
+ Use this skill to read and write your Attio CRM through the REST API v2. Every read or write is a direct API call; agent-swarm does not maintain a separate Attio sync.
4
+
5
+ ## TL;DR
6
+
7
+ 1. Resolve `ATTIO_API_KEY` from swarm config before making calls.
8
+ 2. Base URL: `https://api.attio.com/v2/`
9
+ 3. Use `Authorization: Bearer $ATTIO_API_KEY`, `Content-Type: application/json`, and `Accept: application/json`.
10
+ 4. Prefer upsert over create for People, Companies, and Deals: `PUT /v2/objects/{slug}/records` with `matching_attribute`.
11
+ 5. Rate limits: 100 reads/sec, 25 writes/sec. Pace write bursts to roughly 15-20/sec.
12
+ 6. Attribute values are arrays, even for scalar values: `[{ "value": 42 }]`, never `42`.
13
+
14
+ ## Authentication
15
+
16
+ ```bash
17
+ ATTIO_API_KEY=$(get-config key="ATTIO_API_KEY" includeSecrets=true)
18
+
19
+ curl -sS "https://api.attio.com/v2/objects" \
20
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
21
+ -H "Accept: application/json"
22
+ ```
23
+
24
+ If calls return `401`, re-fetch the key from config. If it still fails, notify the Lead; the key may need rotation. Do not retry silently.
25
+
26
+ ## Core object slugs
27
+
28
+ | Object | API slug | Primary matching attribute |
29
+ |---|---|---|
30
+ | Companies | `companies` | `domains` |
31
+ | People | `people` | `email_addresses` |
32
+ | Deals | `deals` | Usually no global dedupe key; link to company/person records |
33
+
34
+ Custom objects use their configured API slug. Discover them with `GET /v2/objects`.
35
+
36
+ ## Common operations
37
+
38
+ ### 1. Discover objects and slugs
39
+
40
+ ```bash
41
+ curl -sS "https://api.attio.com/v2/objects" \
42
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
43
+ -H "Accept: application/json" \
44
+ | jq '.data[] | {slug: .api_slug, name: .title}'
45
+ ```
46
+
47
+ ### 2. Query records with filters and pagination
48
+
49
+ ```bash
50
+ curl -sS -X POST "https://api.attio.com/v2/objects/companies/records/query" \
51
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
52
+ -H "Content-Type: application/json" \
53
+ -d '{
54
+ "filter": {
55
+ "stage": { "$not_equal": "Won" }
56
+ },
57
+ "limit": 100,
58
+ "offset": 0
59
+ }' | jq '.data[] | {record_id: .id.record_id, name: .values.name[0].value}'
60
+ ```
61
+
62
+ Paginate by increasing `offset` until `data` is empty. For no filter, omit the `filter` key.
63
+
64
+ ### 3. Get a single record
65
+
66
+ ```bash
67
+ curl -sS "https://api.attio.com/v2/objects/companies/records/{RECORD_ID}" \
68
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
69
+ -H "Accept: application/json" \
70
+ | jq '.data.values'
71
+ ```
72
+
73
+ ### 4. Upsert a company by domain
74
+
75
+ Use `PUT` with `matching_attribute`. It creates if not found and updates if found, so it is safe to call repeatedly.
76
+
77
+ ```bash
78
+ curl -sS -X PUT "https://api.attio.com/v2/objects/companies/records" \
79
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
80
+ -H "Content-Type: application/json" \
81
+ -d '{
82
+ "data": {
83
+ "values": {
84
+ "name": [{ "value": "Acme Corp" }],
85
+ "domains": [{ "domain": "acme.com" }],
86
+ "employee_count": [{ "value": 150 }]
87
+ }
88
+ },
89
+ "matching_attribute": "domains"
90
+ }' | jq '{record_id: .data.id.record_id}'
91
+ ```
92
+
93
+ ### 5. Upsert a person by email
94
+
95
+ ```bash
96
+ curl -sS -X PUT "https://api.attio.com/v2/objects/people/records" \
97
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
98
+ -H "Content-Type: application/json" \
99
+ -d '{
100
+ "data": {
101
+ "values": {
102
+ "name": [{ "first_name": "Jane", "last_name": "Doe" }],
103
+ "email_addresses": [{ "email_address": "jane@acme.com" }],
104
+ "job_title": [{ "value": "CTO" }]
105
+ }
106
+ },
107
+ "matching_attribute": "email_addresses"
108
+ }' | jq '{record_id: .data.id.record_id}'
109
+ ```
110
+
111
+ ### 6. Update specific attributes on an existing record
112
+
113
+ ```bash
114
+ curl -sS -X PATCH "https://api.attio.com/v2/objects/companies/records/{RECORD_ID}" \
115
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
116
+ -H "Content-Type: application/json" \
117
+ -d '{
118
+ "data": {
119
+ "values": {
120
+ "icp_score": [{ "value": 85 }],
121
+ "icp_tier": [{ "value": "Tier 1" }]
122
+ }
123
+ }
124
+ }'
125
+ ```
126
+
127
+ ### 7. Write a note to a record
128
+
129
+ ```bash
130
+ curl -sS -X POST "https://api.attio.com/v2/notes" \
131
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
132
+ -H "Content-Type: application/json" \
133
+ -d '{
134
+ "data": {
135
+ "parent_object": "companies",
136
+ "parent_record_id": "{RECORD_ID}",
137
+ "title": "Enrichment - 2026-06-02",
138
+ "content": "Employee count: 150. Funding stage: Series A. Tech stack: Node.js, React."
139
+ }
140
+ }' | jq '{note_id: .data.id.note_id}'
141
+ ```
142
+
143
+ ### 8. Create a task linked to a record
144
+
145
+ ```bash
146
+ curl -sS "https://api.attio.com/v2/workspace_members" \
147
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
148
+ -H "Accept: application/json" \
149
+ | jq '.data[] | {member_id: .id.workspace_member_id, name: .name, email: .email_address}'
150
+
151
+ curl -sS -X POST "https://api.attio.com/v2/tasks" \
152
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
153
+ -H "Content-Type: application/json" \
154
+ -d '{
155
+ "data": {
156
+ "content": "Follow up - no contact in 21 days",
157
+ "is_completed": false,
158
+ "assignees": [
159
+ { "referenced_actor_type": "workspace-member", "referenced_actor_id": "{MEMBER_ID}" }
160
+ ],
161
+ "linked_records": [
162
+ { "target_object": "deals", "target_record_id": "{DEAL_RECORD_ID}" }
163
+ ]
164
+ }
165
+ }' | jq '{task_id: .data.id.task_id}'
166
+ ```
167
+
168
+ ### 9. Post a comment on a record
169
+
170
+ ```bash
171
+ curl -sS -X POST "https://api.attio.com/v2/comments" \
172
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
173
+ -H "Content-Type: application/json" \
174
+ -d '{
175
+ "data": {
176
+ "record": { "target_object": "companies", "target_record_id": "{RECORD_ID}" },
177
+ "content": [
178
+ { "type": "text", "text": "Possible duplicate of acme-corp-old - please review and merge." }
179
+ ]
180
+ }
181
+ }' | jq '{comment_id: .data.id.comment_id}'
182
+ ```
183
+
184
+ ### 10. Query a list or pipeline view
185
+
186
+ ```bash
187
+ curl -sS "https://api.attio.com/v2/lists" \
188
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
189
+ -H "Accept: application/json" \
190
+ | jq '.data[] | {list_id: .id.list_id, name: .title}'
191
+
192
+ curl -sS -X POST "https://api.attio.com/v2/lists/{LIST_ID}/entries/query" \
193
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
194
+ -H "Content-Type: application/json" \
195
+ -d '{ "limit": 100, "offset": 0 }' \
196
+ | jq '.data[] | {entry_id: .id.entry_id, record_id: .record_id}'
197
+ ```
198
+
199
+ ### 11. Global search across objects
200
+
201
+ ```bash
202
+ curl -sS -X POST "https://api.attio.com/v2/records/search" \
203
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
204
+ -H "Content-Type: application/json" \
205
+ -d '{ "query": "acme", "limit": 10 }' \
206
+ | jq '.data[] | {object: .object_type, record_id: .id.record_id}'
207
+ ```
208
+
209
+ ## Webhooks
210
+
211
+ Attio delivers webhooks at least once. Payloads contain IDs only, so always re-fetch the full record via `GET` before acting.
212
+
213
+ Key event types:
214
+
215
+ - `record.created`, `record.updated`, `record.deleted`
216
+ - `list-entry.created`, `list-entry.updated`, `list-entry.deleted`
217
+ - `note.created`
218
+ - `task.created`, `task.completed`
219
+
220
+ Webhook timeout is 5 seconds. Respond `200` immediately and do async processing in a follow-up swarm task.
221
+
222
+ ## Rate limits
223
+
224
+ | Operation | Hard limit | Safe working rate |
225
+ |---|---|---|
226
+ | Reads | 100 req/sec | ~80 req/sec |
227
+ | Writes | 25 req/sec | ~15-20 req/sec |
228
+
229
+ Add `sleep 0.05` between write calls in loops. Attio does not provide a native batch endpoint for these operations.
230
+
231
+ ## Operational rules
232
+
233
+ - Upsert first. Use `PUT /records` with `matching_attribute` for create-or-update. `POST /records` can create duplicates.
234
+ - Re-fetch webhook records. Webhook payloads are event hints, not full source-of-truth records.
235
+ - Values are arrays. Every attribute value must be wrapped in an array.
236
+ - No merge endpoint. Attio has no API-level record merge; dedupe agents should flag duplicates as comments or tasks for human review.
237
+ - Check config first. Fetch `ATTIO_API_KEY` via `get-config includeSecrets=true`; never hardcode it.
238
+
239
+ ## Error handling
240
+
241
+ | Status | Likely cause | Action |
242
+ |---|---|---|
243
+ | 401 | API key invalid or expired | Re-fetch from config. If still failing, notify Lead for rotation. |
244
+ | 403 | Key lacks permission | Check the Attio API key's workspace permissions. |
245
+ | 404 | Wrong object slug or record ID | Re-discover slugs with `GET /v2/objects`. |
246
+ | 400 | Malformed body | Ensure attribute values are wrapped in arrays. |
247
+ | 422 | Validation or conflict error | Read the `errors` array for field-level details. |
248
+ | 429 | Rate-limited | Back off and retry after `Retry-After` if provided. |
249
+
250
+ ## Worked example: stale deal reactivation
251
+
252
+ ```bash
253
+ ATTIO_API_KEY=$(get-config key="ATTIO_API_KEY" includeSecrets=true)
254
+
255
+ DEALS=$(curl -sS -X POST "https://api.attio.com/v2/objects/deals/records/query" \
256
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
257
+ -H "Content-Type: application/json" \
258
+ -d '{"filter": {"stage": {"$not_equal": "Won"}}, "limit": 200}')
259
+
260
+ echo "$DEALS" | jq -r '.data[] | .id.record_id' | while read -r RECORD_ID; do
261
+ RECORD=$(curl -sS "https://api.attio.com/v2/objects/deals/records/$RECORD_ID" \
262
+ -H "Authorization: Bearer $ATTIO_API_KEY" \
263
+ -H "Accept: application/json")
264
+ # Compute staleness from the relevant date attribute. If stale, create a task.
265
+ sleep 0.05
266
+ done
267
+ ```
268
+
269
+ ## Related references
270
+
271
+ - Official Attio REST API docs: https://developers.attio.com/reference
272
+ - Official Attio MCP overview: https://docs.attio.com/mcp/overview
@@ -9,5 +9,6 @@
9
9
  "category": "skills",
10
10
  "placeholders": [],
11
11
  "runAllSeedersCandidate": true,
12
+ "systemDefault": true,
12
13
  "tags": ["state", "automation", "idempotency"]
13
14
  }
@@ -9,6 +9,7 @@
9
9
  "category": "skills",
10
10
  "placeholders": [],
11
11
  "runAllSeedersCandidate": true,
12
+ "systemDefault": true,
12
13
  "tags": [
13
14
  "pages",
14
15
  "reporting",
@@ -9,5 +9,6 @@
9
9
  "category": "skills",
10
10
  "placeholders": [],
11
11
  "runAllSeedersCandidate": true,
12
+ "systemDefault": true,
12
13
  "tags": ["schedules", "reliability", "polling"]
13
14
  }
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: swarm-scripts
3
+ description: Use swarm scripts for bulk SDK calls, repetitive fan-out, and context-efficient data processing.
4
+ ---
5
+
6
+ # Swarm Scripts
7
+
8
+ Use swarm scripts when direct tool calls would create repetitive work, flood the context window, or require deterministic data processing across many records. Scripts run out-of-process with a typed Swarm SDK and return only the final result to your context.
9
+
10
+ ## Decision Rubric
11
+
12
+ | Situation | Use |
13
+ |---|---|
14
+ | 1-10 SDK calls, result fits in context | Direct tool call |
15
+ | 10+ items or bulk fan-out SDK operations | Script |
16
+ | Heavy fetch, parse, transform, or aggregation | Script or context-mode |
17
+ | Single expensive web fetch | `ctx_fetch_and_index` |
18
+ | Multi-agent parallel work | Workflow |
19
+ | Logic needed across sessions or agents | Named script |
20
+
21
+ ## Loading Script Tools
22
+
23
+ The script tools are deferred. Before authoring or running a script, load the relevant tools with ToolSearch:
24
+
25
+ ```text
26
+ script-query-types
27
+ script-upsert
28
+ script-run
29
+ script-search
30
+ script-delete
31
+ ```
32
+
33
+ Use `script-query-types` before non-trivial work so the script matches the live `swarm-sdk.d.ts` and stdlib signatures.
34
+
35
+ ## Inline Script Pattern
36
+
37
+ Use `script-run` with inline source for one-off work:
38
+
39
+ ```typescript
40
+ export default async function main(args: { status: string; limit: number }, ctx) {
41
+ const { swarm, logger } = ctx;
42
+ const result = await swarm.task_list({ status: args.status, limit: args.limit });
43
+ logger.info(`Fetched ${result.tasks.length} tasks`);
44
+ return {
45
+ total: result.tasks.length,
46
+ tasks: result.tasks.map((task) => ({
47
+ id: task.id,
48
+ status: task.status,
49
+ title: task.task.slice(0, 120),
50
+ })),
51
+ };
52
+ }
53
+ ```
54
+
55
+ Keep logs useful but compact. The value returned from `main` is what comes back to your context.
56
+
57
+ ## Named Script Pattern
58
+
59
+ Use `script-upsert` when the same logic is likely to be reused by another task or agent. Give the script a searchable name, a concrete description, and an intent that explains when to choose it.
60
+
61
+ Good named scripts:
62
+
63
+ - Aggregate failures by agent, schedule, or error family.
64
+ - Fetch and normalize a third-party API response.
65
+ - Fan out over many swarm tasks, memories, repos, or schedules.
66
+ - Convert noisy JSON or HTML into a compact summary.
67
+
68
+ ## SDK And Context Gotchas
69
+
70
+ - `agentId` is propagated to scripts via the `X-Agent-ID` header, so SDK calls run as the invoking agent.
71
+ - `taskId` is not ambient. If a script needs to call `ctx.swarm.task_storeProgress`, pass `taskId` explicitly in `args`.
72
+ - Scripts invoked from a workflow script node may run with a workflow identity rather than a human or worker agent identity.
73
+ - Return compact structured data. Do not return raw logs, full HTML, huge JSON arrays, or large file contents.
74
+ - For a single large web fetch, prefer context-mode `ctx_fetch_and_index`; for repeated fetch/parse/aggregate work, prefer a script.
75
+
76
+ ## Progress Updates From Scripts
77
+
78
+ Thread task identity explicitly:
79
+
80
+ ```typescript
81
+ export default async function main(args: { taskId: string; items: string[] }, ctx) {
82
+ const { swarm } = ctx;
83
+ await swarm.task_storeProgress({
84
+ taskId: args.taskId,
85
+ progress: `Processing ${args.items.length} items with a script`,
86
+ });
87
+ return { processed: args.items.length };
88
+ }
89
+ ```
90
+
91
+ Do not assume the runtime can infer the current task.
@@ -0,0 +1,14 @@
1
+ {
2
+ "kind": "skill",
3
+ "name": "swarm-scripts",
4
+ "displayName": "Swarm Scripts",
5
+ "slug": "swarm-scripts",
6
+ "title": "Swarm Scripts",
7
+ "description": "Use swarm scripts for bulk SDK calls, repetitive fan-out, and context-efficient data processing.",
8
+ "version": "1.0.0",
9
+ "category": "skills",
10
+ "placeholders": [],
11
+ "runAllSeedersCandidate": true,
12
+ "systemDefault": true,
13
+ "tags": ["scripts", "automation", "context"]
14
+ }
@@ -0,0 +1,86 @@
1
+ # Swarm Scripts
2
+
3
+ Use swarm scripts when direct tool calls would create repetitive work, flood the context window, or require deterministic data processing across many records. Scripts run out-of-process with a typed Swarm SDK and return only the final result to your context.
4
+
5
+ ## Decision Rubric
6
+
7
+ | Situation | Use |
8
+ |---|---|
9
+ | 1-10 SDK calls, result fits in context | Direct tool call |
10
+ | 10+ items or bulk fan-out SDK operations | Script |
11
+ | Heavy fetch, parse, transform, or aggregation | Script or context-mode |
12
+ | Single expensive web fetch | `ctx_fetch_and_index` |
13
+ | Multi-agent parallel work | Workflow |
14
+ | Logic needed across sessions or agents | Named script |
15
+
16
+ ## Loading Script Tools
17
+
18
+ The script tools are deferred. Before authoring or running a script, load the relevant tools with ToolSearch:
19
+
20
+ ```text
21
+ script-query-types
22
+ script-upsert
23
+ script-run
24
+ script-search
25
+ script-delete
26
+ ```
27
+
28
+ Use `script-query-types` before non-trivial work so the script matches the live `swarm-sdk.d.ts` and stdlib signatures.
29
+
30
+ ## Inline Script Pattern
31
+
32
+ Use `script-run` with inline source for one-off work:
33
+
34
+ ```typescript
35
+ export default async function main(args: { status: string; limit: number }, ctx) {
36
+ const { swarm, logger } = ctx;
37
+ const result = await swarm.task_list({ status: args.status, limit: args.limit });
38
+ logger.info(`Fetched ${result.tasks.length} tasks`);
39
+ return {
40
+ total: result.tasks.length,
41
+ tasks: result.tasks.map((task) => ({
42
+ id: task.id,
43
+ status: task.status,
44
+ title: task.task.slice(0, 120),
45
+ })),
46
+ };
47
+ }
48
+ ```
49
+
50
+ Keep logs useful but compact. The value returned from `main` is what comes back to your context.
51
+
52
+ ## Named Script Pattern
53
+
54
+ Use `script-upsert` when the same logic is likely to be reused by another task or agent. Give the script a searchable name, a concrete description, and an intent that explains when to choose it.
55
+
56
+ Good named scripts:
57
+
58
+ - Aggregate failures by agent, schedule, or error family.
59
+ - Fetch and normalize a third-party API response.
60
+ - Fan out over many swarm tasks, memories, repos, or schedules.
61
+ - Convert noisy JSON or HTML into a compact summary.
62
+
63
+ ## SDK And Context Gotchas
64
+
65
+ - `agentId` is propagated to scripts via the `X-Agent-ID` header, so SDK calls run as the invoking agent.
66
+ - `taskId` is not ambient. If a script needs to call `ctx.swarm.task_storeProgress`, pass `taskId` explicitly in `args`.
67
+ - Scripts invoked from a workflow script node may run with a workflow identity rather than a human or worker agent identity.
68
+ - Return compact structured data. Do not return raw logs, full HTML, huge JSON arrays, or large file contents.
69
+ - For a single large web fetch, prefer context-mode `ctx_fetch_and_index`; for repeated fetch/parse/aggregate work, prefer a script.
70
+
71
+ ## Progress Updates From Scripts
72
+
73
+ Thread task identity explicitly:
74
+
75
+ ```typescript
76
+ export default async function main(args: { taskId: string; items: string[] }, ctx) {
77
+ const { swarm } = ctx;
78
+ await swarm.task_storeProgress({
79
+ taskId: args.taskId,
80
+ progress: `Processing ${args.items.length} items with a script`,
81
+ });
82
+ return { processed: args.items.length };
83
+ }
84
+ ```
85
+
86
+ Do not assume the runtime can infer the current task.
@@ -9,6 +9,7 @@
9
9
  "category": "skills",
10
10
  "placeholders": [],
11
11
  "runAllSeedersCandidate": true,
12
+ "systemDefault": true,
12
13
  "tags": [
13
14
  "workflows",
14
15
  "authoring",
@@ -9,5 +9,6 @@
9
9
  "category": "skills",
10
10
  "placeholders": [],
11
11
  "runAllSeedersCandidate": true,
12
+ "systemDefault": true,
12
13
  "tags": ["workflows", "json", "validation"]
13
14
  }
package/tsconfig.json CHANGED
@@ -43,6 +43,7 @@
43
43
  "logs",
44
44
  "plugin",
45
45
  "docs-site",
46
- "assets/video-source"
46
+ "assets/video-source",
47
+ "mockups"
47
48
  ]
48
49
  }