SOURCE / CHANGELOG.mdAT / 2dbeaf1View on GitHub ↗History ↗

Changelog

Unreleased (0.6.5) — v0.6.4 maintenance: CI and the Plugin Directory#

No runtime behaviour changes from 0.6.4. The version moved because claude plugin update compares versions: an installation of 0.6.4 (b9c6d3e) is told it is up to date and would never receive these commits. The detail: docs/implementation-v0.6.4.md.

  • After publication: CI and the Plugin Directory. CI on main failed twice on b9c6d3e, where the pull request had passed: 4b one more untracked file among 5000 is CHANGED ran 5.1 s and 7.4 s against the test kit's 5 s default. The test host's new model of stat looked each path up in the list of untracked files, which made the 5000-file fixture quadratic; it builds a set once per call now. The fingerprint itself grows with the number of untracked files as v0.6.3's did, at a constant factor more (measured from 2,500 to 19,000 files). Tests 4 and 4b also carry an explicit 20 s timeout; the fixture and its assertions are unchanged. The Directory reported MOD_CAPABILITY_USE_NOT_PLAIN at hooks/register.tsx lines 2191, 2220 and 2241: v0.6.4 had declared a second ask, a nested stat helper of the fingerprint's inspection, beside the dialog helper $ is passed to. It is runStat now, with no change in behaviour. A review found the same shape, not reported, for the host's own read: a local read in the tracked-file measurement, there since v0.5.3, is hashing now. scripts/check-capability-shape.mjs now reports a second binding of such a name in any scope, the host's imported read and update included, and on bound by anything but a parameter; it finds both cases on b9c6d3e. The README's capability table adds the alert-label store key, what runs at session start and at Stop, and the images, sounds and fonts shipped. The Directory's own re-validation has not been run: NOT VERIFIED.
  • Documentation after 0.6.5 (no version change, no runtime change). The 0.6.4 description of the measurement memory limit was corrected: it is 1 GiB of virtual address space per process, with at most two top-level measurement processes at once, and not an aggregate ceiling (docs/implementation-v0.6.4.md, SECURITY.md). The optional Cobalt Recall research roadmap from draft pull request #5 was added (docs/roadmap-cobalt-recall-xerj.md), and stale status lines for v0.6.3 and the security follow-ups were corrected.

Unreleased (0.6.4) — Fingerprint resource hardening (security)#

