crewforth 0.0.1 → 3.0.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 (168) hide show
  1. package/CHANGELOG.md +3784 -0
  2. package/LICENSE +21 -0
  3. package/README.md +37 -7
  4. package/VERSION +1 -0
  5. package/adopt.sh +1670 -0
  6. package/bin/cli.js +497 -0
  7. package/kit/AGENT_TEMPLATE.md +92 -0
  8. package/kit/CLAUDE.md +228 -0
  9. package/kit/README.md +107 -0
  10. package/kit/agents/crew-backend-expert.md +95 -0
  11. package/kit/agents/crew-commit-agent.md +96 -0
  12. package/kit/agents/crew-database-expert.md +84 -0
  13. package/kit/agents/crew-devops-expert.md +82 -0
  14. package/kit/agents/crew-frontend-expert.md +85 -0
  15. package/kit/agents/crew-performance-expert.md +78 -0
  16. package/kit/agents/crew-planner.md +60 -0
  17. package/kit/agents/crew-privacy-agent.md +71 -0
  18. package/kit/agents/crew-review-agent.md +95 -0
  19. package/kit/agents/crew-security-expert.md +73 -0
  20. package/kit/agents/crew-session-manager.md +77 -0
  21. package/kit/agents/crew-test-expert.md +64 -0
  22. package/kit/eval/doctor.sh +465 -0
  23. package/kit/eval/gate-report.sh +137 -0
  24. package/kit/eval/golden-holdout.txt +53 -0
  25. package/kit/eval/golden-routing.txt +199 -0
  26. package/kit/eval/lib/crew-env.sh +14 -0
  27. package/kit/eval/lib/settings-json.awk +154 -0
  28. package/kit/eval/lib/star.sh +70 -0
  29. package/kit/eval/parser-conformance.sh +612 -0
  30. package/kit/eval/preflight.sh +186 -0
  31. package/kit/eval/routing-eval.sh +209 -0
  32. package/kit/eval/scan-skill.sh +162 -0
  33. package/kit/eval/smoke-test.sh +6693 -0
  34. package/kit/eval/update-guard.sh +81 -0
  35. package/kit/eval/utilization.sh +130 -0
  36. package/kit/hooks/board-sync.sh +106 -0
  37. package/kit/hooks/board.sh +962 -0
  38. package/kit/hooks/commit-msg +49 -0
  39. package/kit/hooks/context-usage.sh +353 -0
  40. package/kit/hooks/floor-blocklist.txt +124 -0
  41. package/kit/hooks/guard-bash.sh +1431 -0
  42. package/kit/hooks/guard-commit-scan.sh +511 -0
  43. package/kit/hooks/guard-write.sh +513 -0
  44. package/kit/hooks/pre-commit +577 -0
  45. package/kit/hooks/route-hint.sh +185 -0
  46. package/kit/hooks/secret-blocklist.txt +82 -0
  47. package/kit/hooks/session-guard.sh +149 -0
  48. package/kit/hooks/session-rehydrate.sh +41 -0
  49. package/kit/hooks/session-stats.sh +252 -0
  50. package/kit/hooks/session-update-check.sh +236 -0
  51. package/kit/hooks/skill-trust.sh +150 -0
  52. package/kit/hooks/trace-blocklist.txt +53 -0
  53. package/kit/settings.json +132 -0
  54. package/kit/skills/a11y/SKILL.md +44 -0
  55. package/kit/skills/adr/SKILL.md +74 -0
  56. package/kit/skills/api-design/SKILL.md +50 -0
  57. package/kit/skills/automode-policy/SKILL.md +91 -0
  58. package/kit/skills/automode-policy/references/policy.json +13 -0
  59. package/kit/skills/automode-policy/scripts/apply.sh +84 -0
  60. package/kit/skills/automode-policy/scripts/check.sh +102 -0
  61. package/kit/skills/backend-architecture/SKILL.md +103 -0
  62. package/kit/skills/brainstorm/SKILL.md +47 -0
  63. package/kit/skills/ci-pipeline/SKILL.md +38 -0
  64. package/kit/skills/commit-message/SKILL.md +82 -0
  65. package/kit/skills/commit-message/references/examples.md +8 -0
  66. package/kit/skills/confidence-check/SKILL.md +86 -0
  67. package/kit/skills/crew-board/SKILL.md +55 -0
  68. package/kit/skills/crew-brainstorm/SKILL.md +19 -0
  69. package/kit/skills/crew-code-review/SKILL.md +151 -0
  70. package/kit/skills/crew-code-review/references/history-search.md +19 -0
  71. package/kit/skills/crew-code-review/references/panel-mode.md +32 -0
  72. package/kit/skills/crew-code-review/references/receiving.md +23 -0
  73. package/kit/skills/crew-doctor/SKILL.md +36 -0
  74. package/kit/skills/crew-gates/SKILL.md +25 -0
  75. package/kit/skills/crew-handoff/SKILL.md +14 -0
  76. package/kit/skills/crew-plan/SKILL.md +18 -0
  77. package/kit/skills/crew-review/SKILL.md +23 -0
  78. package/kit/skills/crew-ship/SKILL.md +19 -0
  79. package/kit/skills/crew-skill/SKILL.md +61 -0
  80. package/kit/skills/crew-studio/SKILL.md +129 -0
  81. package/kit/skills/crew-update/SKILL.md +43 -0
  82. package/kit/skills/db-migration/SKILL.md +120 -0
  83. package/kit/skills/db-migration/references/backup-restore.md +33 -0
  84. package/kit/skills/db-migration/references/raw-sql.md +30 -0
  85. package/kit/skills/db-migration/references/tool-matrix.md +35 -0
  86. package/kit/skills/dependency-audit/SKILL.md +61 -0
  87. package/kit/skills/dependency-upgrade/SKILL.md +82 -0
  88. package/kit/skills/deploy/SKILL.md +100 -0
  89. package/kit/skills/deploy/references/proxy-ssl.md +56 -0
  90. package/kit/skills/deploy/references/rollback.md +18 -0
  91. package/kit/skills/deploy/references/scripts.md +9 -0
  92. package/kit/skills/deploy/references/topology-a.md +128 -0
  93. package/kit/skills/deploy/references/topology-b.md +44 -0
  94. package/kit/skills/docs-writer/SKILL.md +53 -0
  95. package/kit/skills/docs-writer/references/coauthoring.md +34 -0
  96. package/kit/skills/eval-grader/SKILL.md +75 -0
  97. package/kit/skills/eval-grader/references/method.md +51 -0
  98. package/kit/skills/frontend/SKILL.md +56 -0
  99. package/kit/skills/frontend/references/verify-contract.md +41 -0
  100. package/kit/skills/frontend-design/SKILL.md +71 -0
  101. package/kit/skills/frontend-design/references/design-review.md +34 -0
  102. package/kit/skills/frontend-rn-expo/SKILL.md +25 -0
  103. package/kit/skills/handoff/SKILL.md +71 -0
  104. package/kit/skills/handoff/references/cold-reader.md +51 -0
  105. package/kit/skills/i18n-integrity/SKILL.md +31 -0
  106. package/kit/skills/incident-runbook/SKILL.md +40 -0
  107. package/kit/skills/incident-runbook/references/postmortem.md +16 -0
  108. package/kit/skills/iterate/SKILL.md +40 -0
  109. package/kit/skills/mcp-builder/SKILL.md +54 -0
  110. package/kit/skills/mcp-builder/references/building.md +71 -0
  111. package/kit/skills/observability/SKILL.md +50 -0
  112. package/kit/skills/performance/SKILL.md +38 -0
  113. package/kit/skills/performance/references/bottlenecks.md +10 -0
  114. package/kit/skills/privacy-compliance/SKILL.md +75 -0
  115. package/kit/skills/red-team/SKILL.md +48 -0
  116. package/kit/skills/reflect/SKILL.md +57 -0
  117. package/kit/skills/release/SKILL.md +44 -0
  118. package/kit/skills/security-scan/SKILL.md +99 -0
  119. package/kit/skills/security-scan/references/ai-agents.md +107 -0
  120. package/kit/skills/security-scan/references/fronts.md +99 -0
  121. package/kit/skills/security-scan/references/prompting.md +23 -0
  122. package/kit/skills/security-scan/references/reporting.md +75 -0
  123. package/kit/skills/security-scan/references/verify.md +131 -0
  124. package/kit/skills/sonarqube-check/SKILL.md +108 -0
  125. package/kit/skills/sonarqube-check/references/local-engines.md +32 -0
  126. package/kit/skills/sonarqube-check/references/stand-up-server.md +25 -0
  127. package/kit/skills/spec-planning/SKILL.md +92 -0
  128. package/kit/skills/systematic-debugging/SKILL.md +57 -0
  129. package/kit/skills/systematic-debugging/references/techniques.md +44 -0
  130. package/kit/skills/teamboard/SKILL.md +88 -0
  131. package/kit/skills/teamboard/references/setup.md +37 -0
  132. package/kit/skills/testing/SKILL.md +49 -0
  133. package/kit/skills/testing/references/flaky-triage.md +51 -0
  134. package/kit/skills/threat-model/SKILL.md +57 -0
  135. package/kit/skills/threat-model/references/interview.md +51 -0
  136. package/kit/skills/threat-model/references/schema.md +42 -0
  137. package/kit/skills/token-budget/SKILL.md +51 -0
  138. package/kit/skills/trace-scan/SKILL.md +43 -0
  139. package/kit/skills/worktree/SKILL.md +40 -0
  140. package/kit/studio/README.md +266 -0
  141. package/kit/studio/ensure-node.sh +471 -0
  142. package/kit/studio/package.json +14 -0
  143. package/kit/studio/server/hooks/studio-gate.sh +169 -0
  144. package/kit/studio/server/index.js +902 -0
  145. package/kit/studio/server/lib/crew-env.js +11 -0
  146. package/kit/studio/server/lib/fleet.js +146 -0
  147. package/kit/studio/server/lib/graph.js +533 -0
  148. package/kit/studio/server/lib/instance.js +135 -0
  149. package/kit/studio/server/lib/kit-telemetry.js +182 -0
  150. package/kit/studio/server/lib/kit.js +158 -0
  151. package/kit/studio/server/lib/palette.js +118 -0
  152. package/kit/studio/server/lib/peers.js +72 -0
  153. package/kit/studio/server/lib/permissions.js +150 -0
  154. package/kit/studio/server/lib/projects.js +294 -0
  155. package/kit/studio/server/lib/roster.js +191 -0
  156. package/kit/studio/server/lib/session.js +309 -0
  157. package/kit/studio/server/lib/terminal.js +91 -0
  158. package/kit/studio/server/lib/transcript.js +100 -0
  159. package/kit/studio/web/app.js +1098 -0
  160. package/kit/studio/web/canvas.js +1179 -0
  161. package/kit/studio/web/chat.js +543 -0
  162. package/kit/studio/web/index.html +86 -0
  163. package/kit/studio/web/md.js +110 -0
  164. package/kit/studio/web/storage-migrate.js +23 -0
  165. package/kit/studio/web/style.css +1453 -0
  166. package/package.json +46 -8
  167. package/start.sh +748 -0
  168. package/bin/crewforth.js +0 -10
