@desplega.ai/agent-swarm 1.87.0 → 1.88.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 (59) hide show
  1. package/README.md +2 -1
  2. package/openapi.json +13 -1
  3. package/package.json +5 -5
  4. package/src/be/db.ts +49 -7
  5. package/src/be/migrations/080_skill_system_defaults.sql +8 -0
  6. package/src/be/modelsdev-cache.json +1123 -1034
  7. package/src/be/seed/registry.ts +3 -2
  8. package/src/be/seed-skills/index.ts +172 -0
  9. package/src/cli.tsx +33 -4
  10. package/src/commands/e2b-stack-wizard.tsx +394 -0
  11. package/src/commands/e2b.ts +1352 -53
  12. package/src/commands/onboard/dashboard-url.ts +29 -0
  13. package/src/commands/onboard/steps/post-dashboard.tsx +3 -1
  14. package/src/commands/onboard.tsx +3 -1
  15. package/src/commands/runner.ts +1 -0
  16. package/src/e2b/dispatch.ts +234 -18
  17. package/src/http/memory.ts +13 -1
  18. package/src/http/skills.ts +53 -0
  19. package/src/http/webhooks.ts +75 -0
  20. package/src/integrations/kapso/client.ts +82 -0
  21. package/src/memory/automatic-task-gate.ts +47 -0
  22. package/src/prompts/base-prompt.ts +16 -1
  23. package/src/prompts/session-templates.ts +51 -0
  24. package/src/providers/claude-adapter.ts +19 -0
  25. package/src/providers/codex-adapter.ts +22 -0
  26. package/src/providers/ctx-mode-env.ts +10 -0
  27. package/src/providers/opencode-adapter.ts +50 -1
  28. package/src/slack/blocks.ts +12 -4
  29. package/src/slack/watcher.ts +3 -3
  30. package/src/telemetry.ts +14 -1
  31. package/src/templates.d.ts +4 -0
  32. package/src/tests/base-prompt.test.ts +41 -0
  33. package/src/tests/claude-adapter.test.ts +86 -1
  34. package/src/tests/codex-adapter.test.ts +89 -0
  35. package/src/tests/e2b-dispatch.test.ts +603 -11
  36. package/src/tests/http-api-integration.test.ts +113 -0
  37. package/src/tests/kapso-client.test.ts +74 -1
  38. package/src/tests/kapso-inbound.test.ts +60 -2
  39. package/src/tests/opencode-adapter.test.ts +95 -0
  40. package/src/tests/prompt-template-session.test.ts +4 -2
  41. package/src/tests/self-improvement.test.ts +89 -0
  42. package/src/tests/skill-update-scope.test.ts +88 -1
  43. package/src/tests/slack-blocks.test.ts +15 -0
  44. package/src/tests/system-default-skills.test.ts +119 -0
  45. package/src/tests/telemetry-init.test.ts +86 -0
  46. package/src/tools/skills/skill-delete.ts +14 -0
  47. package/src/tools/skills/skill-update.ts +14 -0
  48. package/src/tools/store-progress.ts +19 -5
  49. package/src/types.ts +1 -0
  50. package/templates/skills/artifacts/config.json +1 -0
  51. package/templates/skills/kv-storage/config.json +1 -0
  52. package/templates/skills/pages/config.json +1 -0
  53. package/templates/skills/scheduled-task-resilience/config.json +1 -0
  54. package/templates/skills/swarm-scripts/SKILL.md +91 -0
  55. package/templates/skills/swarm-scripts/config.json +14 -0
  56. package/templates/skills/swarm-scripts/content.md +86 -0
  57. package/templates/skills/workflow-iterate/config.json +1 -0
  58. package/templates/skills/workflow-structured-output/config.json +1 -0
  59. package/tsconfig.json +2 -1
