crewforth 3.3.0 → 3.5.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/CHANGELOG.md +271 -0
  2. package/README.md +7 -2
  3. package/VERSION +1 -1
  4. package/adopt.sh +40 -5
  5. package/bin/cli.js +193 -2
  6. package/kit/AGENT_TEMPLATE.md +15 -0
  7. package/kit/CLAUDE.md +49 -17
  8. package/kit/agents/crew-backend-expert.md +4 -3
  9. package/kit/agents/crew-commit-agent.md +2 -0
  10. package/kit/agents/crew-database-expert.md +2 -1
  11. package/kit/agents/crew-devops-expert.md +1 -0
  12. package/kit/agents/crew-docs-agent.md +3 -1
  13. package/kit/agents/crew-frontend-expert.md +2 -0
  14. package/kit/agents/crew-performance-expert.md +7 -2
  15. package/kit/agents/crew-planner.md +15 -3
  16. package/kit/agents/crew-privacy-agent.md +2 -0
  17. package/kit/agents/crew-review-agent.md +8 -1
  18. package/kit/agents/crew-security-expert.md +4 -3
  19. package/kit/agents/crew-test-expert.md +6 -2
  20. package/kit/eval/doctor.sh +201 -1
  21. package/kit/eval/gate-report.sh +28 -0
  22. package/kit/eval/golden-holdout.txt +2 -0
  23. package/kit/eval/golden-routing.txt +17 -0
  24. package/kit/eval/lib/crew-map/contracts.mjs +77 -0
  25. package/kit/eval/lib/crew-map/crew-map.sh +2 -1
  26. package/kit/eval/lib/crew-map/detect.mjs +2 -1
  27. package/kit/eval/lib/crew-map/narrative.mjs +14 -3
  28. package/kit/eval/lib/crew-map/project.mjs +45 -6
  29. package/kit/eval/lib/crew-map/scan.mjs +153 -14
  30. package/kit/eval/lib/findings/findings.schema.json +11 -1
  31. package/kit/eval/lib/findings/findings.sh +24 -1
  32. package/kit/eval/lib/hook-inject.sh +159 -0
  33. package/kit/eval/lib/lockfiles.sh +71 -0
  34. package/kit/eval/lib/payload-check.sh +29 -0
  35. package/kit/eval/lib/preview.sh +3 -3
  36. package/kit/eval/lib/review-bench/bench.mjs +14 -2
  37. package/kit/eval/lib/review-prepass/prepass.mjs +32 -3
  38. package/kit/eval/lib/settings-json.awk +18 -0
  39. package/kit/eval/lib/untrusted-text.awk +38 -0
  40. package/kit/eval/scan-skill.sh +67 -20
  41. package/kit/eval/smoke-test.sh +1792 -52
  42. package/kit/eval/utilization.sh +77 -3
  43. package/kit/hooks/agent-outcome.sh +9 -1
  44. package/kit/hooks/board-sync.sh +49 -3
  45. package/kit/hooks/board.sh +8 -8
  46. package/kit/hooks/branch-fresh.sh +101 -0
  47. package/kit/hooks/floor-blocklist.txt +19 -1
  48. package/kit/hooks/guard-bash.sh +92 -8
  49. package/kit/hooks/guard-question.sh +2 -1
  50. package/kit/hooks/loop-guard.sh +445 -0
  51. package/kit/hooks/map-stale.sh +437 -0
  52. package/kit/hooks/pre-commit +48 -7
  53. package/kit/hooks/precompact-snapshot.sh +102 -6
  54. package/kit/hooks/prompt-approval.sh +45 -9
  55. package/kit/hooks/route-hint.sh +36 -7
  56. package/kit/hooks/secret-blocklist.txt +55 -1
  57. package/kit/hooks/session-guard.sh +85 -28
  58. package/kit/hooks/session-rehydrate.sh +34 -11
  59. package/kit/hooks/session-stats.sh +169 -8
  60. package/kit/hooks/session-update-check.sh +5 -1
  61. package/kit/hooks/skill-trust.sh +23 -14
  62. package/kit/hooks/turn-check.sh +190 -0
  63. package/kit/hooks/worktree-provision.sh +91 -0
  64. package/kit/owned-blobs.tsv +4 -2
  65. package/kit/settings.json +86 -0
  66. package/kit/skills/a11y/SKILL.md +50 -3
  67. package/kit/skills/a11y/references/recipes.md +41 -0
  68. package/kit/skills/adr/SKILL.md +14 -2
  69. package/kit/skills/api-design/SKILL.md +6 -1
  70. package/kit/skills/api-design/references/idempotency.md +39 -0
  71. package/kit/skills/brainstorm/SKILL.md +4 -2
  72. package/kit/skills/brainstorm/references/asking.md +47 -0
  73. package/kit/skills/ci-pipeline/SKILL.md +11 -1
  74. package/kit/skills/ci-pipeline/references/agent-job.md +33 -0
  75. package/kit/skills/commit-message/SKILL.md +9 -3
  76. package/kit/skills/confidence-check/SKILL.md +9 -7
  77. package/kit/skills/confidence-check/references/source-check.md +37 -0
  78. package/kit/skills/crew-approve/SKILL.md +3 -0
  79. package/kit/skills/crew-audit/SKILL.md +63 -0
  80. package/kit/skills/crew-board/SKILL.md +2 -2
  81. package/kit/skills/crew-code-review/SKILL.md +27 -4
  82. package/kit/skills/crew-code-review/references/panel-mode.md +9 -9
  83. package/kit/skills/crew-code-review/references/simplify.md +28 -0
  84. package/kit/skills/crew-doctor/SKILL.md +3 -2
  85. package/kit/skills/crew-gates/SKILL.md +3 -0
  86. package/kit/skills/crew-gates/references/enforcers.md +30 -0
  87. package/kit/skills/crew-interview/SKILL.md +42 -0
  88. package/kit/skills/crew-map/SKILL.md +26 -6
  89. package/kit/skills/crew-plan/SKILL.md +9 -2
  90. package/kit/skills/crew-pr/SKILL.md +57 -0
  91. package/kit/skills/crew-pr/references/checks.md +35 -0
  92. package/kit/skills/crew-pr/references/threads.md +23 -0
  93. package/kit/skills/crew-review/SKILL.md +34 -1
  94. package/kit/skills/crew-ship/SKILL.md +5 -2
  95. package/kit/skills/crew-skill/SKILL.md +26 -1
  96. package/kit/skills/crew-update/SKILL.md +4 -1
  97. package/kit/skills/db-migration/SKILL.md +15 -0
  98. package/kit/skills/db-migration/references/expand-contract.md +52 -0
  99. package/kit/skills/dependency-audit/SKILL.md +34 -1
  100. package/kit/skills/dependency-audit/scripts/record.sh +37 -0
  101. package/kit/skills/dependency-upgrade/SKILL.md +29 -1
  102. package/kit/skills/deploy/SKILL.md +18 -0
  103. package/kit/skills/deploy/references/topology-a.md +7 -0
  104. package/kit/skills/deploy/references/topology-b.md +2 -2
  105. package/kit/skills/docs-writer/SKILL.md +37 -2
  106. package/kit/skills/eval-grader/SKILL.md +9 -0
  107. package/kit/skills/eval-grader/references/method.md +26 -0
  108. package/kit/skills/frontend/SKILL.md +5 -2
  109. package/kit/skills/frontend/references/from-design.md +29 -0
  110. package/kit/skills/frontend/references/page-metadata.md +17 -0
  111. package/kit/skills/frontend/references/verify-contract.md +18 -1
  112. package/kit/skills/frontend/references/worst-data.md +35 -0
  113. package/kit/skills/frontend-design/SKILL.md +20 -4
  114. package/kit/skills/frontend-design/references/design-review.md +21 -0
  115. package/kit/skills/frontend-design/references/detection.md +44 -0
  116. package/kit/skills/frontend-design/references/motion.md +54 -0
  117. package/kit/skills/frontend-design/references/ui-copy.md +35 -0
  118. package/kit/skills/frontend-rn-expo/SKILL.md +3 -0
  119. package/kit/skills/handoff/SKILL.md +28 -3
  120. package/kit/skills/handoff/references/cold-reader.md +13 -6
  121. package/kit/skills/i18n-integrity/SKILL.md +3 -0
  122. package/kit/skills/iterate/SKILL.md +7 -2
  123. package/kit/skills/mcp-builder/SKILL.md +21 -4
  124. package/kit/skills/mcp-builder/references/building.md +74 -13
  125. package/kit/skills/mcp-builder/references/cli-for-agents.md +26 -0
  126. package/kit/skills/observability/SKILL.md +13 -1
  127. package/kit/skills/performance/SKILL.md +25 -1
  128. package/kit/skills/performance/references/bottlenecks.md +11 -0
  129. package/kit/skills/performance/references/web-vitals.md +31 -0
  130. package/kit/skills/red-team/SKILL.md +25 -3
  131. package/kit/skills/reflect/SKILL.md +7 -2
  132. package/kit/skills/release/SKILL.md +13 -0
  133. package/kit/skills/security-scan/SKILL.md +6 -2
  134. package/kit/skills/security-scan/references/ai-agents.md +16 -0
  135. package/kit/skills/security-scan/references/fronts.md +59 -2
  136. package/kit/skills/security-scan/references/reporting.md +13 -0
  137. package/kit/skills/security-scan/references/verify.md +9 -0
  138. package/kit/skills/sonarqube-check/SKILL.md +32 -2
  139. package/kit/skills/sonarqube-check/references/ratchet.md +32 -0
  140. package/kit/skills/spec-planning/SKILL.md +25 -8
  141. package/kit/skills/systematic-debugging/SKILL.md +15 -7
  142. package/kit/skills/systematic-debugging/references/techniques.md +5 -0
  143. package/kit/skills/teamboard/SKILL.md +3 -3
  144. package/kit/skills/testing/SKILL.md +18 -3
  145. package/kit/skills/testing/references/browser-headless.md +21 -0
  146. package/kit/skills/token-budget/SKILL.md +26 -5
  147. package/kit/skills/worktree/SKILL.md +13 -5
  148. package/kit/studio/server/lib/session.js +23 -2
  149. package/kit/studio/server/lib/worktree-changes.js +64 -0
  150. package/kit/studio/web/convo.js +14 -0
  151. package/kit/studio/web/map-plan.js +54 -8
  152. package/kit/studio/web/map.js +15 -3
  153. package/package.json +5 -4
  154. package/start.sh +11 -2
