@ra3orblade/swarm 0.10.0 → 0.11.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 CHANGED
@@ -24,7 +24,7 @@ A local-first control plane for AI-agent development on any repository.</p>
24
24
 
25
25
  <p align="center"><a href="https://getswarm.vercel.app"><img src="docs/art/screens/fleet.png" alt="Swarm Fleet view — every agent session on the machine, live" width="100%"></a></p>
26
26
 
27
- Run more than one [Claude Code](https://claude.com/claude-code) session at a time — or a [Codex CLI](https://github.com/openai/codex) or Grok run on the side — and you lose the thread fast: which session is on which branch, what it's costing, which worktree has uncommitted work nobody owns, why that edit got blocked. Swarm is one daemon that watches every session on your machine — live tool calls, reasoning, token spend, cost — keeps a ledger of who holds which task, worktree and runtime resource, turns the "never do X" prose in `CLAUDE.md` into real permission decisions, and streams all of it to one dashboard.
27
+ Run more than one [Claude Code](https://claude.com/claude-code) session at a time — or a [Codex CLI](https://github.com/openai/codex), Gemini, Grok, Aider or opencode run on the side — and you lose the thread fast: which session is on which branch, what it's costing, which worktree has uncommitted work nobody owns, why that edit got blocked. Swarm is one daemon that watches every session on your machine — live tool calls, reasoning, token spend, cost — keeps a ledger of who holds which task, worktree and runtime resource, turns the "never do X" prose in `CLAUDE.md` into real permission decisions, and streams all of it to one dashboard.
28
28
 
29
29
  It runs entirely on your machine. No account, no telemetry, works offline. Nothing is added to your repositories.
30
30
 
@@ -32,13 +32,13 @@ It runs entirely on your machine. No account, no telemetry, works offline. Nothi
32
32
  bunx @ra3orblade/swarm setup
33
33
  ```
34
34
 
35
- > Status: early, but real — observability, task claims in isolated worktrees, runtime resources, configurable rules, incidents, a cross-forge merge queue, spawned agents (`swarm run` / `swarm dispatch`), executed verification gates, handoffs, session replay, search and spend budgets are built and dogfooded daily — Swarm dispatches its own tasks. Agent-to-agent messaging, declarative workflows and a built-in review gate are next on the [roadmap](ROADMAP.md).
35
+ > Status: early, but real, and shipping fast eleven releases so far. Observability across six agent CLIs, task claims in isolated worktrees, runtime resources, rules and incidents, a cross-forge merge queue, spawned agents (`swarm run` / `swarm dispatch`), declarative workflows, executed verification gates (including a built-in reviewer), handoffs, agent-to-agent messaging, session replay, outcome tracking, the collision graph, search, budgets, signed org policy and a self-hosted team daemon are all built and dogfooded daily — Swarm dispatches its own tasks. What's next is on the [roadmap](ROADMAP.md).
36
36
 
37
37
  ---
38
38
 
39
39
  ## What you get
40
40
 
41
- **Fleet** — every session across every project, live: agent, title, branch, what it's doing right now, model, a trend sparkline, output tokens, context size, cost, age. Filter by agent (Claude Code, Codex, Grok).
41
+ **Fleet** — every session across every project, live: agent, title, branch, what it's doing right now, model, a trend sparkline, output tokens, context size, cost, age. Filter by agent (all six). A session that starts repeating a failing command gets a **Stuck** badge and a desktop notification — a heuristic, and nothing is ever interrupted.
42
42
 
43
43
  **Session** — an agent's reasoning and tool calls as a live stream, with cost per turn, cache hit rate, thinking share, tool histogram and the transcript path. **Replay** steps through its tool calls one at a time with full input and output; an ended session gets **Resume where it died**, which spawns a run from what it left behind; a session inside a worktree shows its **Diff**.
44
44
 
@@ -56,6 +56,10 @@ bunx @ra3orblade/swarm setup
56
56
 
57
57
  **Ask the human** — an agent that hits a decision only you can make calls `swarm_ask`; the question shows on the session page with the options as buttons, Fleet shows an **Asking** badge, a desktop notification fires, and the answer reaches the agent on its own.
58
58
 
59
+ **Workflows** — `[[workflows]] name = "ship" steps = ["implement", "gate:tests", "gate:review", "pr"]` in `.swarm.toml`, and the daemon advances it: run steps spawn an agent in the task's worktree, gate steps must pass to continue, `pr` pushes the branch and opens the pull request. A failed step stops with an incident that says which one.
60
+
61
+ **Messaging** — `swarm_send(to, text)` reaches another session by id, whoever holds a task, or `"lead"` (your interactive session in the project). It arrives as injected context on the recipient's next tool call, over stdin to a spawned run, or via `swarm_inbox` — exactly once.
62
+
59
63
  **PRs** — one merge queue across GitHub and GitLab, read through your already-authenticated `gh` / `glab`. Merge from the dashboard when checks and review are clear. No tokens stored.
60
64
 
61
65
  **Timeline** — session lanes per project, coloured by agent, 3–72 h.
@@ -66,15 +70,21 @@ bunx @ra3orblade/swarm setup
66
70
 
67
71
  **Search** — full-text memory over everything Swarm remembers: handoffs, incidents, gate runs and what sessions said. **Dry-run rules** replays a project's history under rule modes you pick before switching anything on.
68
72
 
73
+ **Outcomes** — did the work survive? Sessions join to a branch, the branch to its PR, the PR to merged or reverted, scored per model and per agent: merge rate, median time from session start to merge, dollars per merge.
74
+
75
+ **Graphs** — a live bipartite graph of running sessions against the files they touch. A file two sessions hold with at least one writer turns red: a merge conflict you can still prevent.
76
+
77
+ <p align="center"><img src="docs/art/screens/outcomes.png" alt="Outcomes view — merge rate, median time to merge and dollars per merge, per model and per agent" width="100%"></p>
78
+
69
79
  <p align="center"><img src="docs/art/screens/stats.png" alt="Stats view" width="100%"></p>
70
80
 
71
- **Multi-agent** — Claude Code via its hooks and transcripts; Codex CLI and Grok by tailing the session logs they already write (`~/.codex`, ACP `updates.jsonl`). Every session is tagged with its agent; Spend breaks down per agent.
81
+ **Multi-agent** — six brands, one ledger: Claude Code via its hooks and transcripts (the full picture rules, MCP, spawned runs), and Codex CLI (`~/.codex`), Gemini CLI (`~/.gemini`), Grok (ACP `updates.jsonl`), Aider (`.aider.chat.history.md`) and opencode (its SQLite database, read-only) by reading the session logs they already write. Every session is tagged with its agent; Spend, Timeline and Outcomes break down per agent.
72
82
 
73
83
  **Zero instrumentation** — it reads the hooks and transcripts the agents already write. Every table is a real data grid: sort, resize, reorder, filter, persisted layouts. Light and dark themes.
74
84
 
75
85
  ## Install
76
86
 
77
- Requires [Bun](https://bun.sh) ≥ 1.3, git, and at least one agent: [Claude Code](https://claude.com/claude-code) (`claude` on your PATH — hooks, rules and MCP need it), [Codex CLI](https://github.com/openai/codex) and/or Grok (observed by tailing their logs; no hooks, so no rules). Optional: `gh` and/or `glab` (authenticated) for the PRs view.
87
+ Requires [Bun](https://bun.sh) ≥ 1.3, git, and at least one agent: [Claude Code](https://claude.com/claude-code) (`claude` on your PATH — hooks, rules and MCP need it), plus [Codex CLI](https://github.com/openai/codex), Gemini CLI, Grok, Aider and opencode (observed by reading their logs; no hooks, so no rules). Optional: `gh` and/or `glab` (authenticated) for the PRs view.
78
88
 
79
89
  ```sh
80
90
  bunx @ra3orblade/swarm setup # daemon + hooks + MCP, opens the dashboard
@@ -176,16 +186,15 @@ swarm install | uninstall # add/remove Swarm hooks in ~/.claude/settings.js
176
186
  ## How it works
177
187
 
178
188
  ```
179
- Claude Code sessions ──hooks──▶ swarm-hook ──┐
180
- (any folder, any repo) │
181
- transcripts (JSONL) ──────┼──▶ swarmd ──▶ SQLite (~/.swarm)
182
- Codex CLI ─── ~/.codex rollout logs ────────────┤ │
183
- Grok ─── ACP updates.jsonl ────────────────┘ └──▶ SSE ──▶ dashboard · CLI · MCP
184
- ▼ ▲
185
- rules engine (ask / deny incidents)
186
- ledger: claims · worktrees · gates · handoffs · resources · budgets
187
-
188
- swarm run / dispatch ──▶ claude -p in a claimed worktree ──┘
189
+ Claude Code · Codex · Gemini · Grok · Aider · opencode
190
+ │ hooks · transcripts · session logs
191
+
192
+ swarmd ──▶ SQLite (~/.swarm) the only place state lives
193
+
194
+ ├──▶ rules engine ──▶ ask · deny · incident
195
+ ├──▶ ledger ──▶ claims · worktrees · gates · handoffs · ports · budgets
196
+ ├──▶ SSE ──▶ dashboard · CLI · MCP · desktop app
197
+ └──▶ swarm run / dispatch ──▶ an agent in a claimed worktree
189
198
  ```
190
199
 
191
200
  - **Identity** is the git common dir, so every worktree of a repo maps to one project.
@@ -195,9 +204,15 @@ swarm install | uninstall # add/remove Swarm hooks in ~/.claude/settings.js
195
204
 
196
205
  Design docs (architecture, data model, protocol, interface, roadmap) are rendered at [getswarm.vercel.app/docs/design](https://getswarm.vercel.app/docs/design/) and live in [`docs/`](docs/00-index.md).
197
206
 
207
+ ## Teams
208
+
209
+ One machine is free and always will be. When it outgrows one laptop, `swarm-teamd` is a second, self-hosted service your machines *forward* to — audit events, spend rollups and claims, never transcript text unless a machine opts in, and always after your redaction rules. You get one view of the fleet (machines, cluster-wide claims, spend by person, project, machine and day), a claim taken on one laptop is refused on another with the holder's name, org `policy.toml` is ed25519-signed and verified against a key pinned at `swarm login`, team budgets enforce warn / ask / stop, and monthly chargeback exports come out by user, machine, model or **ticket id**. Every laptop stays local-first and keeps working offline. [Teams guide](https://getswarm.vercel.app/docs/11-teams).
210
+
211
+ *Licensing: `packages/team` is the single source-available package ([FSL-1.1-ALv2](packages/team/LICENSE.md), Apache-2.0 after two years). Everything else is and stays Apache-2.0.*
212
+
198
213
  ## Privacy
199
214
 
200
- Everything is local. Swarm reads the hook payloads and transcript files (Claude Code, Codex, Grok) that already exist on your disk, stores derived state in `~/.swarm/swarm.db`, and serves a dashboard on `127.0.0.1`. Optional outbound paths, all under your control: fetching model prices from the public LiteLLM list (`SWARM_OFFLINE=1` skips it); the PRs view shelling out to your already-authenticated `gh` / `glab` (Swarm stores no forge tokens); and the desktop app asking GitHub Releases for updates when you click *Check for Updates…*. No data about your sessions leaves your machine.
215
+ Everything is local. Swarm reads the hook payloads and session logs (all six agents) that already exist on your disk, stores derived state in `~/.swarm/swarm.db`, and serves a dashboard on `127.0.0.1`. Optional outbound paths, all under your control: fetching model prices from the public LiteLLM list (`SWARM_OFFLINE=1` skips it); the PRs view shelling out to your already-authenticated `gh` / `glab` (Swarm stores no forge tokens); and the desktop app asking GitHub Releases for updates when you click *Check for Updates…*. No data about your sessions leaves your machine.
201
216
 
202
217
  ## Configuration
203
218
 
@@ -47,6 +47,38 @@ function resolveBaseUrl(explicit) {
47
47
  // packages/core/src/actor.ts
48
48
  var HUMAN_ALIASES = new Set(["cli", "dashboard", "me", "desktop", "human"]);
49
49
  var DAEMON_ALIASES = new Set(["daemon", "system", "swarm"]);
50
+ // packages/core/src/art.ts
51
+ var ROBOT = [
52
+ " g g ",
53
+ " X X ",
54
+ " X X ",
55
+ " ddddddddddddd ",
56
+ " dXXXXXXXXXXXd ",
57
+ " dggXXXXXXXXXd ",
58
+ " dddXXddXXXddXXddd ",
59
+ " dddXXddXXXddXXddd ",
60
+ " dddXXXXXXXXXXXddd ",
61
+ " dddXXdddddddXXddd ",
62
+ " dXXXXXXXXXXXd ",
63
+ " dXXXXXXXXXXXd ",
64
+ " ddddddddddddd ",
65
+ " XXX ",
66
+ " ddddd ",
67
+ " ddddddddddd ",
68
+ " dXXdggXXXXXXXdXXd ",
69
+ " dXXdXggggXddddXXd ",
70
+ " dXXdXggggXXXXdXXd ",
71
+ " dXXdXXXXXXddddXXd ",
72
+ " dXXdXXXXXXXXXdXXd ",
73
+ " dXXdXdddXXXXXdXXd ",
74
+ " ddddXXXXXXXXXdddd ",
75
+ " ddddddddddd ",
76
+ " XX XX ",
77
+ " XX XX ",
78
+ " XXXX XXXX ",
79
+ " dddd dddd "
80
+ ];
81
+ var ROBOT_HEAD = ROBOT.slice(0, 13);
50
82
  // packages/core/src/audit.ts
51
83
  var AUDIT_TYPES = new Set([
52
84
  "session.started",
@@ -230,6 +262,13 @@ function guardWrite(target, current, claims, modes = DEFAULT_MODES, kind = "file
230
262
  }
231
263
  return { action: "allow" };
232
264
  }
265
+ // packages/core/src/hygiene.ts
266
+ var HYGIENE_DEFAULTS = {
267
+ staleDays: 7,
268
+ abandonedDays: 30,
269
+ hungryRssKb: 1024 * 1024,
270
+ heavyKb: 2 * 1024 * 1024
271
+ };
233
272
  // packages/core/src/ledger.ts
234
273
  var EDIT_TOOLS = new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
235
274
  // packages/core/src/outcomes.ts
package/dist/swarm.js CHANGED
@@ -150,7 +150,6 @@ class SwarmClient {
150
150
  throw new Error(`swarmd: ${r.status}`);
151
151
  }
152
152
  }
153
-
154
153
  // packages/core/src/actor.ts
155
154
  var HUMAN_ALIASES = new Set(["cli", "dashboard", "me", "desktop", "human"]);
156
155
  var DAEMON_ALIASES = new Set(["daemon", "system", "swarm"]);
@@ -167,6 +166,38 @@ var HOOK_EVENTS = [
167
166
  "Notification",
168
167
  "PreCompact"
169
168
  ];
169
+ // packages/core/src/art.ts
170
+ var ROBOT = [
171
+ " g g ",
172
+ " X X ",
173
+ " X X ",
174
+ " ddddddddddddd ",
175
+ " dXXXXXXXXXXXd ",
176
+ " dggXXXXXXXXXd ",
177
+ " dddXXddXXXddXXddd ",
178
+ " dddXXddXXXddXXddd ",
179
+ " dddXXXXXXXXXXXddd ",
180
+ " dddXXdddddddXXddd ",
181
+ " dXXXXXXXXXXXd ",
182
+ " dXXXXXXXXXXXd ",
183
+ " ddddddddddddd ",
184
+ " XXX ",
185
+ " ddddd ",
186
+ " ddddddddddd ",
187
+ " dXXdggXXXXXXXdXXd ",
188
+ " dXXdXggggXddddXXd ",
189
+ " dXXdXggggXXXXdXXd ",
190
+ " dXXdXXXXXXddddXXd ",
191
+ " dXXdXXXXXXXXXdXXd ",
192
+ " dXXdXdddXXXXXdXXd ",
193
+ " ddddXXXXXXXXXdddd ",
194
+ " ddddddddddd ",
195
+ " XX XX ",
196
+ " XX XX ",
197
+ " XXXX XXXX ",
198
+ " dddd dddd "
199
+ ];
200
+ var ROBOT_HEAD = ROBOT.slice(0, 13);
170
201
  // packages/core/src/audit.ts
171
202
  var AUDIT_TYPES = new Set([
172
203
  "session.started",
@@ -530,6 +561,13 @@ function loadConfigDetailed(opts = {}) {
530
561
  // packages/core/src/rules.ts
531
562
  var LIVE_WINDOW_MS = 10 * 60000;
532
563
  var WRITE_TOOLS = new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
564
+ // packages/core/src/hygiene.ts
565
+ var HYGIENE_DEFAULTS = {
566
+ staleDays: 7,
567
+ abandonedDays: 30,
568
+ hungryRssKb: 1024 * 1024,
569
+ heavyKb: 2 * 1024 * 1024
570
+ };
533
571
  // packages/core/src/ledger.ts
534
572
  var EDIT_TOOLS = new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
535
573
  // packages/core/src/outcomes.ts