@getspur/spur-graph 1.1.17
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/.gitignore +2 -0
- package/CHANGELOG.md +260 -0
- package/README.md +222 -0
- package/binary-install.js +212 -0
- package/binary.js +128 -0
- package/install.js +4 -0
- package/npm-shrinkwrap.json +546 -0
- package/package.json +71 -0
- package/run-capture-baselines.js +4 -0
package/.gitignore
ADDED
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
## Unreleased
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
- **`spur-graph` content-hash invalidation substrate (bd-jvers, v2.1).**
|
|
5
|
+
Replaces mtime/size per-file invalidation with a filtered-content hash
|
|
6
|
+
over `(path, content_oid)` pairs, where `content_oid` is the git blob OID
|
|
7
|
+
(from `git ls-files -s` for clean files; locally computed via
|
|
8
|
+
`sha1("blob " || decimal(size) || "\0" || bytes)` for dirty / untracked /
|
|
9
|
+
fs-mode files; `gitlink:<oid>` for submodules). Cache key derivation
|
|
10
|
+
reads only the git index + dirty file bytes — does not depend on `HEAD`.
|
|
11
|
+
- **Canonical artifact** at `<git_common_dir>/spur-graph/artifacts/<manifest_version>/<graph_content_hash>.json`
|
|
12
|
+
(immutable per key, content-addressed).
|
|
13
|
+
- **Per-worktree** `.spur/graph-index.json` retained as a full artifact,
|
|
14
|
+
hardlinked to the canonical (with `fs::copy` fallback across filesystems).
|
|
15
|
+
Existing direct consumers (`crates/spur-tui/src/mentions/code_graph/source.rs`)
|
|
16
|
+
are source-compatible — no API changes.
|
|
17
|
+
- **Optional pointer sidecar** at `.spur/graph-index.pointer.json` carries
|
|
18
|
+
provenance (`indexed_commit_oid`, `source_kind`, `manifest_version`).
|
|
19
|
+
- **Bucket reuse.** Within a worktree, unchanged paths (same `content_oid`
|
|
20
|
+
as the previous artifact) are cloned wholesale — no tree-sitter parsing
|
|
21
|
+
or symbol extraction. This is the per-build extraction-saving mechanism.
|
|
22
|
+
- **Cross-worktree dedup.** Two worktrees with identical filtered content
|
|
23
|
+
derive the same canonical key regardless of commit history, so the
|
|
24
|
+
second writer skips the canonical JSON write and hardlinks the existing
|
|
25
|
+
artifact. (Each worktree still computes its own discovery + hash;
|
|
26
|
+
pre-extraction shortcircuit is tracked as a followup, bd-5yful.)
|
|
27
|
+
- **Dirty == committed (I2).** A worktree's dirty `content_oid` equals
|
|
28
|
+
the blob OID git would assign if the file were committed, so
|
|
29
|
+
`graph_content_hash` before and after committing identical bytes
|
|
30
|
+
matches and every bucket is reused on the next build.
|
|
31
|
+
- `fs2` exclusive lock with 5s timeout + worktree-only fallback on
|
|
32
|
+
contention; atomic write via tmp + rename + best-effort `fsync_dir`.
|
|
33
|
+
- Schema bumped to `spur-graph-schema-v4`: `GraphFileManifestEntry` swaps
|
|
34
|
+
`mtime_nanos`/`size_bytes` for `content_oid`; `GraphIndexArtifact` gains
|
|
35
|
+
`graph_content_hash` and value-level `tombstones` (no commit OID).
|
|
36
|
+
- Design spec: `docs/architecture/spur-graph-git-invalidation.md`.
|
|
37
|
+
- **`spur-graph` benchmark gate.** Criterion bench at
|
|
38
|
+
`crates/spur-graph/benches/incremental.rs` covers four scenarios:
|
|
39
|
+
clean cold (cache miss), clean warm (cache hit via hardlink), 1k-file
|
|
40
|
+
change set over baseline, and dirty unstaged mods overlay. Env-knob
|
|
41
|
+
scaling via `BENCH_FILE_COUNT` / `BENCH_CHANGE_SET` / `BENCH_DIRTY_MODS`.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
- **`spur-graph` cache lock-timeout no longer leaves a ghost pointer**
|
|
45
|
+
(bd-jvers followup). On `fs2` lock contention, `write_with_dedup`
|
|
46
|
+
previously wrote the worktree artifact and ALSO wrote a pointer sidecar
|
|
47
|
+
whose `canonical_artifact_path` referenced a canonical file that was
|
|
48
|
+
never created — any pointer-following reader hit a deterministic
|
|
49
|
+
missing-file failure. Fix: on lock-timeout, write the worktree artifact
|
|
50
|
+
(still authoritative) and remove any pre-existing pointer so it cannot
|
|
51
|
+
be stale. Convergent finding from claude-code and kimi reviews. Test
|
|
52
|
+
`lock_timeout_writes_worktree_only` extended to stage a stale pointer
|
|
53
|
+
before the lock-contended write and assert no pointer exists after.
|
|
54
|
+
|
|
55
|
+
- **Experimental TUI Insights view (`--features analytics`, default OFF).**
|
|
56
|
+
`Alt+a` from any view opens a 4-tab Insights surface (Overview / Timeline /
|
|
57
|
+
Breakdown / Live) backed by `spur-context::AnalyticsEngine`'s DuckDB store.
|
|
58
|
+
- Overview: KPI cards (Today / 7d / 30d / Cache hit), 7d cost sparkline,
|
|
59
|
+
cost-provenance gauge (native / priced / unpriced), top-3 agent / model /
|
|
60
|
+
project lists.
|
|
61
|
+
- Timeline: BarChart with `D`/`W`/`M` granularity toggle (no re-query).
|
|
62
|
+
- Breakdown: Pivot table over Agent / Model / Project (`A` / `M` / `P`).
|
|
63
|
+
- Live: per-session burn rate, hourly projection, refresh interval drops to
|
|
64
|
+
5s while this tab is active (60s otherwise).
|
|
65
|
+
Refresh is driven by an async `tokio::spawn` task with a signal channel and
|
|
66
|
+
30s timeout; the view never blocks the UI thread.
|
|
67
|
+
- **Five well-known agents are first-class in analytics**: Claude Code,
|
|
68
|
+
Codex, Gemini, OpenCode, Kimi. Kiro remains a Phase-2 stub
|
|
69
|
+
(no token data via filesystem; ACP `UsageUpdate` capture pending).
|
|
70
|
+
- **`spur-context` Gemini extractor (R4).** Parses `~/.gemini/tmp/<uuid>/chats/session-*.json`
|
|
71
|
+
with `tokens.{input,output,cached,thoughts,tool}` folding. Wires into
|
|
72
|
+
`AnalyticsEngine` alongside existing Claude / Codex / OpenCode / Kimi paths.
|
|
73
|
+
- **OpenCode model-prefix strip (R1).** `anthropic/claude-opus-4-5` is now
|
|
74
|
+
stored as `claude-opus-4-5` so the pricing registry's `LIKE` matcher works.
|
|
75
|
+
Eliminates spurious `cost_source='unpriced'` rows for OpenCode users.
|
|
76
|
+
- **Kimi `kimi-for-coding` pricing (R2).** Registered at $0.60 input /
|
|
77
|
+
$2.50 output / $0.15 cache-read per million tokens. Kimi events now surface
|
|
78
|
+
with correct `cost_source='priced'` instead of `'unpriced'`.
|
|
79
|
+
- **OpenCode SQLite mtime in cache staleness (R3).** `newest_agent_mtime`
|
|
80
|
+
now includes `~/.local/share/opencode/opencode.db`, fixing permanently-stale
|
|
81
|
+
cache for OpenCode-only users.
|
|
82
|
+
- **Dashboard cost-source switch (when feature on).** Dashboard's total cost
|
|
83
|
+
reads from a periodically-refreshed `LiveCostCache` populated via
|
|
84
|
+
`AnalyticsEngine::live_session_snapshot` instead of `ExecutorLineage`. The
|
|
85
|
+
status bar shows a `via analytics` pill while the cache has data for the
|
|
86
|
+
active session. Single source of truth for cost when feature is enabled.
|
|
87
|
+
- **CI matrix for `spur-tui`.** New workflow runs
|
|
88
|
+
`cargo check + cargo test --lib` for `--no-default-features`, default, and
|
|
89
|
+
`--features analytics` configurations on every PR and `main` push.
|
|
90
|
+
- **P0 cost-correctness fixes harvested onto this branch.**
|
|
91
|
+
- P0.1: Claude event dedup on `(sessionId, requestId, message.id)`.
|
|
92
|
+
- P0.2/3/4: `cost_source` column + Codex cache double-count fix.
|
|
93
|
+
- P0.6: `include_str!` per-report SQL with synced cache columns.
|
|
94
|
+
- P0.8: `SessionRow::models` aggregates across mid-session model switches.
|
|
95
|
+
|
|
96
|
+
### Changed
|
|
97
|
+
- **Read-only future metadata saves now fail visibly.** When
|
|
98
|
+
`.spur/session_metadata.json` was written by a future SPUR version,
|
|
99
|
+
`SessionMetadataStore::save()` now returns `Err(ReadOnlyFutureSchema)`
|
|
100
|
+
instead of silently accepting and discarding in-session edits. App
|
|
101
|
+
save paths route through `App::persist_metadata`, which surfaces the
|
|
102
|
+
refusal as a dismissible warning banner.
|
|
103
|
+
- **Peer mailbox reconciler now emits `WorkerPeerMessageAuditFailed`** on
|
|
104
|
+
non-terminal transition errors during startup reconciliation. The
|
|
105
|
+
`WorkerPeerMailboxReconciled.audit_failed_emitted` counter, which was
|
|
106
|
+
always `0` prior to this release, may now report non-zero values when
|
|
107
|
+
the persistent ledger introduces transition failures. Dashboards and
|
|
108
|
+
alerts that filter `audit_failed_emitted == 0` as a "no anomalies"
|
|
109
|
+
signal should switch to alerting on the
|
|
110
|
+
`WorkerPeerMessageAuditFailed { transition_kind: "reconcile_to_delivered" }`
|
|
111
|
+
event directly. (bd-cpf.5b)
|
|
112
|
+
|
|
113
|
+
### Added
|
|
114
|
+
- **Tolerant input-history deserialize.** A malformed `ProtectedRange` or
|
|
115
|
+
`InputHistoryEntry` in `.spur/session_metadata.json` no longer aborts
|
|
116
|
+
the entire load: bad rows are skipped with `tracing::warn!`, while
|
|
117
|
+
remaining valid history is preserved.
|
|
118
|
+
- **`schema_version` field on `SessionMetadata`.** Persisted as the
|
|
119
|
+
on-disk JSON key `"version"` for backward compatibility. Files written
|
|
120
|
+
by a future SPUR version are loaded read-only; in-memory mutations are
|
|
121
|
+
not persisted until SPUR understands that schema.
|
|
122
|
+
- **Read-only mode banner.** Future-version metadata now shows a top-row
|
|
123
|
+
warning at first paint and after every refused save attempt. `Esc`
|
|
124
|
+
dismisses the current banner without clearing read-only mode.
|
|
125
|
+
- **`SessionMetadataStore::is_read_only()` getter.** Callers can poll
|
|
126
|
+
whether metadata is in read-only mode before enabling write-oriented UI.
|
|
127
|
+
- **Worker heartbeat watchdog configuration.** New `[worktree]` config keys:
|
|
128
|
+
`worker_heartbeat_watchdog_enabled` (bool, default `false`),
|
|
129
|
+
`worker_heartbeat_timeout_secs` (u64, default `90`),
|
|
130
|
+
`worker_heartbeat_initial_grace_secs` (u64, default `60`). See
|
|
131
|
+
`docs/architecture.md` Risk #23 for operational guidance and the
|
|
132
|
+
no-runtime-toggle rollback constraint. (bd-arch.23)
|
|
133
|
+
- **`DelegationAbortReason` enum** distinguishing `BrainRequested` from
|
|
134
|
+
`WorkerHeartbeatTimeout`. Stage-2 will extend with `ResourceLimitExceeded`
|
|
135
|
+
/ `SandboxTerminated` for cgroup-based termination. (bd-arch.23)
|
|
136
|
+
- **Peer mailbox production wire-up (Stage-1).** The peer mailbox subsystem
|
|
137
|
+
(hardened in bd-cpf.1–7) is now constructed and attached when
|
|
138
|
+
`peer_mailbox_enabled = true` is set in config. A long-lived reconciler
|
|
139
|
+
task drains stranded peer messages and emits audit events. Startup
|
|
140
|
+
reconcile runs at brain session boundaries. Default is `false`; no
|
|
141
|
+
behavioral change for existing deployments. Operators who opt in should
|
|
142
|
+
monitor for `WorkerPeerMessageUndeliverable` events and be aware that
|
|
143
|
+
the in-memory ledger does not prune entries (Risk #22). To disable,
|
|
144
|
+
set `peer_mailbox_enabled = false` and restart SPUR — runtime toggle
|
|
145
|
+
is not supported. (bd-arch.21)
|
|
146
|
+
- **Peer mailbox drain lifecycle events.** `WorkerPeerMessageDrainStarted`
|
|
147
|
+
and `WorkerPeerMessageDrainTimedOut` add symmetric observability to the
|
|
148
|
+
post-prompt ack drain. `DrainStarted` carries the candidate-set size
|
|
149
|
+
and the cap/quiet-window limits in effect; `DrainTimedOut` carries the
|
|
150
|
+
same payload shape as `WorkerPeerMessageDrainCappedOut` plus
|
|
151
|
+
`quiet_window_ms`, so dashboards can reuse panel queries across both
|
|
152
|
+
exit events. `DrainTimedOut` is emitted only when the quiet-window
|
|
153
|
+
exit leaves remaining non-terminal messages; clean-exit drains
|
|
154
|
+
(`remaining_messages == 0`) emit no exit event. Diagnostic-only —
|
|
155
|
+
message loss continues to be tracked per-message via
|
|
156
|
+
`WorkerPeerMessageIgnored`. (bd-cpf.7)
|
|
157
|
+
- **`WorkerPeerMailboxReconciled.inflight_already_delivered` counter.**
|
|
158
|
+
Tracks benign idempotent races during startup reconciliation where an
|
|
159
|
+
entry was already in `Delivered` state when the reconciler attempted
|
|
160
|
+
to advance it. Always 0 in Stage-1; becomes non-zero under Stage-2
|
|
161
|
+
crash-loop or concurrent-reconcile scenarios. (bd-cpf.5c)
|
|
162
|
+
- **Spur Way skill bundle.** Six bundled skills harden brain-worker-beads
|
|
163
|
+
collaboration: `spur-way` (beads-first invariant), `beads-lifecycle`
|
|
164
|
+
(status state machine), `worker-signals` (`[[spur-signal v1]]` protocol),
|
|
165
|
+
`brain-review-gate` (beads-aware approval checklist), `plan-task-discipline`
|
|
166
|
+
(DAG integrity rules), and `worker-mention-routing` (user `@`-mention
|
|
167
|
+
overrides algorithmic selection). All compile into `spur-core` via
|
|
168
|
+
`include_str!` and render across the seven agent adapters. See
|
|
169
|
+
`docs/superpowers/specs/2026-04-22-superpower-skill-hardening-spur-way.md`.
|
|
170
|
+
- **Role-gated skill rendering + Kimi adapter.** Skills now carry a `role`
|
|
171
|
+
field (`brain | worker | both`). Brain-only skills (`brain-review-gate`,
|
|
172
|
+
`brain-delegation`) no longer leak into worker agent directories. Worker
|
|
173
|
+
skills (`test-driven-development`, `systematic-debugging`) are tagged
|
|
174
|
+
explicitly. New `Adapter::Kimi` renders to `.kimi/skills/`, closing the
|
|
175
|
+
gap where Kimi workers accidentally relied on `.claude/skills/` fallback.
|
|
176
|
+
See `docs/superpowers/specs/2026-04-22-multi-agent-skill-embedding-research.md`.
|
|
177
|
+
|
|
178
|
+
### Fixed
|
|
179
|
+
- **Risk #4 (worktree orphaning under unclean shutdown).** New
|
|
180
|
+
`WorktreeAuthority` actor sweeps dead-session worktrees safely under
|
|
181
|
+
multi-process operation. Branch namespace migrated to
|
|
182
|
+
`spur/worker/v2/{agent}/{brain_session_id}/{worker_session_id}` so
|
|
183
|
+
sweep enumeration can be precisely scoped to v2 worktrees. Pre-v2
|
|
184
|
+
branches are NOT auto-cleaned; operators reclaim legacy debt via the
|
|
185
|
+
separate `spur-worktree-gc-legacy.sh` script (deferred). The actor
|
|
186
|
+
uses a `SessionLivenessProbe` over advisory `flock(2)` and a
|
|
187
|
+
`SelfHeldSet` to skip self-owned sessions. See
|
|
188
|
+
`docs/superpowers/specs/2026-04-26-worktree-authority-design.md` for
|
|
189
|
+
the full invariants I-1..I-7.
|
|
190
|
+
- **Worker child processes now die with their orchestrator** via
|
|
191
|
+
`kill_on_drop(true)` on the `tokio::process::Command` spawn paths in
|
|
192
|
+
`crates/spur-acp/src/connection/{native,stdio_adapter,cli_wrap_adapter,stream_json_adapter}.rs`.
|
|
193
|
+
Closes Risk #4's hard prerequisite.
|
|
194
|
+
- **`spur-bot/tests/runtime_flow.rs` compile errors absorbed.** 12
|
|
195
|
+
inline `AgentSessionReady` event initializers were missing the
|
|
196
|
+
`fs_unsafe: bool` field added in the single-attach invariant work
|
|
197
|
+
(commit `84e91895`). Fixed inline so the workspace smoke test gate
|
|
198
|
+
passes. This is cross-stream cleanup — not part of the
|
|
199
|
+
WorktreeAuthority design but required for plan closure.
|
|
200
|
+
- **Architecture Risk #23 (semaphore indefinite wait).** Permit acquire is now
|
|
201
|
+
cancellable: `cancel_delegation` arriving while a task is queued for a
|
|
202
|
+
permit short-circuits immediately without acquiring. A heartbeat-based
|
|
203
|
+
watchdog (default-off) detects silent worker hangs and releases the held
|
|
204
|
+
permit after `worker_heartbeat_timeout_secs` (default 90s, configurable).
|
|
205
|
+
Watchdog is gated behind `worker_heartbeat_watchdog_enabled` (default
|
|
206
|
+
`false`) until a v1 `_spur/heartbeat` emitter lands; operators may opt
|
|
207
|
+
in early if their workers emit heartbeats. Watchdog firings map to
|
|
208
|
+
`DelegationStatus::Timeout`, preserving the `Timeout` (worker-hang)
|
|
209
|
+
vs `TimedOut` (review-gate) semantic split. Brain-initiated cancellations
|
|
210
|
+
continue to map to `DelegationStatus::Cancelled`. (bd-arch.23)
|
|
211
|
+
- **Architecture Risk #21.** The peer mailbox reconciler is now spawned
|
|
212
|
+
at orchestrator boot and aborted on shutdown via `Orchestrator::drop`.
|
|
213
|
+
Previously the receiver was dropped immediately after construction,
|
|
214
|
+
causing stranded messages to be silently lost — but the surrounding
|
|
215
|
+
wire-up was also missing in production, so the entire subsystem (62
|
|
216
|
+
tests, bd-cpf.1–7 hardening) was inert. (bd-arch.21)
|
|
217
|
+
|
|
218
|
+
## v1.1.8 — 2026-05-13
|
|
219
|
+
|
|
220
|
+
Spur 1.1.8 ships fresh defaults for the agents you actually run and makes two long-standing rough edges disappear: `/model` now feels instant on every agent, and long GitHub fetches stop looking like a hang.
|
|
221
|
+
|
|
222
|
+
- **Fresh out-of-the-box agent versions.** `spur init` now seeds new repos with `claude-agent-acp 0.33.1` (up from 0.26.0) and `codex-acp 0.14.0` (up from 0.11.1). New users get the latest ACP features and fixes on first run — no manual version-pinning, no stale prompts about deprecated flags. Existing `.spur/config.toml` files are preserved as-is; bump the pinned versions there when you're ready.
|
|
223
|
+
- **`/model` feels instant on every agent.** Some agents (including older Claude Code and Kimi builds) don't emit a `config_option_update` after a model switch, so the status bar used to keep showing the previous model until you reconnected. Spur now applies an optimistic override the moment you pick a model — the label flips immediately and reconciles with the agent's confirmation when it arrives.
|
|
224
|
+
- **GitHub ingest shows live progress.** `spur pm` ingesting a large GitHub repo's issues used to look frozen for minutes on the first run. The PM layer now surfaces per-page progress as fetches stream in, so you can see it working and estimate how much longer it'll take instead of wondering whether to kill it.
|
|
225
|
+
|
|
226
|
+
## v1.1.7 — 2026-05-13
|
|
227
|
+
|
|
228
|
+
Spur 1.1.7 makes everyday agent-switching and navigation feel right. Changing models works everywhere, the picker puts what you actually want at the top, and the code graph is there when you need it without any setup.
|
|
229
|
+
|
|
230
|
+
- **`/model` now works on every supported agent.** Switching models in Gemini CLI and Kimi CLI was broken before — both now behave like Codex, Claude Code, and OpenCode. Pick a model, get that model.
|
|
231
|
+
- **Status bar reflects the model you're actually on.** After a `/model` switch, the label updates live instead of showing the old name until you restart the session.
|
|
232
|
+
- **Smarter `@mention` picker.** Files no longer get buried under issues and workers. Results are grouped under clear section headers and ordered so the thing you're most likely reaching for is at the top.
|
|
233
|
+
- **Code graph just works.** Spur now auto-discovers the project's code graph at the worktree root — no environment variable to set, no "run `spur graph build`" hint when the graph is already there. Rebuilds are also faster and symbol names stay stable across runs, so jumping between files is more reliable.
|
|
234
|
+
|
|
235
|
+
## v0.4.5 — 2026-04-19
|
|
236
|
+
|
|
237
|
+
Spur 0.4.5 focuses on getting around faster and trusting what you see. A new universal palette (Ctrl+K) jumps you between sessions, workers, traces, and commands from anywhere. The `@mention` and `/slash` pickers now share one consistent interface. Agent output renders markdown and mermaid diagrams inline, and streaming stays smooth under bursty traffic.
|
|
238
|
+
|
|
239
|
+
### Added
|
|
240
|
+
- **Universal palette (Ctrl+K).** Fuzzy-search and jump to any session, worker, trace entry, or command from anywhere in the TUI. A `[Ctrl+K: go]` badge in the status bar reminds you it's there.
|
|
241
|
+
- **Unified completion for `@mention` and `/slash`.** Both now flow through the same picker — same keys, same preview, same ranking. One interface to learn.
|
|
242
|
+
- **Rerun recent prompts with Ctrl+R.** Session picker surfaces your recent prompts; pick one to rerun against the current session.
|
|
243
|
+
- **Auto-resume landing.** Launching spur drops you straight back on the last session you were working in.
|
|
244
|
+
- **Markdown and mermaid in agent output.** Rich content renders inline in the trace view — no more raw source for formatted replies or diagrams.
|
|
245
|
+
- **Dashboard view.** New top-level view for at-a-glance status across sessions and workers.
|
|
246
|
+
- **Skills installer across adapters.** `.spur/skills/` installs to Cursor, Codex, Kiro, Gemini, and OpenCode in one step, with edits you own preserved on upgrade.
|
|
247
|
+
- **Delegation visibility in the timeline.** Delegation plans now appear in the TUI timeline as they happen; `list_available_workers` returns richer descriptors (tier, cost, suitability hints).
|
|
248
|
+
|
|
249
|
+
### Improved
|
|
250
|
+
- **Smoother streaming.** A new scroll anchor and per-frame drain cap keep long, bursty outputs readable instead of jittery.
|
|
251
|
+
- **Faster palette and pickers.** Single-pass reranking and cached search patterns.
|
|
252
|
+
- **Session metadata persists across restarts.**
|
|
253
|
+
|
|
254
|
+
### Preview features (opt-in)
|
|
255
|
+
- **Brain delegation framework.** A new orchestration model for deciding which worker handles a task. Opt in via your config:
|
|
256
|
+
```toml
|
|
257
|
+
[brain.delegation]
|
|
258
|
+
framework = "v1"
|
|
259
|
+
```
|
|
260
|
+
Release builds default to `legacy` for 0.4.5; the v1 framework will become default once it stabilizes.
|
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# SPUR
|
|
2
|
+
|
|
3
|
+
**The control tower for your CLI coding agents.**
|
|
4
|
+
|
|
5
|
+
> Issue in, PR out — across every agent, in parallel, with one review surface.
|
|
6
|
+
|
|
7
|
+
SPUR is a Rust-native terminal layer that sits above the AI coding agents you already run — Claude Code, Codex, Gemini, Kimi, OpenCode, or any [ACP](https://github.com/anthropics/agent-client-protocol)-speaking agent. A "brain" reasons about your task and delegates to one or more "workers." Each worker runs in its own isolated git worktree. SPUR coordinates dispatch, human review, cherry-pick, retries, cross-vendor cost, and project-management state in one place.
|
|
8
|
+
|
|
9
|
+
> ⚠️ **Early stage** — APIs and config format may change.
|
|
10
|
+
|
|
11
|
+
## The Problem
|
|
12
|
+
|
|
13
|
+
Running 2+ AI coding agents today means living with four frustrations:
|
|
14
|
+
|
|
15
|
+
- **Rate-limit ambush.** Claude Code Max users blow through 5-hour windows in under 90 minutes. *"Paying $200 a month, I hit my weekly in 3 days last week"* (esperent, HN 47626833). When the lockout hits, the in-flight context is gone.
|
|
16
|
+
- **Cost opacity.** Tokens accrue across five vendors with no single ledger. *"I'm paying for Max, and when I use the tooling to calculate the spend returned by the API, I can see it's almost $1k!"* (buremba, HN 44598254). Devs only discover the gap by reverse-engineering their own bill.
|
|
17
|
+
- **Multi-agent chaos.** *"I run 5–10 Claude Code agents at a time across different repos. Keeping track of which one is waiting for input, which one is working, and which one broke something was chaos. I needed a control tower"* (Beefin, HN 47104424).
|
|
18
|
+
- **Worktree merge tax.** DIY tmux + worktrees is the workaround. *"I expected this to become less necessary over time as models got faster, but the opposite has happened"* (nojs, HN 47573483).
|
|
19
|
+
|
|
20
|
+
SPUR addresses all four: cross-vendor brain-swap when one vendor rate-limits you, a unified live cost ledger across every CLI you pay for, one review surface for parallel workers, and DAG-ordered cherry-pick of approved diffs onto a staging branch.
|
|
21
|
+
|
|
22
|
+
## How It Works
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
┌─────────────────────┐ ┌──────────────────────────────────┐ ┌─────────────────────┐
|
|
26
|
+
│ Project Management │ │ SPUR TUI │ │ Worker Agents │
|
|
27
|
+
│ │ │ │ │ │
|
|
28
|
+
│ beads (native) │◄───►│ ┌────────────────────────────┐ │ │ Claude Code │
|
|
29
|
+
│ GitHub Issues │ │ │ Brain Agent (orchestrator) │──┼────►│ Codex │
|
|
30
|
+
│ │ │ └────────────────────────────┘ │ │ Gemini │
|
|
31
|
+
│ │ │ ┌─────────┬────────┬─────────┐ │ │ Kimi │
|
|
32
|
+
│ │ │ │Dashboard│Insights│Plan View│ │ │ OpenCode │
|
|
33
|
+
│ │ │ └─────────┴────────┴─────────┘ │ │ Kiro (partial) │
|
|
34
|
+
└─────────────────────┘ └──────────────────────────────────┘ │ Generic ACP │
|
|
35
|
+
▲ └─────────────────────┘
|
|
36
|
+
│ ACP (JSON-RPC 2.0 / stdio)
|
|
37
|
+
▼
|
|
38
|
+
┌──────────────────────────────────┐
|
|
39
|
+
│ Git Worktrees per Worker │
|
|
40
|
+
│ DuckDB Analytics Engine │
|
|
41
|
+
│ Beads Plan Store + Reconciler │
|
|
42
|
+
│ MCP Server (delegation tools) │
|
|
43
|
+
└──────────────────────────────────┘
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Capabilities
|
|
47
|
+
|
|
48
|
+
*Ordered by uniqueness — what no single-vendor or cloud peer can match by design.*
|
|
49
|
+
|
|
50
|
+
- **Unified cost ledger across every vendor.** Five live extractors (Claude, Codex, Gemini, OpenCode, Kimi) feeding a DuckDB analytics engine that reads vendor JSONL/SQLite in place — no ETL. The Insights view (`Alt+a`) shows 7-day cost sparklines, per-session burn rate, and a `cost_source` provenance gauge. Devin, Cosine, Cursor, Aider, and Claude Code each only see their own bill; SPUR sees all of them in one number.
|
|
51
|
+
- **Brain-swap across vendors mid-flow.** Hit a Claude rate limit → keep working on Codex → come back to Claude when the window resets. Per-agent capability negotiation; `/model` and `/effort` synthesized from each agent's `InitializeResponse`. Impossible inside any single-vendor tool.
|
|
52
|
+
- **Session resume via event replay.** Close the laptop, restart SPUR, the brain picks up exactly where it left off. Not a soft-reconnect — a full replay from an event-sourced log.
|
|
53
|
+
- **Local-first durability.** Plans persist as beads epics in SQLite, events as NDJSON, outcomes as content-addressed git blobs. Survives crashes, OS updates, and network outages — resilience cloud-only competitors cannot match without offline sync.
|
|
54
|
+
- **Review loop with Reflexion retry.** Every worker completion produces a review card — Approve / Reject / Modify / Retry. Retries feed prior attempts back as context (max 3, auto-reject on exhaustion). A first-class state machine, not a UI convenience.
|
|
55
|
+
- **Parallel delegation, isolated.** `delegate_to_worker`, `delegate_parallel`, and DAG-ordered `submit_plan` dispatch workers concurrently. Each gets its own git worktree on `spur/worker/v2/{agent}/...`, protected by advisory `flock` liveness probes and an orphan-collector.
|
|
56
|
+
- **Cherry-pick in DAG order.** Approved subtask commits are cherry-picked in topological order onto a staging branch. Collapses the post-worktree merge tax that DIY tmux+worktree users hit every day.
|
|
57
|
+
- **Telegram bot on the same state machine.** `spur-bot` mirrors review cards and session streams into Telegram forum topics. Same review lane, same event bus, same approval semantics as the TUI — review on the train, not just at the desk.
|
|
58
|
+
- **Native ACP + MCP dual channel.** Structured JSON-RPC, not PTY scraping or prompt injection. Any ACP-speaking agent works out of the box.
|
|
59
|
+
- **Durable plan mutations.** `submit_plan_mutation` supports split / replace / amend in-flight; the reconciler ticks adaptively, validates ownership, and previews overlay conflicts.
|
|
60
|
+
- **Multi-brain safety.** Plans are locked to a single active brain via a `spur:plan-owner:<id>` label. Tier-1 mutating tools fail on session mismatch. `force_reclaim_plan` breaks deadlocks when a brain wedges.
|
|
61
|
+
- **Structured delegation reasoning.** Brains pass a `DelegationPlan` (candidates, rationale, decomposition) with every dispatch. SPUR verifies the chosen agent matches the actual payload — preventing the LLM from lying to its own reviewer.
|
|
62
|
+
- **Stable-identity code graph.** Tree-sitter parses Rust / Python / TS / TSX / Markdown into a graph with SHA256 stable symbol IDs and incremental per-file rebuilds. Auto-discovered at the worktree root — no env var setup.
|
|
63
|
+
- **Built for orchestration, not chat.** Dashboard with lineage tree, full-screen ReAct trace with inline markdown + mermaid, grouped `@mention` picker (Workers / Files / Issues / Code Graph), `Ctrl+K` universal palette, Plan Inspector (`Alt+P`), live status bar (running count, pending reviews, total cost, model labels).
|
|
64
|
+
|
|
65
|
+
## What SPUR is NOT
|
|
66
|
+
|
|
67
|
+
SPUR is built to sit *above* the agents and tools you already use. We don't try to replace them — and several excellent products own jobs SPUR explicitly does not compete on:
|
|
68
|
+
|
|
69
|
+
- **Not a Devin replacement.** Devin owns "autonomous engineer I can assign tickets to in Slack." SPUR keeps the human in the loop on purpose — review is a state machine, not a slogan. If you want a fully autonomous agent, hire Devin.
|
|
70
|
+
- **Not a Cursor competitor.** Cursor owns the AI IDE. SPUR sits *next to* your editor, not inside it. Most SPUR users keep Cursor open in another window.
|
|
71
|
+
- **Not an Aider replacement.** Aider owns the simplest free BYO-key single-agent CLI. SPUR's value materializes at fleet size ≥ 2 — "add SPUR above Aider," not "switch from Aider." Aider-as-a-SPUR-worker is on the roadmap.
|
|
72
|
+
- **Not a Claude Code replacement.** SPUR uses Claude Code as a worker. We don't try to beat the in-session UX; we add what Claude Code doesn't attempt — cross-session durability, cross-vendor failover, and a cost ledger that spans every CLI.
|
|
73
|
+
- **Not autonomous.** Review gate is required by design. If you want a "set and forget" system, this is the wrong tool.
|
|
74
|
+
|
|
75
|
+
And on the boring scope side:
|
|
76
|
+
|
|
77
|
+
- Not a chat UI. Every interaction is task-structured.
|
|
78
|
+
- Not an IDE. No editor, no LSP, no inline diff gutter.
|
|
79
|
+
- Not CI/CD. Plans run locally with local worktrees, not on remote runners.
|
|
80
|
+
- Not a universal PM sync. Only beads (native) and GitHub (via `gh`) are implemented today.
|
|
81
|
+
|
|
82
|
+
## Crate Structure
|
|
83
|
+
|
|
84
|
+
| Crate | Purpose |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `spur-cli` | Binary entry point and CLI commands |
|
|
87
|
+
| `spur-tui` | `ratatui` terminal interface — views, components, input handling |
|
|
88
|
+
| `spur-core` | Orchestration engine, review loop, lineage, event pipeline |
|
|
89
|
+
| `spur-acp` | ACP client, transports (stdio / native / cli-wrap), capability negotiation |
|
|
90
|
+
| `spur-mcp` | MCP server exposing delegation tools to the brain (delegate, plan, signals) |
|
|
91
|
+
| `spur-context` | DuckDB analytics engine + per-agent log extractors |
|
|
92
|
+
| `spur-cost` | Pricing registry + SQLite session ledger |
|
|
93
|
+
| `spur-graph` | Tree-sitter code graph, stable IDs, incremental rebuild |
|
|
94
|
+
| `spur-pm` | Project management adapters (beads, GitHub) |
|
|
95
|
+
| `spur-worktree` | Git worktree creation, isolation, flock liveness, cleanup |
|
|
96
|
+
| `spur-interactive` | Frontend bridge for non-TUI clients |
|
|
97
|
+
| `spur-bot` | Telegram bot frontend |
|
|
98
|
+
| `spur-blob-store` | Content-addressed delegation outcome artifacts |
|
|
99
|
+
| `spur-license` / `spur-license-admin` | Tier / feature-key registry |
|
|
100
|
+
|
|
101
|
+
## Quickstart
|
|
102
|
+
|
|
103
|
+
### Install
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
curl -sSL https://getspur.dev/install.sh | sh
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Installs the signed `spur` binary. Free Community tier — no key required. Pro / Team / Enterprise unlock via a signed license file from your account dashboard.
|
|
110
|
+
|
|
111
|
+
> Note: install domain is provisional; final URL will be confirmed at launch.
|
|
112
|
+
|
|
113
|
+
### Initialize a project
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
cd your-project
|
|
117
|
+
spur init
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Creates a `.spur/config.toml` with detected agents and sensible defaults.
|
|
121
|
+
|
|
122
|
+
### Run
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
spur
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The TUI launches with your configured brain and worker agents. Type a task or pick an issue from your PM integration.
|
|
129
|
+
|
|
130
|
+
### Check config
|
|
131
|
+
|
|
132
|
+
```sh
|
|
133
|
+
spur config check
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Validates your configuration and reports warnings.
|
|
137
|
+
|
|
138
|
+
## Configuration
|
|
139
|
+
|
|
140
|
+
SPUR is configured via `.spur/config.toml` at your project root:
|
|
141
|
+
|
|
142
|
+
```toml
|
|
143
|
+
[brain]
|
|
144
|
+
agent = "claude-code-acp"
|
|
145
|
+
|
|
146
|
+
[agents.entries.claude-code-acp]
|
|
147
|
+
role = "brain"
|
|
148
|
+
transport = "native"
|
|
149
|
+
|
|
150
|
+
[agents.entries.codex]
|
|
151
|
+
role = "worker"
|
|
152
|
+
transport = "stdio"
|
|
153
|
+
good_for = ["rust", "tests"]
|
|
154
|
+
tier = 1
|
|
155
|
+
|
|
156
|
+
[agents.entries.kimi]
|
|
157
|
+
role = "worker"
|
|
158
|
+
transport = "stdio"
|
|
159
|
+
good_for = ["long-context-exploration", "research"]
|
|
160
|
+
|
|
161
|
+
[pm.github]
|
|
162
|
+
repo = "owner/repo"
|
|
163
|
+
|
|
164
|
+
[worktree]
|
|
165
|
+
enabled = true
|
|
166
|
+
|
|
167
|
+
[cost]
|
|
168
|
+
db_path = "~/.spur/cost.db"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Each agent entry supports delegation descriptors (`good_for`, `avoid_for`, `tier`, `cost_tier`) used by the brain for routing. Run `spur config check` to lint your configuration.
|
|
172
|
+
|
|
173
|
+
## Telemetry and Privacy
|
|
174
|
+
|
|
175
|
+
SPUR ships anonymous-identifier-based telemetry: Tier 1 crash diagnostics and performance are default ON, Tier 2 usage is default OFF (opt-in).
|
|
176
|
+
Disable all telemetry in one line: `SPUR_TELEMETRY=0 spur`.
|
|
177
|
+
For persistent disable, run `spur telemetry disable all`.
|
|
178
|
+
Collected fields, retention (90 days), deletion-by-ID steps, and pseudonymity details: [docs/PRIVACY.md](docs/PRIVACY.md).
|
|
179
|
+
|
|
180
|
+
## A Day in the Life
|
|
181
|
+
|
|
182
|
+
**Parallel refactor.** "Refactor error handling across the codebase." Brain submits a 5-task plan → 5 worktrees, 5 workers run in parallel → review cards appear → approve 4, reject 1 with feedback → rejected worker retries with your note → approved branches cherry-picked to staging. Status bar: total cost $2.40.
|
|
183
|
+
|
|
184
|
+
**Cost burn check.** Hit `Alt+a` for Insights. Live tab shows 3 active sessions — Codex is on the wrong model. Switch to that session, type `/model gpt-4o`, status bar updates instantly. Breakdown tab shows yesterday $18 (60% Claude, 40% Codex).
|
|
185
|
+
|
|
186
|
+
**Stuck plan recovery.** Overnight 12-task plan; one task stuck in `Dispatched` (worker died). `Alt+P` Plan Inspector → `force_reclaim_plan` promotes it to `AwaitingReview` → inspect partial diff → reject and split via `submit_plan_mutation` → plan resumes, 11 completed tasks intact.
|
|
187
|
+
|
|
188
|
+
## Development
|
|
189
|
+
|
|
190
|
+
```sh
|
|
191
|
+
# Build all crates
|
|
192
|
+
cargo build --workspace
|
|
193
|
+
|
|
194
|
+
# Run the full test suite
|
|
195
|
+
cargo test --workspace
|
|
196
|
+
|
|
197
|
+
# Run tests for a single crate
|
|
198
|
+
cargo test -p spur-tui
|
|
199
|
+
|
|
200
|
+
# Lint
|
|
201
|
+
cargo clippy --workspace -- -D warnings
|
|
202
|
+
|
|
203
|
+
# Format
|
|
204
|
+
cargo fmt --all
|
|
205
|
+
|
|
206
|
+
# Run locally
|
|
207
|
+
cargo run -p spur-cli -- --help
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Commit format
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
<type>(<scope>): <short imperative>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Types: `feat`, `fix`, `test`, `docs`, `refactor`, `chore`. Keep subjects under 72 characters.
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
SPUR is a proprietary product. The free Community tier is available without a license key under the terms of the EULA at [https://getspur.dev/eula](https://getspur.dev/eula). Pro / Team / Enterprise tiers require a signed license file. See [LICENSE](LICENSE) for terms.
|
|
221
|
+
|
|
222
|
+
> The source in this repository is not open source. Issues, feedback, and feature requests are welcome via [https://getspur.dev/feedback](https://getspur.dev/feedback) or your team's support channel.
|