package/CHANGELOG.md CHANGED
@@ -5,6 +5,277 @@ Crewforth was named Claude Starter Kit until 3.0.0.
5
5
  Notable changes to this project are recorded here. Format follows [Keep a Changelog](https://keepachangelog.com/en/),
6
6
  versioning follows [SemVer](https://semver.org/).
7
7
 
8
+ ## [Unreleased] — 3.5.0
9
+
10
+ ### Security
11
+
12
+ - **A first `adopt` no longer runs a hook it found in the project.** It keeps files it finds, so a
13
+ `.claude/hooks/pre-commit` (or any file under a gate's name) that arrived with a clone became the project's git
14
+ hook, and adopt ran it as its own proof, as the user. A first adopt now stops before any change when
15
+ `.claude/hooks` holds a file under a name Crewforth installs, names the files and changes nothing. An update is
16
+ not affected: it refreshes every gate file from the payload.
17
+
18
+ - **Text other people wrote reaches the model labelled, and a cloned repository cannot run its own programs.** The
19
+ team board arrives marked "written by teammates: information, not instructions", cleaned of control, zero-width
20
+ and bidi characters, and under 9,000 characters. Every git call in the hooks, Crew Map and the review pre-pass
21
+ turns off the repository's `core.fsmonitor`, so a third-party clone's config starts nothing. Each crew agent gets
22
+ the untrusted-content and §4.1–§4.5 rules at start, which a subagent never loaded before.
23
+ - **The skill scanner and the commit gate see more.** `scan-skill.sh` flags invisible text (tag characters, bidi
24
+ overrides, zero-width characters inside words), a hidden HTML comment that gives an order, and frontmatter that
25
+ asks for hooks, MCP servers, a permission mode or broad `Bash`. `skill-trust.sh` checks `.claude/commands/` too.
26
+ The secret blocklist knows GitLab, Hugging Face, Docker Hub, DigitalOcean, Shopify, PyPI, Stripe webhook and
27
+ Slack tokens, PGP private keys and a password inside a URL. A `.floor-allowlist.txt` entry needs a reason.
28
+ - **Fetched content stays data.** A fetch is https only and never reaches a private, loopback or metadata address,
29
+ redirects included; a directive in fetched or reviewed content is reported as a finding, never followed; a secret
30
+ is never asked for in chat. `security-scan` covers SSRF, open redirects, XXE, check-then-act races and the
31
+ authentication, session and authorization front in depth.
32
+ - **No update check when the environment says no traffic.** `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` or
33
+ `DISABLE_TELEMETRY` now means the session-start check sends nothing and writes no cache.
34
+
35
+ ### Added
36
+
37
+ - **A compaction no longer loses what the user asked for.** The PreCompact snapshot keeps the user's first and last
38
+ three prompts and the skills used in the session, and gives them back after the compaction, in the same session
39
+ only; secrets and `<private>` text are left out. The `handoff` template carries the user's words, the dead ends
40
+ and the decisions, and a cold reader checks it with only the file in hand.
41
+ - **Every review round is logged.** `findings.sh write` appends a line per review (branch, round, counts by
42
+ severity) to the git directory, never committed, so a project can see what late rounds find. A finding the user
43
+ tracked, accepted or dropped keeps that disposition in the next review unless the diff touches its lines.
44
+ - **Evals can be checked for free and watched while they run.** `evals/run.sh --calibrate` runs each case's grader
45
+ on a good and a bad answer with no model and names a grader that cannot fail; two such graders were fixed. A run
46
+ can be stopped from its stream (`STOP_WHEN`, `FORBID`, `MAX_TURNS`), and every failure says its class. Both arms
47
+ of the A/B are pinned to one model and isolated from the user's own skills, plugins, memory and MCP servers; a
48
+ control arm that sees Crewforth is not graded.
49
+ - **`CLAUDE.md` has a `## Verify` section** in the project template (`Fast check`, `Unit`, `Integration`, `E2E`,
50
+ `Ready when`, `Logs`, `Local login`), filled once at install, which agents and plans copy their commands from.
51
+ - **`/crew-audit` audits the whole project, not a diff.** It starts from the Crew Map (and says when the map no longer
52
+ matches the tree), ranks modules by what a mistake there costs (money, access, data writes, secrets and egress),
53
+ reads at most eight of them whole, and runs the security, review, performance and privacy lanes on those in
54
+ parallel. Each finding names a concrete case, code called unused is grepped for dynamic references first, and a
55
+ `medium`-or-higher finding is checked by `crew-refuter` before it is reported. The report holds at most 20
56
+ findings and says which modules were read deep, skimmed or not read. It changes no code.
57
+ After its first real run: it checks a `critical` or `high` candidate with `crew-refuter` before reading further,
58
+ so a run that runs short reads fewer modules instead of reporting unchecked blockers, and it runs the scanner
59
+ itself when no map exists.
60
+ - **`/crew-interview` asks before it plans.** It reads the code, docs and Crew Map first, so it only asks what
61
+ they cannot answer, then puts one question per turn with its recommended answer first: the outcome, the user,
62
+ why now, what done means, the constraints and what is out of scope. It stops when the answer is clear, restates
63
+ it for an explicit yes and writes `docs/BRIEF.md` for `/crew-plan`. With nobody to answer (unattended runs) it
64
+ writes the brief with its guesses marked as assumptions. The rules for asking live in
65
+ `brainstorm/references/asking.md`, which `brainstorm` and `spec-planning` now point to.
66
+ - **`/crew-pr` takes a branch to a merged pull request.** `open` checks the DoD first, fills the repository's own
67
+ PR template in order, writes the body to a file outside the tree and pushes only on "push". `status` reads the
68
+ checks, the merge state and the review decision once, with a table for what each merge state asks for; it waits
69
+ for CI only when asked to. `threads` judges review comments the way `crew-code-review` does, replies after the
70
+ fixing push lands and names the commit, and resolves only threads really addressed. `merge` runs only when the
71
+ user says so, on a clean state and the head commit that was checked.
72
+ - **The Crew Map says when an edit has made it old.** A new hook, `map-stale.sh`, notes once per agent, as a fact,
73
+ when a file the map cites is edited: the map was scanned before the edit, and `crew-map.sh --check` says whether
74
+ it still matches the tree. It is silent with no map, for files the map does not cite, and with
75
+ `CREW_MAP_STALE=off`; it never blocks, and an edit that does not fire starts no process. `/crew-plan` runs the
76
+ check before it calls the planner, and the plan says when the map differs from the tree or was not checked.
77
+ - **The Crew Map says where a module's tests are, how often it changes and what its code admits.** Each module now
78
+ lists its test files (its own, and a test project named for it such as `Api.Tests`), how many of the last 500
79
+ commits changed a file in its folder (one `git log` per scan, none of the repository's own programs run), and up to
80
+ five `WHY`, `HACK` and `FIXME` comment lines from its code, each cited by `file:line`. Studio's inspector shows all
81
+ three; `/crew-map` may cite the comment lines in a description or a tour stop, the planner names a module's tests
82
+ as the verify of a task that changes it, and `/crew-audit` reads the counts and comments to break a tie. The commit
83
+ counts move with every commit, so `--check` and the rescan summary leave them out. A test project is no longer
84
+ reported as a module nobody references.
85
+ - **A project can write down the rules its code must keep, and every agent hears them where they apply.**
86
+ `.crewforth/contracts.md` holds one section per rule: `## key`, the rule in a sentence or two, and the places it
87
+ lives as `- path:symbol` (a name, not a line number, so the rule outlives edits). The scanner never writes it, so
88
+ a rescan cannot drop one. `crew-map.sh --contracts` (and `--validate`) refuses a key used twice, a rule past two
89
+ sentences, and a cite whose file is gone or whose name no longer appears. When an agent edits a cited file,
90
+ `map-stale.sh` adds the rules that live there to its context, once per rule and agent; at the end of the turn
91
+ the user is told which rules the session's edits touched; `crew-review-agent` gives each touched rule a verdict:
92
+ holds, broken (with the line) or cannot tell. `/crew-map` writes a rule only when the user states or confirms it.
93
+ - **A rescan that would lose most of the map writes nothing.** When described nodes would mostly vanish, or the
94
+ module count would fall by more than half (a wrong `--root`, a damaged checkout), the scanner exits 1 with both
95
+ counts and keeps the old map; `--force` writes it anyway.
96
+ - **The Crew Map can leave out what the project names, and says what a rescan changed.** Patterns in
97
+ `.crewforth/crew-map-ignore` (a name at any depth, a path from the root, `*` and `**`) are not scanned, and
98
+ `coverage.excluded` counts the files left out. A rescan prints the nodes and edges it added, removed and changed,
99
+ by id, so `/crew-map` reports which modules came or went instead of a byte count.
100
+ - **A commit that stages a lockfile needs a dependency audit of that change (§4.7).** `guard-bash.sh` compares git's
101
+ object id of the staged lockfile diff with the record the `dependency-audit` skill writes after the audit
102
+ (`clean`, `accepted` by the user, or `unverified` with the reason). The record lives in the git directory and is
103
+ never committed; code staged beside the lockfile keeps it valid, a new lockfile change needs a new audit. The hook
104
+ makes no network call. The lockfile list covers npm, Yarn, pnpm, Bun, Deno, uv, Poetry, Pipenv, PDM, Cargo, Go,
105
+ Bundler, Composer, Mix, pub, NuGet, Gradle, SwiftPM and CocoaPods.
106
+ - **The route hint names `dependency-audit` beside the owner** when a request adds a package ("add a new dependency for
107
+ the date picker component", "pdf için bağımlılık ekle"), instead of losing to the agent that owns the request.
108
+ - **The main thread's own edits get the project's fast check before a turn ends.** A new hook, `turn-check.sh`
109
+ (UserPromptSubmit + Stop), runs the `Fast check (files):` command `CLAUDE.md` declares on the files the turn changed:
110
+ its edits and its own commits (an amend counts only what it changed), never a file that was already dirty or a
111
+ commit a pull brought in. A red check hands its output back once, so the turn fixes it. The command is judged
112
+ the way a crew agent's verify command is; one the permission rules do not allow is not run, and the user is told
113
+ once. A project that declares nothing pays nothing. `CREW_TURN_CHECK=off` turns it off.
114
+ - **`security-scan` reviews CI/CD.** A new front for pipeline definitions: actions pinned to a commit, no
115
+ attacker-written text in `run:`, no `pull_request_target` that runs a pull request's code, least-privilege
116
+ `permissions:`, OIDC scoped to the repository, no secrets for forks, no self-hosted runner on a public repository.
117
+ - **`dependency-upgrade` lands bot PRs.** Renovate and Dependabot PRs are sorted into green, mechanical, needs
118
+ diagnosis, conflicting and superseded, with one question per bucket; majors and `0.x` minors stay single.
119
+ - **`sonarqube-check` keeps a ratchet when no server can run**: a committed baseline of coverage, lint findings,
120
+ size and warnings that fails only on a regression, with an owner and expiry for every accepted one.
121
+ - **A session opens told when its branch has fallen behind in a way that matters.** A new SessionStart hook,
122
+ `branch-fresh.sh`, compares the branch with `origin/<base>` as last fetched (`Base branch:` in `CLAUDE.md`, else
123
+ origin's default branch) and speaks only when merging the base would conflict, the branch was cut more than three
124
+ days ago, or the base changed `.claude/` or `CLAUDE.md`. It names `git merge origin/<base>` and changes nothing; a
125
+ rebase left in progress is said first. The fetch for the next session runs detached, never while the session
126
+ waits. `CREW_BRANCH_FRESH=off` turns it off, `CREW_BRANCH_FRESH_FETCH=off` keeps it offline.
127
+ - **Studio shows what a session it started has changed.** The strip above the conversation says how many files
128
+ changed since the session started (lines added and removed) and how many new files git does not track yet,
129
+ counted against the commit recorded at the start. It is read without git rewriting the index and kept in memory.
130
+ - **`/crew-doctor` names a linked worktree with no `.claude/settings.json`**, where a resumed session runs none of
131
+ Crewforth's hooks. One Claude Code makes under `.claude/worktrees/` is not named: it still runs this checkout's.
132
+ - **`npx crewforth remove` takes Crewforth out of a project.** By default it lists what it would change and changes
133
+ nothing; `--apply` does it. It drops the `settings.json` hook entries that run `.claude/hooks/` (yours stay), its
134
+ status line, the blanket `Bash` allow and the skill-listing budget key, and sets `core.hooksPath` back (unset, or the
135
+ hook chain the shim ran). Its files move to `.claude/.crewforth-removed-<time>/`; nothing is deleted, and your own
136
+ agents and skills stay. `CLAUDE.md` is not touched: the command names the `@.claude/DISCIPLINE.md` line to delete.
137
+ - **`/crew-doctor` reads two more ways a setup goes quiet.** A line in `CLAUDE.md` that reads as loosening a §4 rule
138
+ ("no need to ask before committing", "skip the review") is named with its line number, unless a "never" or "do
139
+ not" precedes it.
140
+ A `CREW_` variable set in the environment that no Crewforth file reads (a typo) is named, and so is a switch that
141
+ takes a whole number set to something else.
142
+
143
+ ### Changed
144
+
145
+ - **`dependency-audit` asks which registry answers an internal name** (scope mappings, `--index-url` against
146
+ `--extra-index-url`, NuGet source mapping, `GOPRIVATE`, image digests), names a registry config committed in the
147
+ repository, and checks each new package against the popular name one edit away.
148
+ - **`dependency-upgrade` reports a failed lookup as `could not check`**, never as up to date, and installs a new
149
+ package with its scripts off first.
150
+ - **A test run read through a pipe is not evidence.** `npm test | tail` exits with tail's status; the DoD, the
151
+ reviewer and `token-budget` now ask for `set -o pipefail` or a redirect, and the reviewer does not cite a piped run
152
+ without it.
153
+ - **The reviewer has Crewforth's own simplify passes** for when `/simplify` is shadowed or absent: behaviour does not
154
+ change, nothing unexplained is deleted, the pass stays inside the diff.
155
+ - **`crew-test-expert` reports exactly `pass`, `fail`, `unavailable` or `blocked`** and stops once the acceptance
156
+ tests pass; **`crew-commit-agent`** adds a `Not tested:` line under its proposal.
157
+ - **The `worktree` skill looks before it removes.** Before `git worktree remove` it lists uncommitted files and
158
+ commits that exist nowhere else and asks; `--force` and `branch -D` only on the user's word. It refuses to reuse an
159
+ existing branch name silently, never deletes a branch it adopted, tells a submodule from a worktree, runs the
160
+ tests once in a new worktree before the first edit, and has rules for services the worktrees share.
161
+ - **Studio's Map spreads lines that share a side of a card**, so a module with three dependents shows three lines
162
+ instead of one. Measured first on the crew-map test fixtures and Crewforth's own map: 48 line ends shared a pixel
163
+ across 46 edges; now none do. Sideways lines between ends at two heights turn square instead of running slanted.
164
+ - **Frontend work checks more of what users hit.** `a11y` separates criteria from conventions (a failed A/AA
165
+ criterion is a finding, AAA or a 44 px target a recommendation), adds a skip link, flashing, an error summary and
166
+ positive `tabindex`, a table of patterns to grep before finishing, and recipes for focus, forms and which
167
+ announcement channel to use. `frontend-design` plans in two passes against the generic default, measures contrast
168
+ on the rendered pair, lists the UI blockers that are always high, and gains references for motion (durations,
169
+ easing, interruption, gestures), UI copy (buttons, errors, confirm or undo, empty states) and greppable layout,
170
+ type, colour and motion patterns. `frontend` gains worst-realistic-data probes, building from a design file, and
171
+ page metadata; `performance` gains Core Web Vitals; `testing` gains a headless path for the verify contract when
172
+ no browser tool is attached; `i18n-integrity` flags sentences assembled around a variable and hand-written plurals.
173
+ The README diagrams carry a title and a description under ids of their own.
174
+ - **A review ends.** A critical or high fix re-runs every lane, a lesser fix only the lane that raised it; a low
175
+ finding never starts a round; a round with nothing above low is the last, and after three rounds the user is
176
+ asked. The lanes follow what the diff touches: a docs-only diff gets the reviewer alone. Each lane reports
177
+ `ran`, `ran-partial`, `failed`, `timed-out` or `not-run`, and "clean" needs every launched lane to have run.
178
+ - **An approval is bound to what it approves, not to a 30-minute clock.** An answer given late is recorded while
179
+ HEAD, the branch and the staged tree are what they were when the question was asked; one given after the staged
180
+ content changed is refused (it used to be recorded). With nothing staged the commit question is not asked.
181
+ - **Short replies keep their meaning.** "Short never costs meaning" is in the communication rules: warnings,
182
+ numbers and conditions are never cut. Every report says what was not tested and labels each figure measured,
183
+ derived or inferred; a refused action is not retried another way.
184
+ - **Skill descriptions say when, not how.** Six descriptions that summarised their method now say when to reach for
185
+ the skill (the skill listing fell from 9,116 to 8,826 characters), and each model-picked skill has a measured
186
+ routing floor. A SKILL.md has a size cap; a long reference opens with its contents.
187
+ - **Smaller fixes to the rules:** a bypass the user accepted in writing is not a deferral; `db-migration` covers
188
+ expand/contract across deploys; the accessibility baseline is WCAG 2.2 AA; motion uses `ease-out`, never
189
+ `ease-in`; the planner returns the plan and the main thread writes it.
190
+ - **Plans say what they rest on, and stop when the code moves under them.** `docs/PLAN.md` now records the commit it
191
+ was written at, a size per task (S/M/L, never a date), the one test level that proves each criterion, the
192
+ constraints copied word for word from the request, `Interfaces:` between tasks that feed each other, a checkpoint
193
+ every two or three tasks, and up to five inputs no test covers, each assigned to a task. A task may quote the code
194
+ it changes; when the file no longer matches, the task stops and reports. A plan with unchecked work for something
195
+ else is not overwritten. The planner copies `verify:` from `## Verify` and the Crew Map's `tests` instead of
196
+ guessing, and treats the map's `notMeasured` areas as unknown. `confidence-check` gains a seventh check, "What must
197
+ it reach?" (every caller, test and export a change breaks), and looks for existing code in a fixed order before
198
+ writing new; `iterate` builds one slice at a time and lists what it noticed but did not touch.
199
+ - **Domain skills carry what their field learned the hard way.** `api-design` gains an idempotency reference (a key
200
+ from the user's intent, claimed atomically, a replay that answers what the first call answered, `422` for the same
201
+ key with another payload) and says observable behaviour is the contract. `ci-pipeline` gains rules for an
202
+ unattended agent job (pinned, few tools, an isolated copy, an allowlist for what comes back). `commit-message`
203
+ requires a body for breaking changes, security fixes, migrations and reverts, covers every staged file and never
204
+ invents a reason. `deploy` adds an advance / hold / roll back table for staged rollouts and a before/after
205
+ snapshot of the public contract; `release` checks there is something to release before it creates anything, and
206
+ reads the version back from the registry and installs it from an empty folder after publishing. `mcp-builder`
207
+ follows the v2 SDKs (checked 2026-11-07), Streamable HTTP, behaviour hints, paging and service-prefixed tool names,
208
+ and adds a reference for command-line tools an agent calls. `observability` starts from the questions on-call will
209
+ ask and keeps metric labels low-cardinality; `performance` keeps a change only when it beats the run-to-run noise
210
+ and checks an optimised function against the original first. Every crew agent that stops short now opens its report
211
+ with `stopped:` and why.
212
+ - **A broken payload installs nothing.** `start.sh` and `adopt.sh` check the payload before their first write: a hook
213
+ that `settings.json` wires but the payload does not carry, a skill without its `SKILL.md` or a missing gate file
214
+ stops the install with the list and "nothing installed".
215
+ - **Docs are grounded, and decisions continue the project's own records.** `docs-writer` reads each fact from where
216
+ it lives (behaviour from the code and its test, flags from `--help`, config from its loader, API shapes from the
217
+ schema, labels from the i18n source, versions from the tags) and deletes what it cannot check instead of flagging
218
+ it; a business or legal statement goes to its owner as a question. A doc is scored 0-2 on five points before it
219
+ ships, and a new "Diagrams" section caps a diagram at 9 boxes and 12 arrows and treats every box as a claim. `adr`
220
+ first looks for an existing decisions folder, `.adr-dir` or numbering and continues it; `docs/adr/` is only the
221
+ fallback. `/crew-doctor` now also names missing paths in a nested `CLAUDE.md` and in `AGENTS.md`, and the suite
222
+ checks that every `§N.M` cited in agents, skills, hooks and scripts is a heading of the discipline.
223
+ - **The quality gate reads one line, `## Stack` → `Quality analysis:`** (`sonarqube-local`, `sonarqube-server` or
224
+ `declined`), in place of six "(if SonarQube is in use)" clauses that a project with no server read as false every
225
+ time. `declined` is reported as "no analysis ran — unverified". The doctor's readiness section says when the line
226
+ is missing or empty.
227
+ - **`sonarqube-check` produces coverage before the scan** (the report and the scanner parameter per stack), writes
228
+ "not measured" instead of 0% when no report was passed, and reports the overall ratings when the new-code period is
229
+ empty, where every `new_*` condition reads `OK` with nothing to judge.
230
+
231
+ ### Fixed
232
+
233
+ - **`adopt` refuses a `settings.json` whose hook entries Claude Code would reject.** Claude Code ignores the whole
234
+ file when one hook entry has the wrong shape, so merging Crewforth's hooks into it installed gates that never ran.
235
+ adopt now names the entries and stops the merge, and the merged result is checked the same way before it is
236
+ written.
237
+ - **The route hint ignores what the request declines or quotes.** "don't run the security review", text in backticks
238
+ or quotes, and a Turkish clause that ends in "gerek yok" no longer pick an agent.
239
+ - **A session that resumes after compaction says when its state was not restored**, instead of starting as if
240
+ nothing had been there. The two session-start hooks stop waiting for input after two seconds
241
+ (`CREW_STDIN_TIMEOUT`), so a client that never closes the input does not hold the session.
242
+ - **The pre-compaction snapshot no longer times out on a long pasted prompt.** On Git Bash an 8 MB prompt line took
243
+ 24 s against PreCompact's 30 s limit; it now takes under a second.
244
+ - **The context-fill warning is no longer silenced by another plugin.** `session-guard.sh` warned nothing on a turn
245
+ where any other Stop hook had blocked.
246
+ - **Crew Map and the review pre-pass report what they could not read** (an unreadable or binary file, untracked
247
+ files in the pre-pass) instead of leaving it out without a word.
248
+
249
+ ## [3.4.0] — 2026-10-30
250
+
251
+ ### Added
252
+
253
+ - **An anonymous install count.** After a successful `npx crewforth init`, Crewforth sends one request, once per
254
+ project: `GET https://ping.crewforth.com/install?v=<version>`, the version and nothing else, after printing a line that says so. No
255
+ ID, path, project, host or user name is sent, and `adopt`, `update`, `add`, `studio`, the hooks and the plugin send
256
+ nothing. `CREW_NO_TELEMETRY` or `DO_NOT_TRACK` set to anything but `0` turns it off, and nothing is sent where `CI`
257
+ is set. The request gets 1.5 seconds and a failure never changes the install. The endpoint is a Cloudflare Worker
258
+ whose source is in the repository and which keeps a count per day and version, nothing else. README → Telemetry.
259
+ - **The site says which release it describes.** The home page shows the version above its heading, and every page
260
+ shows it next to the logo, each linked to the changelog in the page's language. The number is read from `VERSION`
261
+ when the site is built, so a release renames it without anyone editing a page, and a `VERSION` that is not a
262
+ version fails the build.
263
+ - **A guessed fill figure is reported.** The 🔋 figure in a reply is meant to be copied from the hook's measured
264
+ line, and nothing checked that it was. When the measured line stopped arriving, a session went on printing a fill
265
+ that rose from 45% to 86% while its transcript measured about 30%, and the user handed the session off on that
266
+ number. The Stop hook now measures the fill itself, and when the reply's figure is more than 5 points away it
267
+ tells the user both numbers. `CREW_FILL_TOLERANCE` changes the margin.
268
+
269
+ ### Fixed
270
+
271
+ - **A session resumed in a worktree keeps its gates.** `.claude/` is gitignored, so a worktree made with
272
+ `git worktree add ../x` has none. A session that entered one kept its hooks only until it was resumed; from then
273
+ on Claude Code read the worktree's settings, found none, and ran no Crewforth hook at all: no commit approval, no
274
+ write gate, no fill reading. A new hook copies this checkout's `.claude/` into such a worktree when a session
275
+ enters it, without `worktrees/`, `state/`, the review record and the gate log, and refuses the move when the copy
276
+ cannot be made. Worktrees Claude Code creates under `.claude/worktrees/` were not affected and are left alone. The
277
+ plugin edition does not need it: its hooks load in a repository's worktrees too.
278
+
8
279
  ## [3.3.0] — 2026-10-29
9
280
 
10
281
  ### Added
package/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  <p align="center"><img src="https://raw.githubusercontent.com/Crewforth/crewforth/main/assets/logo.svg" alt="Crewforth" width="420"></p>
2
2
 
3
- **Crewforth is your engineering crew for Claude Code.** It adds subagents, skills, commands and hooks to Claude Code: 14 specialist agents that each own a domain, 40 skills that hold the method, 14 commands you start with `/crew-…`, and hooks that enforce the rules that matter.
3
+ **Crewforth is your engineering crew for Claude Code.** It adds subagents, skills, commands and hooks to Claude Code: 14 specialist agents that each own a domain, 40 skills that hold the method, 17 commands you start with `/crew-…`, and hooks that enforce the rules that matter.
4
4
 
5
5
  ```bash
6
6
  npx crewforth init # set up a new project
7
7
  npx crewforth adopt # hand it over onto an existing repository, on a branch
8
8
  npx crewforth add <agent|skill> # copy one agent or skill into ./.claude
9
9
  npx crewforth studio # open the Studio panel; installs nothing
10
+ npx crewforth remove # show what removing it would take out (--apply does it)
10
11
  ```
11
12
 
12
13
  Then open Claude Code and run `/crew-doctor` to confirm the setup. Requires bash and git; on Windows, use Git Bash (the gates run only when Claude Code finds it; when it does not, the tools that write or run commands are stopped and `/crew-doctor` names the path to set).
@@ -31,7 +32,7 @@ Then open Claude Code and run `/crew-doctor` to confirm the setup. Requires bash
31
32
 
32
33
  - **14 specialist agents**, from `crew-planner` to `crew-commit-agent`, each owning one domain.
33
34
  - **40 skills** holding the method: testing, migrations, API contracts, observability, accessibility, deployment.
34
- - **14 commands**, each started with its `/crew-…` name: `/crew-plan`, `/crew-review`, `/crew-ship`, `/crew-handoff`, `/crew-brainstorm`, `/crew-update`, `/crew-doctor`, `/crew-gates`, `/crew-skill`, `/crew-studio`, `/crew-approve`, `/crew-loosen`, `/crew-allow-verify`, `/crew-map`.
35
+ - **17 commands**, each started with its `/crew-…` name: `/crew-plan`, `/crew-review`, `/crew-ship`, `/crew-handoff`, `/crew-brainstorm`, `/crew-update`, `/crew-doctor`, `/crew-gates`, `/crew-skill`, `/crew-studio`, `/crew-approve`, `/crew-loosen`, `/crew-allow-verify`, `/crew-map`, `/crew-audit`, `/crew-interview`, `/crew-pr`.
35
36
  - In `auto` mode a commit or a push waits for you: type `/crew-approve` and what was just refused is approved, tied to what is staged.
36
37
  - A stopped destructive command says what it would have touched; a review starts from a deterministic pre-pass, and `crew-refuter` tries to refute each finding that blocks.
37
38
  - **Organisation presets.** `npx crewforth init --preset strict` (or `solo`, or your own JSON file) carries critical paths, model floors and verify commands to every project.
@@ -41,6 +42,10 @@ Then open Claude Code and run `/crew-doctor` to confirm the setup. Requires bash
41
42
 
42
43
  When a new version is published, Claude asks once at the start of a session whether to update; it never updates on its own. Run `/crew-update` inside a session, or `npx crewforth@latest update`.
43
44
 
45
+ ## Telemetry
46
+
47
+ After a successful `npx crewforth init`, Crewforth sends one anonymous count, once per project: `GET https://ping.crewforth.com/install?v=<version>`, the version and nothing else, after printing a line that says so. No ID, path, project, host or user name is sent; `adopt`, `update`, `add` and `studio` send nothing. Turn it off with `CREW_NO_TELEMETRY=1` or `DO_NOT_TRACK=1`; nothing is sent where `CI` is set. Details: [README → Telemetry](https://github.com/Crewforth/crewforth#telemetry).
48
+
44
49
  ## Links
45
50
 
46
51
  Documentation: [crewforth.com](https://crewforth.com) · Source and issues: [github.com/Crewforth/crewforth](https://github.com/Crewforth/crewforth) · Licence: MIT
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.3.0
1
+ 3.5.0-rc.1
package/adopt.sh CHANGED
@@ -64,6 +64,15 @@ unset _hl _hh _ht
64
64
 
65
65
  SRC="$HERE/kit"
66
66
  [ -d "$SRC" ] || { echo "ERROR: kit/ not found (must be in the same directory as adopt.sh)."; exit 1; }
67
+ # A payload that lost files (a truncated archive, a folder dropped in a copy) is refused before the first write, so
68
+ # a broken download says so instead of installing gates that fail on every call. English, like the check above: it
69
+ # answers before the language is chosen. eval/lib/payload-check.sh says what it reads.
70
+ if [ "${CREW_PAYLOAD_UNCHECKED:-0}" != 1 ] && [ -f "$SRC/eval/lib/payload-check.sh" ]; then
71
+ _pc="$(bash "$SRC/eval/lib/payload-check.sh" "$SRC" 2>&1)" || {
72
+ echo "ERROR: the kit/ payload is incomplete — nothing installed:"; printf '%s\n' "$_pc" | sed 's/^/ /'
73
+ echo "Download it again (npx crewforth@latest, or a fresh archive). CREW_PAYLOAD_UNCHECKED=1 installs it anyway."
74
+ exit 1; }
75
+ fi
67
76
 
68
77
  # --- flags (B5 — where a refresh lands) --- --here: the current branch · --new-branch: a fresh review branch.
69
78
  # Left empty, Stage 2 picks a smart default (first adopt -> new; update + untracked .claude -> here; update +
@@ -323,6 +332,7 @@ _mt() { # $1 = English text (the key); further args fill %s; result in _M
323
332
  "settings.json: %s") s='settings.json: %s' ;;
324
333
  "merge failed -> project setting PRESERVED (not overwritten)") s='birleştirme başarısız -> proje ayarı KORUNDU (üzerine yazılmadı)' ;;
325
334
  "existing file is INVALID JSON -> merge ABORT (no silent overwrite). Fix it by hand first.") s='mevcut dosya GEÇERSİZ JSON -> birleştirme İPTAL (üzerine sessizce yazılmaz). Önce elle düzeltin.' ;;
335
+ "existing file has a hook entry Claude Code rejects (it then ignores the whole file) -> merge ABORT. Fix the entries below by hand first.") s="mevcut dosyada Claude Code'un reddettiği bir hook girdisi var (o zaman dosyanın tamamını yok sayar) -> birleştirme İPTAL. Önce aşağıdaki girdileri elle düzeltin." ;;
326
336
  "settings.json: retired §4.4 ask rule(s) REMOVED (%s) — guard-bash.sh now asks for these itself; an ask rule would override its CLAUDE_GIT_OK allow. Re-add one only if your project wants that trade.") s='settings.json: emekliye ayrılan §4.4 ask kuralları KALDIRILDI (%s) — bunları artık guard-bash.sh kendisi soruyor; bir ask kuralı onun CLAUDE_GIT_OK iznini ezerdi. Bu bedeli bilerek istiyorsanız geri ekleyin.' ;;
327
337
  "Stage 4 — arm the git gates (SHIM via husky) + PROOF") s='Aşama 4 — git kapılarını devreye al (husky üzerinden SHIM) + KANIT' ;;
328
338
  "core.hooksPath -> .claude/hooks (no existing hook chain)") s='core.hooksPath -> .claude/hooks (başka hook zinciri yok)' ;;
@@ -359,6 +369,8 @@ _mt() { # $1 = English text (the key); further args fill %s; result in _M
359
369
  "%s written") s='%s yazıldı' ;;
360
370
  "%s written (persistent handover decision)") s='%s yazıldı (devralmanın kalıcı karar kaydı)' ;;
361
371
  "%s already exists — untouched (never-overwrite)") s='%s zaten var — dokunulmadı (üzerine asla yazılmaz)' ;;
