Releases: tu11aa/squadrant
Releases · tu11aa/squadrant
Release list
v0.19.5
[0.19.5] - 2026-09-05
Fixed
claude.tsemitted--messaging-socket-pathbefore--plugin-diron the crew launch command, truncating cmux's stored argv and breaking role classification/restore (#759). cmux <=0.64.18 truncateslaunchCommand.argumentsat--messaging-socket-pathwhen storing it inclaude-hook-sessions.json, so anything appended after it — including--plugin-dir— was dropped from the stored command; the flag actually reached the live Claude process fine, but the truncated stored argv is what cmux's role classification/session-restore reads. The flag is now appended at the end of the command, matching the ordering the launch-cmd path (#697) already used.
Added
- PermissionRequest registered as a hook source + Notification reclassified by
notification_type(#760).PermissionRequestfires ~6s before the matchingNotificationand carriestool_name/tool_inputdirectly — a richer, earliertask.blockedsource than sniffingNotification.message. Added to the managed hook set (#615) and the crew's own per-session hook set, via a newformatPermissionRequestQuestionhelper that never dumps fulltool_input(only a short, truncated file-path/command hint).Notificationis now classified by the structurednotification_typefield (a 14-value enum on current Claude clients) instead of English substring matching; the old substring test is kept only as a fallback for clients that omit the field. - Stop hook's
prompt_idthreaded through as the real per-turnturnId(#761).Stop/PermissionRequest/Notificationpayloads all carryprompt_id, a UUID that matches across events of the same turn (verified live, claude 2.1.260).mapClaudeHookToEventnow uses it asturnIdinstead of the constant"hook-stop", falling back to the constant when absent (older clients). - Stop now vetoes turn-completion on active
background_tasks/session_crons(#762). These are a structural, agent-reported veto on turn-completion, stronger than the #492pendingToolveto because they also cover Claude's own background tasks and session crons, whichpendingToolcannot see. When either is non-empty,Stopmaps totask.progressinstead oftask.turn.completed; the existing trailing-question detection still takes priority. - New
StopFailurehook source for API-error turn deaths (#763). Previously a crew turn that died on an API error (529/overload/etc) was invisible until the watchdog reported a plain stall — the wrong story.StopFailureis now registered in the managed hook set (#615) and the crew's own per-session hook set, mapped to a newControlEventvarianttask.turn.failedcarrying the resolvedturnIdand a redacted error string.task.turn.failedis deliberately nottask.failed(anti-#2576: no hook may terminalize a task).
Together, #760–#763 add two new entries to the squadrant-owned hook set installed into ~/.claude/settings.json (PermissionRequest, StopFailure); Notification and Stop were already registered, only their in-code classification changed. Both new entries are written on the next daemon boot via installClaudeHooks, not on npm install.
v0.19.4
[0.19.4] - 2026-09-04
Fixed
- False "First turn not delivered" warning + duplicate first-turn paste on cold Claude Code boot (#745).
pollFirstTurnConfirmedAt's fixed 100s window was anchored at spawn start, but the hook can only stamp confirmation after the scrape submits — and the scrape itself gets up to ~106s of readiness/submit retries, so the poll could time out ~9s before a delivery that had, in fact, landed. The poll now runs through the scrape's unsettled window plus a 15s post-settle grace (180s absolute cap) and cancels once a verdict is reached. Separately, the "paste never rendered → re-paste once" rule fired onsawDraft=falseeven when a cold-boot paste had already been submitted before the draft was observed, submitting the whole turn twice; the re-paste (and itsconfirmedSendToPanefallback) is now gated on the pane still being frozen at the pre-send image. heal daemonfalse-FAIL on the plist-drift race, and a same-version-bump misclassified as a hijack (#751, #752).forceKickstartAndVerifycaptured its "before" pid afterreconcilePlistAndService's bootout+bootstrap had already started the new instance, so akickstart -kracing that fresh process could never observe a pid change and reported FAILED on an already-healthy daemon;reregisterDaemonnow snapshots the pid before reconcile runs. Separately, the #670 foreign-install guard compared full paths, so a routine same-manager version bump (e.g. pnpm's.pnpm/squadrant@0.19.2/→.pnpm/squadrant@0.19.3/) was misread as a hijack and printed the refusal banner on every CLI call; same-manager/different-version is now classified as an upgrade and reconciled with a one-line notice, while a genuine different-manager hijack still refuses. Read-only crew subcommands (list/read/tasks) now skipensureDaemonentirely.- Gap-session handoff facts lost everything but the last exchange (#753).
extractTranscriptTailkept only the final user/assistant message per gap-session transcript, so an incidental last message (e.g. a daemon notice) could erase all record of what the session actually did. It now walks the full tail and builds a per-transcript digest — ordered user prompts, assistant final text per turn, tool-call counts, files touched, and PR/issue/commit references — capped at ~8KB, oldest entries truncated first. - Boot-gap "daemon was down" alert read as a live outage when delivered late (#744). The alert text carried only a bare minute count, so a copy stuck in an unreachable captain's mailbox for hours read as a current outage once finally delivered.
formatDownAlertTextnow bakes the actual outage window (local time + tz offset) into the message, and the delivery loop prefixes a[stale — generated N ago]tag when a daemon-sourced message is delivered more than 1h after it was generated.
v0.19.3
[0.19.3] - 2026-09-03
Fixed
- Socket directory created world-readable, blocking captain/crew launch on Claude Code ≥2.1.259 (#749).
ensureSocksDir()now creates/tmp/cc-sockswith mode0700; Claude Code 2.1.259 refuses to operate against a755socket directory.
v0.19.2
[0.19.2] - 2026-08-31
Added
- Event architecture Phase 0-1: fact pipeline + opencode cutover (#739, #740, #743). Introduces
@squadrant/core's own event-tracking module — anAgentFactvocabulary, per-agentFactAdapterseam, aLifecycleSourcefacade wiring adapters to the pipeline, a flight-recorder ring buffer for post-hoc debugging, and a pure fact-to-ControlEventmapping layer with an adapter conformance test suite. Ships invariant checks I1–I3 (depth-based tool-call pairing) and I4–I6 (trust, unknown-rate, and liveness-disagreement).opencodeis moved onto the fact pipeline via aFactAdapterreading SSE frames directly, retiring the oldOpencodeControlSource;claudestays on its existing path (shadow only) per the approved design. A generatedControlEventproducer/consumer table plus a--checkgate now catches producer/consumer drift at build time.
Fixed
- False "First turn not delivered" warning + duplicate first-turn re-send (#745).
crew spawn's own screen-scrape confirmation could time out even when the first turn genuinely landed, because the crew'sUserPromptSubmithook confirms delivery to the daemon independently of — and can outrace — that scrape. Hook confirmation is now raced against the scrape for the scrape's own full timeout window and treated as primary, not a post-failure fallback: a scrape failure alone no longer concludes non-delivery when the hook already confirmed. As defense in depth,crew sendnow refuses to re-send the exact original task text once delivery is confirmed, closing the double-run scenario where following the (previously false) warning's guidance re-ran the task a second time. - Heal daemon false-FAIL on the plist-drift race (#741, #742).
squadrant heal daemoncould report a failed restart even when the daemon had actually come back up cleanly, racing its own plist-drift detection against the just-completed restart. Fixed at the source of the race rather than papering over it with a retry. - Opencode fact-pipeline perf regression and event-index cache-miss fallback (#743). A per-frame performance regression in the new opencode adapter (introduced during Phase 0-1 development) is fixed before shipping; chatty opencode frames are filtered,
resolve()is TTL-cached, and dead snapshot state is removed. TheeventsTaskIndexnow falls back to a live store lookup on a cache miss instead of losing the event.
Notes
- Phase 2 (per-crew
FactLogcleanup,claudeshadow-mode cutover, lifecycle refinement) is deliberately deferred — not part of this release. - First opencode crew after upgrade should be watched for event-pipeline health (I5 invariant floods, subagent-orchestrating crews' known ~2 CREW IDLE per task).
v0.19.1
[0.19.1] - 2026-08-28
Added
- Per-role thinking level →
--effort. Roles could already pin a model (defaults.roles.<role>.model); they can now also pin a thinking level via a newthinkingfield, emitted as claude's--effort <level>flag (plussquadrant launch --thinking/crew spawn --thinkingCLI overrides). Deliberately distinct from the existingdefaults.efforttokenomics dial (squadrant effort) — same word, different concept, kept apart on purpose. Claude-only; codex/opencode/gemini reject the flag. - Crew answer (#592).
squadrant crew answer <project> <name> <option>deliberately answers a crew's openAskUserQuestion/permission modal — reads the rendered option list, requires an explicit index/text match (never an implicit default), and drives the selection via Down/Up + Enter.crew replynow delivers through the same path ascrew sendbefore transitioning task state, instead of silently dropping the message body on a no-op "success".
Fixed
- False CREW STALLED from a stale pendingTool (#542). Root cause: the daemon's cmux events-bridge had no case for
agent.hook.PostToolUse, so pendingTool never closed for a crew whose tool call had genuinely finished. The #492 stall veto then vetoed every real turn-completion forever, and the watchdog eventually fired a false CREW STALLED against an idle crew. Fixed at the transition — events-bridge now closes the window on PostToolUse, the state machine recognizes the cmux bridge's own PostToolUse spelling, and the watchdog gained a defense-in-depth check that recovers toawaiting-inputinstead of stalling when idle evidence already exists. - Pane-error false terminalization (#704). The interactive-probe's error detector matched its error vocabulary against any pane line — including content a crew merely displayed or quoted — and unconditionally terminalized the crew. It now skips visibly quoted/prefixed lines (box borders, blockquotes,
cat -nechoes) and cross-checks the crew's surface-liveness probe before terminalizing; an "alive"/"unknown" verdict downgrades to a new non-terminaltask.warnControlEvent, surfaced to the captain pane as "CREW WARN" instead of being silently dropped. - Heal daemon restart verification (#729).
squadrant heal daemonpreviously deferred to a cautious plainkickstart(no-k), a documented no-op on an already-healthy daemon, so a plist-matching heal run could report "restart complete" without touching the running process. It now forceskickstart -k, polls the pid until it actually changes, and retries thekickstart -kcall itself (default 5×300ms) to avoid racing a preceding bootout's still-unloading exit handler. - Unclean daemon death detection and delivery jam isolation (#589, #590). Persists a JSON exit marker on every shutdown path (including crash handlers) plus a running heartbeat marker touched every ~60s; a running marker that survives to the next boot with no exit marker to explain it is now logged and alerted as an UNCLEAN death (SIGKILL/OOM/power-loss), instead of reading identically to a first boot. The delivery loop also wraps each project's per-tick pass in its own try/catch so one project's exception can't starve delivery for every project after it, and backs off exponentially (capped at 60s) once a project crosses its max-defer threshold instead of polling forever.
- Task records no longer terminalize while the crew surface is alive (#595).
reapOrphanedCrews, the wall-clock task-timeout sweep, andstore.put()could all previously terminalize or silently overwrite a task record without checking the crew's own pane was actually gone. All three are now gated on the surface-liveness probe (alive/unknown fail safe),awaiting-inputis added to the existing #629 blocked/review ceiling exemption, andcrew send's reopen is now reported back to the caller instead of being invisible. - Oversized first-turn text corruption (#730). A multi-KB first-turn paste into a claude crew's pane could look "settled" before fully landing, letting Enter submit a truncated draft. First-turn text above 1200 bytes is now spilled to a temp file with a short "cat it and follow it exactly" pointer instead of being pasted verbatim; the daemon dispatch still receives the full task text.
- Captain memory write gate (#556). Crews previously had unrestricted write access to their captain's long-term memory directory, which is loaded into every future session. The existing unmatched PreToolUse hook now denies a matching Write/Edit/MultiEdit/NotebookEdit, or a Bash command whose text references a memory path, when issued inside a crew session — with an exact deny reason logged to stderr. Crews report, captains decide what is durable.
- Named peer identity for daemon-sent messages (#711).
squadrantd's receipt socket now registers a~/.claude/sessions/<pid>.jsonentry keyed to the socket it bound, so CREW DONE/BLOCKED/IDLE/TAKEOVER messages render as a named peer instead of the anonymous "Another Claude session" framing. Registrykindcorrected to"daemon"(verified against the Claude Code 2.1.241 binary'sinteractive|bg|daemon|daemon-workerallowlist), and stale entries are cleaned up on both pid reuse and process exit. - Delivery probe failures no longer read as "no-box" (#713, #714). A failed cmux
read-screeninvocation was previously conflated with a genuinely unconfirmed input box. It is now classified as a distinctprobe-faileddefer reason with its own DELIVERY STUCK wording, and the delivery loop re-resolves the captain surface once per attempt on a probe-failed defer (no-box/modal/draft never re-resolve, since the surface is known alive). - Heal status delivery-queue visibility (#715).
heal statusnow surfaces delivery-queue health via a structuralstuckboolean onComponentHealth/HealComponent(no string parsing) — only a genuinely stuck queue fails heal status; a merely deferring queue is advisory. - Liveness-tick captain log spam (#732).
runLivenessTicklogged a captain's derived state on every ~6s tick regardless of change, burying real events for stopped-but-still-listed projects. It now logs only on an actual state transition (or first observation).
Changed
- Docs. Added the AFK auto-continue safe-option-only clause to captain/crew templates (#616); made the #711 kind-allowlist evidence reproducible in-comment; dropped the stale "unreadable screen" phrasing from the no-box doc (#714); corrected opencode channel state, the captain socket path, and shadow-rollout wording across the agent-control-channel and architecture diagrams (#667).
v0.19.0
[0.19.0] - 2026-08-23
Added
- Agent Control Channel & Captain Channel (#667). Replaces screen-scraped liveness and pane-typing delivery inference with native agent control channels and socket messaging.
- Implemented the
ControlChannelport with a five-branchDeliveryOutcome(delivered,held,denied,unreachable,accepted), plus nativeLifecycleSourceimplementations (ClaudePeerRegistrySource,OpencodeControlSource). - Added rollout configuration flags:
defaults.controlChannelfor crew delivery anddefaults.captainChannelfor captain delivery (off/shadow/on). - Claude Peer Channel (Slice 3): Routes crew messaging over Claude's native
--messaging-socket-pathwith NDJSON framing, T1-confirms-T0 delivery receipts, a background receipt listener for held/denied/delivered observability, and recordsaccepted-unconfirmedstatus. - Captain Channel (Slice 4): Routes captain-bound delivery through the peer control socket (
captainChannel), bypassing pane-defer machinery (ghosts, modals,no-box). Added Telegram delivery receipts for held and unreachable captain deliveries, andsquadrant pingnow reports honest delivery outcomes.
- Implemented the
- CLI Agent & Model Runtime Overrides (#627). Added
--agent <name>and--model <name>flags tosquadrant launch <project>so operators can override configured captain agent and model defaults at runtime. - Claude Instruction File Projection Target (#705). Brought
CLAUDE.mdinto the cross-agent projection system (packages/shared/src/agents/projection.ts), unifying instruction emission alongside Codex, Gemini, and opencode to eliminate instruction-file drift across formats. - Captain Session Self-Description & Identity Wiring (#708, #709).
- Passed Claude's
-n, --nameflag during launch and crew spawn so captains (squadrant-captain-<project>) and crews (squadrant-crew-<project>-<name>) are self-describing in session registries. - Resolved captain
sessionIdfrom launch-time socket paths and wired it into captain-bound messages, restoring pid-reuse protection.
- Passed Claude's
- Local Dev Daemon Opt-In (#694). Added the
SQUADRANT_DEV_DAEMONenvironment variable allowing developers to run a local daemon from a repo checkout while maintaining strict refusal for linked worktrees.
Fixed
- Captain channel init retry loop (#712). Fixed an issue where transient socket bind errors (
EACCES) at daemon boot permanently latched the daemon into pane-only fallback mode for its entire lifetime. It now retries initialization with capped exponential backoff, unrefs the timer, and catches retry errors cleanly. - Captain socket collisions during batch launches (#706). Fixed
launch.tsusing an undefined command-level positional argument instead of the target project name, which caused batch (--all) and parallel launches to collide on/tmp/cc-socks/squadrant-captain-undefined.sock. - Receipt listener daemon crash on boot and CLI hang (#695, #696).
- Handled UDS error events during listener startup, scoped receipt sockets by PID (
squadrantd-<pid>.sock), and cleaned up stale socket files before binding to prevent crash-loops. - Unref'd the receipt server and cleaned up socket files on exit so short-lived CLI commands (like
squadrant ping) do not hang.
- Handled UDS error events during listener startup, scoped receipt sockets by PID (
- Captain and crew resolution on symlinked paths (#689, #696). Switched registry lookups from working directory paths (which broke on macOS symlinks like
/tmpvs/private/tmp) to launch-timemessagingSocketPath, preventing falsegoneoraccepted-unconfirmeddelivery verdicts. - Captain re-adoption with truncated cmux argv (#699). Fall back to reading live arguments from the OS process table (
ps) when cmux truncates stored argv at--messaging-socket-path, and addedsquadrant heal captain [project] --allto reconcile degraded registry entries. - Fast-turn confirmation race (#691). Used
statusUpdatedAttimestamps to reliably confirm turns on fast-responding agents. - Control channel exception safety in crew send (#686). Guarded control-channel exceptions in
runCrewSend(both shadow and on modes) to ensure errors log cleanly and fall back safely to pane delivery without breaking the turn loop. - Claude captain visibility in liveness registry (#697). Gated launch
--messaging-socket-pathinjection strictly oncaptainChannel !== 'off'and positioned it last in the command arguments to prevent cmux store truncation from breaking role classification.
Security
- Refuse silent Anthropic fallback (#627). When an alternative agent (opencode/codex/gemini) is launched with no explicit model and defaults to an Anthropic model via global configuration,
squadrant launchnow refuses to boot rather than silently falling back to Anthropic. - Hardened daemon worktree guard (#682). Strengthened the daemon's refusal to bind production sockets from inside linked worktrees against caller context bypasses.
- Daemon socket process isolation (#687). Derived the daemon socket path from
SQUADRANT_CONFIG, enabling complete process isolation across test and dev environments.
Removed
- Complete removal of GitNexus integration (#703). Removed all remaining references, skills, and configuration for GitNexus across the codebase, architecture documentation, and agent instruction files following its deprecation.
v0.18.1
[0.18.1] - 2026-08-13
Security
- Restricted permissions on configuration files and directories (#668). Previously,
config.json(which holds sensitive data liketelegram.botToken) was world-readable (0644). Config files are now tightened to0600, the config and project directories to0700, and the daemon socket to0600after binding. A one-shot migration automatically secures existing paths on update. Additionally,DEFAULT_CONFIG_PATHandCONFIG_DIRnow honor theSQUADRANT_CONFIGenvironment variable.
Fixed
- Daemon crash-loop due to duplicate global installs (#670). Fixed an issue where having Squadrant installed globally multiple times (e.g., via
npmandpnpmsimultaneously) hijacked thelaunchdplist and caused a daemon crash-loop.- The update banner now prints the upgrade command for the install's specific package manager.
ensureDaemonnow refuses to seize a plist owned by a different, still-installed Squadrant binary.squadrant doctorwarns operators of multiple installations.squadrantdrefuses to bind the production socket from a monorepo or worktree checkout.
- False 'healthy' status when daemon is offline (#671).
squadrant heal statuspreviously reported all components as healthy if the daemon was completely offline, treating an empty component list as vacuously healthy. It now proactively probes daemon liveness via a real socket connection before trusting component data.
v0.18.0
[0.18.0] - 2026-08-07
Breaking
squadrant crew closerefuses dirty worktrees. Previously, closing a crew would silently destroy its worktree even if it contained uncommitted files. It now REFUSES to close and requires an explicit--forceflag. Anyone automating crew close will see a new failure if dirty files exist. (#649)
Added
- Operator Takeover Protocol (#649). When the operator works directly inside a crew's tab, they can now record that fact so the captain knows to keep hands off. The crew keeps running normally; what changes is that the captain will not send to it, close it, or act on its lifecycle signals until handback.
- Added CLI commands
squadrant crew takeoverandsquadrant crew handback. - Added in-terminal slash commands
/takeoverand/handback. - Task records now track
operatorHoldstatus. - Operator-held status surfaces in
list,tasks, andhandoff facts. - The watchdog nudges operators on long-running takeovers.
- The daemon suppresses captain pushes and refuses
send/closeoperations on held crews.
- Added CLI commands
Changed
- Crew worktrees base on the captain's branch (#661). Crew worktrees are now based on the captain's currently checked-out branch instead of the GitHub default branch, ensuring they branch off the correct contextual state.
Fixed
- Sweep ceiling measures current working stretch (#664). The sweep ceiling now measures the current working stretch instead of the overall task age. Task records now track the start time of the current stretch on
task.startedandtask.reopened.
v0.17.1
[0.17.1] - 2026-08-05
Fixed
- Read fetchAgeMs post-fetch to resolve false staleness (#654). 'squadrant handoff facts --fetch' reported fetchAgeMs measured BEFORE the fetch, so a just-fetched repo could still trip the 24h stale warning. Age is now read after the fetch; test pins an exact post-fetch age.
- Human review gate embedded in templates and made signal-agnostic (#656). It now covers CREW REVIEW, CREW DONE and CREW IDLE. Previously only REVIEW was gated, so a crew signalling done or going idle could get its work merged without operator sign-off. Contradicting 'merge if appropriate' wording removed.
Changed
- Captain startup rules moved to templates (#653). Captain startup rules (fetch origin, check branchState flags, identify current task, read handoff) moved into templates/captain.claude.md and captain.generic.md. They previously lived only in plugin/skills/captain-ops/SKILL.md, which loads only on voluntary skill invocation and never for non-Claude captains. Dead status.md reference removed.
- Template and skill audit. Audit of all 9 templates and 16 skills: replaced 5 hardcoded /Applications/cmux.app cmux invocations with squadrant runtime equivalents, removed dead read-status.sh and two further dead status.md references.
v0.17.0
[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.