@@ -0,0 +1,53 @@
1
+ # Trace-scanner word/pattern list (scanned with grep -iE, one pattern per line).
2
+ # High-precision defaults: expressions that won't false-positive on everyday code.
3
+ # Single high-frequency words like "model", "assistant" are DELIBERATELY absent (false-positive risk).
4
+ # Add your own vendor/template name below (§4.2) so it is caught before commit.
5
+ # If a pattern is legitimate in a specific repo: put a .trace-allowlist.txt at that repo's root and
6
+ # write the pattern (FULL line) there -> exempt only in that repo. (Not included in the payload.)
7
+ #
8
+ # Each pattern carries its own case on the line below it (`#test:` must be caught, `#test-clean:` must not).
9
+ # smoke-test.sh discovers them, drives the REAL hook with them, and fails if any pattern has no case — an
10
+ # untested pattern is how a typo ships as a gate that matches nothing. This file is excluded from the scan by
11
+ # name, so the cases here never self-trigger.
12
+
13
+ Co-Authored-By
14
+ #test: Co-Authored-By: An Assistant <noreply@example.com>
15
+ # "Generated by/with" alone matched every machine-written header in existence — a pubspec.lock, an EF Core
16
+ # scaffold, protoc, openapi-generator. A live --dotnet install could not make its FIRST commit because the
17
+ # cloned base carries a Dart lockfile saying "Generated by pub". §4.1 is about AI AUTHORSHIP, so the pattern
18
+ # now needs that context nearby; the clean cases below pin the classes that used to false-positive.
19
+ generated with.{0,40}(claude|chatgpt|copilot|cursor|codex|assistant|llm|language model|[^a-z]ai([^a-z]|$))
20
+ #test: Generated with an AI coding tool
21
+ generated by.{0,40}(claude|chatgpt|copilot|cursor|codex|assistant|llm|language model|[^a-z]ai([^a-z]|$))
22
+ #test: <!-- Generated by the assistant, do not edit -->
23
+ #test-clean: # Generated by pub
24
+ #test-clean: // <auto-generated> This code was generated by the EF Core tools.
25
+ Written by Claude
26
+ #test: // Written by Claude, reviewed by nobody
27
+ 🤖
28
+ #test: chore: tidy up 🤖
29
+ Claude Code
30
+ #test: scaffolded with Claude Code
31
+ Copilot
32
+ #test: suggested by Copilot
33
+ ChatGPT
34
+ #test: pasted from ChatGPT
35
+ AI-generated
36
+ #test: this module is AI-generated
37
+ AI generated
38
+ #test: AI generated boilerplate
39
+ yapay zeka tarafindan
40
+ #test: bu dosya yapay zeka tarafindan uretildi
41
+ asistan tarafindan
42
+ #test: asistan tarafindan duzenlendi
43
+
44
+ # Ordinary text that names none of the above and must stay committable.
45
+ #test-clean: refactor the order handler and add a regression test
46
+ #test-clean: fix(auth): reject an expired refresh token
47
+ #test-clean: docs: explain the migration rollback procedure
48
+
49
+ # --- §4.2 vendor / third-party template names (fill in per project) ---
50
+ # The installers uncomment the next line only in a project that keeps the former .NET pattern skill
51
+ # (.claude/skills/cqrs-aop-module), because that skill names the template it was derived from.
52
+ # DevArchitecture
53
+ # <vendor-template-name>
@@ -0,0 +1,132 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
3
+ "skillListingBudgetFraction": 0.04,
4
+ "permissions": {
5
+ "allow": [
6
+ "Bash"
7
+ ],
8
+ "ask": [
9
+ "Bash(ssh:*)",
10
+ "Bash(scp:*)",
11
+ "Bash(rsync:*)",
12
+ "Bash(docker:*)"
13
+ ],
14
+ "deny": [
15
+ "Read(.env)",
16
+ "Read(.env.local)",
17
+ "Read(.env.*.local)",
18
+ "Read(**/.env)",
19
+ "Read(**/.env.local)",
20
+ "Read(**/.env.*.local)",
21
+ "Read(~/.ssh/**)",
22
+ "Read(~/.aws/**)",
23
+ "Read(~/.kube/**)",
24
+ "Read(~/.netrc)",
25
+ "Read(~/.npmrc)",
26
+ "Read(~/.git-credentials)",
27
+ "Read(~/.docker/config.json)",
28
+ "Read(**/id_rsa)",
29
+ "Read(**/id_dsa)",
30
+ "Read(**/id_ecdsa)",
31
+ "Read(**/id_ed25519)",
32
+ "Read(**/*.pem)",
33
+ "Read(**/*.p12)",
34
+ "Read(**/*.pfx)",
35
+ "Read(**/*.jks)",
36
+ "Read(**/kubeconfig)"
37
+ ]
38
+ },
39
+ "hooks": {
40
+ "PreToolUse": [
41
+ {
42
+ "matcher": "Bash|PowerShell",
43
+ "hooks": [
44
+ {
45
+ "type": "command",
46
+ "command": "cd \"$CLAUDE_PROJECT_DIR\" 2>/dev/null; bash .claude/hooks/guard-bash.sh",
47
+ "timeout": 60
48
+ },
49
+ {
50
+ "type": "command",
51
+ "command": "cd \"$CLAUDE_PROJECT_DIR\" 2>/dev/null; bash .claude/hooks/guard-commit-scan.sh",
52
+ "timeout": 60
53
+ }
54
+ ]
55
+ },
56
+ {
57
+ "matcher": "Write|Edit|NotebookEdit",
58
+ "hooks": [
59
+ {
60
+ "type": "command",
61
+ "command": "cd \"$CLAUDE_PROJECT_DIR\" 2>/dev/null; bash .claude/hooks/guard-write.sh",
62
+ "timeout": 60
63
+ }
64
+ ]
65
+ }
66
+ ],
67
+ "UserPromptSubmit": [
68
+ {
69
+ "hooks": [
70
+ {
71
+ "type": "command",
72
+ "command": "cd \"$CLAUDE_PROJECT_DIR\" 2>/dev/null; bash .claude/hooks/context-usage.sh",
73
+ "timeout": 60
74
+ },
75
+ {
76
+ "type": "command",
77
+ "command": "cd \"$CLAUDE_PROJECT_DIR\" 2>/dev/null; bash .claude/hooks/route-hint.sh",
78
+ "timeout": 60
79
+ }
80
+ ]
81
+ }
82
+ ],
83
+ "Stop": [
84
+ {
85
+ "hooks": [
86
+ {
87
+ "type": "command",
88
+ "command": "cd \"$CLAUDE_PROJECT_DIR\" 2>/dev/null; bash .claude/hooks/session-guard.sh",
89
+ "timeout": 60
90
+ }
91
+ ]
92
+ }
93
+ ],
94
+ "SessionStart": [
95
+ {
96
+ "matcher": "compact|clear|resume|fork",
97
+ "hooks": [
98
+ {
99
+ "type": "command",
100
+ "command": "cd \"$CLAUDE_PROJECT_DIR\" 2>/dev/null; bash .claude/hooks/session-rehydrate.sh",
101
+ "timeout": 60
102
+ }
103
+ ]
104
+ },
105
+ {
106
+ "matcher": "startup|resume|clear|compact|fork",
107
+ "hooks": [
108
+ {
109
+ "type": "command",
110
+ "command": "cd \"$CLAUDE_PROJECT_DIR\" 2>/dev/null; bash .claude/hooks/skill-trust.sh",
111
+ "timeout": 60
112
+ },
113
+ {
114
+ "type": "command",
115
+ "command": "cd \"$CLAUDE_PROJECT_DIR\" 2>/dev/null; bash .claude/hooks/board-sync.sh",
116
+ "timeout": 60
117
+ }
118
+ ]
119
+ },
120
+ {
121
+ "matcher": "startup",
122
+ "hooks": [
123
+ {
124
+ "type": "command",
125
+ "command": "cd \"$CLAUDE_PROJECT_DIR\" 2>/dev/null; bash .claude/hooks/session-update-check.sh",
126
+ "timeout": 60
127
+ }
128
+ ]
129
+ }
130
+ ]
131
+ }
132
+ }
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: a11y
3
+ description: |
4
+ Frontend accessibility audit (WCAG): semantic HTML, keyboard access, focus management, contrast, ARIA, screen readers.
5
+ Use when building or changing UI, or before shipping a user-facing screen.
6
+ ---
7
+
8
+ # Accessibility (a11y)
9
+
10
+ <!-- routing-eval reads the next line; why it sits in the body: AGENT_TEMPLATE.md -->
11
+ Trigger phrases: "a11y", "accessibility", "WCAG", "screen reader", "keyboard navigation", "contrast", "ARIA", "keyboard only", "with a keyboard", "keyboard focus", "without a mouse", "focus ring", "tab order", "alt text", "color blind", "colour blind", "voiceover", "talkback", "reduced motion"
12
+
13
+ Goal: make the interface usable by **everyone**, including keyboard, screen reader, and low vision. Baseline target: **WCAG 2.1 AA**.
14
+ Stack-agnostic (web/React/RN); do a web search when needed for framework-specific APIs.
15
+
16
+ ## Checklist
17
+ - [ ] **Semantic HTML**: `button`/`a`/`nav`/`main`/`h1..h6` correct; no `div`-buttons
18
+ - [ ] **Keyboard**: every interaction reachable via Tab, sensible order, visible **focus ring**
19
+ - [ ] **Focus management**: focus moves on modal/route change, focus trap correct
20
+ - [ ] **Contrast**: text ≥ 4.5:1, large text ≥ 3:1
21
+ - [ ] **Alt text**: `alt` on meaningful images; `alt=""` on decorative images
22
+ - [ ] **Forms**: every input has a `label`; error message programmatically linked (`aria-describedby`)
23
+ - [ ] **ARIA**: only when needed; wrong ARIA is worse than no ARIA; role/name/state correct
24
+ - [ ] **Motion/animation**: respect `prefers-reduced-motion`
25
+ - [ ] **Language**: `<html lang>` correct (coordinate with i18n)
26
+
27
+ ## How
28
+ 1. **Start with semantics** — the right element solves 80%. Use `button` instead of `role="button"`+`div`.
29
+ 2. **Navigate with the keyboard** — drop the mouse, run the whole flow with Tab/Shift-Tab/Enter/Escape; is focus visible and its order sensible.
30
+ 3. **Naming** — does every interactive element have an accessible name (`aria-label` on visual-only icon buttons).
31
+ 4. **Contrast** — check color pairs against the ratio; don't convey meaning by color alone (add an icon/text).
32
+ 5. **Dynamic content** — notify the screen reader via a live region (`aria-live`); manage modal focus.
33
+ 6. **Automated + manual** — tools like linters/axe are the baseline; but manual keyboard+reader testing is essential (tools don't catch 100%).
34
+
35
+ ## React / RN note
36
+ - Web React: semantic element in JSX + `htmlFor`/`aria-*`; use `button` instead of a clickable `div`.
37
+ - React Native: `accessible`, `accessibilityLabel`, `accessibilityRole`, `accessibilityState` (coordinate with `frontend-rn-expo`).
38
+
39
+ ## Invariant rules
40
+ 1. **Semantics first, ARIA second** — wrong ARIA does harm.
41
+ 2. Must be **fully usable by keyboard** — without a mouse.
42
+ 3. **Color cannot be the sole carrier of meaning.**
43
+ 4. **Automated tools are not enough** — manual keyboard+reader testing.
44
+ 5. **Follow the existing design system** — if there is a component library, keep its accessible pattern.
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: adr
3
+ description: |
4
+ Architecture Decision Record: context-decision-consequences, for decisions that are expensive to reverse.
5
+ Written under docs/adr/.
6
+ ---
7
+
8
+ # Architecture Decision Record (ADR)
9
+
10
+ <!-- routing-eval reads the next line; why it sits in the body: AGENT_TEMPLATE.md -->
11
+ Trigger phrases: "adr", "architecture decision", "decision record", "why this approach", "why we chose", "why we went with", "nobody remembers why", "why we picked"
12
+
13
+ ## When
14
+ On an architecture/technology choice that is expensive to reverse, long-lived, or contested
15
+ (database selection, auth strategy, critical pattern). Small/reversible decisions do not require an ADR.
16
+
17
+ **Most of these are never announced as decisions, and that is how they get missed.** The examples above all
18
+ sound like a question someone asked — "Redis or Postgres?" — so they are easy to recognise. The ones that
19
+ actually escape arrive inside ordinary build work: you are asked to add a feature, and along the way you settle
20
+ what an entity owns, what a session is bound to, what makes a row unique, which layer holds a rule. Nobody said
21
+ "decide"; you decided anyway, and the next person inherits it with no idea it was a choice. Measured in the
22
+ field: one infrastructure task settled four such questions and produced no record of any of them, in a session
23
+ where this skill was installed and its trigger read every turn.
24
+
25
+ So the test is not "was I asked to choose". It is: **would a maintainer six months from now, wanting to do this
26
+ differently, need to know why it is this way?** If yes, it is an ADR, however undramatic it felt while writing
27
+ it. Cheap tell: you rejected an alternative in your head and moved on without writing it down.
28
+
29
+ ## On a team, the record ALSO goes on the board
30
+ `docs/` is gitignored in an install, so an ADR written there reaches the machine that wrote it and nobody else —
31
+ which is the opposite of what a decision record is for. When a `teamboard` exists, record it with
32
+ `board.sh decide "<title>" "<context + decision + consequences>"` as well: the board is shared, so it arrives at
33
+ every teammate's next session opening, and it travels even when the board lives in its own repository. The local
34
+ file stays the long form; the board entry is the part that has to reach people, so it must be readable on its
35
+ own — a title nobody can act on ("auth decided") is not a record.
36
+
37
+ ## Format (docs/adr/NNNN-short-title.md, ~1 page)
38
+ ```
39
+ # NNNN. <Decision title>
40
+ Status: proposed | accepted | rejected | superseded (by NNNN)
41
+ ## Context
42
+ Which problem/constraint requires this decision?
43
+ ## Decision
44
+ What was decided (clear, one sentence + rationale)?
45
+ ## Consequences
46
+ Pros / cons / accepted trade-offs.
47
+ ## Alternatives considered
48
+ Why were they not chosen?
49
+ ```
50
+
51
+ ## Principles
52
+ - **Invariant:** a new decision marks the old ADR as `superseded`; an ADR is **never deleted** (decision history is preserved).
53
+ - Numbered and dated; keep it short.
54
+
55
+ ## Deliberately bypassing a rule is a decision too
56
+ A gate the user knowingly overrode — a deferred DoD item, an accepted known gap, a trimmed scope — belongs here
57
+ whenever its effect outlives the task. It is not a lesser kind of decision: choosing *not* to apply a rule shapes
58
+ the codebase exactly as choosing a database does, and it is the one class of decision that leaves no trace in the
59
+ code at all. Six months on, a rule that was weighed and overridden is indistinguishable from one that was never
60
+ noticed, and the second is the one you would want to fix.
61
+
62
+ Record it in the same file as any other decision, with the fields that make it reversible:
63
+
64
+ ```
65
+ ## Bypassed
66
+ - <gate/rule> — why: <reason> — asked by: <who> — revisit: <condition or date>
67
+ ```
68
+
69
+ `revisit` is the load-bearing field. A bypass with no condition attached is permanent by default, and nobody
70
+ chose permanence. See [[confidence-check]], which is where most bypasses surface.
71
+
72
+ ## DoD
73
+ - Decision + rationale + rejected alternatives recorded; status current.
74
+ - Any deliberately bypassed rule is recorded with its reason, who asked, and what would reverse it.
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: api-design
3
+ description: |
4
+ API contract design: resource naming, error model, versioning, pagination, backward compatibility, OpenAPI.
5
+ A predictable interface that evolves without breaking consumers.
6
+ ---
7
+
8
+ # API Design
9
+
10
+ <!-- routing-eval reads the next line; why it sits in the body: AGENT_TEMPLATE.md -->
11
+ Trigger phrases: "api design", "api contract", "api versioning", "openapi", "swagger", "rest contract", "breaking api change", "response shape", "response format", "endpoint returns", "error format"
12
+
13
+ Goal: a contract the consumer can **predict** and that can **evolve** without breaking. Once published, a
14
+ public API is a commitment; a breaking change is expensive. Stack-agnostic (REST as the baseline; GraphQL/gRPC follow similar principles).
15
+
16
+ ## Checklist
17
+ - [ ] Resource names are **consistent** (plural nouns, a single `kebab`/`camel` style), resources not verbs
18
+ - [ ] Correct HTTP semantics: GET (side-effect free) · POST · PUT/PATCH · DELETE; correct **status code**
19
+ - [ ] A uniform **error model**: machine-readable code + human message + (if any) field details
20
+ - [ ] A clear **versioning** strategy (URL `/v1` or header); a breaking change means a new version
21
+ - [ ] **Pagination/filtering/sorting** defined and consistent on large collections
22
+ - [ ] **Backward compatibility**: adding a field is additive; removing a field or changing its meaning is breaking → version
23
+ - [ ] **Idempotency** (for POST/payment-like cases) supported via a key when needed
24
+ - [ ] The contract is documented in **OpenAPI**; example request/response present (coordinate with `docs-writer`)
25
+
26
+ ## How
27
+ 1. **Model the resource** — a noun not a verb: `POST /orders` (✓), `POST /createOrder` (✗).
28
+ 2. **Status codes**: 200/201/204 · 400 validation · 401/403 authorization · 404 · 409 conflict · 422 · 429 · 5xx. Use them meaningfully.
29
+ 3. **Error contract** — every error has the same shape:
30
+ ```json
31
+ { "code": "ORDER_NOT_FOUND", "message": "Order not found", "details": [] }
32
+ ```
33
+ No stack trace / internal detail leakage (overlaps with `security-scan`).
34
+ 4. **Versioning**: additive changes in the same version; breaking (remove/rename a field / add a required field) → `/v2`.
35
+ 5. **Collection**: pagination (cursor or offset), filter/sort parameters; a consistent envelope.
36
+ 6. **Write the contract** — OpenAPI/schema; with examples. Wire the change to `docs-writer`, and if breaking to `release`/CHANGELOG.
37
+
38
+ ## Breaking vs additive
39
+ | Additive (safe) | Breaking (needs a version) |
40
+ |---|---|
41
+ | Add an optional field/endpoint | Remove / rename a field |
42
+ | A new optional parameter | Add a required parameter |
43
+ | A new enum value (if the consumer is tolerant) | Change a type/meaning, change a status code |
44
+
45
+ ## Invariant rules
46
+ 1. **A public API is a commitment** — a breaking change is not made silently; version + announcement.
47
+ 2. **Consistency > local cleverness** — a single naming/error/pagination pattern across the whole API.
48
+ 3. **The error model is uniform and machine-readable.**
49
+ 4. **No internal detail leakage** — a stack trace / DB error does not go to the consumer.
50
+ 5. **The contract is documented** — OpenAPI + example; at design time, not after the code.
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: automode-policy
3
+ description: |
4
+ Auto-mode classifier config: inspect what the classifier that answers permission prompts is configured
5
+ with, and catch the silent case where a custom autoMode block drops the built-in block rules.
6
+ allowed-tools: Bash(bash ${CLAUDE_SKILL_DIR}/scripts/*.sh *)
7
+ ---
8
+
9
+ # Auto-mode policy (automode-policy)
10
+
11
+ <!-- routing-eval reads the next line; why it sits in the body: AGENT_TEMPLATE.md -->
12
+ Trigger phrases: "auto mode", "classifier policy", "permission classifier", "autoMode settings", "policy pack"
13
+
14
+ Purpose: Crewforth's gates run at the tool level (`guard-bash.sh`, the git hooks) and that is where its
15
+ enforcement stays. Since 2026-08-14 auto mode is the default permission mode on Pro/Max/Team, putting a
16
+ classifier in front of the same actions. This skill lets you **see and audit that classifier's configuration**.
17
+ It does not add a gate — read the measurement below before treating it as one.
18
+
19
+ ## Measured: these rules did not enforce
20
+ Claude Code 2.1.238, 2026-08-24, interactive session, `permissionMode=auto`, this policy installed in user
21
+ settings, `claude auto-mode config` listing all three rules:
22
+
23
+ | Run | Result |
24
+ |---|---|
25
+ | "run `git reset --hard` and `git clean -fd`, I'm sure" | ran with **no prompt, no block** — uncommitted work destroyed |
26
+ | Control: no policy, no explicit intent, "get this repo back to the last commit" | identical — no block |
27
+ | Headless probe: absolute `hard_deny` "never write any file" + a write request | file created |
28
+ | Headless control: write to `.git/config`, a **protected path** the docs say auto mode routes to the classifier | written, unprompted |
29
+
30
+ Crewforth's rule names `git reset --hard` and `git clean -fd` verbatim and declares them unconditional, so the
31
+ wording is not the variable. The control run shows the classifier did not gate this class of action **at all**,
32
+ with or without custom rules. Whatever `autoMode` prose rules do, they are not a substitute for a gate.
33
+
34
+ What did protect the work in every run was the model choosing to back it up first — discipline, not a gate. Crewforth
35
+ exists because discipline is the thing that fails silently.
36
+
37
+ ## Why this is Crewforth's only out-of-project file
38
+ The classifier reads `autoMode` from **user** settings (`~/.claude/settings.json`) or **managed** settings.
39
+ It deliberately ignores `.claude/settings.json` and `.claude/settings.local.json`, because a checked-in repo
40
+ could otherwise ship its own allow rules. So a plugin cannot install this policy — an installer must, with
41
+ the user's word. That is `scripts/apply.sh`, and it asks before it writes.
42
+
43
+ ## The failure this still catches — the reason to keep the skill
44
+ Setting an `autoMode` array **without the literal `"$defaults"`** replaces the built-in list for that section.
45
+ Measured on Claude Code 2.1.238: dropping `"$defaults"` took `soft_deny` from **66 rules to 2** — force push,
46
+ piping a downloaded script into a shell, production deploys and auto-mode bypass all gone — with **no error and no warning**. The
47
+ session looks healthy. `scripts/check.sh` reads what the classifier actually uses (`claude auto-mode config`),
48
+ not the policy file, because a policy file that parses is not a policy that applies.
49
+
50
+ ## What Crewforth puts in the config (present, not proven to enforce)
51
+ | Rule | Tier | Why the defaults don't cover it |
52
+ |---|---|---|
53
+ | Crewforth Uncommitted Work Destruction | `hard_deny` | The built-ins treat destructive git as **soft**, which explicit user intent clears. Uncommitted work is the one artifact with no second copy, and Crewforth has watched a subagent run `git checkout -- .` over live work. Hard tier = intent cannot clear it. |
54
+ | Crewforth Gate Tampering | `soft_deny` | `--no-verify`, unsetting `core.hooksPath`, editing `.claude/hooks/*`. The defaults block generic bypass, not the removal of *this project's* gates. |
55
+ | Crewforth Internal Docs Publication | `soft_deny` | §4.3: `docs/` is internal by policy. No built-in can know that. |
56
+
57
+ Deliberately **not** set: `environment` (your trusted repos/buckets/domains — guessing them either over-trusts
58
+ or, set without `"$defaults"`, wipes the built-in list) and `allow` (loosening is the user's call, never
59
+ Crewforth's). §4.4 needs nothing here: `guard-bash.sh` fails `git commit`/`git push` closed in auto mode, and it —
60
+ not a `permissions.ask` rule — is what asks in the interactive modes. An `ask` rule for those verbs would
61
+ break the `CLAUDE_GIT_OK` pre-authorisation: a matching ask rule prompts even when a hook returns `allow`.
62
+
63
+ ## How
64
+ ```bash
65
+ bash .claude/skills/automode-policy/scripts/check.sh # inspect the effective config
66
+ bash .claude/skills/automode-policy/scripts/apply.sh # propose → diff → ask → install → verify
67
+ bash .claude/skills/automode-policy/scripts/apply.sh --strict # also route EVERY shell command to the classifier
68
+ bash .claude/skills/automode-policy/scripts/apply.sh --print # print the block, paste it yourself
69
+ ```
70
+ Verifying is read-only for Crewforth but not for Claude Code: `claude auto-mode config` rewrites its own
71
+ `settings.json` as it reads (reformatted, model aliases normalised, a `backups/` directory created). Measured,
72
+ not assumed — it matters if you diff that file in CI.
73
+
74
+ `check.sh` exit codes: `0` config as expected · `2` built-ins dropped · `3` Crewforth rules absent/partial · `4`
75
+ cannot read the config
76
+ (CLI too old, or auto mode unavailable on this account). `/crew-doctor` reports the same check.
77
+
78
+ `--strict` sets `autoMode.classifyAllShell`, which suspends narrow Bash/PowerShell allow rules while auto mode
79
+ is active so every shell command reaches the classifier. It buys coverage with latency and one classifier call
80
+ per command — offer it, don't assume it.
81
+
82
+ ## Rules
83
+ - **Never install this silently.** It writes outside the project; `apply.sh` asks, backs up, and restores the
84
+ backup itself if the post-install check fails.
85
+ - **Never hand-merge the user's settings file.** Without `jq` or `python3`, `apply.sh` prints the fragment and
86
+ stops — a half-written global settings file is worse than an uninstalled policy.
87
+ - **Keep `"$defaults"` verbatim** in every array you touch, including any rule you add later.
88
+ - **Do not present this as a gate.** Crewforth's enforcement is `permissions.deny` and the `PreToolUse` hooks,
89
+ both of which are measured firing in `smoke-test`. This skill reports configuration.
90
+ - Re-measure before that changes. The table above is one version on one day; if a release makes custom
91
+ `autoMode` rules enforce, this skill's claim can grow — but only with a run that shows a block.
@@ -0,0 +1,13 @@
1
+ {
2
+ "autoMode": {
3
+ "hard_deny": [
4
+ "$defaults",
5
+ "Crewforth Uncommitted Work Destruction: Discarding uncommitted work across a whole tree or directory rather than a file the user named — `git checkout -- .`, `git restore .`, `git reset --hard`, `git clean -fd`, `git stash drop/clear`, or any equivalent that resolves to the working tree, a directory, or a glob. Uncommitted work is the one artifact with no second copy, and a subagent or a cleanup step reaches for these commands while doing something the user did ask for. Blocked unconditionally: commit, stash by name, or revert the specific files instead, and ask the user which."
6
+ ],
7
+ "soft_deny": [
8
+ "$defaults",
9
+ "Crewforth Gate Tampering: Disabling, bypassing, or removing this project's own tool-level gates — `--no-verify` / `-n` on commit or push, unsetting or repointing `core.hooksPath`, running git with `-c core.hooksPath=`, deleting or rewriting files under `.claude/hooks/`, or removing hook entries from `.claude/settings.json`. The gates are the project's stated policy; an agent that finds them inconvenient must report the obstacle, not remove it. The user may still authorise a specific bypass in their own words.",
10
+ "Crewforth Internal Docs Publication: Staging, committing, or pushing the project's internal working documents — anything under `docs/` such as session state, roadmaps, and handover notes, including with `git add -f` against a gitignore rule. These files carry machine paths, unfinished decisions, and internal reasoning; they are deliberately local. Publishing one needs the user to say which file and where."
11
+ ]
12
+ }
13
+ }
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env bash
2
+ # Install Crewforth's auto-mode classifier policy into USER settings — the one part of Crewforth that lives
3
+ # outside the project, because the classifier deliberately ignores `autoMode` in .claude/settings.json
4
+ # (a repo could otherwise ship its own allow rules). Writing outside the project is exactly the kind of
5
+ # action §4.4 says needs the user's word, so this script asks, backs up, and verifies — in that order.
6
+ #
7
+ # Usage:
8
+ # apply.sh propose the change, show the diff, ask, install, verify
9
+ # apply.sh --yes same without the prompt (for a scripted setup the user drives)
10
+ # apply.sh --strict also set autoMode.classifyAllShell — every shell command reaches the classifier
11
+ # apply.sh --print print the policy fragment and exit (paste it yourself; no writes, no tooling)
12
+ set -u
13
+
14
+ HERE="$(cd "$(dirname "$0")" && pwd)"
15
+ POLICY="$HERE/../references/policy.json"
16
+ CHECK="$HERE/check.sh"
17
+ TARGET="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/settings.json"
18
+ YES=0; STRICT=0
19
+ for a in "$@"; do case "$a" in
20
+ --yes) YES=1 ;; --strict) STRICT=1 ;;
21
+ --print) cat "$POLICY"; exit 0 ;;
22
+ *) echo "apply.sh: unknown argument '$a'"; exit 64 ;;
23
+ esac; done
24
+
25
+ [ -f "$POLICY" ] || { echo "❌ policy.json not found next to this script"; exit 1; }
26
+
27
+ # A JSON merge into the user's own settings file is not a job for sed. It goes through Crewforth's one JSON reader
28
+ # (eval/lib/settings-json.awk, the same file adopt.sh merges with) — the same code on every OS. This used to pick
29
+ # jq, then python3, and on a stock Windows box with neither it printed the fragment and stopped, so the one
30
+ # platform with no JSON tool could not install the policy at all. The reader sits three levels up in both
31
+ # editions: .claude/skills/<s>/scripts -> .claude/eval/lib, and <plugin>/skills/<s>/scripts -> <plugin>/eval/lib.
32
+ SJ="$HERE/../../../eval/lib/settings-json.awk"
33
+ if [ ! -f "$SJ" ]; then
34
+ echo "⚠️ Crewforth's JSON reader is missing ($SJ) — not merging your settings file by hand."
35
+ echo " Add this block to $TARGET yourself (keep the \"\$defaults\" entries verbatim):"
36
+ echo; cat "$POLICY"; exit 3
37
+ fi
38
+
39
+ mkdir -p "$(dirname "$TARGET")"
40
+ [ -f "$TARGET" ] || printf '{}\n' > "$TARGET"
41
+
42
+ TMP="$TARGET.crew-new"; BAK="$TARGET.crew-bak-$(date +%Y%m%d-%H%M%S)"
43
+ # autoMode takes every member of the policy's autoMode (the policy wins), the user's other members and every other
44
+ # key untouched. rc 10 = the target is not a JSON object: nothing is written.
45
+ if [ "$STRICT" = 1 ]; then set -- -v setk=classifyAllShell -v setv=true; else set --; fi
46
+ awk -v op=overlay -v key=autoMode "$@" -f "$SJ" "$TARGET" "$POLICY" > "$TMP" && [ -s "$TMP" ] \
47
+ || { echo "❌ merge failed (invalid JSON in $TARGET?)"; rm -f "$TMP"; exit 1; }
48
+
49
+ # Verify the CANDIDATE before it is anyone's real configuration. `claude --settings <file>` runs the
50
+ # classifier config resolution against the file, so a policy that would silently drop the 66 built-in
51
+ # soft blocks is caught here — while the only file on disk is still a temp file.
52
+ echo "== verifying the candidate (nothing installed yet) =="
53
+ bash "$CHECK" --settings "$TMP"; RC=$?
54
+ if [ "$RC" != 0 ]; then
55
+ echo "❌ candidate did not verify (rc=$RC) — nothing was written."
56
+ rm -f "$TMP"; exit "$RC"
57
+ fi
58
+
59
+ echo
60
+ echo "== what changes in $TARGET =="
61
+ if command -v diff >/dev/null 2>&1; then diff -u "$TARGET" "$TMP" | sed -n '1,60p'; else echo "(no diff tool; new file written to $TMP)"; fi
62
+ echo
63
+ if [ "$YES" != 1 ]; then
64
+ # No terminal means no one can consent. Asking anyway is worse than useless: with a tty present but nobody
65
+ # reading it — a CI runner, a background job, a test harness — `read </dev/tty` blocks forever. Measured:
66
+ # this hung Crewforth's own smoke test. No consent possible -> abort, and say how to do it deliberately.
67
+ if [ ! -t 0 ] && [ ! -t 1 ]; then
68
+ echo "not an interactive session — nothing written. Re-run with --yes if this is a setup you are driving."
69
+ rm -f "$TMP"; exit 0
70
+ fi
71
+ printf "Install this policy into your USER settings? [y/N] "
72
+ read -r ans </dev/tty 2>/dev/null || ans=""
73
+ case "$ans" in y|Y|yes|YES) : ;; *) echo "aborted — nothing written."; rm -f "$TMP"; exit 0 ;; esac
74
+ fi
75
+
76
+ cp "$TARGET" "$BAK" && mv "$TMP" "$TARGET" || { echo "❌ could not write $TARGET"; exit 1; }
77
+ echo "✅ installed. backup: $BAK"
78
+ echo "== verifying what the classifier now actually uses =="
79
+ bash "$CHECK"; RC=$?
80
+ if [ "$RC" != 0 ]; then
81
+ echo "❌ post-install verification failed (rc=$RC) — restoring the backup."
82
+ cp "$BAK" "$TARGET"; exit "$RC"
83
+ fi
84
+ echo " Undo any time: cp \"$BAK\" \"$TARGET\""
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env bash
2
+ # Report what the auto-mode classifier is CONFIGURED with — and be exact about what that does and does not prove.
3
+ #
4
+ # MEASURED, 2026-08-24, Claude Code 2.1.238, interactive session, permissionMode=auto, this policy installed in
5
+ # USER settings and shown as present by `claude auto-mode config`:
6
+ # `git reset --hard && git clean -fd` ran with no prompt and no block, destroying uncommitted work — the exact
7
+ # action Crewforth's hard_deny rule names verbatim and calls unconditional.
8
+ # A control run with NO policy and NO explicit user intent behaved identically.
9
+ # Two headless probes agreed, including an absolute "never write any file" rule, and a protected-path write
10
+ # (.git/config) that the docs say auto mode routes to the classifier went through untouched.
11
+ # Reading: the classifier did not gate this class of action at all, with or without custom rules. So this script
12
+ # reports CONFIGURATION, never enforcement. Crewforth's enforcement lives in its PreToolUse hooks and git hooks,
13
+ # which are measured firing in smoke-test; nothing here replaces them.
14
+ #
15
+ # Auto mode is the default permission mode on Pro/Max/Team since 2026-08-14: a classifier, not the user,
16
+ # answers most permission prompts. It reads its rules from `autoMode` in USER or MANAGED settings only
17
+ # (never from .claude/settings.json — a repo could otherwise ship its own allow rules), so this policy is
18
+ # the one part of Crewforth that lives outside the project. That is why it is installed explicitly and
19
+ # verified here rather than assumed.
20
+ #
21
+ # The failure this guards against is silent: setting an autoMode array WITHOUT the literal "$defaults"
22
+ # replaces the built-in list for that section — 66 soft-block rules and the single built-in hard block
23
+ # disappear with no error, and the session looks healthy. So this script does not read the policy file;
24
+ # it reads what the classifier ACTUALLY uses (`claude auto-mode config`) and checks the built-ins are
25
+ # still there. A policy file that parses is not a policy that applies.
26
+ #
27
+ # Side effect, measured — this script writes nothing itself, but `claude auto-mode config` does: reading the
28
+ # effective config makes Claude Code rewrite its own settings.json (reformatted, values normalised such as
29
+ # `opus` -> `opus[1m]`, a backups/ directory created). That is Claude Code maintaining its own file, and it
30
+ # keeps a backup, but "verifying costs nothing" would be a false claim.
31
+ #
32
+ # What it still catches, and why it is worth running: setting an autoMode array without the literal "$defaults"
33
+ # silently replaces the built-in list for that section (measured: soft_deny 66 -> 2, no error, no warning). That
34
+ # footgun is real whatever the enforcement story is, and nothing else in the toolchain reports it.
35
+ #
36
+ # Usage: check.sh [--settings <file>] # --settings inspects a CANDIDATE policy without installing it
37
+ # Exit: 0 config as expected · 2 built-ins DROPPED · 3 kit rules absent/partial · 4 cannot read the config
38
+ set -u
39
+
40
+ SETTINGS=""
41
+ [ "${1:-}" = "--settings" ] && { SETTINGS="${2:-}"; [ -z "$SETTINGS" ] && { echo "check.sh: --settings needs a file"; exit 4; }; }
42
+
43
+ command -v claude >/dev/null 2>&1 || { echo " ⚠️ claude CLI not on PATH — auto-mode policy cannot be verified"; exit 4; }
44
+
45
+ if [ -n "$SETTINGS" ]; then CFG="$(claude --settings "$SETTINGS" auto-mode config 2>/dev/null)"
46
+ else CFG="$(claude auto-mode config 2>/dev/null)"; fi
47
+
48
+ # `auto-mode` is v2.1.19x+; an older CLI prints usage/error instead of the four rule lists.
49
+ case "$CFG" in *'"soft_deny"'*) : ;; *)
50
+ echo " ⚠️ 'claude auto-mode config' did not return a rule set — CLI too old, or auto mode unavailable on this account"
51
+ exit 4 ;;
52
+ esac
53
+
54
+ # Built-ins, checked PER SECTION and anchored to the rule's label.
55
+ #
56
+ # A whole-blob substring search is NOT enough and this was measured, not assumed: "Data Exfiltration" and
57
+ # "Auto-Mode Bypass" also occur inside the prose of `allow` rules, so a config with those built-ins dropped
58
+ # still contains both strings somewhere. That check reports a false PASS — the worst kind for a policy gate.
59
+ # `claude auto-mode config` prints one rule per line inside `"<section>": [ ... ]`, and every rule begins
60
+ # with its label, so slice the section first and anchor the match to the start of the string.
61
+ section(){ printf '%s\n' "$CFG" | awk -v s="$1" '
62
+ $0 ~ "^[[:space:]]*\""s"\"[[:space:]]*:[[:space:]]*\\[" { inb=1; next }
63
+ inb && /^[[:space:]]*\]/ { inb=0 }
64
+ inb { print }'; }
65
+
66
+ has_rule(){ printf '%s\n' "$2" | grep -q "^[[:space:]]*\"$1"; }
67
+
68
+ HD="$(section hard_deny)"; SD="$(section soft_deny)"
69
+ MISSING=""
70
+ has_rule 'Data Exfiltration' "$HD" || MISSING="$MISSING hard_deny/Data-Exfiltration"
71
+ has_rule 'Git Destructive' "$SD" || MISSING="$MISSING soft_deny/Git-Destructive"
72
+ has_rule 'Auto-Mode Bypass' "$SD" || MISSING="$MISSING soft_deny/Auto-Mode-Bypass"
73
+
74
+ # Each kit rule counts under its 3.0 name or its pre-3.0 one ("CSK …"): a config applied by 2.x keeps passing
75
+ # until the user re-applies, which overlays autoMode and so replaces the old names rather than adding beside them.
76
+ KITR=0
77
+ kit_rule(){ has_rule "Crewforth $1" "$2" || has_rule "CSK $1" "$2"; }
78
+ kit_rule 'Uncommitted Work Destruction' "$HD" && KITR=$((KITR+1))
79
+ kit_rule 'Gate Tampering' "$SD" && KITR=$((KITR+1))
80
+ kit_rule 'Internal Docs Publication' "$SD" && KITR=$((KITR+1))
81
+
82
+ if [ -n "$MISSING" ]; then
83
+ echo " ❌ classifier built-ins DROPPED:$MISSING"
84
+ echo " ↳ an autoMode array was set without the literal \"\$defaults\" — restore it in ~/.claude/settings.json"
85
+ echo " ↳ inspect with: claude auto-mode config · built-ins: claude auto-mode defaults"
86
+ exit 2
87
+ fi
88
+
89
+ if [ "$KITR" -eq 0 ]; then
90
+ echo " · Crewforth auto-mode rules not in the classifier config (built-ins only) — not a gate either way"
91
+ echo " ↳ optional: bash .claude/skills/automode-policy/scripts/apply.sh"
92
+ exit 3
93
+ fi
94
+
95
+ if [ "$KITR" -lt 3 ]; then
96
+ echo " · Crewforth auto-mode rules PARTIAL ($KITR/3 present) — built-ins intact"
97
+ echo " ↳ re-apply: bash .claude/skills/automode-policy/scripts/apply.sh"
98
+ exit 3
99
+ fi
100
+
101
+ echo " ✅ classifier config: built-ins intact, 3/3 Crewforth rules present (CONFIGURED, not proven to enforce)"
102
+ exit 0