372
+ "STOP: .claude/hooks already holds files under names Crewforth installs as its gates:%s") s="DUR: .claude/hooks içinde Crewforth'un kapı olarak kurduğu adlarla dosyalar zaten var:%s" ;;
373
+ "Crewforth did not write them. A first adopt would keep them, make them your git hooks and run them during the install. Nothing was changed. Look at them, move them out of .claude/hooks, then run adopt again.") s="Bunları Crewforth yazmadı. İlk kurulum onları olduğu gibi bırakır, git hook'larınız yapar ve kurulum sırasında çalıştırırdı. Hiçbir şey değişmedi. Dosyalara bakın, .claude/hooks dışına taşıyın, sonra adopt'u yeniden çalıştırın." ;;
362
374
  "+ .gitattributes: eol pins so the shared hooks stay LF on a Windows checkout") s="+ .gitattributes: paylaşılan hook'lar Windows checkout'unda LF kalsın diye eol sabitlendi" ;;
363
375
  "Review in your editor — nothing committed yet") s='Editörünüzde inceleyin — henüz hiçbir şey commit edilmedi' ;;
364
376
  "staged") s='stage edilen' ;;
@@ -706,6 +718,22 @@ KIT_PRESENT=0; KIT_VER=""
706
718
  # not make a never-installed project look installed — that turns on the force-refresh and overwrites its files.
