v0.17.0
·
222 commits
to develop
since this release
[0.17.0] - 2026-08-04
Added
squadrant handoff factsreplaces the old handoff authoring layer, which fabricated state instead of reporting it (#650, #651). The previous command copied fields straight from in-process state (currentState = s.completed), which produced emptyblockedItemswhenever the live picture didn't map cleanly onto that shape, and let a captain misreport "188 commits ahead" sourced from a stale local ref nobody had fetched. The new command makes no synthesis decisions — it gathers facts and groups them by provenance (liveRepo,claudeMem,checkpoint,gapSessions) so a reader can see which claims come from the live repo versus a stale archive versus a gap in session history, and judgment about what those facts mean is left to the captain reading them, not baked into the tool.handoff.jsonis now archived on read instead of deleted, so a broken reconstruction can be diagnosed after the fact instead of vanishing with the read. Branch-state verification (branchState) adds fetch-gated truth:upstreamStatus,dirtyWorkingTree,onUnexpectedBranch, andmergedIntoBaseflags, with network access opt-in via--fetchrather than silently hitting the remote on every read. Alongside this, the captain session registry (#651) writes one line per session start to{spokeVault}/captain-sessions.jsonlfrom theSessionStarthook, so transcript attribution has an authoritative record instead of guessing which transcript file belongs to the current captain by file mtime.squadrant tokens— attribute token spend from Claude transcripts (#626). Streams~/.claude/projects/<slug>/*.jsonlline-by-line (never slurps a whole file — transcripts here run up to 5.7MB) to report, per project and in total: captain vs crew, boot prefix vs accumulated conversation (boot = turn-1 total, confirmed via turn-2cache_read), and the four token classes separately (input/output/cache_read/cache_write) — no collapsed total, no baked-in dollar rates. Claude-only today; no speculative multi-reader interface added ahead of a second driver writing an equivalent transcript. A same-day follow-up made the command disclose its rolling ~30-day data window: Claude Code's own transcript retention (cleanupPeriodDays, default 30 days) prunes older sessions, so a shrinking file count read like a drop in spend rather than what it actually was — retention. The reader now tracks and prints the actual[earliest, latest]timestamp range each session covers, everywhere a count is reported.- Persisted work-item primitive —
squadrant work(#630 step B). Per-project JSON store under~/.config/squadrant/work(atomic write+rename, path-traversal guard, 30-day TTL GC on done/cancelled items, no daemon dependency) with a minimal CLI:start/list/done/cancel,--parentfor hierarchical waves, andwork list --tree. A same-day follow-up fixed the default view: hiding all terminal (done/cancelled) items orphaned any still-open child of a done parent, rendering it as a parentless root with no sign it belonged to a wave — the exact "wave finished out of order, what's left?" scenario--parentexists to surface. The default view now keeps a done/cancelled parent visible (dimmed) whenever any descendant is still open, andwork done <id>now warns (non-refusing) when it still has open children. Step A of the same effort removed the deadwrite-status.shinstructions and stopped readingstatus.mdfor task counts — nothing writes that file anymore, sostatus/standup/retrowere silently rendering stale or zero data; they now say plainly they have no task-count data source.
Fixed
- A crew's shared production daemon could be bounced by any one of the 26 registered projects' crew processes, exposing every in-flight task across all of them to the restart window (#636).
ensureDaemon()'s implicit self-heal ran on every CLI invocation, including crew-spawned ones — which inherit a different PATH/build (worktree-resolved node/pnpm) than the captain, making their plist-drift check unreliable. Fixed in three passes, converging on fail-closed: the daemon's mutating path (plist write, bootout, bootstrap, kickstart) now requires a positively-identified captain invocation (SQUADRANT_ROLE=captain, set at exactly one choke point —launchOneWorkspace) rather than merely the absence of a crew marker, which failed open for codex crews that never receive that marker at all (same failure shape as #499 — marker-absence treated as a positive signal). A small explicit allowlist (isOperatorInitiatedCommand,{launch, init}) covers the two remaining legitimate self-heal cases the captain-only gate would otherwise miss: a fresh install (before any captain marker exists) and a captain launched before this code shipped, whose already-running process can't retroactively gain the env marker until relaunched.squadrant heal daemonis unaffected — it already calls the explicit reconcile path directly, for any role. gitnexus_impactwas mandated in CLAUDE.md as an absolute pre-edit safety gate despite returning confirmed false negatives — a crew followed the mandate exactly and broke 6 daemon-core files (#642 item 1). The tool reports 0 callers / LOW risk for symbols that do have real callers. CLAUDE.md's Always Do / Never Do wording is softened so a LOW/0 result now reads as "no information" (cross-check with grep + typecheck) rather than authoritative assurance; HIGH/CRITICAL results are unaffected and remain meaningful. Advisory pending a full replacement decision.- Crew boot prefix (61.2k tokens, measured via the new
squadrant tokens) was heavier than the captain's own boot (54.5k) and paid on every spawn with little amortization (#625). CrewCLAUDE.mdtemplates only ever referencesquadrant:karpathy-principles— the other 15 squadrant skills (captain-ops, telegram, wiki-ops, etc.) are captain/command-only, but crews were served the full plugin directory's skill listing anyway. A new "subset" plugin-dir mode mirrors~/.config/squadrant/plugin-crewas a strict allowlist (currently justkarpathy-principles) and points the claude driver's--plugin-dirat it for rolecrewonly; captain, command, and side roles are unaffected. Measured 33,436 → 32,079 first-turn tokens (a 1,357-token cut) in a controlled headless comparison.