The threat model, the reproduction under hard limits, the design, measurements, compatibility changes, residual risks and the acceptance procedure: docs/implementation-v0.6.4.md.

  • Security: the working-tree fingerprint could exhaust memory or block. v0.6.3 let a repository decide what its measurement read. git hash-object read through an untracked symbolic link to /dev/zero; a core.excludesFile, core.attributesFile, diff.orderFile, objects/info/alternates or linked-worktree commondir pointed at a device made Git read it whole; a FIFO where Git expects a file (.gitignore, .gitattributes, HEAD, the index, config) blocked. Reproduced under hard limits: memory ran out within a second (1.7 GB in 846 ms through the link), and a FIFO blocked until the process was killed. The host's process timeout bounds time, not memory.
  • Every measurement process is bounded. Each git, stat, find, readlink and realpath that the fingerprint, the HUD refresh, the release check and helper Git preflight start now runs through one fixed sh -c script. It lowers (never raises) the address space to 1 GiB where the platform enforces it, CPU time to 20 s, file size to 64 MiB and core dumps to 0, then execs the command's own arguments, which are never part of the script. Git also runs with repository hooks off, no diff order file, small pack windows, streaming for files over 16 MiB and no index threads, under MALLOC_ARENA_MAX=2. The memory limit is set wherever the shell accepts it. Whether the platform enforces it is probed once per load (again 30 s after a probe that did not answer), and /cockpit doctor shows the result (OK when the cap is enforced, WARN when it is not). Measured: every v0.6.3 vector now ends at the 1 GiB cap in about 0.2 s, and ordinary repositories run each step in at most 10 ms and 6.3 MB.
  • Nothing that is not an ordinary file is read. Paths are inspected with stat before any read, without following the last link. A regular file is hashed; a symbolic link is measured by its own text, as Git records it; a FIFO, socket or device is measured by its kind alone and never opened. Git's excludes, attributes and alternates files must each be an ordinary file of at most 1 MiB (followed through a link) before Git reads them. A file over 1 GiB, more than 8 GiB in all, a file that changes between its inspection and its read, and a measurement over 90 s each make the tree UNKNOWN, with the reason.
  • A stamp a chosen change cannot match. The fingerprint's content hash is now SHA-256, cut to 128 bits. It used to be two 32-bit FNV hashes, and file names, link texts and kinds are chosen by whoever writes the tree, so a crafted change could have produced the earlier value and read as unchanged.
  • An UNKNOWN never keeps an earlier verification. A goal check accepted on a measured tree is withdrawn when the tree can no longer be measured; before, it was kept. align is refused when the checks were observed on a measured tree that can no longer be measured, and a passing command seen on such a tree stales the checks observed before. Once the checks are run again, align is accepted and says why later changes cannot be seen. A measurement cut short only because a file changed or vanished while it was read is taken once more before it counts. A tree that was never measurable keeps the documented behaviour.
  • A repository that cannot be measured is never accepted as protected. Where a Git repository is present but its fingerprint cannot be taken safely (unsafe metadata, a file over the size bounds, no commit yet, a damaged .git, a measurement that fails or times out), a goal check claimed ALIGNED is recorded as UNKNOWN with the reason, and the task does not read DONE until the cause is fixed and the goal check is made again. A failed measurement is read as neither a clean nor a changed tree. A project outside every Git repository keeps today's behaviour: ALIGNED is accepted and marked UNPROTECTED in the reply and the status. "Outside Git" needs both Git's own answer and no .git entry in the directory or any parent.
  • Measurement processes end with their process group, never start without limits, and share two slots. The limit script runs each command under GNU timeout -s KILL, a second inside the host's timeout, so a blocked Git and any child it started in its process group end together, even after the host has exited (measured in a genuine Claude Code process: 0 processes left behind, where the earlier code left 2). Where no shell can set the limits, nothing is started and the tree is UNKNOWN. At most two top-level measurement processes run at once in each Claude Code process. The 1 GiB address-space limit applies to each process separately, and every child inherits one of its own, so the slots are not an aggregate memory ceiling (this entry said "2 GiB in all" until corrected after 0.6.5; see what the memory limit does not bound). The Linux limits were checked one by one in disposable fixtures: memory 1 GiB, CPU 20 s, file size 64 MiB, no core, a stricter outer limit kept.
  • Helper Git inspection. A helper's read-only Git command, rebuilt by Cockpit and run by Claude Code's Bash tool, now also turns repository hooks off and overrides the diff order file.
  • Compatibility. The fingerprint's hash changed, so a task that spans the upgrade asks for one more check. A changed or untracked symbolic link is measured by its target text, not by the file it leads to. A global ignore or attributes file over 1 MiB, one that cannot be read, or one that is a FIFO or a device, makes the fingerprint, the HUD's Git line and the release check UNKNOWN; so do a tracked or untracked file over 1 GiB and more than 8 GiB to read. An accepted goal check is withdrawn when the tree can no longer be measured, even for a timeout, and a repository that cannot be measured (including one with no commit yet) cannot reach DONE until the cause is fixed. Without a shell that can set limits, measurement is off. Measurement now starts stat as well as Git, a few more processes per fingerprint. Behind sh the host's own handling of git no longer applies, so Cockpit turns repository hooks off itself.
  • Not covered. Where the memory cap is not enforced (/cockpit doctor says so; not verified on macOS), a file Git reads on its own (a linked worktree's commondir, a configuration include, grafts, sparse-checkout) is bounded only by CPU time and the timeout. Without GNU timeout, a child a blocked measurement starts may outlive it; /cockpit doctor says so. With it, a descendant that creates its own session or process group escapes the group kill. There is no aggregate ceiling on resident memory or on the measurement process tree; that would need a cgroup or equivalent operating-system enforcement, which Cockpit does not set up. Git commands that Claude Code runs itself are outside Cockpit.
  • Tests: tests/fingerprint-bounds.test.ts (112) is new; 54 of its first 74 tests fail against v0.6.3, and the rest test code that did not exist. tests/world.ts models the limit script, its probes and typed stat. Tests in five earlier files changed for the new processes, their cost and the rebuilt helper command; the design page lists them. Independent reviews of the change, of each round of corrections and of the owner's two further requirements found no blocking defect; what they raised and what was done is in the design page.

Unreleased (0.6.3) — Cobalt Guard Calibration#

Design, the simulation, the figures, departures from the proposal and limits: docs/implementation-v0.6.3.md.

  • Three commands under /cockpit alerts. review [page] lists recorded incidents, unreviewed first; label <id> notify|record|noise|clear records whether you would have wanted a notification; calibration prints the report. Review is not a look: it writes no look marker and takes up no acknowledgment.
  • Only a person labels. The terminal's own Enter or the Remote Control bridge; claude -p and Agent SDK turns, models, subagents, plugins, hooks and any other origin are refused before anything is read or written. A label acknowledges nothing, resolves nothing and sends nothing.
  • One store key per label. alert-label:<project hash>:<occurrence id> holds the label and a time and nothing else, written whole and never read back and rewritten, so two sessions cannot lose each other's labels. A label whose occurrence is gone is counted nowhere and is deleted by a later label command only under the orphan rule in the design page.
  • A simulation of the live policy, with its gaps stated. The report runs each recorded incident through the policy's own decide and holdOf on a copy of the configuration with alerts treated as on, covering notified kinds, quiet hours and level. The cooldown, the session budget, reminders, silence, send failures and the telling of a deferred alert are not simulated and the report names them.
  • Figures and thresholds. Counts first; a rate needs at least 10 labelled incidents and carries a 95% Wilson score interval; below that the report says INSUFFICIENT EVIDENCE, which is not a finding about the policy. Unreviewed incidents are in no figure, and the missed-wanted share is not detection recall.
  • Read-only and silent. Review and the report write nothing and send nothing, change no setting, gate, hold or enforcement, and recommend no setting. security-failure stays a notified kind.
  • The export is unchanged. /cockpit alerts export stays at schema version 2 and carries no labels.
  • Tests: tests/alerts-calibration.test.ts (54), tests/alerts-labels.test.ts (90) and tests/alerts-labels-shared.test.ts (42) are new, with seeded sweeps and a check against the live alert pass; scripts/acceptance-harness.sh gains eight two-process checks, and scripts/acceptance-interactive.sh launch profiles and an sdk probe.
  • Documentation: three stale v0.6.2 lines corrected (the roadmap's status, its index entry and a test count).

Unreleased (0.6.2) — Persistent Attention#

Design, the observation rule, measurements, limits and the acceptance procedure: docs/implementation-v0.6.2.md.

  • An Attention section in /cockpit alerts digest. Acknowledged incidents whose condition is observed still open are listed apart from the unacknowledged ones, by level and kind (at most five detailed, the rest counted), with the new-since-last-look count and the acknowledged incidents whose state cannot be observed (UNVERIFIED CONDITION STATE). Each incident is counted in one group only. Acknowledging stops reminders and resolves nothing.
  • A condition is OPEN only where this session observes it. The standing is read from the session's own task each time and is never stored: a record without a resolution mark is not evidence that a condition is open, and an incident raised by another session, an earlier task or a release NO-GO whose history cannot be read is UNKNOWN, never resolved. Records, keys and the export are unchanged.
  • The inbox and the digest no longer call an unobservable condition "no longer open". For another session's incident the line reads condition state UNKNOWN from this session, under its own heading; the digest's history figure excludes it.
  • HUD row. After an acknowledgment the row went blank while the condition still held. It now adds N acknowledged, still open and N unverified (static, INFO level, same narrow forms); unchanged when there are none.
  • Another session's incident is no longer recorded resolved by a pass that cannot observe it. The resolve pass now closes only conditions of a task this process has held, and not a release NO-GO whose history cannot be read; the reminder timer follows the same rule. A stored record of a task nobody here holds used to be closed on the first look and now stays, never notified, as UNKNOWN. /cockpit alerts ack says when a condition cannot be observed instead of "no longer holds".
  • Export schema version 2. /cockpit alerts export reported ENDED for any condition not open here, including another session's. condition is now OPEN, RESOLVED, ENDED (observed not holding, in this session's own task) or UNKNOWN (cannot be observed from here). Nothing else in the schema changed. The export is a record and not an observation: a resolved mark written by an earlier version's session that could not observe the condition still exports as RESOLVED.
  • Read-only and silent: the digest writes nothing, no timer, process or network call was added, and an acknowledged incident that stays open is not notified again. The Stop Guard, security holds, release approvals and native permissions are untouched. Six earlier tests changed for the wording, row and resolution differences above; tests/alerts-attention.test.ts adds 40 (and tests/alerts-export.test.ts covers the export).

Unreleased (0.6.1) — Smarter swarm operations#

Why Haiku was under-used, the exact reviewer permissions, the corrections to earlier rules, measurements, the review record and the acceptance procedure: docs/implementation-v0.6.1.md.

  • Scoped read-only Git inspection. A task that owns named paths (not *) can now run git diff, show, log, status, grep and ls-files on those paths, where v0.6.0 refused its shell outright. The rule is an allowlist (hooks/git-inspect.ts): one plain command; a fixed list of options per subcommand; revisions that are plain names, each proved to be a commit before the command runs; an explicit -- and literal paths, each checked against the task's ownership; git show <rev>:<path> only for a path that is owned both as written and as resolved. The command that runs is rebuilt from the parsed words, single-quoted, behind the safe flags and pinned with -C to the verified directory. A refusal says what to change. Nothing is widened by a command: a path outside the scope is refused, and a * scope is still the commander's to grant.
  • The -- separator. The v0.6.0 rule for * readers refused every command containing -- (the bare separator matched its own list of refused long-option prefixes), so git diff main...HEAD -- hooks/x.ts and git grep -n x -- hooks never ran. It is accepted now; a word after it that begins with a dash is refused, so nothing unchecked can be read as an option. A subagent's single-quoted pattern may contain $, <, > or a backtick (its command is rebuilt before it runs); the commander's own commands, which run as typed, are judged without that.
  • Security corrections to rules v0.6.0 already had, found by this release's review and reproduced with real bash and git before they were fixed:
    • A * reader could run a program through git grep -nO'<command>' or git grep --op='<command>': Git bundles short options and accepts any unambiguous prefix of a long one, and the refusal list tested only how a word begins. A one-dash word containing O is now refused, and a long option whose name is a prefix of a refused one, or begins with one. A harmless value can be refused for its letter (-SOWNER).
    • The commander's rule could call a command read-only when bash would run more: a carriage return before # (a blank to the reader, a word character to bash) and brace expansion (--{output=x,}). Control characters are refused in every rule, and the commander's rule refuses what bash would expand: any brace but a revision's own, and a filename pattern in an option or at the start of a word.
    • The destructive-command guard failed open for a command that began with a program named like an inherited property (valueOf -x; git push --force): the wrapper lookup found a function, the guard threw, and a guard that throws is treated as no refusal. The lookup reads the table's own entries only. This guard runs with orchestration on or off.
  • Security hotfix: a guard that throws now refuses. The tool hook read an exception inside the destructive-command, attribution or instruction-file guard as "no refusal" and let the call go to the host (guard(...).catch(() => null)), against SECURITY.md. Each guard now runs under failClosed (hooks/guard-rules.ts): a throw becomes a refusal that names the guard, the tool and the error kind, never the command, path or error message, and says how the person can reload the plugin or switch that guard off with its own option; other tools and the next call are unaffected, and nothing is retried or approved on the caller's behalf. The same shape was fixed beside it: an instruction-file check whose filesystem call failed read as "the file exists" (so CLAUDE.md could be created unasked), and the subscriptionOnly refusal read a failed read of the authentication state as "not API" (it now refuses and says so; an unverified mode was refused only from the closeout below). Tests: tests/guard-failure.test.ts; a static check in scripts/audit-public.py keeps the old shapes out.
  • Security closeout: instruction files and subscriptionOnly. An Edit with an empty old_string, a MultiEdit and a NotebookEdit could create CLAUDE.md or AGENTS.md without the question a Write raised; the question is now asked whichever tool creates the file, and not for a file that exists. A prompt that merely mentions the file ("do NOT create CLAUDE.md", "explain AGENTS.md", "create CLAUDE.md") is never permission, from any origin: a new file is confirmed through the guard dialog, and with nobody to ask it is refused. The only thing that stands in for the question is a /init typed at the terminal or sent over the Remote Control bridge, judged on the engine-stamped origin, never an sdk turn (a nested claude -p an agent can start), a plugin or a peer. The shell reader also sees install, ln (including into a directory given as ., .., a trailing slash or -t), dd of=, truncate, a script piped into a shell and a script handed to sh -c or eval. With subscriptionOnly on, only a confirmed subscription sign-in passes: an unconfirmed one (no credential reported, or the engine not answering), a state not yet read and a state that cannot be read are refused, with /login and the option named as the way out and no credential in the text. Tests: tests/closeout.test.ts.
  • Route suggestion. Each assignment records the tier the existing routeTask policy would suggest, read only from fields the commander set (mode, the role's words, a named effort, the wave), never from the objective's words. The commander's tier stands; the reply to assign names a differing suggestion (ROUTE / HAIKU suggested (…); SONNET kept as assigned. Advice only. …) and how it could be followed. Nothing is spawned, re-tiered or queued by it.
  • Delegation funnel. /cockpit agents shows, per tier, suggested · requested · admitted · spawned · completed · verified as six separate figures, and how many assignments differ from the suggestion; /cockpit agents <task> shows that task's route; swarm status carries the same counts. A task from an earlier Ledger has no suggestion and is counted as unrecorded, never guessed.
  • Claims and task ids say what happened. An owned_resources entry that is a pattern, starts with ~ or does not resolve has always been taken as *; the assign reply now says so (SCOPE / … this task's claim is *). Assigning a task id that has already ended now answers that nothing was assigned and that an id is never reused.
  • Instructions that match the guard. The commander's section says when a Haiku scout or utility suits, to batch them at the start of reconnaissance, what a scoped helper can do and what a claim costs the commander. The scout, utility, explorer, researcher and reviewer definitions give the exact Git forms that run under an assignment, and no longer tell a reviewer it can run tests there.
  • Home-directory names. One rule (hooks/paths.ts) for free text, resource claims and diagnostics. The name is no longer shown under /var/home/<name> (Fedora Atomic and other immutable desktops), /usr/home, /export/home, /mnt/<x>/Users, /<drive>/Users, /cygdrive/<d>/Users, /Volumes/<v>/Users, /System/Volumes/Data/Users|home, /media/<name>, /run/media/<name>, ~name/…, C:\Users\<name> (either slash, single or doubled), file:// paths and host:/path, as well as /home and /Users; Users in any case. A claim of a home directory itself (/home/<name>) no longer shows whole. /cockpit version shows its source path without the name. Web URLs, relative paths and ordinary text are untouched. This is pattern matching, not anonymization: the unrecognised forms are listed in PRIVACY.md.
  • A swarm line on the HUD. SWARM: 2 BLOCKED · 1 QUIET 5m+ · 1 ESCALATED · /cockpit agents, with orchestration enforced and only while a task is blocked (admission refused it), quiet (the swarm's stalled mark: no activity observed for the threshold, which is not a stopped agent) or escalated (stopped with an unresolved question). Queued tasks are not counted. It is read from the Ledger the render already holds: no timer, poll or process was added, it is never animated, and it takes a row the agent strips would have used, so the band is never taller. Narrow bands get shorter forms, down to SWARM: 4 ATTN.
  • Wording. The narrow /cockpit agents header no longer merges stalled and escalated tasks into "stuck"; the pane's TASK GRAPH row and the Activity Field's labels count blocked apart from quiet and escalated. summarizeSwarm().blocked is the blocked state alone, with stalled and escalated beside it.
  • No setting was added or changed. Observation remains the default; every pool ceiling, dependency, ownership rule, native permission prompt, security hold and release NO-GO is as it was.

Unreleased (0.6.0) — Mission Control operations#

Details, the Directory compliance work, measurements and the acceptance procedure: docs/implementation-v0.6.0.md.

  • /cockpit agents and /cockpit agents <task>: a read-only agent inspector over the swarm and the Run Ledger: states, waves, capacity, ownership, dependencies, requested/launched/applied/engine-reported effort, last observed activity, reported versus verified outcomes, untracked host agents.
  • Blocker explanations from the swarm's own admission rule (dependency, ownership conflict, capacity, commander or architect occupied, awaiting spawn, stalled, escalation, cancellation, failure, unverified result), with information-only suggestions.
  • /cockpit ready: which recorded conditions stand between the task and DONE, from the existing completion rules; PERMITS DONE exactly when the task reads DONE.
  • /cockpit alerts export (person-only, bounded JSON, schema v1) and /cockpit alerts legacy [delete <code>] (dry run first; deletes only fully migrated, fully understood earlier-format keys).
  • Directory capability-inspection repair: every call that passes $ to a helper of the module is a statement of its own (sixteen sites hoisted; a dead helper removed); the host analyzer's report is unchanged. scripts/check-capability-shape.sh (a self-tested local approximation of the Directory's guidance, now in CI) guards the shape.
  • scripts/acceptance-harness.sh: two genuine Claude Code processes against a disposable store (no model, no credentials, no operator data).
  • README capability table; SECURITY and PRIVACY updated.
  • Documentation only, no runtime change: the README is restructured as a front page (banner, a captured demo, module panels, a profile comparison, expandable reference), and its long sections moved word for word into topic files under docs/ (docs/README.md). The capability table and the account of what Cockpit runs, reads and sends stay in the README. The demo is scripted input run through the plugin's own renderers in the offline test host, and is labelled so (docs/assets/README.md). Two corrections to the text that moved: the rule for the architect's identity in docs/sonnet-led.md now matches the code and SECURITY.md (exact agent type, not a suffix), and the README's list of environment variables read by name gains SSH_CONNECTION and SSH_TTY, which SECURITY.md already listed.

Unreleased (0.5.9) — Record-only mode and the since-last-look summary#

Details, the mode table, what the store does and does not guarantee, and the acceptance procedure: docs/implementation-v0.5.9.md.

  • guardRecordOnly (off by default, person-only): with guardAlerts off, the conditions Cobalt Guard alerts about are written down with their level and shown by /cockpit alerts and /cockpit alerts digest; nothing is ever sent, played or rung. With guardAlerts also on nothing changes (it is not a way to mute alerts). A new outcome, recorded, says so: it is never SENT, FAILED or DEFERRED. No cooldown or budget is used. Turning alerts on later does not announce what was recorded.
  • SINCE LAST LOOK: 1 CRITICAL · 2 HIGH · 3 NORMAL at the top of /cockpit alerts and in /cockpit alerts digest: the occurrences not shown at the last look a person made, counted by identity and not by time, split into active and history and by what became of the notification. A person's display of the inbox marks the occurrences it showed; the digest, the session-start line and any other origin mark nothing. Looking acknowledges nothing. Best effort across sessions (a read and a write of one key); it can over-report and never marks an occurrence seen that was not shown.
  • The HUD row says RECORDING, pins the most important unresolved recorded incident (RECORDED, no notification) or counts the unacknowledged history, and is absent when there is nothing to show.
  • Each occurrence's records are a key of their own (alert-occ:<project>:<id>), so two sessions recording different occurrences can no longer lose each other's records. The v0.5.8 and v0.5.7 history keys are still read and no longer written.
  • An acknowledgment key can outlive its record: /cockpit alerts ack of such an id says so instead of "unknown". /cockpit doctor and /cockpit guard describe the mode.

Unreleased (0.5.8) — Inbox consistency and return digest#

Details, what the host's store does and does not guarantee, and the acceptance procedure for two concurrent sessions: docs/implementation-v0.5.8.md.

  • Acknowledgments are keys of their own, alert-ack:<project>:<id>, set once with a fixed value (one atomic host set, no read-modify-write), so a stale or concurrent session cannot undo one. Sessions apply them to their own records at each look (a tool call, a command, the timer, a session start).
  • History is one key per project, alert-history:<project> (four projects, 32 records each), so projects cannot overwrite each other. The v0.5.7 single key is still read and never written. The stored history is last-writer-wins for records and says so; an acknowledgment is not kept there.
  • /cockpit alerts digest and the opt-in guardDigest (one terminal line at session start, once per session, no desktop notification, no model call).
  • /cockpit alerts, digest, acknowledgment and guardDigest work with guardAlerts off; nothing new is recorded or retained for a user who has alerts off.
  • A held-back record that is all an open condition has is the last to be evicted. The unfinished v0.5.7 limit about concurrent acknowledgments is closed for acknowledgments; it remains for records.

Unreleased (0.5.7) — Alert inbox and recovery#

A bounded, persistent and actionable inbox over the alert records Cobalt Guard already keeps. Notifications, quiet hours, priorities, budgets and the single timer are unchanged, with the two corrections listed below. Details and the acceptance procedure: docs/implementation-v0.5.7.md.

  • /cockpit alerts [page]: every recorded occurrence, open and unacknowledged first and the gravest first, then open and acknowledged, then history (newest first), eight to a page. Each line: id, level, kind, task, the time it was recorded, what the host reported about its notification, whether it was acknowledged, and whether its condition holds now (read off the task, not inferred).
  • /cockpit alerts ack <id>: acknowledges exactly one occurrence and ends its reminders. Person-only. An unknown, expired or malformed id changes nothing and says why; acknowledging a condition that has already cleared says it only marks the record. /cockpit guard ack still acknowledges everything.
  • Each record carries an 8-hex occurrence id (derived the same way for records from v0.5.6). A new alert-history plugin-store key keeps each project's records (four projects, 32 records each) so a new session in the same project shows what was recorded earlier; a damaged value is ignored. Nothing is replayed after a restart: what was told stays told.
  • The HUD's GUARD row shows N unacknowledged in history when recorded alerts no longer hold and were never acknowledged; open conditions are pinned as before, and the widest pin ends /cockpit alerts. Nothing says a person saw anything or that a connection dropped.
  • Corrected: a condition that clears and holds again is now a new occurrence with guardRepeat off as well (v0.5.6 recorded resolved only with it on, so the recurrence was never told and the pin described the earlier notification). It is bounded by the cooldown, the session budget and the retry cap. An acknowledgment typed while a notification is being written is now matched by a count rather than a clock reading, so a clock stepped back no longer makes a later record read as acknowledged.
  • The v0.5.6 shortened long-window timer test keeps its host run at one hour; the five-hour-forty-five-minute case is now a pure test of the same rule.

Unreleased (0.5.6) — Alert priorities, quiet hours and the pinned alert row#

Alerts that are less intrusive and harder to miss. What is sent, and when, does not change unless a new option is set; with alerts on, the HUD's GUARD row does change by default (see below). Details and the acceptance procedure: docs/implementation-v0.5.6.md.

  • Fixed priority levels: security-failure CRITICAL; release-no-go, verification-exhausted, review-hold HIGH; run-blocked NORMAL. They order the HUD row and define what quiet hours treat as critical. The order alerts are sent in is unchanged.
  • guardNotifyKinds: which kinds are notified. The critical kind cannot be turned off; a kind left out is recorded and stays visible.
  • Quiet hours (guardQuietHours, guardQuietTimezone, guardQuietOrdinary, guardQuietCritical), off by default: a daily wall-clock window in a named zone, midnight-crossing and daylight-saving aware. A deferred alert sends no notification and plays no sound, because on a bell channel the notification is the sound; it is recorded deferred, stays on the HUD, and is told once afterwards (several as one notification). Settings that are not understood turn quiet hours off, with the reason shown.
  • An alert kept during the window is reported as audible on a bell channel and as unknown elsewhere, never as silent.
  • The HUD's GUARD row pins open, unacknowledged conditions with their level and notification state, and an unconfirmed transport while armed. It clears on resolution or acknowledgment and never states that a notification was seen.
  • A new condition raised while the session is silenced is now recorded (silenced) so it stays visible; it is still not notified.
  • /cockpit guard and /cockpit doctor show priorities, notified kinds, the quiet window with the time in its zone, active conditions and deferred alerts.
  • The new settings are person-only, like the other alert settings. No new process, timer, network call or credential: the existing 30-second host timer also looks for the end of the window.

0.5.5 — Verified notification transport#

Diagnostics and a person's confirmation for whether Cobalt Guard's notifications reach the current terminal. Details and the operator checklist: docs/implementation-v0.5.5.md.

  • /cockpit guard test [sound]: one notification labelled TEST with a random four-character code; optionally the existing alert sound (always with guardSound). Needs no task, works with alerts off, and has its own limit (one per 30 s, six per session). It spends none of the alert budget or cooldown and writes no alert record.
  • /cockpit guard seen [code]: records that the person saw the latest test of this session, within 10 minutes of it. With the code it showed; without one only for a bell-only channel (kept as "confirmed without the code"). A wrong or missing code, a second confirmation, a late one, one with no test, or one after the connection kind changed changes nothing. A confirmation counts for 12 hours.
  • Four states: NOT TESTED, ATTEMPTED, SENT, USER CONFIRMED. Nothing is recorded as delivered; a confirmation is a person's statement.
  • A confirmation is held with its session id and connection kind (SSH session or not, from whether SSH_CONNECTION or SSH_TTY is set; the values are not kept). Another session starts NOT TESTED. A reconnect cannot be detected and the output says so.
  • /cockpit guard and /cockpit doctor show the reported channel, bell-only, the sound outcome, the last test and confirmation, whether the confirmation applies now, and a warning while alerts are armed on an unconfirmed transport.
  • Both commands are person-only and change no gate, hold, review, approval, percentage or alert. No new process, service, tunnel, network call or credential.
  • Not verified here: any real terminal. Konsole on Fedora, and Claude Code in Boat over SSH, remain for the operator to test.

Unreleased (0.5.4) — Persistent alerts#

Opt-in extension of Cobalt Guard's owner alerts (hooks/alerts.ts). With every new option off, 0.5.3 behaviour is unchanged. Details: docs/implementation-v0.5.4.md.

  • guardRepeat (default off, needs guardAlerts): an alert whose condition is still open is repeated every guardRepeatSec (default 900, minimum 60), at most guardMaxReminders times for each condition (default 3, maximum 10), inside the existing cooldown and session budget. The budget's last alert is never spent on a reminder, and a reminder that failed to send counts.
  • Lifecycle: /cockpit guard ack ends the reminders of what is open; /cockpit guard silence stops everything for the session and the new /cockpit guard unsilence resumes for new conditions (all three typed by a person only); a condition that no longer holds is recorded resolved without a notification, and is told as a new alert if it returns.
  • guardSound (default off): the existing checkpoint cue, with the terminal bell as the player chain's last resort, is tried with each alert and reminder; it honours sounds and /cockpit mute. Recorded as attempted, never as heard.
  • One host timer ($.clock.every, 30 s) exists only while something can still be repeated; it is cancelled on acknowledgment, silence, resolution, exhaustion and session end and re-armed from the kept records after a reload. No new process, no network, no desktop notifier.
  • /cockpit guard and /cockpit doctor show persistence, sound, each open condition and its reminders. An acknowledgment now survives a restart.
  • The four new options are protected like the other guard settings: only the person changes them in the config menu.
  • Alerts and reminders still change no gate, hold, review, release approval or percentage, and their text is a closed sentence with numbers only.
  • Not verified here: that a terminal notification or sound raised on a remote machine reaches the operator's desktop. That is interactive acceptance.

Unreleased (0.5.3) — Authorization and identity hardening#

Remediation of the reproduced findings of the independent review of 0.5.2. Details and compatibility notes: docs/implementation-v0.5.3.md.

  • M1, SDK origin is not human authority. The host stamps every claude -p / Agent SDK turn sdk and cannot tell a person from an agent-controlled nested claude -p. /cockpit reset, guard trust, guard untrust, guard release, guard ack, guard silence, discovery <level> and router <mode> now accept only the composer and the Remote Control bridge. A headless SDK session can still start and classify tasks and read every status.

  • M2, project identity. The working-tree fingerprint carries the project (the git work tree) it was taken in. The project is a 128-bit SHA-256 of the work tree path (no path is stored). Another checkout, worktree or repository, a fingerprint saved by 0.5.2 and the earlier 32-bit form compare UNKNOWN, never unchanged, and UNKNOWN runs the check (once for a saved task). Stored fingerprints are bounded at 160 characters.

  • M3, consultation identity. Only the exact agent type cobalt-cockpit:architect, from a definition the host attributes to this plugin, is the architect. Another plugin's or a project's agent that ends in :architect cannot take an admitted consultation.

  • L1. The Stop guard's and the alerts' settings (stopGuard, verifyScript, verifyScriptSha256, verifyTimeoutSec, stopMaxContinuations, stopVolatile, stopWatch, guardAlerts, guardCooldownSec, guardMaxAlerts) change only by the person in the config menu; a plugin's $.config.set and the bridge are refused.

  • L2. The refusal budget is kept on the held task (stopHold.refusals) and is the larger of that and the check log, so a lost, corrupted or flooded log cannot restore a held task's attempts. The log is also bounded per task (16) and in total (128). No cross-process atomicity is claimed.

  • L3. A release candidate is not established while the index hides a path with assume-unchanged or skip-worktree, and the check runs git with the hardened invocation (no fsmonitor, replace refs or untracked cache).

  • L4. verifyTimeoutSec is capped at 600, the host's process.run limit; a larger value is lowered instead of making the check fail.

  • Final recovery: candidate identity and fingerprints measure every intended commit path independently of the index; unreliable roots, active external filters and incomplete reads fail closed. Native EOL normalization, supported symlinks and executable-mode policy remain compatible. UNKNOWN suspends current release clearance.

  • Refusal recovery preserves the maximum held/log budget, reserves attempts before verification, and fails closed on damaged counters and discarded legacy guard records. Failed state-write regressions preserve the disclosed cross-process persistence limitation.

  • Submission preparation: exact-archive inventory and entrypoint checks, updated disclosures and separate local/external evidence. Anthropic external validation remains unverified; Persistent Alerts are excluded.

0.5.2 — Observability and state integrity#

  • /cockpit reset is refused from any origin that is not the person's (composer, bridge, SDK); an unknown origin fails closed.
  • Local model telemetry (telemetry, default on): a bounded, whitelisted record of observed requests, subagents, routing and consultations in per-process sealed segments under ~/.local/state/cobalt-cockpit/telemetry/ (64 KiB segments, 4 MiB total, 13 months). No prompt, code, path or secret is stored; nothing is uploaded. /cockpit stats 7d|30d|all [--json|--csv] reads it. Storage is not append-only and file modes are claimed only after a stat read-back.
  • Neural Flow (flow, default on): a one-row HUD line, input → discovery → routing → workers → verify → done, drawn only from real task state; the moving marker appears only while work is live; honours reduced motion. /cockpit flow prints it in words.
  • /cockpit doctor: read-only installation, host, Auto-mode, telemetry-storage and subagent prompt-cache diagnostics. The cache policy is configuration intent and an opt-in recommendation only: Cockpit edits no settings file, sets no variable, makes no extra model call and claims no savings.
  • Optional Stop-hook verification guard (stopGuard, default OBSERVE): in ENFORCE it runs the owner's verifyScript (argv only, no shell, optional sha-256 pin, hashed at session start) when a changed task tries to finish, refuses the stop with the failure until it exits 0 or the attempt budget is spent, then marks the task BLOCKED and allows the stop. A pass sets only the TEST gate.
  • Cobalt Guard (guardAlerts, default off): a terminal notification through the host's own channel when a run needs a person (retries exhausted, security failure, release NO-GO, open mandatory review at stop, blocked run). Deduplicated, throttled, bounded, redacted by construction, recorded in the Run Ledger, shown as GUARD: in the HUD and by /cockpit guard (ack, silence). An alert never clears a hold, approves a release or changes a verdict; SENT means the host wrote it to the terminal, not that anyone saw it. No webhook, email or push (deferred).
  • Stop guard hardening after independent review: scripts are enrolled by a person with /cockpit guard trust (raw-byte sha-256, per project, persistent), every check counts toward the refusal budget, the tree must be stable across a check, and the hold is protected task state (stopHold): no progress action, test report, re-plan, read-only declaration or forged blocker lifts it; only a passing enrolled check or a person's /cockpit guard release does, and release sets no gate. The script is re-hashed before every execution. Tasks saved by the previous schema are migrated deterministically from the guard's own Ledger records, never from blocker text, and a migrated hold reconciles a saved DONE at once. A "read-only" plan is a claim measured against the tree the host fingerprinted when the task began (never against the moment it is declared); an unknown baseline or tree counts as changed. A prompt does not drop a hold (only /cockpit reset does, and the Ledger keeps what was abandoned), and the check records are also kept in a durable versioned store key so a new session's empty Ledger cannot reset a budget.
  • Completion integrity: a task never reads DONE while a Stop check is unresolved. Every check that did not complete the task holds it at once (not only when the budget is spent); a read-only task that changes becomes a coding task with every gate required and cannot be re-declared read-only; a person's release keeps TEST required and pending; /clear records an abandoned hold; a prompt adopts a legacy hold first. Change detection is UNCHANGED, CHANGED or UNKNOWN with the reason recorded; unknown neither passes nor convicts. The fingerprint now sees assume-unchanged and skip-worktree files and the exclude sources, and its cap is 20,000 files.
  • Guard-owned completion: in ENFORCE a task reads DONE only on a record the Stop guard wrote for that task and tree (guardDone); nothing the model reports can create it. A provisional hold is placed before every check, prompts, SessionStart and interrupted turns reconcile a finished task against the record and hold it when it is missing or stale, a pass on an unidentifiable tree is not a completion, a helper's edit converts a read-only task, and a release reopens the work. The fingerprint's git calls ignore replace refs, fsmonitor, submodule ignore settings and the untracked cache, and ignored entries are part of the stamp. A tracked file that is only stat-dirty is compared with its base blob, so a clean filter cannot hide a change and a merely touched file is not one. stopVolatile and stopWatch are operator-set scopes; no model input narrows the fingerprint.
  • Directory compatibility: local h callback parameters in hooks/register.tsx (the ones the directory flagged at lines 254, 256 and 300 of 0.5.1, plus the same name elsewhere) are renamed, since h is reserved by the JSX runtime; no behavior changes. scripts/audit-public.py now flags a TSX binding of h or Fragment. The directory's own validator is not available locally.
  • Stop guard change detection after the second and third reviews: a task with no starting fingerprint, work done with no task, and edits to ignored files, watched directories and embedded repositories can no longer read as unchanged; a git listing that warns on stderr (an unreadable directory) or a watched path that cannot be reached is UNKNOWN, never unchanged or "missing". Bounds: 100,000 ignored and watched files, 25 s. /cockpit doctor warns when a script is configured but the mode is OBSERVE. Residuals are listed in the notes.
  • Details and limits: docs/implementation-v0.5.2.md.

0.5.1 — Discovery and decision quality#

  • Adaptive discovery: a deterministic LIGHT, STANDARD or DEEP level per task, from the prompt, the files edited and the existing consultation grounds. LIGHT work gets no added prompt text; STANDARD and DEEP get one short line, once per level. No new model call, router or consultation path.
  • The progress tool gains discover, decide and align. Decisions are bounded records in the Run Ledger (alternatives, reasons, evidence, status), redacted before storage; older ledgers stay readable. /ledger export decisions prints them as Markdown. Nothing is written to a project.
  • Completion integrity: a change to the implementation after the goal check (main session, helper, or any tool that changes the git working tree) returns the goal check to PENDING, clears the criterion evaluations and sets passed gates back to pending, even after DONE. Unknown criterion statuses are refused, the plan's goal is classified, a failed milestone clears the evidence, and /cockpit discovery auto never lowers a level. The fingerprint is of file contents against a commit (staging and committing change nothing), is settled into the task at once, and the goal check is refused over a tree that changed after the checks were observed. Coverage gaps (no git, ignored files, prompts from other origins, a model that never calls the progress tool) are listed in the README.
  • Release-review budget: a mandatory release consultation no longer shares the three-per-task discretionary budget. It is tied to the full commit id of a clean working tree (unidentifiable candidates fail closed), is limited to one returned review and one retry per commit and six per session, is recorded in the plugin store across restarts, and is taken back when the commit or the tree changes. Discretionary consultations stay at three per task and are now also bounded at twelve per session.
  • Original-goal check: a coding task above LIGHT stays UNVERIFIED until align reports ALIGNED. Explicit acceptance criteria are mandatory above LIGHT: without them alignment is BLOCKED (CRITERIA / MISSING) and DONE is refused; each criterion needs its own observation-naming evidence (basis reported), and edits, replans, revised criteria, failing gates or reopened unknowns make earlier evidence stale. It is a hold inside the existing progress model, beside the six gates and any mandatory Opus consultation, never in place of them.
  • Release-approval integrity: the architect's recommendation is exactly one DECISION: GO or DECISION: NO-GO line (a missing, repeated, conflicting, hedged, differently cased or decorated line approves nothing). A recorded recommendation is final, a later turn of an architect that already returned is kept beside its answer and changes neither it nor the consultation, and a release review fulfils an explicit request for Opus only when both grounds were raised by the same prompt (recorded as provenance, and withdrawn with the release approval). A mandatory review raised before any plan survives later prompts until Opus has answered it.
  • scripts/dev-launch.sh: a guarded Auto-mode development launcher that loads an out-of-tree snapshot and refuses an empty or overlapping plugin directory. See docs/development-auto-mode.md.
  • /cockpit discovery shows and pins the level for the session.
  • Existing fixtures that exercise milestones and gates only now pin LIGHT; the shared test helper reports the goal check after the gates.
  • Details, schema, measurements and limits: docs/implementation-v0.5.1-discovery.md.

0.5.0 — Sonnet-led profile and session router#

The session router:

  • New /cockpit router: each session chooses off (the default in every new session), nobodywho (the local decision router, local provider only) or jev (the same router's TypeSafe JEV provider). The choice is session state and is never saved. One router is active at a time, and a switch discards what the previous one said.
  • A router recommends one of five routes for a new task: handle it directly, scout with Haiku, delegate to Sonnet, consider a higher effort, or consider an Opus consultation. It starts, admits and approves nothing. The rules go first: when they settle the route no router is asked, and a recommendation for Opus is refused unless a consultation ground already holds, in which case you are shown a notice instead.
  • Position-independent questions. The local classifier's first-option bias was traced to the router's seeded shuffle, which never reorders a two-option list, combined with early stopping. Cockpit now asks five fixed yes/no features, each in both orders, and discards a reading when fewer than four agree or more than three are affirmed.
  • JEV is external: since the security audit it receives fixed-vocabulary keywords and a size bucket, never prompt text (NobodyWho, which stays on your machine, still sees up to 400 characters). A prompt in which credential-shaped text is recognised, including AWS ASIA key IDs, is not sent to either router. Orchestration free text and consultation packets are redacted before they are stored.
  • Each decision is a bounded ledger record: provider, model, receipts, both latencies, the recommendation, and whether the rules accepted it. Router figures are never counted as model usage.
  • Removed before release: the localAdvice option and the router call at Opus admission. Admission is by the rules alone.
  • Measurements, limits and the live acceptance are in docs/delivery-v0.5.0-router.md.

Found by independent review before release, and fixed:

  • A mandatory Opus review could be discharged without an answer from Opus: by planning again, by a verdict on a consultation that never ran, by a consultation on a different ground, or by adopting another agent into it. A new plan now inherits the review, a verdict is accepted only once the architect has run and finished, only a consultation on one of the review's own grounds advances it, and adoption is refused for Opus tasks.
  • The architecture ground no longer holds on the length of the main session's own plan, only on the files the host observed or the person's words.
  • The Glob and Grep pattern refusal added for scoped helpers no longer applies to a helper that owns everything, as in 0.4.0.
  • Suite: 1049 → 1098. What an upgrading user sees is in docs/release-v0.5.0.md.

Release hardening:

  • Fixed: the Opus architect could not read the files it was consulted about. A location written path:line became its owned resource verbatim. Line references are now dropped from the read scope, which is confined to project files. A consultation that names no file reads the project, not everything as before. A Glob or Grep pattern that is absolute, home-relative or climbs out is refused, and so is a ~ path.
  • Fixed: admitted Opus consultations ran at Medium. They now request High, under the operator ceiling. The engine's applied level is recorded, and any difference is reported as a fallback. The main loop's effort is untouched.
  • Progress: when the main loop edits a second file in a task with no plan, it gets one reminder, from that observed edit. action: "gate" takes several gates at once (gates), all or none. Listing the progress tool in the prompt was measured (+768 tokens a request, no more reporting) and not adopted.
  • Root causes, measurements, the security review and the isolated live acceptance are in docs/delivery-v0.5.0-hardening.md.

The Sonnet-led profile:

  • New profile option. OPUS_LED (the default) keeps 0.4.0's models and admission. SONNET_LED means: Sonnet builds, Haiku scouts, Opus reviews. The main loop is requested on Sonnet 5.5 at the user's own effort, and Opus 5.5 runs only as an admitted, read-only cobalt-cockpit:architect consultation.
  • Opus admission (swarm action consult): a ground that must hold on evidence (architecture, security, repeated failure, explicit request, release approval) and a bounded evidence packet. One Opus at a time; an unchanged problem is consulted once; one retry; three per task. Routes around it (an unassigned Opus or architect spawn, an OPUS assignment) are refused.
  • Mandatory consultations: an explicit request for Opus, a release approval, or a change to security-sensitive files holds the task below 100% until the consultation returns and the main session verifies its advice.
  • HUD and Ledger: role labels (MAIN, SCOUT, ENGINEER, ARCHITECT, LOCAL CONTROL), consultation records (ground, decision, verification, receipt), host-reported usage per tier, and the host's cost total. Nothing is estimated.
  • SONNET_LED AUTO budgets: 4 helpers in all (2 Sonnet, 2 Haiku, 1 Opus).
  • Suite: 995 → 1023 → 1049 with the hardening. Design, migration and rollback are in docs/implementation-v0.5-sonnet-led.md.

0.4.0 — Read-only helpers deliver their reports#

  • Fixed: a read-only helper could finish its work and have no way to report it. Claude Code delivers a background helper's report through its own hand-back tool (SubagentHandback) and reaches deferred tools through tool discovery (ToolSearch). Cockpit's read-only guard refused both, so a commander running v0.3.2 was told only that the helper "ended without delivering a report", and the commander's own tool discovery was held while any helper was active. A bound helper may now use those two host control tools, and the commander's discovery is no longer held.
  • Nothing else widened. Neither tool has a resource effect. A read-only helper's write, shell command and delegation are still refused, a tool that discovery surfaces still passes its own ownership guard and Claude Code's permission check, and a hand-back records only the calling helper's own report.
  • Each task now records how its report arrived, in swarm status and the Run Ledger: reported (the helper filed a structured result), host_accepted (the host accepted its hand-back), answer_observed (an ordinary final answer was observed) or unavailable (the host reported completion with no answer). A lost report is visible instead of silently absent. None of these states is verification; only the commander verifies.
  • New host-hook tests hold the fix and its limits: discovery and hand-back delivery, concurrent read-only reports beside a failing sibling, no write consent from discovery, a preserved native rejection, completion racing inside the hand-back tool, a report kept across an interruption, and a host completion with no answer evidence. Suite: 987 → 995.
  • Verified live on Claude Code 2.1.295 before release, with real Opus, Sonnet and Haiku sessions: interactive background helpers delivered through the hand-back tool (host_accepted); headless foreground and background helpers delivered as answers; two concurrent helpers both delivered; a read-only helper's Write and shell command were refused, and still refused after it used tool discovery; a cancelled helper ended cancelled. Details are in docs/release-v0.4.0.md.
  • No setting was added and no default changed. Saved preferences and Run Ledgers are kept on update.
  • The optional memory and browser companion that was developed in this repository (commits 6700483 and 796171e) has moved to its own repository, echelong/cobalt-capabilities, with its own releases. This plugin's folder holds only Cockpit again, and Cockpit neither installs nor needs the companion.

0.3.2 — Directory compliance and fail-closed guards#

  • A hook that fails no longer lets an action through. The engine skips a hook that throws, times out or answers a wrong shape and runs what is beneath it, so every Cockpit hook that can refuse now carries a .catch handler that refuses in its place: the tool guard, the agent-offer and agent-spawn guards, the /config row guard, the /model and /advisor guards, the checkpoint commands and /cockpit itself. This closes a real fail-open in the blast-radius, ownership and Fable gates. Hooks that only observe still forward.
  • Decided with the engine's own rule for each event: a guard that had already passed the call on leaves that result standing (next.called), and a handler judges the event it was given with the hook's own predicate, so a failure does not refuse a /model opus, an ordinary /config row, /advisor off or an ordinary agent type.
  • turn.step cannot fail before it decides. A hook that throws before next is skipped, and this one's decisions are the Fable, subscription and strict-advisor refusals, so its two pre-decision readings (taskOfAgent and the ownership heartbeat) are wrapped in a new quietly helper. It carries no .catch handler: for a streaming event the handler must itself be a generator, which the engine's failure rule for is not verifiable here.
  • An unescaped invisible character was removed from the hooks module: the Fable policy's character class and two test strings carried six format code points (U+00AD, U+200B, U+200F, U+2060, U+2064, U+FEFF) typed literally. They are written as escapes now, with the same meaning. No other file in the repository carries a format character.
  • The name next is the pass-through parameter and nothing else: the preferences patch, an iterator step, a React key and the swarm accumulators that shared the name are renamed, so a reader or a scanner cannot mistake them for a pass-through.
  • tool.call hands the engine its own event when the guards, the effort policy and the read-only shell rewrite changed nothing; the copy goes on only when something in it was changed. agent.spawn and prompt.submit write their one intentional change as an explicit branch instead of a ternary.
  • agent.offer and attribution.text are block-bodied hooks with explicit answers.
  • scripts/audit-public.py now refuses an unescaped format character in any shipped file, a pass-through named for something else in the hooks module, and any hook that can refuse without a .catch handler.
  • 20 new tests (tests/compliance.test.ts) hold every handler, its fail-closed decision, the event it judges, and the pass-through rule above. Suite: 960 → 980. claude plugin validate --strict --json lists 18 gating hooks, every one with a handler.
  • The listing icon is VECTOR's own portrait, rendered rather than redrawn: scripts/make-icon.py prints mascotSvg from hooks/mascot.ts and scales it whole, 36×, onto the page's void ground. 1024×1024, 8-bit RGB, 32,706 bytes, no text or profile chunks, byte-identical across runs. The manifest's icon field names it (kept out of the marketplace entry, where the validator reads that field as unknown). scripts/audit-public.py now checks it: square, 512–2048 px, under 2 MB, complete PNG, no metadata.
  • Cockpit no longer has a hook on the permission check. The directory's two blocking findings, read from its own per-finding report on main @ 310da52, were neither of the two this release first guessed at. MOD_PERMISSION_ANSWER_UNREAD named the tool.check watcher, which returned the engine's verdict through a name after reading it to light the HUD's "Needs approval" state; the directory confirms a hook there only when its return is the pass-through itself. The watcher enforced nothing, so it is removed rather than rewritten, and no permission query replaces it. Every guard is where it was, in tool.call, agent.spawn, agent.offer, config.set, prompt.submit and turn.step.
  • Changed: the HUD no longer shows QUERY, and a subagent row no longer reads "Needs approval", while Claude Code's own permission dialog is open. Questions put to you and Cockpit's own asks still do.
  • MOD_IMPORT_DYNAMIC_MISSING named a type in hooks/replay.ts written as an import call, which the directory read as a file loaded while the mod runs. That type and three more like it (hooks/field.ts, hooks/orchestra.ts) are now named through each file's static import type. Types only: nothing loads differently.
  • scripts/audit-public.py refuses an import call anywhere in the hooks, a $.tool.check query, and a tool.check hook that returns anything but next(e). Seven tests hold that ordinary allowed calls cause no permission query and that a cancelled destructive command, a Fable route and an unowned write are still refused. Suite: 980 → 987; 17 gating hooks, each with a handler.
  • Documentation: docs/implementation-v0.3.2.md records the directory findings, what could not be reproduced locally, the external-behaviour inventory, the icon's provenance, and how to re-run the portal's validation.

0.3.1 — Effort fidelity#

  • A subagent's reasoning level is now set natively, on its own Agent call's effort parameter (Claude Code 2.1.292 or newer), instead of by rewriting each request. It is per invocation, so parallel agents never share a setting, and the level the engine resolves is the one recorded as applied.
  • Fixed: a requested HIGH could silently become MEDIUM. The engine's reported level describes the loop's own settings and does not include a turn.step rewrite, so it read MEDIUM for a request that carried HIGH; that report was taken for a downgrade, the level was dropped from the observed capability map, and later requests really were clamped. A report of a request this plugin rewrote is no longer recorded as applied, warned about or learned from.
  • Fixed: a subagent's first request could arrive before its spawn was bound to its task and ran at the tier's baseline instead of the assigned level. The task is now found by the id its description carries.
  • Fixed: the main Opus loop's effort was rewritten to HIGH on every request, over an explicit /effort, --effort or CLAUDE_CODE_EFFORT_LEVEL. Cockpit no longer writes the main loop's effort at all: the level the engine resolved is sent untouched and recorded as the engine's, with what was seen of its origin (the variable, a /effort of this session, the settings, or the host's own). AUTO, MANUAL, the maxEffort ceiling and subagent launches leave it alone, and maxEffortLevel caps it visibly, with both levels named.
  • Changed: with no effort selected anywhere, the main loop now runs at Claude Code's own default for the model rather than a HIGH that Cockpit forced. That default was measured as MEDIUM for Opus 5.5 in an offline run of Claude Code 2.1.294 (an account's own default may differ); run /effort high once (it is saved) to keep the earlier level. /cockpit version names what AUTO would have chosen, as advice.
  • The engine's own limits take precedence and are visible: maxEffortLevel, an organization's cap, CLAUDE_CODE_EFFORT_LEVEL and model support decide a subagent's final level, and a level resolved differently from the one asked for is named (EFFORT FALLBACK) with both levels.
  • A level put on the Agent call by hand is respected as the task's requested level when the assignment names none; the assignment's own level and the operator ceiling still win.
  • The Run Ledger distinguishes a level the engine resolved (engine, observed) from one this plugin requested by rewrite (request, observed unknown). /cockpit version names which of the two a subagent's level uses.
  • An observation of a level above the requested one no longer marks the requested level as supported.

0.3.0 — Dynamic reasoning#

  • Task-aware reasoning effort: AUTO selects a level from the work, a commander can name one per assignment, and MANUAL honours fixed per-tier levels.
  • Separate requested and applied effort, an operator maxEffort ceiling, and per-model capability fallback that is named (EFFORT FALLBACK) rather than hidden.
  • Capability is learned only from the engine's own reported applied level; a downgrade removes the level, an honoured request adds it, and the observed map is persisted in plugin state.
  • One-step escalation of a failing task: effort within the tier first, then Haiku → Sonnet → Opus, bounded by a budget and never a jump to the top.
  • HUD and pane show the reasoning mode and applied effort; /cockpit version prints the loaded version, source path, reasoning mode, ceiling and observed capability.
  • New reasoningMode and maxEffort configuration options.

0.2.0 — Elastic swarm#

  • Claude-native commander, Sonnet engineering pool and Haiku utility pool with independent resource budgets.
  • Explicit task ownership, queueing, dependencies, waves, cancellation intent, structured handoffs and commander verification.
  • Schema-two Run Ledger with schema-one migration, lifecycle replay and bounded tier aggregation.
  • Preserve read-only NobodyWho telemetry, milestone gates and park/resume.

0.1.1 — First public release#

  • Cyberpunk HUD, VECTOR / Activity Field, milestones and verification-gated DONE.
  • Main/subagent orchestration telemetry, radar, context and Git/activity tracking.
  • Local Run Ledger and sanitized JSON export.
  • Bounded replay and deterministic park/resume checkpoints.
  • Blast-radius and repository-hygiene guards; graceful audio fallback.
  • Hot reload persistence and engine image-view compatibility.
  • Optional, read-only NobodyWho Decision and Pruning telemetry.
  • Public observation defaults and opt-in strict Cobalt architecture.
  • Portable synthetic fixtures, privacy documentation and preserved MIT notices.
SITE HUDSOURCE / 2dbeaf1 · mainVERSION / 0.6.5 (manifest on main)SYNC / via GitHub APIHow this page stays current

Suggested

  • PAGEInstall

    Two commands, then /cockpit

  • PAGECommands

    Every documented command

  • PAGEConfiguration

    Every option and its default

  • PAGEDiscovery, decisions and goal check

    What DONE requires

  • PAGESafety and trust

    What Cockpit observes, stores and never approves