707
719
  if [ "$KIT_PRESENT" = 0 ]; then for n in $KIT_OLD; do [ -f ".claude/agents/$n.md" ] && { KIT_PRESENT=1; break; }; done; fi
708
720
  [ -f .claude/VERSION ] && KIT_VER="$(head -1 .claude/VERSION 2>/dev/null)"
721
+ # A FRESH adopt keeps a file it finds (never-overwrite), and then makes .claude/hooks the git hooks directory, runs
722
+ # pre-commit there as its proof, runs guard-bash.sh and skill-trust.sh, and wires the rest into settings.json. So a
723
+ # file already sitting in .claude/hooks under a name Crewforth ships would be run as Crewforth, by the user, during
724
+ # the install and on every commit after it. Git never runs hooks that arrive with a clone; a cloned repository that
725
+ # carries .claude/hooks/pre-commit would make this installer do exactly that. Nothing has changed yet at this
726
+ # point, so the run stops here and names the files. An update (KIT_PRESENT=1) refreshes every one of them from
727
+ # the payload instead, so it is not affected.
728
+ if [ "$KIT_PRESENT" = 0 ] && [ -d .claude/hooks ]; then
729
+ _planted=""
730
+ for _hf in "$SRC"/hooks/*; do [ -f "$_hf" ] || continue; _hn="${_hf##*/}"; [ -e ".claude/hooks/$_hn" ] || [ -L ".claude/hooks/$_hn" ] && _planted="$_planted $_hn"; done
731
+ if [ -n "$_planted" ]; then
732
+ _mt 'STOP: .claude/hooks already holds files under names Crewforth installs as its gates:%s' "$_planted"; printf '%s\n' "$_M"
733
+ _mt 'Crewforth did not write them. A first adopt would keep them, make them your git hooks and run them during the install. Nothing was changed. Look at them, move them out of .claude/hooks, then run adopt again.'; printf '%s\n' "$_M"
734
+ exit 1
735
+ fi
736
+ fi
709
737
  # Backend pattern of the existing install. Since 3.0 there is ONE shape (generic) and this only answers a
