@desplega.ai/agent-swarm 1.91.0 → 1.92.1
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.
- package/README.md +3 -2
- package/openapi.json +1005 -152
- package/package.json +6 -6
- package/plugin/skills/pages/SKILL.md +5 -2
- package/src/be/db.ts +662 -19
- package/src/be/memory/constants.ts +2 -1
- package/src/be/memory/providers/openai-embedding.ts +2 -5
- package/src/be/memory/providers/sqlite-store.ts +293 -76
- package/src/be/memory/types.ts +35 -0
- package/src/be/migrations/083_script_workflows.sql +51 -0
- package/src/be/migrations/084_script_run_journal_duration.sql +5 -0
- package/src/be/migrations/085_script_runs_kind.sql +9 -0
- package/src/be/migrations/086_pages_default_authed.sql +64 -0
- package/src/be/migrations/087_skill_files.sql +19 -0
- package/src/be/modelsdev-cache.json +42310 -38617
- package/src/be/scripts/typecheck.ts +49 -0
- package/src/be/seed-scripts/catalog/boot-triage.ts +221 -0
- package/src/be/seed-scripts/catalog/catalog-report.ts +457 -0
- package/src/be/seed-scripts/catalog/compound-insights.ts +310 -6
- package/src/be/seed-scripts/catalog/gh-pr-snapshot.ts +1 -1
- package/src/be/seed-scripts/catalog/memory-eval.ts +1059 -0
- package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +506 -0
- package/src/be/seed-scripts/catalog/schedule-health.ts +78 -2
- package/src/be/seed-scripts/catalog/task-context-gathering.ts +92 -0
- package/src/be/seed-scripts/catalog/task-failure-audit.ts +48 -1
- package/src/be/seed-scripts/catalog/tool-usage.ts +6 -3
- package/src/be/seed-scripts/index.ts +51 -5
- package/src/be/seed-skills/index.ts +3 -3
- package/src/be/skill-sync.ts +91 -7
- package/src/be/swarm-config-guard.ts +17 -0
- package/src/commands/runner.ts +49 -4
- package/src/heartbeat/templates.ts +20 -16
- package/src/http/db-query.ts +20 -5
- package/src/http/index.ts +51 -7
- package/src/http/mcp-user.ts +23 -0
- package/src/http/mcp.ts +58 -0
- package/src/http/memory.ts +58 -0
- package/src/http/pages.ts +1 -1
- package/src/http/script-runs.ts +557 -0
- package/src/http/scripts.ts +39 -2
- package/src/http/skills.ts +225 -0
- package/src/prompts/session-templates.ts +24 -4
- package/src/providers/claude-adapter.ts +107 -28
- package/src/script-workflows/executor.ts +110 -0
- package/src/script-workflows/harness.ts +73 -0
- package/src/script-workflows/label-lint.ts +51 -0
- package/src/script-workflows/limits.ts +22 -0
- package/src/script-workflows/supervisor.ts +139 -0
- package/src/script-workflows/workflow-ctx.ts +209 -0
- package/src/scripts-runtime/sdk-allowlist.ts +4 -0
- package/src/scripts-runtime/swarm-sdk.ts +13 -0
- package/src/scripts-runtime/types/stdlib.d.ts +61 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +61 -0
- package/src/server.ts +4 -0
- package/src/slack/handlers.ts +11 -4
- package/src/slack/message-text.ts +98 -0
- package/src/slack/thread-buffer.ts +5 -3
- package/src/tests/claude-adapter-binary.test.ts +271 -74
- package/src/tests/create-page-tool.test.ts +19 -2
- package/src/tests/db-query.test.ts +28 -0
- package/src/tests/error-tracker.test.ts +121 -0
- package/src/tests/harness-provider-resolution.test.ts +33 -0
- package/src/tests/heartbeat-checklist.test.ts +36 -0
- package/src/tests/mcp-tools.test.ts +6 -0
- package/src/tests/mcp-transport-gc.test.ts +58 -0
- package/src/tests/memory-health-endpoint.test.ts +78 -0
- package/src/tests/memory-store.test.ts +221 -1
- package/src/tests/pages-http.test.ts +20 -2
- package/src/tests/pages-storage.test.ts +26 -0
- package/src/tests/prompt-template-session.test.ts +34 -5
- package/src/tests/script-runs-http.test.ts +278 -0
- package/src/tests/script-workflows-label-lint.test.ts +43 -0
- package/src/tests/script-workflows-runtime-e2e.test.ts +170 -0
- package/src/tests/scripts-mcp-e2e.test.ts +102 -2
- package/src/tests/seed-scripts.test.ts +468 -3
- package/src/tests/skill-files-http.test.ts +171 -0
- package/src/tests/skill-files.test.ts +162 -0
- package/src/tests/skill-get-file-tool.test.ts +110 -0
- package/src/tests/skill-sync.test.ts +125 -6
- package/src/tests/slack-message-text.test.ts +250 -0
- package/src/tests/system-default-skills.test.ts +40 -0
- package/src/tools/create-page.ts +2 -2
- package/src/tools/db-query.ts +16 -6
- package/src/tools/script-runs.ts +123 -0
- package/src/tools/skills/index.ts +1 -0
- package/src/tools/skills/skill-get-file.ts +80 -0
- package/src/tools/slack-read.ts +12 -3
- package/src/tools/tool-config.ts +6 -2
- package/src/types.ts +72 -0
- package/src/utils/error-tracker.ts +40 -1
- package/src/utils/internal-ai/complete-structured.ts +10 -4
- package/src/workflows/executors/raw-llm.ts +76 -59
- package/templates/schedules/daily-blocker-digest/content.md +68 -54
- package/templates/schedules/daily-compounding-reflection/content.md +4 -4
- package/templates/schedules/daily-hn-briefing/content.md +5 -5
- package/templates/schedules/daily-workflow-health-audit/content.md +6 -6
- package/templates/schedules/gtm-weekly-review/content.md +9 -9
- package/templates/schedules/weekly-dependabot-triage/content.md +24 -20
- package/templates/skills/agentmail-sending/content.md +6 -7
- package/templates/skills/desloppify/content.md +8 -9
- package/templates/skills/jira-interaction/content.md +25 -33
- package/templates/skills/kapso-whatsapp/content.md +29 -30
- package/templates/skills/linear-interaction/content.md +8 -9
- package/templates/skills/pages/content.md +205 -55
- package/templates/skills/profile-corruption-escalation/content.md +44 -85
- package/templates/skills/script-workflows/config.json +14 -0
- package/templates/skills/script-workflows/content.md +68 -0
- package/templates/skills/sprite-cli/content.md +4 -5
- package/templates/skills/swarm-scripts/content.md +2 -3
- package/templates/skills/turso-interaction/content.md +14 -17
- package/templates/skills/workflow-iterate/content.md +38 -391
- package/templates/skills/x-api-interactions/content.md +4 -6
- package/templates/skills/scheduled-task-resilience/config.json +0 -14
- package/templates/skills/scheduled-task-resilience/content.md +0 -95
|
@@ -1,85 +1,235 @@
|
|
|
1
1
|
# Pages
|
|
2
2
|
|
|
3
|
-
Pages are persistent, shareable HTML documents created via the swarm's
|
|
3
|
+
Pages are persistent, shareable HTML documents created via the swarm's page tooling. Use them when the output benefits from layout, tables, headers, and persistent sharing. A page should be a clean human-facing report, not a raw dump with a URL.
|
|
4
|
+
|
|
5
|
+
This skill covers both how to publish and how to design the page. It distills the current external design guidance from Anthropic's `frontend-design`, Vercel's `composition-patterns`, and Vercel's `web-design-guidelines`: start from content hierarchy, use a small spacing system, keep typography readable, prefer restraint over decoration, and make responsive behavior intentional.
|
|
4
6
|
|
|
5
7
|
## When to Create a Page
|
|
6
8
|
|
|
7
9
|
- A report, dashboard, or summary that benefits from structured layout
|
|
8
10
|
- Analysis that should be linkable and bookmarkable
|
|
9
|
-
- Results that need to be reviewed asynchronously
|
|
10
|
-
- Content that
|
|
11
|
+
- Results that need to be reviewed asynchronously
|
|
12
|
+
- Content that is too long or rich for a `store-progress.output` string
|
|
11
13
|
|
|
12
14
|
Do NOT use pages for:
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
15
|
+
|
|
16
|
+
- In-flight progress notes; use `store-progress.progress`
|
|
17
|
+
- Secrets, private credentials, or unapproved personal data
|
|
18
|
+
- Large binary files; use agent-fs for PNG/MP4
|
|
19
|
+
- Raw verbose logs; summarize them and link to artifacts
|
|
20
|
+
|
|
21
|
+
## Page Design Defaults
|
|
22
|
+
|
|
23
|
+
Every page should be useful at a glance.
|
|
24
|
+
|
|
25
|
+
- Put the page's point in the first viewport: title, one-sentence summary, and 3-6 key numbers or statuses.
|
|
26
|
+
- Use a single-column reading spine with `max-width: 1120px`; keep prose measure around 65-75 characters.
|
|
27
|
+
- Use system fonts unless there is a clear reason not to: `Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif`.
|
|
28
|
+
- Use a restrained palette: neutral background, high-contrast text, white panels, one accent color, and semantic colors for statuses only.
|
|
29
|
+
- Use a consistent spacing scale: `8, 12, 16, 24, 32, 48, 72`.
|
|
30
|
+
- Use clear type hierarchy: page title 36-48px desktop / 30-36px mobile, section titles 22-28px, body 15-16px, supporting text 13-14px.
|
|
31
|
+
- Keep tables readable: sticky/scannable headers where useful, padded cells, zebra-free or very subtle row borders, `tabular-nums` for numbers, horizontal scroll on narrow screens.
|
|
32
|
+
- Prefer cards only for repeated records or metrics. Do not nest cards inside cards.
|
|
33
|
+
- Hide raw JSON behind a collapsed `<details>` block at the bottom.
|
|
34
|
+
- Make mobile explicit with media queries: single-column grids, reduced padding, no overflow except intentional table scroll.
|
|
35
|
+
|
|
36
|
+
## Content Structure
|
|
37
|
+
|
|
38
|
+
Use this order unless the task gives a better domain-specific structure:
|
|
39
|
+
|
|
40
|
+
1. Hero: title, short summary, timestamp/source context
|
|
41
|
+
2. Key metrics: 3-6 tiles that answer "how big / how bad / what changed?"
|
|
42
|
+
3. Findings or sections grouped by theme, owner, severity, or stage
|
|
43
|
+
4. Evidence tables or samples under each finding
|
|
44
|
+
5. Next actions or recommendations
|
|
45
|
+
6. Raw evidence links / collapsed JSON appendix
|
|
46
|
+
|
|
47
|
+
Write section headings as labels, not slogans. Favor "Critical Routing Gaps" over "Things We Found".
|
|
16
48
|
|
|
17
49
|
## Creating a Page
|
|
18
50
|
|
|
51
|
+
Use the page tool with an HTML body. Prefer `contentType: "text/html"` and an explicit `authMode` for internal reports.
|
|
52
|
+
|
|
19
53
|
```javascript
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
<
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
54
|
+
const html = `<!doctype html>
|
|
55
|
+
<html lang="en">
|
|
56
|
+
<head>
|
|
57
|
+
<meta charset="utf-8">
|
|
58
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
59
|
+
<title>Q2 SEO Performance</title>
|
|
60
|
+
<style>
|
|
61
|
+
:root {
|
|
62
|
+
color-scheme: light;
|
|
63
|
+
--bg: #f6f4f0;
|
|
64
|
+
--panel: #ffffff;
|
|
65
|
+
--ink: #18181b;
|
|
66
|
+
--muted: #62646a;
|
|
67
|
+
--line: #dedbd2;
|
|
68
|
+
--accent: #2563eb;
|
|
69
|
+
--danger: #b42318;
|
|
70
|
+
--warn: #b54708;
|
|
71
|
+
--ok: #067647;
|
|
72
|
+
--radius: 8px;
|
|
73
|
+
--shadow: 0 1px 2px rgba(24, 24, 27, 0.06), 0 12px 32px rgba(24, 24, 27, 0.07);
|
|
74
|
+
}
|
|
75
|
+
* { box-sizing: border-box; }
|
|
76
|
+
body {
|
|
77
|
+
margin: 0;
|
|
78
|
+
background: var(--bg);
|
|
79
|
+
color: var(--ink);
|
|
80
|
+
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
81
|
+
font-size: 16px;
|
|
82
|
+
line-height: 1.55;
|
|
83
|
+
}
|
|
84
|
+
main {
|
|
85
|
+
width: min(1120px, calc(100% - 32px));
|
|
86
|
+
margin: 0 auto;
|
|
87
|
+
padding: 48px 0 72px;
|
|
88
|
+
}
|
|
89
|
+
header { margin-bottom: 32px; }
|
|
90
|
+
.eyebrow {
|
|
91
|
+
margin: 0 0 8px;
|
|
92
|
+
color: var(--muted);
|
|
93
|
+
font-size: 13px;
|
|
94
|
+
font-weight: 700;
|
|
95
|
+
letter-spacing: 0.08em;
|
|
96
|
+
text-transform: uppercase;
|
|
97
|
+
}
|
|
98
|
+
h1 {
|
|
99
|
+
margin: 0;
|
|
100
|
+
max-width: 780px;
|
|
101
|
+
font-size: clamp(2rem, 4vw, 3rem);
|
|
102
|
+
line-height: 1.05;
|
|
103
|
+
letter-spacing: 0;
|
|
104
|
+
}
|
|
105
|
+
.lede {
|
|
106
|
+
max-width: 760px;
|
|
107
|
+
margin: 16px 0 0;
|
|
108
|
+
color: var(--muted);
|
|
109
|
+
font-size: 18px;
|
|
110
|
+
}
|
|
111
|
+
.metrics {
|
|
112
|
+
display: grid;
|
|
113
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
114
|
+
gap: 12px;
|
|
115
|
+
margin: 32px 0;
|
|
116
|
+
}
|
|
117
|
+
.metric, .section {
|
|
118
|
+
background: var(--panel);
|
|
119
|
+
border: 1px solid var(--line);
|
|
120
|
+
border-radius: var(--radius);
|
|
121
|
+
box-shadow: var(--shadow);
|
|
122
|
+
}
|
|
123
|
+
.metric { padding: 18px; }
|
|
124
|
+
.metric strong {
|
|
125
|
+
display: block;
|
|
126
|
+
font-size: 32px;
|
|
127
|
+
line-height: 1;
|
|
128
|
+
font-variant-numeric: tabular-nums;
|
|
129
|
+
}
|
|
130
|
+
.metric span {
|
|
131
|
+
display: block;
|
|
132
|
+
margin-top: 8px;
|
|
133
|
+
color: var(--muted);
|
|
134
|
+
font-size: 13px;
|
|
135
|
+
font-weight: 650;
|
|
136
|
+
}
|
|
137
|
+
.section {
|
|
138
|
+
margin-top: 18px;
|
|
139
|
+
padding: 24px;
|
|
140
|
+
}
|
|
141
|
+
h2 { margin: 0 0 12px; font-size: 24px; line-height: 1.2; }
|
|
142
|
+
h3 { margin: 0 0 8px; font-size: 17px; line-height: 1.3; }
|
|
143
|
+
p { margin: 0 0 12px; }
|
|
144
|
+
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); }
|
|
145
|
+
table { width: 100%; border-collapse: collapse; min-width: 640px; }
|
|
146
|
+
th, td { padding: 10px 12px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
|
|
147
|
+
th { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; }
|
|
148
|
+
td { font-size: 14px; }
|
|
149
|
+
code, pre { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
150
|
+
details { margin-top: 24px; }
|
|
151
|
+
summary { cursor: pointer; font-weight: 700; }
|
|
152
|
+
pre { overflow: auto; padding: 16px; background: #111827; color: #f9fafb; border-radius: var(--radius); }
|
|
153
|
+
@media (max-width: 760px) {
|
|
154
|
+
main { width: min(100% - 24px, 1120px); padding-top: 32px; }
|
|
155
|
+
.metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
156
|
+
.section { padding: 18px; }
|
|
157
|
+
}
|
|
158
|
+
@media (max-width: 520px) {
|
|
159
|
+
.metrics { grid-template-columns: 1fr; }
|
|
160
|
+
.lede { font-size: 16px; }
|
|
161
|
+
}
|
|
162
|
+
</style>
|
|
163
|
+
</head>
|
|
164
|
+
<body>
|
|
165
|
+
<main>
|
|
166
|
+
<header>
|
|
167
|
+
<p class="eyebrow">Generated 2026-06-04</p>
|
|
168
|
+
<h1>Q2 SEO Performance</h1>
|
|
169
|
+
<p class="lede">Organic traffic grew sharply, but the next gains depend on fixing thin page metadata and publishing three high-intent pillar pages.</p>
|
|
170
|
+
</header>
|
|
171
|
+
|
|
172
|
+
<section class="metrics" aria-label="Key metrics">
|
|
173
|
+
<div class="metric"><strong>18.6k</strong><span>Organic clicks</span></div>
|
|
174
|
+
<div class="metric"><strong>+50%</strong><span>Quarter over quarter</span></div>
|
|
175
|
+
<div class="metric"><strong>23</strong><span>Metadata fixes</span></div>
|
|
176
|
+
<div class="metric"><strong>3</strong><span>Priority pages</span></div>
|
|
177
|
+
</section>
|
|
178
|
+
|
|
179
|
+
<section class="section">
|
|
180
|
+
<h2>Summary</h2>
|
|
181
|
+
<p>Start with the conclusion. Add tables only after the reader understands what changed and what to do next.</p>
|
|
182
|
+
<div class="table-wrap">
|
|
183
|
+
<table>
|
|
184
|
+
<thead><tr><th>Metric</th><th>Q1</th><th>Q2</th><th>Change</th></tr></thead>
|
|
185
|
+
<tbody><tr><td>Organic clicks</td><td>12,400</td><td>18,600</td><td>+50%</td></tr></tbody>
|
|
186
|
+
</table>
|
|
187
|
+
</div>
|
|
188
|
+
</section>
|
|
189
|
+
</main>
|
|
190
|
+
</body>
|
|
191
|
+
</html>`;
|
|
192
|
+
|
|
193
|
+
await create_page({
|
|
194
|
+
title: "Q2 SEO Performance",
|
|
195
|
+
slug: "q2-seo-performance",
|
|
196
|
+
description: "Human-readable SEO performance report with summary metrics and next actions.",
|
|
197
|
+
contentType: "text/html",
|
|
198
|
+
authMode: "authed",
|
|
199
|
+
body: html,
|
|
200
|
+
});
|
|
36
201
|
```
|
|
37
202
|
|
|
38
|
-
Returns a page ID. Build
|
|
39
|
-
|
|
203
|
+
Returns a page ID. Build share URLs from environment:
|
|
204
|
+
|
|
205
|
+
```text
|
|
40
206
|
${APP_URL}/pages/<pageId> # opens in SPA with chrome
|
|
41
207
|
${APP_URL}/pages/<pageId>?mode=full # slim header, full viewport
|
|
42
|
-
${MCP_BASE_URL}/p/<pageId> # direct HTML
|
|
208
|
+
${MCP_BASE_URL}/p/<pageId> # direct HTML
|
|
43
209
|
```
|
|
44
210
|
|
|
45
|
-
Read `APP_URL` and `MCP_BASE_URL` from environment
|
|
211
|
+
Read `APP_URL` and `MCP_BASE_URL` from environment. Never hardcode localhost or example hosts in shared output.
|
|
46
212
|
|
|
47
|
-
##
|
|
213
|
+
## Design Checklist
|
|
48
214
|
|
|
49
|
-
|
|
50
|
-
1. **Short summary** (1 paragraph) — what this covers and the key finding
|
|
51
|
-
2. **Source links** — links to the data, agent-fs artifacts, or upstream systems
|
|
52
|
-
3. **Structured content** — tables, headers, numbered lists
|
|
53
|
-
4. **Next actions** — what should happen next, who owns it
|
|
215
|
+
Before publishing:
|
|
54
216
|
|
|
55
|
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
217
|
+
- The first viewport states what the page is, why it matters, and the key numbers.
|
|
218
|
+
- The page has a clear hierarchy: `h1`, short lede, metrics, sections, evidence.
|
|
219
|
+
- Body text is readable on mobile and desktop.
|
|
220
|
+
- Tables scroll horizontally on mobile instead of crushing columns.
|
|
221
|
+
- Status colors are semantic and not the whole visual identity.
|
|
222
|
+
- Raw JSON/logs are collapsed or linked, not the primary experience.
|
|
223
|
+
- No nested cards, decorative gradients, oversized hero art, or cramped default browser styles.
|
|
224
|
+
- No text overlaps, clipped buttons, or unreadable low-contrast text.
|
|
59
225
|
|
|
60
|
-
## Page vs
|
|
226
|
+
## Page vs Agent-fs
|
|
61
227
|
|
|
62
228
|
| Use pages for | Use agent-fs for |
|
|
63
229
|
|---|---|
|
|
64
230
|
| Reports, dashboards, human-readable summaries | Markdown research notes, code files, recordings |
|
|
65
231
|
| Content that benefits from HTML layout | Searchable knowledge base entries |
|
|
66
|
-
| Quick share links to non-technical stakeholders | Binary artifacts
|
|
232
|
+
| Quick share links to non-technical stakeholders | Binary artifacts such as PNG or MP4 |
|
|
67
233
|
| Time-bounded deliverables | Long-lived reference documentation |
|
|
68
234
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
Always use the platform share URL (from `APP_URL` env var) rather than hardcoded local hosts. Append `?mode=full` for a standalone view (hides sidebar/header — good for screenshots or embedding in Slack previews).
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
# Get the share URL
|
|
75
|
-
PAGE_URL="${APP_URL}/pages/${pageId}?mode=full"
|
|
76
|
-
|
|
77
|
-
# Post to Slack
|
|
78
|
-
slack-reply --taskId <id> --message "Report ready: ${PAGE_URL}"
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## Trade-offs
|
|
82
|
-
|
|
83
|
-
**Pages vs Slack messages:** Slack messages are ephemeral and scroll out of view. Pages are persistent and bookmarkable. Use pages for anything you'd want to reference in 3 months; use Slack for in-the-moment communication.
|
|
84
|
-
|
|
85
|
-
**Pages vs agent-fs:** Pages are rendered HTML with a share URL — great for non-technical stakeholders. Agent-fs files are raw content — great for other agents and developers who need the source data. For a research memo, write the source to agent-fs and create a page for the human-facing summary.
|
|
235
|
+
For a research memo, write the source to agent-fs and create a page for the human-facing summary.
|
|
@@ -1,105 +1,64 @@
|
|
|
1
1
|
# Profile Corruption Escalation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use this skill when an agent's persisted profile (`SOUL.md`, `IDENTITY.md`, or equivalent DB fields) appears to be overwritten with placeholder, fixture, truncated, or otherwise invalid content.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- `src/tools/update-profile.ts:231` — gated the file write on `requestInfo.agentId === process.env.AGENT_ID`
|
|
7
|
-
- `src/hooks/hook.ts:359` — raised `IDENTITY_FILE_MIN_LENGTH` from 100 → 500 (defense in depth)
|
|
5
|
+
## When to Use
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
- An agent profile contains sentinel text such as "Test Worker", "Updated by Myself", repeated padding, or another canned payload.
|
|
8
|
+
- The profile is much shorter than the expected baseline.
|
|
9
|
+
- A recently restored profile was overwritten again.
|
|
10
|
+
- A hook, seeder, migration, test fixture, or profile-update tool may be writing to the wrong agent.
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
## Triage Loop
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
1. Capture the corrupted payload, agent ID, and `lastUpdatedAt` timestamp before changing anything.
|
|
15
|
+
2. Search memory and recent task history for the same sentinel string or same agent.
|
|
16
|
+
3. Grep the source repo for exact sentinel strings. Stable placeholder text usually points to a fixture, seed path, or test helper faster than manual restoration does.
|
|
17
|
+
4. Inspect code paths that can write profile files or profile DB fields: profile-update tools, startup hooks, stop/session hooks, seeders, migrations, and tests that set agent identity env vars.
|
|
18
|
+
5. If you find the writer, fix or escalate the code path before restoring the profile.
|
|
19
|
+
6. Restore only after evidence is captured, and only if restoration will not destroy useful debugging evidence.
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
## Escalation Threshold
|
|
16
22
|
|
|
17
|
-
|
|
23
|
+
Escalate instead of repeatedly restoring when any of these are true:
|
|
18
24
|
|
|
19
|
-
|
|
25
|
+
- The same profile is corrupted more than once in a short period.
|
|
26
|
+
- The sentinel text appears to come from code that knows schema limits or exact file paths.
|
|
27
|
+
- You cannot identify the writer quickly.
|
|
28
|
+
- A previous fix should already have eliminated this corruption family.
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
## Escalation Package
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
grep -rn '"Test Worker"' /workspace/repos/agent-swarm/src
|
|
25
|
-
grep -rn '"Updated by Myself"' /workspace/repos/agent-swarm/src
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
If you find the writer in <5 minutes, fix it (or open a PR) instead of restoring. That's the 1000× higher-value outcome.
|
|
32
|
+
Post a concise report to the operator channel or issue tracker with:
|
|
29
33
|
|
|
30
|
-
|
|
34
|
+
- Agent name and ID.
|
|
35
|
+
- Fresh write timestamp.
|
|
36
|
+
- Exact sentinel strings to search for.
|
|
37
|
+
- Whether you already grepped the repo and what matched.
|
|
38
|
+
- Suspected writer classes: hook, seeder, migration, test fixture, startup script, or profile-update tool.
|
|
39
|
+
- Whether you restored the profile or left it corrupted as evidence.
|
|
40
|
+
- Link to the task, log, or memory entry containing the captured payload.
|
|
31
41
|
|
|
32
|
-
##
|
|
42
|
+
## Report Template
|
|
33
43
|
|
|
34
|
-
|
|
44
|
+
```text
|
|
45
|
+
Profile corruption detected
|
|
35
46
|
|
|
36
|
-
|
|
47
|
+
Agent: <agent-name> (<agent-id>)
|
|
48
|
+
Fresh write at: <timestamp>
|
|
49
|
+
Sentinel strings:
|
|
50
|
+
- "<literal-1>"
|
|
51
|
+
- "<literal-2>"
|
|
37
52
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- **1st–12th occurrence**: Restore the profile (surgical update-profile with the agent's best-known-good SOUL/IDENTITY from your memory). Write a new `{agent}-{N}th-profile-corruption-{YYYY-MM-DD}` memory recording the state + escalation status.
|
|
43
|
-
- **13th+ occurrence**: **STOP RESTORING.** Rebuild fatigue has proven the restore doesn't stick — the bug lives in code you don't control. Escalate instead.
|
|
44
|
-
|
|
45
|
-
If you can't determine N from memory, treat anything ≥ 2 prior corruptions in < 7 days as "escalate now."
|
|
46
|
-
|
|
47
|
-
**Post PR #374 (Apr 2026):** any new sentinel-payload corruption of any agent should be treated as recurrence 1 of a NEW bug — investigate fresh code paths, do not assume it's the same `update-profile.ts:231` issue.
|
|
48
|
-
|
|
49
|
-
## Escalation package (what to post)
|
|
50
|
-
|
|
51
|
-
Use `slack-post` to the ops channel. Include ALL of:
|
|
52
|
-
|
|
53
|
-
1. **Sentinel payload strings as grep targets** — exact literals to search for in the source repo. Example: `"Test Worker"`, `"Updated by Myself"`, `xxxxx...` patterns. **State whether you already grepped (and what the result was).**
|
|
54
|
-
2. **Proof of fresh write** — `lastUpdatedAt` timestamp from `get-swarm`, newer than the previous restore. Without this it could be stale state, not new corruption.
|
|
55
|
-
3. **Corruption tally** — "N occurrences in ~M weeks, half-life now <24h."
|
|
56
|
-
4. **Investigation leads** — where to look:
|
|
57
|
-
- Grep the `desplega-ai/agent-swarm` repo for the sentinel strings.
|
|
58
|
-
- Check for scheduled tasks named `validate profile`, `test update-profile`, etc.
|
|
59
|
-
- Check seed/migration scripts that run on container restart.
|
|
60
|
-
- Audit `PostToolUse` hook content-validation (flagged in prior memories as "not shipped").
|
|
61
|
-
- **Post PR #374:** Audit any other code path that writes `/workspace/SOUL.md` or `/workspace/IDENTITY.md` — the original bug was at `src/tools/update-profile.ts:231`; look for siblings.
|
|
62
|
-
5. **What you did NOT do** — explicit "I did not perform the Nth restore. Profile is left corrupted in DB as evidence."
|
|
63
|
-
|
|
64
|
-
## Template
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
:rotating_light: Profile Corruption — {N}th recurrence — escalation trigger fired
|
|
68
|
-
|
|
69
|
-
Agent: {name} ({id})
|
|
70
|
-
Fresh write at: {lastUpdatedAt}
|
|
71
|
-
Tally: {N} corruptions in ~{M} weeks, half-life {<hours>}h.
|
|
72
|
-
|
|
73
|
-
Sentinel grep targets (expect to find in source):
|
|
74
|
-
- "Test Worker"
|
|
75
|
-
- "Updated by Myself"
|
|
76
|
-
- Long "xxxxx…" padding literals
|
|
77
|
-
|
|
78
|
-
I already grepped: {summary of grep result, e.g. "no hits in src/ post-#374 — this is a NEW code path"}.
|
|
79
|
-
|
|
80
|
-
Investigation leads:
|
|
81
|
-
1. Grep agent-swarm for the sentinels above.
|
|
82
|
-
2. Check for scheduled "validate profile" / "test update-profile" tasks.
|
|
83
|
-
3. Audit seed/migration scripts on container restart.
|
|
84
|
-
4. Audit any code path that writes /workspace/SOUL.md or /workspace/IDENTITY.md (original bug was update-profile.ts:231).
|
|
85
|
-
|
|
86
|
-
I did NOT perform the {N}th restore. Profile is corrupted in DB as evidence. Waiting for engineering fix before next restore.
|
|
87
|
-
|
|
88
|
-
See memory: {agent}-{N}th-profile-corruption-{date}
|
|
53
|
+
Repo grep result: <matches or no matches>
|
|
54
|
+
Suspected writer: <hook/seeder/migration/test/tool/unknown>
|
|
55
|
+
Action taken: <restored profile | left as evidence | opened fix PR>
|
|
56
|
+
Evidence: <task/log/memory link>
|
|
89
57
|
```
|
|
90
58
|
|
|
91
59
|
## Gotchas
|
|
92
60
|
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
- **Sentinel-grep first, escalate second.** If a 2nd recurrence happens and you haven't grepped the sentinel literal yet, you're escalating prematurely. Grep is cheap (<5 min) and usually wins.
|
|
98
|
-
|
|
99
|
-
## Related
|
|
100
|
-
|
|
101
|
-
- Memory family: `{agent}-Nth-profile-corruption-YYYY-MM-DD`
|
|
102
|
-
- Memory: `reviewer-corruption-hunt-pattern` — the heuristic that solved the 13-recurrence mystery
|
|
103
|
-
- Memory: `picateclas-14th-restore-post-pr374` — restore payload + the fix details
|
|
104
|
-
- Lead rule #9 in CLAUDE.md: "Sentinel-grep before escalating recurring bugs"
|
|
105
|
-
|
|
61
|
+
- Do not rely on repeated manual restores as the fix. They can hide the writer and destroy evidence.
|
|
62
|
+
- Search exact sentinel strings before broad refactors; fixture text is usually distinctive.
|
|
63
|
+
- Do not overwrite unrelated profile files during restoration.
|
|
64
|
+
- Treat a recurrence after a code fix as a new investigation unless you can prove the same writer is still active.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "skill",
|
|
3
|
+
"name": "script-workflows",
|
|
4
|
+
"displayName": "Script Workflows",
|
|
5
|
+
"slug": "script-workflows",
|
|
6
|
+
"title": "Script Workflows",
|
|
7
|
+
"description": "Launch and inspect durable one-off script workflow runs with journaled swarm-script, raw-llm, and agent-task steps.",
|
|
8
|
+
"version": "1.0.0",
|
|
9
|
+
"category": "skills",
|
|
10
|
+
"placeholders": [],
|
|
11
|
+
"runAllSeedersCandidate": true,
|
|
12
|
+
"systemDefault": true,
|
|
13
|
+
"tags": ["scripts", "workflows", "automation"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
Use this skill when a user asks to launch, monitor, inspect, or debug a durable script workflow run. This is for the Script Workflows v1 runtime: one-off TypeScript workflow source with journaled `swarm-script`, `raw-llm`, and `agent-task` steps.
|
|
2
|
+
|
|
3
|
+
## Tool Flow
|
|
4
|
+
|
|
5
|
+
Load the script workflow tools with ToolSearch when they are not already visible:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
launch-script-run
|
|
9
|
+
get-script-run
|
|
10
|
+
list-script-runs
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Use `launch-script-run` to start a one-off run. It calls the same `/api/script-runs` API as the dashboard, preserves the invoking agent identity, and starts the run in the background.
|
|
14
|
+
|
|
15
|
+
Use `get-script-run` to read terminal status and journal entries. Poll it when needed, but keep polling bounded and report progress for long runs.
|
|
16
|
+
|
|
17
|
+
Use `list-script-runs` to find recent runs or filter by `status` / `agentId`.
|
|
18
|
+
|
|
19
|
+
Do not hand-roll raw HTTP for this flow unless the tool itself is broken and you are explicitly debugging the API. The tool handles auth and `X-Agent-ID` like the existing inline `script-run` tool family.
|
|
20
|
+
|
|
21
|
+
## Source Shape
|
|
22
|
+
|
|
23
|
+
Author TypeScript workflow source as a default export. The runtime provides `args` and `ctx`.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
export default async function main(args, ctx) {
|
|
27
|
+
const lookup = await ctx.step.swarmScript("lookup-data", {
|
|
28
|
+
scriptName: "fetch-readable",
|
|
29
|
+
args: { url: args.url },
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const summary = await ctx.step.rawLlm("summarize", {
|
|
33
|
+
prompt: `Summarize this for an operator:\n${JSON.stringify(lookup)}`,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const task = await ctx.step.agentTask("operator-review", {
|
|
37
|
+
task: `Review this summary and flag risks:\n${JSON.stringify(summary)}`,
|
|
38
|
+
tags: ["script-run"],
|
|
39
|
+
priority: 50,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return { lookup, summary, task };
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Label Rules
|
|
47
|
+
|
|
48
|
+
Step labels are durability keys. They must be stable and unique for each logical step. Do not reuse the same literal label inside a loop; launch will fail with `label_lint_violation`.
|
|
49
|
+
|
|
50
|
+
For looped work, include an item identifier in the label:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
for (const item of args.items) {
|
|
54
|
+
await ctx.step.agentTask(`review-${item.id}`, { task: item.prompt });
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Statuses
|
|
59
|
+
|
|
60
|
+
Terminal statuses to surface clearly:
|
|
61
|
+
|
|
62
|
+
- `completed` — run finished and `output` may be present.
|
|
63
|
+
- `failed` — run ended with `error`.
|
|
64
|
+
- `cancelled` — run was cancelled before completion.
|
|
65
|
+
- `aborted_limit` — runtime guardrail stopped the run, usually step count, agent-task count, or wall-clock cap.
|
|
66
|
+
- `label_lint_violation` — launch-time rejection, not a persisted run status.
|
|
67
|
+
|
|
68
|
+
When a run is not terminal, report the current status, journal count, and latest heartbeat if present.
|
|
@@ -29,7 +29,7 @@ The org token is stored in swarm config as `SPRITES_API_KEY` (global, secret). S
|
|
|
29
29
|
sprite auth setup --token "$SPRITES_API_KEY"
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
Token format is `<org>/<account_id>/<token_id>/<secret>`. The first segment is
|
|
32
|
+
Token format is `<org>/<account_id>/<token_id>/<secret>`. The first segment is your organization slug.
|
|
33
33
|
|
|
34
34
|
## Core commands
|
|
35
35
|
|
|
@@ -45,9 +45,9 @@ Token format is `<org>/<account_id>/<token_id>/<secret>`. The first segment is t
|
|
|
45
45
|
|
|
46
46
|
Flags: every command takes `-s <sprite>` (or sets a default via `sprite use`). `-o <org>` overrides the org if you have multiple.
|
|
47
47
|
|
|
48
|
-
## Sandbox baseline
|
|
48
|
+
## Sandbox baseline
|
|
49
49
|
|
|
50
|
-
- Ubuntu
|
|
50
|
+
- Ubuntu-based microVM image (exact version may change over time)
|
|
51
51
|
- Non-root `sprite` user (uid 1001), passwordless `sudo`
|
|
52
52
|
- No docker, no `/var/run/docker.sock`, no container runtime preinstalled
|
|
53
53
|
- No systemd / init — `service` and `systemctl` won't work; start daemons manually with `sudo <daemon> &` or `nohup`
|
|
@@ -105,7 +105,7 @@ trap "sprite destroy test-$$ --force" EXIT INT TERM
|
|
|
105
105
|
# … work …
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
If a script crashes, `sprite list` shows what's still up. Sweep with `sprite list -o
|
|
108
|
+
If a script crashes, `sprite list` shows what's still up. Sweep with `sprite list -o <org>` and destroy anything you don't recognize.
|
|
109
109
|
|
|
110
110
|
## Setup script snippet
|
|
111
111
|
|
|
@@ -130,4 +130,3 @@ grep -q '/.local/bin' "$HOME/.bashrc" 2>/dev/null || echo 'export PATH="$HOME/.l
|
|
|
130
130
|
- **Daemon survival:** `sprite exec` runs in a fresh subshell. A daemon backgrounded with `&` survives the exec call (sprites use a shared init), but if you want to be safe use `nohup`. To stop it, `sprite exec -s … -- sudo pkill <daemon>`.
|
|
131
131
|
- **Port forwarding:** ports inside the sprite are not exposed to your swarm container. Curl from *inside* the sprite (`sprite exec -s … -- curl localhost:5432`) — not from your container.
|
|
132
132
|
- **Don't leak secrets:** treat the sprite as an untrusted host. Don't put production tokens in there.
|
|
133
|
-
|
|
@@ -66,14 +66,13 @@ Good named scripts:
|
|
|
66
66
|
|
|
67
67
|
For scripts that aggregate over tasks, sessions, or memory, `ctx.swarm.db_query` with direct SQL is far more efficient than fetching lists client-side.
|
|
68
68
|
|
|
69
|
-
**The parameter is `sql
|
|
69
|
+
**The parameter is `sql`:**
|
|
70
70
|
|
|
71
71
|
```typescript
|
|
72
72
|
// CORRECT
|
|
73
73
|
const res = await ctx.swarm.db_query({ sql: "SELECT status, count(*) as cnt FROM agent_tasks GROUP BY status" });
|
|
74
74
|
|
|
75
|
-
//
|
|
76
|
-
const res = await ctx.swarm.db_query({ query: "SELECT ..." });
|
|
75
|
+
// Legacy scripts may still run with `query`, but new code should not use it.
|
|
77
76
|
```
|
|
78
77
|
|
|
79
78
|
**`db_query` returns positional rows, not objects.** The response shape is `{ rows: unknown[][], columns: string[] }`. Zip them into objects:
|