package/README.md CHANGED
@@ -124,7 +124,7 @@ Check [our templates](https://templates.agent-swarm.dev) for a quick start.
124
124
  - **Workflow engine with Human-in-the-Loop** — DAG-based automation with approval gates, retries, and structured I/O. [Workflows →](https://docs.agent-swarm.dev/docs/concepts/workflows)
125
125
  - **Scheduled & recurring tasks** — cron-based automation for standing work. [Scheduling →](https://docs.agent-swarm.dev/docs/concepts/scheduling)
126
126
  - **Harness & LLM agnostic** — run with Claude Code, OpenAI Codex, pi-mono, Devin, Claude Managed Agents, raw LLMs, or opencode. [Harness config →](https://docs.agent-swarm.dev/docs/guides/harness-configuration) · [Add a new provider →](https://docs.agent-swarm.dev/docs/guides/harness-providers)
127
- - **Follow-up continuity across all harnesses** — child tasks inherit bounded prior-task context even on providers without native session resume, while resumable providers still reuse prior sessions when possible. [Task lifecycle →](https://docs.agent-swarm.dev/docs/concepts/task-lifecycle)
127
+ - **Follow-up continuity across all harnesses** — child tasks inherit a bounded prior-task context preamble built from the task chain, so continuity survives restarts and works the same across every provider. [Task lifecycle →](https://docs.agent-swarm.dev/docs/concepts/task-lifecycle)
128
128
  - **Skills & MCP servers** — reusable procedural knowledge and per-agent MCP servers with scope cascade. [MCP tools →](https://docs.agent-swarm.dev/docs/reference/mcp-tools)
129
129
  - **DB-backed pages** — agents publish HTML or JSON pages (reports, dashboards, action specs) via the `create_page` MCP tool with public / authed / password modes, version history, view counters, diff helpers, and PDF export. [MCP tools → Pages](https://docs.agent-swarm.dev/docs/reference/mcp-tools#pages-tools)
130
130
  - **KV store** — Redis-like namespaced key/value store with auto-scoped context (Slack thread / PR / Linear issue / page). [MCP tools → KV](https://docs.agent-swarm.dev/docs/reference/mcp-tools#kv-tools)
@@ -222,6 +222,7 @@ bunx @desplega.ai/agent-swarm <command>
222
222
  | `api` | Start the API + MCP HTTP server |
223
223
  | `worker` | Run a worker agent |
224
224
  | `lead` | Run a lead agent |
225
+ | `e2b` | Build E2B templates and launch/manage grouped API + lead + worker swarms |
225
226
  | `docs` | Open documentation (`--open` to launch in browser) |
226
227
 
227
228
  ## Deployment
package/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Agent Swarm API",
5
- "version": "1.87.0",
5
+ "version": "1.88.0",
6
6
  "description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
7
7
  },
8
8
  "servers": [
@@ -4014,6 +4014,9 @@
4014
4014
  "items": {
4015
4015
  "type": "string"
4016
4016
  }
4017
+ },
4018
+ "persistMemory": {
4019
+ "type": "boolean"
4017
4020
  }
4018
4021
  },
4019
4022
  "required": [
@@ -7620,6 +7623,9 @@
7620
7623
  },
7621
7624
  "ownerAgentId": {
7622
7625
  "type": "string"
7626
+ },
7627
+ "systemDefault": {
7628
+ "type": "boolean"
7623
7629
  }
7624
7630
  },
7625
7631
  "required": [
@@ -7703,6 +7709,9 @@
7703
7709
  "200": {
7704
7710
  "description": "Skill updated"
7705
7711
  },
7712
+ "403": {
7713
+ "description": "System-managed skills cannot be edited"
7714
+ },
7706
7715
  "404": {
7707
7716
  "description": "Skill not found"
7708
7717
  }
@@ -7732,6 +7741,9 @@
7732
7741
  "200": {
7733
7742
  "description": "Skill deleted"
7734
7743
  },
7744
+ "403": {
7745
+ "description": "System-managed skills cannot be deleted"
7746
+ },
7735
7747
  "404": {
7736
7748
  "description": "Skill not found"
7737
7749
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desplega.ai/agent-swarm",
3
- "version": "1.87.0",
3
+ "version": "1.88.0",
4
4
  "description": "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
5
5
  "license": "MIT",
6
6
  "author": "desplega.sh <contact@desplega.sh>",
@@ -111,12 +111,12 @@
111
111
  "@desplega.ai/localtunnel": "^2.2.0",
112
112
  "@inkjs/ui": "^2.0.0",
113
113
  "@linear/sdk": "^77.0.0",
114
- "@earendil-works/pi-agent-core": "^0.76.0",
115
- "@earendil-works/pi-ai": "^0.76.0",
116
- "@earendil-works/pi-coding-agent": "^0.76.0",
114
+ "@earendil-works/pi-agent-core": "^0.78.0",
115
+ "@earendil-works/pi-ai": "^0.78.0",
116
+ "@earendil-works/pi-coding-agent": "^0.78.0",
117
117
  "@modelcontextprotocol/sdk": "^1.25.1",
118
118
  "@openai/codex-sdk": "^0.135.0",
119
- "@opencode-ai/sdk": "^1.15.12",
119
+ "@opencode-ai/sdk": "^1.15.13",
120
120
  "@openfort/openfort-node": "^0.9.1",
121
121
  "@opentelemetry/api": "^1.9.1",
122
122
  "@opentelemetry/exporter-trace-otlp-http": "^0.218.0",
package/src/be/db.ts CHANGED
@@ -691,6 +691,14 @@ export function createAgent(
691
691
  agent.harnessProvider ?? null,
692
692
  );
693
693
  if (!row) throw new Error("Failed to create agent");
694
+ try {
695
+ installSystemDefaultSkillsForAgent(id);
696
+ } catch (err) {
697
+ console.warn(
698
+ "[db] Failed to install system-default skills for new agent:",
699
+ (err as Error).message,
700
+ );
701
+ }
694
702
  try {
695
703
  createLogEntry({ eventType: "agent_joined", agentId: id, newValue: agent.status });
696
704
  } catch {}
@@ -8247,6 +8255,7 @@ type SkillRow = {
8247
8255
  userInvocable: number;
8248
8256
  version: number;
8249
8257
  isEnabled: number;
8258
+ systemDefault: number;
8250
8259
  createdAt: string;
8251
8260
  lastUpdatedAt: string;
8252
8261
  lastFetchedAt: string | null;
@@ -8276,6 +8285,7 @@ function rowToSkill(row: SkillRow): Skill {
8276
8285
  userInvocable: row.userInvocable === 1,
8277
8286
  version: row.version,
8278
8287
  isEnabled: row.isEnabled === 1,
8288
+ systemDefault: row.systemDefault === 1,
8279
8289
  createdAt: row.createdAt,
8280
8290
  lastUpdatedAt: row.lastUpdatedAt,
8281
8291
  lastFetchedAt: row.lastFetchedAt,
@@ -8300,7 +8310,12 @@ function rowToAgentSkill(row: AgentSkillRow): AgentSkill {
8300
8310
  };
8301
8311
  }
8302
8312
 
8303
- type SkillWithInstallRow = SkillRow & { isActive: number; installedAt: string };
8313
+ type SkillWithInstallRow = SkillRow & {
8314
+ isActive: number;
8315
+ installedAt: string;
8316
+ sourceRank?: number;
8317
+ typeRank?: number;
8318
+ };
8304
8319
 
8305
8320
  function rowToSkillWithInstall(row: SkillWithInstallRow): SkillWithInstallInfo {
8306
8321
  return {
@@ -8330,6 +8345,7 @@ export interface SkillInsert {
8330
8345
  agent?: string;
8331
8346
  disableModelInvocation?: boolean;
8332
8347
  userInvocable?: boolean;
8348
+ systemDefault?: boolean;
8333
8349
  }
8334
8350
 
8335
8351
  export function createSkill(data: SkillInsert): Skill {
@@ -8342,8 +8358,8 @@ export function createSkill(data: SkillInsert): Skill {
8342
8358
  id, name, description, content, type, scope, ownerAgentId,
8343
8359
  sourceUrl, sourceRepo, sourcePath, sourceBranch, sourceHash, isComplex,
8344
8360
  allowedTools, model, effort, context, agent, disableModelInvocation, userInvocable,
8345
- version, isEnabled, createdAt, lastUpdatedAt
8346
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 1, ?, ?) RETURNING *`,
8361
+ version, isEnabled, systemDefault, createdAt, lastUpdatedAt
8362
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 1, ?, ?, ?) RETURNING *`,
8347
8363
  )
8348
8364
  .get(
8349
8365
  id,
@@ -8366,6 +8382,7 @@ export function createSkill(data: SkillInsert): Skill {
8366
8382
  data.agent ?? null,
8367
8383
  data.disableModelInvocation ? 1 : 0,
8368
8384
  data.userInvocable === false ? 0 : 1,
8385
+ data.systemDefault ? 1 : 0,
8369
8386
  now,
8370
8387
  now,
8371
8388
  );
@@ -8405,6 +8422,10 @@ export function updateSkill(
8405
8422
  sets.push("isEnabled = ?");
8406
8423
  params.push(updates.isEnabled ? 1 : 0);
8407
8424
  }
8425
+ if (updates.systemDefault !== undefined) {
8426
+ sets.push("systemDefault = ?");
8427
+ params.push(updates.systemDefault ? 1 : 0);
8428
+ }
8408
8429
  if (updates.allowedTools !== undefined) {
8409
8430
  sets.push("allowedTools = ?");
8410
8431
  params.push(updates.allowedTools ?? null);
@@ -8516,7 +8537,7 @@ export interface SkillFilters {
8516
8537
  * which is replaced with an empty string so the row still satisfies `Skill`.
8517
8538
  */
8518
8539
  const SKILL_SLIM_COLUMNS =
8519
- "id, name, description, type, scope, ownerAgentId, sourceUrl, sourceRepo, sourcePath, sourceBranch, sourceHash, isComplex, allowedTools, model, effort, context, agent, disableModelInvocation, userInvocable, version, isEnabled, createdAt, lastUpdatedAt, lastFetchedAt, '' as content";
8540
+ "id, name, description, type, scope, ownerAgentId, sourceUrl, sourceRepo, sourcePath, sourceBranch, sourceHash, isComplex, allowedTools, model, effort, context, agent, disableModelInvocation, userInvocable, version, isEnabled, systemDefault, createdAt, lastUpdatedAt, lastFetchedAt, '' as content";
8520
8541
 
8521
8542
  export function listSkills(filters?: SkillFilters): Skill[] {
8522
8543
  const columns = filters?.includeContent === false ? SKILL_SLIM_COLUMNS : "*";
@@ -8586,6 +8607,19 @@ export function installSkill(agentId: string, skillId: string): AgentSkill {
8586
8607
  return rowToAgentSkill(row);
8587
8608
  }
8588
8609
 
8610
+ export function getSystemDefaultSkills(): Skill[] {
8611
+ return getDb()
8612
+ .prepare<SkillRow, []>(
8613
+ "SELECT * FROM skills WHERE systemDefault = 1 AND isEnabled = 1 ORDER BY name ASC",
8614
+ )
8615
+ .all()
8616
+ .map(rowToSkill);
8617
+ }
8618
+
8619
+ export function installSystemDefaultSkillsForAgent(agentId: string): AgentSkill[] {
8620
+ return getSystemDefaultSkills().map((skill) => installSkill(agentId, skill.id));
8621
+ }
8622
+
8589
8623
  export function uninstallSkill(agentId: string, skillId: string): boolean {
8590
8624
  const result = getDb()
8591
8625
  .prepare("DELETE FROM agent_skills WHERE agentId = ? AND skillId = ?")
@@ -8595,15 +8629,23 @@ export function uninstallSkill(agentId: string, skillId: string): boolean {
8595
8629
 
8596
8630
  export function getAgentSkills(agentId: string, activeOnly = true): SkillWithInstallInfo[] {
8597
8631
  const query = `
8598
- SELECT s.*, as2.isActive, as2.installedAt
8632
+ SELECT s.*, as2.isActive, as2.installedAt, 0 as sourceRank,
8633
+ CASE WHEN s.type = 'personal' THEN 0 ELSE 1 END as typeRank
8599
8634
  FROM skills s
8600
8635
  JOIN agent_skills as2 ON s.id = as2.skillId
8601
8636
  WHERE as2.agentId = ?
8602
8637
  ${activeOnly ? "AND as2.isActive = 1" : ""}
8603
8638
  AND s.isEnabled = 1
8639
+ UNION ALL
8640
+ SELECT s.*, 1 as isActive, s.createdAt as installedAt, 1 as sourceRank,
8641
+ CASE WHEN s.type = 'personal' THEN 0 ELSE 1 END as typeRank
8642
+ FROM skills s
8643
+ WHERE s.systemDefault = 1
8644
+ AND s.isEnabled = 1
8604
8645
  ORDER BY
8605
- CASE WHEN s.type = 'personal' THEN 0 ELSE 1 END,
8606
- s.name
8646
+ sourceRank,
8647
+ typeRank,
8648
+ name
8607
8649
  `;
8608
8650
 
8609
8651
  const rows = getDb().prepare<SkillWithInstallRow, [string]>(query).all(agentId);
@@ -0,0 +1,8 @@
1
+ -- 080_skill_system_defaults.sql
2
+ -- Adds a first-class marker for skills that are installed for every agent.
3
+ -- Forward migration: add nullable-safe column with default 0.
4
+ -- Reverse operation, if ever needed: ALTER TABLE skills DROP COLUMN systemDefault;
5
+
6
+ ALTER TABLE skills ADD COLUMN systemDefault INTEGER NOT NULL DEFAULT 0;
7
+
8
+ CREATE INDEX IF NOT EXISTS idx_skills_system_default ON skills(systemDefault);