710
738
  # migration question: was this a pre-3.0 .NET install? If so its pattern skill stays, as the project's own.
711
739
  # LEGACY_PROFILE is a pre-2.0 leftover of the same kind: it selects nothing, it only drives a notice.
@@ -1243,7 +1271,7 @@ done
1243
1271
  # kit-owned trees: FORCE-refresh on a re-adopt (KIT_PRESENT) so kit updates land; never-overwrite on a fresh adopt
1244
1272
  copy_noclobber "$SRC/agents" .claude/agents "$KIT_PRESENT" "$EXCL_A"; A_ADD=$ret_add; A_SKIP=$ret_skip
1245
1273
  # The summary counts skills and commands the way the README does — one per skill, a `kind: command` skill as a
1246
- # command, an `experimental: true` one as neither. copy_noclobber counts FILES (a skill with references/ is several),
1274
+ # command, an `experimental: "true"` one as neither. copy_noclobber counts FILES (a skill with references/ is several),
1247
1275
  # which is how an update from 2.13.0 once reported "skills +75" for 39 skills. A skill counts as added when the
1248
1276
  # copy put it there or refreshed it; one that was excluded, or that a fresh adopt found already present and left
1249
1277
  # alone, counts as skipped. The "already present" answer is taken before the copy, with builtins only.
