@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 +31 -16
- package/dist/swarm-hook.js +39 -0
- package/dist/swarm.js +39 -1
- package/dist/swarmd.js +1652 -117
- package/package.json +1 -1
- package/web/app.js +702 -66
- package/web/icons.js +2 -2
- package/web/index.html +101 -28
- package/web/menus.js +7 -7
- package/web/release-notes.js +1 -1
- package/web/table.js +1 -1
- package/web/viz.js +76 -2
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)
|
|
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 —
|
|
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 (
|
|
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
|
|
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)
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
|
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
|
|
package/dist/swarm-hook.js
CHANGED
|
@@ -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
|