@@ -1254,7 +1282,7 @@ for kd in "$SRC"/skills/*/; do
1254
1282
  [ -f "$kd/SKILL.md" ] || continue; kn="${kd%/}"; kn="${kn##*/}"; _k=0; _e=0; _d=0
1255
1283
  while IFS= read -r _l || [ -n "$_l" ]; do
1256
1284
  _l="${_l%$'\r'}"
1257
- case "$_l" in ---) _d=$((_d+1)); [ "$_d" -ge 2 ] && break ;; " kind: command") _k=1 ;; " experimental: true") _e=1 ;; esac
1285
+ case "$_l" in ---) _d=$((_d+1)); [ "$_d" -ge 2 ] && break ;; " kind: command") _k=1 ;; " experimental: true"|" experimental: \"true\"") _e=1 ;; esac
1258
1286
  done < "$kd/SKILL.md"
1259
1287
  [ "$_e" = 1 ] && continue
1260
1288
  _got=1
@@ -1704,10 +1732,16 @@ SET_FRESH=0
1704
1732
  if [ ! -f "$PSET" ]; then
1705
1733
  SET_FRESH=1
1706
1734
  [ -f "$KSET" ] && { cp "$KSET" "$PSET"; say "settings.json: was missing in the project -> Crewforth's was installed"; }
1735
+ # The hook entries Claude Code would reject (a hook without "type", a "command" that is not a string, a matcher that
1736
+ # is not a string): it ignores the WHOLE settings.json then, so every gate is off and nothing says so. A project file
1737
+ # like that is not merged into (the merge would carry the entry along); the problems are named and the file is left.
1738
+ elif SET_HC="$(awk -v op=hookcheck -f "$SET_AWK" "$PSET" 2>/dev/null)"; [ "$?" = 1 ]; then
1739
+ SET_NOTE="existing file has a hook entry Claude Code rejects (it then ignores the whole file) -> merge ABORT. Fix the entries below by hand first."
1740
+ _mt "$SET_NOTE"; warnm 'settings.json: %s' "$_M"; printf '%s\n' "$SET_HC" | sed 's/^/ /'
1707
1741
  else
1708
1742
  awk -v op=merge -v retired='Bash(git add:*)|Bash(git commit:*)|Bash(git push:*)|Bash(git checkout -b:*)' -f "$SET_AWK" "$KSET" "$PSET" > "$PSET.tmp" 2>/dev/null
1709
1743
  case "$?" in
1710
- 0) if [ -s "$PSET.tmp" ] && awk -v op=validate -f "$SET_AWK" "$PSET.tmp" 2>/dev/null; then
1744
+ 0) if [ -s "$PSET.tmp" ] && awk -v op=validate -f "$SET_AWK" "$PSET.tmp" 2>/dev/null && awk -v op=hookcheck -f "$SET_AWK" "$PSET.tmp" >/dev/null 2>&1; then
1711
1745
  # Written THROUGH the existing file, not swapped in with mv: a symlinked settings.json (a team's shared
1712
1746
  # file) keeps its link and gets the merge, and a 0600 mode survives.
1713
1747
  cat "$PSET.tmp" > "$PSET"; say 'settings.json: hook-aware MERGE (Crewforth hooks refreshed - %s)' "$KEPT"
@@ -1729,8 +1763,9 @@ elif [ "$SET_FRESH" = 1 ]; then HAND_SET="Crewforth's settings.json installed (t
1729
1763
  else HAND_SET="hook-aware merge (Crewforth hooks REFRESHED to current — new events + timeouts land; your own custom hooks/permissions PRESERVED${RET_GONE:+, except the retired §4.4 ask rule(s) REMOVED: $RET_GONE — guard-bash.sh asks for these itself})"; fi
1730
1764
 
1731
1765
  # The status line, only where none is set (a user's own would lose to the project's setting, so it is never
1732
- # replaced). eval/lib/statusline.sh --install decides and writes; this only says what it did.
1733
- if [ -f .claude/eval/lib/statusline.sh ]; then
1766
+ # replaced). eval/lib/statusline.sh --install decides and writes; this only says what it did. Not after a refused
1767
+ # merge: that file was left as it was on purpose, and the status line is a write to it.
1768
+ if [ -z "$SET_NOTE" ] && [ -f .claude/eval/lib/statusline.sh ]; then
1734
1769
  case "$(bash .claude/eval/lib/statusline.sh --install 2>/dev/null)" in
1735
1770
  installed) say "Status line: Crewforth's (the gate's last word, a standing approval, crew agents, fill, cost)." ;;
1736
1771
  kept) say "Status line: yours is kept; Crewforth's is one command away (see /crew-doctor)." ;;