@bonesofspring/ai-rules 0.2.28 → 0.2.29

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 (245) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +1 -1
  3. package/docs/MAVIS-COMPATIBILITY.md +10 -6
  4. package/docs/MAVIS.md +15 -6
  5. package/docs/OPENCODE-COMPATIBILITY.md +2 -2
  6. package/docs/OPENCODE.md +1 -1
  7. package/package.json +1 -1
  8. package/presets/_shared/core/meta/preset-pr-checklist.md +2 -2
  9. package/presets/claude/android-kotlin/CLAUDE.md +3 -1
  10. package/presets/claude/android-kotlin/REPO_AGENTS.md +1 -1
  11. package/presets/claude/android-kotlin/hooks/README.md +6 -5
  12. package/presets/claude/android-kotlin/hooks/chain-team-phases.sh +18 -0
  13. package/presets/claude/android-kotlin/hooks/examples/README.md +2 -0
  14. package/presets/claude/android-kotlin/hooks/guard-shell-command.sh +32 -9
  15. package/presets/claude/android-kotlin/rules/README.md +1 -1
  16. package/presets/claude/android-kotlin/rules/tooling-and-review/ai-local-overlay.md +0 -5
  17. package/presets/claude/android-kotlin/rules/tooling-and-review/preset-pr-checklist.md +2 -2
  18. package/presets/claude/android-kotlin/settings.json +23 -0
  19. package/presets/claude/go/CLAUDE.md +3 -1
  20. package/presets/claude/go/REPO_AGENTS.md +1 -1
  21. package/presets/claude/go/hooks/README.md +6 -5
  22. package/presets/claude/go/hooks/chain-team-phases.sh +18 -0
  23. package/presets/claude/go/hooks/examples/README.md +2 -0
  24. package/presets/claude/go/hooks/guard-shell-command.sh +32 -9
  25. package/presets/claude/go/rules/README.md +1 -1
  26. package/presets/claude/go/rules/tooling-and-review/ai-local-overlay.md +0 -5
  27. package/presets/claude/go/rules/tooling-and-review/preset-pr-checklist.md +2 -2
  28. package/presets/claude/go/settings.json +23 -0
  29. package/presets/claude/ios-swift/CLAUDE.md +3 -1
  30. package/presets/claude/ios-swift/REPO_AGENTS.md +1 -1
  31. package/presets/claude/ios-swift/hooks/README.md +6 -5
  32. package/presets/claude/ios-swift/hooks/chain-team-phases.sh +18 -0
  33. package/presets/claude/ios-swift/hooks/examples/README.md +2 -0
  34. package/presets/claude/ios-swift/hooks/guard-shell-command.sh +32 -9
  35. package/presets/claude/ios-swift/rules/README.md +1 -1
  36. package/presets/claude/ios-swift/rules/tooling-and-review/ai-local-overlay.md +0 -5
  37. package/presets/claude/ios-swift/rules/tooling-and-review/preset-pr-checklist.md +2 -2
  38. package/presets/claude/ios-swift/settings.json +23 -0
  39. package/presets/claude/java/CLAUDE.md +3 -1
  40. package/presets/claude/java/REPO_AGENTS.md +1 -1
  41. package/presets/claude/java/hooks/README.md +6 -5
  42. package/presets/claude/java/hooks/chain-team-phases.sh +18 -0
  43. package/presets/claude/java/hooks/examples/README.md +2 -0
  44. package/presets/claude/java/hooks/guard-shell-command.sh +32 -9
  45. package/presets/claude/java/rules/README.md +1 -1
  46. package/presets/claude/java/rules/tooling-and-review/ai-local-overlay.md +0 -5
  47. package/presets/claude/java/rules/tooling-and-review/preset-pr-checklist.md +2 -2
  48. package/presets/claude/java/settings.json +23 -0
  49. package/presets/claude/mcp-ts/CLAUDE.md +3 -1
  50. package/presets/claude/mcp-ts/REPO_AGENTS.md +1 -1
  51. package/presets/claude/mcp-ts/hooks/README.md +8 -3
  52. package/presets/claude/mcp-ts/hooks/chain-team-phases.sh +18 -0
  53. package/presets/claude/mcp-ts/hooks/examples/README.md +5 -0
  54. package/presets/claude/mcp-ts/hooks/guard-shell-command.sh +32 -9
  55. package/presets/claude/mcp-ts/rules/README.md +1 -1
  56. package/presets/claude/mcp-ts/rules/tooling-and-review/ai-local-overlay.md +0 -5
  57. package/presets/claude/mcp-ts/rules/tooling-and-review/preset-pr-checklist.md +2 -2
  58. package/presets/claude/mcp-ts/settings.json +23 -0
  59. package/presets/claude/next/CLAUDE.md +3 -1
  60. package/presets/claude/next/REPO_AGENTS.md +1 -1
  61. package/presets/claude/next/hooks/README.md +10 -1
  62. package/presets/claude/next/hooks/chain-team-phases.sh +18 -0
  63. package/presets/claude/next/hooks/examples/README.md +2 -0
  64. package/presets/claude/next/hooks/guard-shell-command.sh +32 -9
  65. package/presets/claude/next/rules/README.md +1 -1
  66. package/presets/claude/next/rules/tooling-and-review/ai-local-overlay.md +0 -5
  67. package/presets/claude/next/rules/tooling-and-review/preset-pr-checklist.md +2 -2
  68. package/presets/claude/next/settings.json +23 -0
  69. package/presets/claude/nuxt/CLAUDE.md +3 -1
  70. package/presets/claude/nuxt/REPO_AGENTS.md +1 -1
  71. package/presets/claude/nuxt/hooks/README.md +7 -4
  72. package/presets/claude/nuxt/hooks/chain-team-phases.sh +18 -0
  73. package/presets/claude/nuxt/hooks/examples/README.md +2 -0
  74. package/presets/claude/nuxt/hooks/guard-shell-command.sh +32 -9
  75. package/presets/claude/nuxt/rules/README.md +1 -1
  76. package/presets/claude/nuxt/rules/tooling-and-review/ai-local-overlay.md +0 -5
  77. package/presets/claude/nuxt/rules/tooling-and-review/preset-pr-checklist.md +2 -2
  78. package/presets/claude/nuxt/settings.json +23 -0
  79. package/presets/claude/php-hexagonal/CLAUDE.md +3 -1
  80. package/presets/claude/php-hexagonal/REPO_AGENTS.md +1 -1
  81. package/presets/claude/php-hexagonal/hooks/README.md +6 -5
  82. package/presets/claude/php-hexagonal/hooks/chain-team-phases.sh +18 -0
  83. package/presets/claude/php-hexagonal/hooks/examples/README.md +3 -1
  84. package/presets/claude/php-hexagonal/hooks/guard-shell-command.sh +32 -9
  85. package/presets/claude/php-hexagonal/rules/README.md +1 -1
  86. package/presets/claude/php-hexagonal/rules/tooling-and-review/ai-local-overlay.md +0 -5
  87. package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-pr-checklist.md +2 -2
  88. package/presets/claude/php-hexagonal/settings.json +23 -0
  89. package/presets/claude/php-laravel/CLAUDE.md +6 -0
  90. package/presets/claude/php-laravel/REPO_AGENTS.md +1 -1
  91. package/presets/claude/php-laravel/hooks/README.md +6 -5
  92. package/presets/claude/php-laravel/hooks/chain-team-phases.sh +18 -0
  93. package/presets/claude/php-laravel/hooks/examples/README.md +3 -1
  94. package/presets/claude/php-laravel/hooks/guard-shell-command.sh +32 -9
  95. package/presets/claude/php-laravel/rules/README.md +1 -1
  96. package/presets/claude/php-laravel/rules/tooling-and-review/ai-local-overlay.md +0 -5
  97. package/presets/claude/php-laravel/rules/tooling-and-review/preset-pr-checklist.md +2 -2
  98. package/presets/claude/php-laravel/settings.json +23 -0
  99. package/presets/claude/svelte/CLAUDE.md +3 -1
  100. package/presets/claude/svelte/REPO_AGENTS.md +1 -1
  101. package/presets/claude/svelte/hooks/README.md +7 -4
  102. package/presets/claude/svelte/hooks/chain-team-phases.sh +18 -0
  103. package/presets/claude/svelte/hooks/examples/README.md +2 -0
  104. package/presets/claude/svelte/hooks/guard-shell-command.sh +32 -9
  105. package/presets/claude/svelte/rules/README.md +1 -1
  106. package/presets/claude/svelte/rules/tooling-and-review/ai-local-overlay.md +0 -5
  107. package/presets/claude/svelte/rules/tooling-and-review/preset-pr-checklist.md +2 -2
  108. package/presets/claude/svelte/settings.json +23 -0
  109. package/presets/cursor/android-kotlin/REPO_AGENTS.md +1 -1
  110. package/presets/cursor/android-kotlin/rules/preset-pr-checklist.mdc +2 -2
  111. package/presets/cursor/go/REPO_AGENTS.md +1 -1
  112. package/presets/cursor/go/rules/preset-pr-checklist.mdc +2 -2
  113. package/presets/cursor/ios-swift/REPO_AGENTS.md +1 -1
  114. package/presets/cursor/ios-swift/rules/preset-pr-checklist.mdc +2 -2
  115. package/presets/cursor/java/REPO_AGENTS.md +1 -1
  116. package/presets/cursor/java/rules/preset-pr-checklist.mdc +2 -2
  117. package/presets/cursor/mcp-ts/REPO_AGENTS.md +1 -1
  118. package/presets/cursor/mcp-ts/rules/preset-pr-checklist.mdc +2 -2
  119. package/presets/cursor/next/REPO_AGENTS.md +1 -1
  120. package/presets/cursor/next/rules/preset-pr-checklist.mdc +2 -2
  121. package/presets/cursor/nuxt/REPO_AGENTS.md +1 -1
  122. package/presets/cursor/nuxt/rules/preset-pr-checklist.mdc +2 -2
  123. package/presets/cursor/php-hexagonal/REPO_AGENTS.md +1 -1
  124. package/presets/cursor/php-hexagonal/rules/preset-pr-checklist.mdc +2 -2
  125. package/presets/cursor/php-laravel/REPO_AGENTS.md +1 -1
  126. package/presets/cursor/php-laravel/rules/preset-pr-checklist.mdc +2 -2
  127. package/presets/cursor/svelte/REPO_AGENTS.md +1 -1
  128. package/presets/cursor/svelte/rules/preset-pr-checklist.mdc +2 -2
  129. package/presets/mavis/README.md +2 -0
  130. package/presets/mavis/android-kotlin/MAVIS.md +10 -1
  131. package/presets/mavis/android-kotlin/REPO_AGENTS.md +1 -1
  132. package/presets/mavis/android-kotlin/adapter-map.json +1 -1
  133. package/presets/mavis/android-kotlin/rules/preset-pr-checklist.md +2 -2
  134. package/presets/mavis/go/MAVIS.md +10 -1
  135. package/presets/mavis/go/REPO_AGENTS.md +1 -1
  136. package/presets/mavis/go/adapter-map.json +1 -1
  137. package/presets/mavis/go/rules/preset-pr-checklist.md +2 -2
  138. package/presets/mavis/ios-swift/MAVIS.md +10 -1
  139. package/presets/mavis/ios-swift/REPO_AGENTS.md +1 -1
  140. package/presets/mavis/ios-swift/adapter-map.json +1 -1
  141. package/presets/mavis/ios-swift/rules/preset-pr-checklist.md +2 -2
  142. package/presets/mavis/java/MAVIS.md +10 -1
  143. package/presets/mavis/java/REPO_AGENTS.md +1 -1
  144. package/presets/mavis/java/adapter-map.json +1 -1
  145. package/presets/mavis/java/rules/preset-pr-checklist.md +2 -2
  146. package/presets/mavis/mcp-ts/MAVIS.md +10 -1
  147. package/presets/mavis/mcp-ts/REPO_AGENTS.md +1 -1
  148. package/presets/mavis/mcp-ts/adapter-map.json +1 -1
  149. package/presets/mavis/mcp-ts/rules/preset-pr-checklist.md +2 -2
  150. package/presets/mavis/next/MAVIS.md +10 -1
  151. package/presets/mavis/next/REPO_AGENTS.md +1 -1
  152. package/presets/mavis/next/adapter-map.json +1 -1
  153. package/presets/mavis/next/rules/preset-pr-checklist.md +2 -2
  154. package/presets/mavis/nuxt/MAVIS.md +10 -1
  155. package/presets/mavis/nuxt/REPO_AGENTS.md +1 -1
  156. package/presets/mavis/nuxt/adapter-map.json +1 -1
  157. package/presets/mavis/nuxt/rules/preset-pr-checklist.md +2 -2
  158. package/presets/mavis/php-hexagonal/MAVIS.md +10 -1
  159. package/presets/mavis/php-hexagonal/REPO_AGENTS.md +1 -1
  160. package/presets/mavis/php-hexagonal/adapter-map.json +1 -1
  161. package/presets/mavis/php-hexagonal/rules/preset-pr-checklist.md +2 -2
  162. package/presets/mavis/php-laravel/MAVIS.md +10 -1
  163. package/presets/mavis/php-laravel/REPO_AGENTS.md +1 -1
  164. package/presets/mavis/php-laravel/adapter-map.json +1 -1
  165. package/presets/mavis/php-laravel/rules/preset-pr-checklist.md +2 -2
  166. package/presets/mavis/platform-contract.json +4 -4
  167. package/presets/mavis/svelte/MAVIS.md +10 -1
  168. package/presets/mavis/svelte/REPO_AGENTS.md +1 -1
  169. package/presets/mavis/svelte/adapter-map.json +1 -1
  170. package/presets/mavis/svelte/rules/preset-pr-checklist.md +2 -2
  171. package/presets/opencode/README.md +1 -1
  172. package/presets/opencode/android-kotlin/OPENCODE.md +8 -1
  173. package/presets/opencode/android-kotlin/REPO_AGENTS.md +1 -1
  174. package/presets/opencode/android-kotlin/adapter-map.json +1 -1
  175. package/presets/opencode/android-kotlin/rules/preset-pr-checklist.md +2 -2
  176. package/presets/opencode/go/OPENCODE.md +8 -1
  177. package/presets/opencode/go/REPO_AGENTS.md +1 -1
  178. package/presets/opencode/go/adapter-map.json +1 -1
  179. package/presets/opencode/go/rules/preset-pr-checklist.md +2 -2
  180. package/presets/opencode/ios-swift/OPENCODE.md +8 -1
  181. package/presets/opencode/ios-swift/REPO_AGENTS.md +1 -1
  182. package/presets/opencode/ios-swift/adapter-map.json +1 -1
  183. package/presets/opencode/ios-swift/rules/preset-pr-checklist.md +2 -2
  184. package/presets/opencode/java/OPENCODE.md +8 -1
  185. package/presets/opencode/java/REPO_AGENTS.md +1 -1
  186. package/presets/opencode/java/adapter-map.json +1 -1
  187. package/presets/opencode/java/rules/preset-pr-checklist.md +2 -2
  188. package/presets/opencode/mcp-ts/OPENCODE.md +8 -1
  189. package/presets/opencode/mcp-ts/REPO_AGENTS.md +1 -1
  190. package/presets/opencode/mcp-ts/adapter-map.json +1 -1
  191. package/presets/opencode/mcp-ts/rules/preset-pr-checklist.md +2 -2
  192. package/presets/opencode/next/OPENCODE.md +8 -1
  193. package/presets/opencode/next/REPO_AGENTS.md +1 -1
  194. package/presets/opencode/next/adapter-map.json +1 -1
  195. package/presets/opencode/next/rules/preset-pr-checklist.md +2 -2
  196. package/presets/opencode/nuxt/OPENCODE.md +8 -1
  197. package/presets/opencode/nuxt/REPO_AGENTS.md +1 -1
  198. package/presets/opencode/nuxt/adapter-map.json +1 -1
  199. package/presets/opencode/nuxt/rules/preset-pr-checklist.md +2 -2
  200. package/presets/opencode/php-hexagonal/OPENCODE.md +8 -1
  201. package/presets/opencode/php-hexagonal/REPO_AGENTS.md +1 -1
  202. package/presets/opencode/php-hexagonal/adapter-map.json +1 -1
  203. package/presets/opencode/php-hexagonal/rules/preset-pr-checklist.md +2 -2
  204. package/presets/opencode/php-laravel/OPENCODE.md +8 -1
  205. package/presets/opencode/php-laravel/REPO_AGENTS.md +1 -1
  206. package/presets/opencode/php-laravel/adapter-map.json +1 -1
  207. package/presets/opencode/php-laravel/rules/preset-pr-checklist.md +2 -2
  208. package/presets/opencode/platform-contract.json +1 -1
  209. package/presets/opencode/svelte/OPENCODE.md +8 -1
  210. package/presets/opencode/svelte/REPO_AGENTS.md +1 -1
  211. package/presets/opencode/svelte/adapter-map.json +1 -1
  212. package/presets/opencode/svelte/rules/preset-pr-checklist.md +2 -2
  213. package/scripts/check-local-overlay.sh +40 -4
  214. package/scripts/check-mavis-local-overlay.mjs +23 -0
  215. package/scripts/check-mavis-platform-contract.mjs +5 -2
  216. package/scripts/check-opencode-local-overlay.mjs +19 -0
  217. package/scripts/check-opencode-platform-contract.mjs +5 -2
  218. package/scripts/check-preset-token-budget.sh +7 -0
  219. package/scripts/fixtures/cli-golden/claude/next.json +10 -10
  220. package/scripts/fixtures/cli-golden/cursor/next.json +2 -2
  221. package/scripts/fixtures/cli-golden/mavis/android-kotlin.json +3 -3
  222. package/scripts/fixtures/cli-golden/mavis/go.json +3 -3
  223. package/scripts/fixtures/cli-golden/mavis/ios-swift.json +3 -3
  224. package/scripts/fixtures/cli-golden/mavis/java.json +3 -3
  225. package/scripts/fixtures/cli-golden/mavis/mcp-ts.json +3 -3
  226. package/scripts/fixtures/cli-golden/mavis/next.json +3 -3
  227. package/scripts/fixtures/cli-golden/mavis/nuxt.json +3 -3
  228. package/scripts/fixtures/cli-golden/mavis/php-hexagonal.json +3 -3
  229. package/scripts/fixtures/cli-golden/mavis/php-laravel.json +3 -3
  230. package/scripts/fixtures/cli-golden/mavis/svelte.json +3 -3
  231. package/scripts/fixtures/cli-golden/opencode/android-kotlin.json +3 -3
  232. package/scripts/fixtures/cli-golden/opencode/go.json +3 -3
  233. package/scripts/fixtures/cli-golden/opencode/ios-swift.json +3 -3
  234. package/scripts/fixtures/cli-golden/opencode/java.json +3 -3
  235. package/scripts/fixtures/cli-golden/opencode/mcp-ts.json +3 -3
  236. package/scripts/fixtures/cli-golden/opencode/next.json +3 -3
  237. package/scripts/fixtures/cli-golden/opencode/nuxt.json +3 -3
  238. package/scripts/fixtures/cli-golden/opencode/php-hexagonal.json +3 -3
  239. package/scripts/fixtures/cli-golden/opencode/php-laravel.json +3 -3
  240. package/scripts/fixtures/cli-golden/opencode/svelte.json +3 -3
  241. package/scripts/lib/generate-mavis-adapter.mjs +10 -1
  242. package/scripts/lib/generate-opencode-adapter.mjs +8 -1
  243. package/scripts/sync-claude-settings.mjs +25 -0
  244. package/scripts/sync-dogfood-claude.sh +62 -0
  245. package/scripts/test-mavis-orchestration.mjs +3 -2
@@ -6,5 +6,28 @@
6
6
  "Bash(git push *)"
7
7
  ],
8
8
  "ask": []
9
+ },
10
+ "hooks": {
11
+ "PreToolUse": [
12
+ {
13
+ "matcher": "Bash",
14
+ "hooks": [
15
+ {
16
+ "type": "command",
17
+ "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-shell-command.sh"
18
+ }
19
+ ]
20
+ }
21
+ ],
22
+ "SubagentStop": [
23
+ {
24
+ "hooks": [
25
+ {
26
+ "type": "command",
27
+ "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/chain-team-phases.sh"
28
+ }
29
+ ]
30
+ }
31
+ ]
9
32
  }
10
33
  }
@@ -9,7 +9,8 @@ See @rules/README.md for the full catalog and loading strategy.
9
9
  ## Conventions
10
10
 
11
11
  - **One topic per file**; for large areas — subfolders under `rules/<topic>/`.
12
- - **Session-start rules** (no `paths:`) — exactly **three**: `next-app-core`, `package-manager`, `code-quality`.
12
+ - **Session-start rules** (no `paths:`) — 3–5: `next-app-core`, `package-manager`, `code-quality`, `ai-local-overlay`.
13
+ - **Local overlay (session-start):** `ai-local-overlay` has no `paths:` and counts in the 3–5 budget. On every turn, probe `ls -la .ai.local`, apply `.ai.local/rules/*.md` and `.ai.local/conventions.md`, and acknowledge `Using .ai.local: <rule-name>`. Guide: `docs/LOCAL-OVERLAY.md`.
13
14
  - **Domain-specific rules** — YAML frontmatter `paths:` (loaded when matching files are in play); `post-change-lint` — requestable (**required after code edits**); orchestrator and code-review — on-demand.
14
15
  - Slash commands — in `commands/`; scenarios — in `skills/`; subagents — in `agents/`.
15
16
 
@@ -49,3 +50,4 @@ Copies `CLAUDE.md`, `rules/**`, `commands/**`, `agents/**`, `hooks/**`, `MCP.md`
49
50
  `git commit/push deny`; JS stacks also `npx jest* deny` and `npm/npx/pnpm/bun`
50
51
  ask). Re-init overwrites the file (consumer can edit afterwards); mirror
51
52
  with root `AGENTS.md` if you change the harness.
53
+ - **Pipeline hooks:** `.claude/settings.json` `hooks` wires `guard-shell-command.sh` (`PreToolUse` / `Bash`, `permissionDecision` `ask` or `allow`) and `chain-team-phases.sh` (`SubagentStop` for kebab-case `agent_type`). See `hooks/README.md`. No `hooks.json`.
@@ -71,4 +71,4 @@ A `.ai.local/` directory MAY exist at the repo root or at any nesting depth in m
71
71
 
72
72
  Plain markdown rules under `.ai.local/rules/*.md` are read by the agent with higher priority than preset rules. Living gotchas live in `.ai.local/conventions.md`.
73
73
 
74
- Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules` package. The `ai-local-overlay` rule (always-on for Cursor, on-demand for Claude) is the mechanism; this `MANDATORY` section is the reinforcement.
74
+ On every turn, probe `ls -la .ai.local`, apply `.ai.local/rules/*.md` and `.ai.local/conventions.md`, and acknowledge `Using .ai.local: <rule-name>`. Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules` package. The `ai-local-overlay` rule is always-on on Cursor and session-start on Claude (no `paths:`). Mavis and OpenCode have no native `alwaysApply`; this section plus the platform entry's essential-rules list is the reinforcement.
@@ -5,4 +5,13 @@
5
5
  | `chain-team-phases.sh` | Continues `/task` after a producer receipt. Reads/writes `.ai.local/team/`. Agents must not patch `status.json` / `metrics.json`. |
6
6
  | `guard-shell-command.sh` | Destructive git / package-manager guard |
7
7
 
8
- No `hooks.json`. Wire `chain-team-phases.sh` per [Claude Code hooks](https://code.claude.com/docs/en/hooks). Cookbook: `hooks/examples/` (not enabled by default).
8
+ No `hooks.json`. Default chain and shell guard are registered in `.claude/settings.json` (see **Shipped wiring**). Cookbook scripts in `hooks/examples/` stay unwired.
9
+
10
+ ## Shipped wiring (Claude Code settings)
11
+
12
+ `.claude/settings.json` `hooks` (https://code.claude.com/docs/en/hooks) registers:
13
+
14
+ - `PreToolUse` matcher `Bash` → `guard-shell-command.sh` (reads `tool_input.command`; emits `permissionDecision` `ask` or `allow`)
15
+ - `SubagentStop` → `chain-team-phases.sh` (kebab-case `agent_type` maps to `status: completed`; empty or non-kebab types are ignored; `stop_hook_active` does not recurse)
16
+
17
+ There is no `hooks.json`. Cookbook scripts under `hooks/examples/` stay unwired. A hook crash is not a deny (Cursor `failClosed` has no Claude field); `ask` is the supported review decision.
@@ -21,6 +21,24 @@ try {
21
21
  process.exit(0);
22
22
  }
23
23
 
24
+ // Claude Code SubagentStop has hook_event_name / agent_type / stop_hook_active, not status.
25
+ // Kebab-case agent_type (preset roles) is the completed signal. Empty or non-kebab
26
+ // types (Claude internal agents) do not advance the pipeline. stop_hook_active
27
+ // means this hook already continued the turn — do not recurse.
28
+ // Manual pipes of {"status":"completed"} skip this block.
29
+ if (hookInput.hook_event_name === 'SubagentStop') {
30
+ if (hookInput.stop_hook_active === true) {
31
+ process.stdout.write('{}');
32
+ process.exit(0);
33
+ }
34
+ const agentType = typeof hookInput.agent_type === 'string' ? hookInput.agent_type : '';
35
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(agentType)) {
36
+ process.stdout.write('{}');
37
+ process.exit(0);
38
+ }
39
+ if (hookInput.status == null) hookInput.status = 'completed';
40
+ }
41
+
24
42
  if (hookInput.status !== 'completed') {
25
43
  process.stdout.write('{}');
26
44
  process.exit(0);
@@ -10,6 +10,8 @@ Optional scripts under `hooks/examples/`. **Not** referenced from default `hooks
10
10
 
11
11
  ## Wiring (Claude Code)
12
12
 
13
+ Default `.claude/settings.json` already registers `guard-shell-command.sh` on `PreToolUse` (matcher `Bash`) and `chain-team-phases.sh` on `SubagentStop`. Cookbook scripts are not in that default set.
14
+
13
15
  Claude Code has no preset `hooks.json`; hooks are registered in `.claude/settings.json` and fire on events such as `PreToolUse`, `PostToolUse`, and `Stop`.
14
16
 
15
17
  1. Copy an example into `hooks/` (drop `.example` suffix), e.g. `cp hooks/examples/secret-guard.example.sh hooks/secret-guard.sh`.
@@ -17,20 +17,43 @@ try {
17
17
  process.exit(0);
18
18
  }
19
19
 
20
- const command = String(event.command || event.input?.command || '');
21
- if (!command.trim()) {
22
- process.stdout.write('{ "permission": "allow" }');
23
- process.exit(0);
24
- }
20
+ const claudePreTool = event.hook_event_name === 'PreToolUse';
21
+ const command = String(
22
+ event.command
23
+ || (event.input && event.input.command)
24
+ || (event.tool_input && event.tool_input.command)
25
+ || '',
26
+ );
25
27
 
26
- function out(permission, userMessage, agentMessage) {
28
+ function out(permission, userMessage) {
29
+ if (claudePreTool) {
30
+ const decision = permission === 'ask' || permission === 'deny' ? permission : 'allow';
31
+ const hookSpecificOutput = {
32
+ hookEventName: 'PreToolUse',
33
+ permissionDecision: decision,
34
+ };
35
+ if (userMessage && decision !== 'allow') {
36
+ hookSpecificOutput.permissionDecisionReason = userMessage;
37
+ }
38
+ process.stdout.write(JSON.stringify({ hookSpecificOutput }));
39
+ return;
40
+ }
41
+ if (!userMessage) {
42
+ process.stdout.write('{ "permission": "allow" }');
43
+ return;
44
+ }
27
45
  process.stdout.write(JSON.stringify({
28
46
  permission,
29
47
  user_message: userMessage,
30
- agent_message: agentMessage || userMessage,
48
+ agent_message: userMessage,
31
49
  }));
32
50
  }
33
51
 
52
+ if (!command.trim()) {
53
+ out('allow');
54
+ process.exit(0);
55
+ }
56
+
34
57
  const dangerousGit = /\bgit\s+(reset\s+--hard|clean\s+-[^\n]*f|push\s+--force|push\s+-f|checkout\s+--\s+)/;
35
58
  if (dangerousGit.test(command)) {
36
59
  out(
@@ -59,7 +82,7 @@ if (!expected && fs.existsSync('package.json')) {
59
82
  }
60
83
 
61
84
  if (!expected) {
62
- process.stdout.write('{ "permission": "allow" }');
85
+ out('allow');
63
86
  process.exit(0);
64
87
  }
65
88
 
@@ -73,5 +96,5 @@ if (used && used !== expected) {
73
96
  process.exit(0);
74
97
  }
75
98
 
76
- process.stdout.write('{ "permission": "allow" }');
99
+ out('allow');
77
100
  NODE
@@ -14,7 +14,7 @@ In Claude Code all `.md` files under `rules/` are **discovered recursively**. Bo
14
14
 
15
15
  ## Loading strategy
16
16
 
17
- - **Session start (no `paths:`):** 3–5 — `next-app-core`, `package-manager`, `code-quality`
17
+ - **Session start (no `paths:`):** 3–5 — `next-app-core`, `package-manager`, `code-quality`, `ai-local-overlay`
18
18
  - **On-demand (`paths:` or via commands):** `post-change-lint` (**must after code edits**), `agent-team-intake`, `agent-team-orchestrator`, `code-review-mr`, `security-next`, architecture, imports, UI, tests, feature-delivery-workflow, `design-guidance`, `mcp-usage`, `anti-sycophancy-discipline`, `react-next-anti-hallucination`, reference-features, next-app-router, react-a11y-coding, `technical-retro`, `mockup-review`, `ux-design`, **preset-*** meta (paths on `packages/ai-rules/presets/**`)
19
19
  - **Skills:** long workflows (`feature-delivery`, `spec-authoring`, `spec-discovery`, `code-review`, …)
20
20
 
@@ -1,10 +1,5 @@
1
1
  ---
2
2
  description: Local overlay from .ai.local/ (consumer-owned rules with priority over preset rules) — MANDATORY
3
- paths:
4
- - "**/.ai.local/**"
5
- - "**/AGENTS.md"
6
- - "**/CLAUDE.md"
7
- alwaysApply: false
8
3
  impact: CRITICAL
9
4
  ---
10
5
 
@@ -30,7 +30,7 @@ Checklist for PRs that touch `packages/ai-rules/presets/**` (and dogfood `.curso
30
30
  - [ ] **README:** stack `rules/README.md` core→stack mapping / catalog updated if stems added
31
31
  - [ ] **CHANGELOG / package README:** note when public preset paths or install surface change
32
32
  - [ ] **i18n anchors:** kept-marked Cyrillic fragments in `tests-unit.md(c)` stay consistent with their English counterparts. Run `packages/ai-rules/scripts/check-preset-i18n.sh`.
33
- - [ ] **Dogfood:** run `packages/ai-rules/scripts/sync-dogfood-cursor.sh` (and `sync-dogfood-mavis.sh` / `sync-dogfood-opencode.sh` when those platforms changed), or document an intentional skip, when maintaining this monorepo
33
+ - [ ] **Dogfood:** run `packages/ai-rules/scripts/sync-dogfood-cursor.sh`, `sync-dogfood-claude.sh`, `sync-dogfood-mavis.sh`, and `sync-dogfood-opencode.sh` when those platforms changed, or document an intentional skip, when maintaining this monorepo
34
34
  - [ ] **shared-core drift:** for embed-mode stems, run `packages/ai-rules/scripts/check-shared-core-drift.sh` (or document intentional fork)
35
35
 
36
36
  ## Pointers
@@ -40,6 +40,6 @@ Checklist for PRs that touch `packages/ai-rules/presets/**` (and dogfood `.curso
40
40
  - Budget: `preset-token-budget`
41
41
  - Leakage: `preset-no-cross-stack-leakage`
42
42
  - Validation: stack `agents/build-verifier.md` → preset-structure section
43
- - Dogfood scripts: `packages/ai-rules/scripts/sync-dogfood-cursor.sh`, `sync-dogfood-mavis.sh`, `sync-dogfood-opencode.sh`
43
+ - Dogfood scripts: `packages/ai-rules/scripts/sync-dogfood-cursor.sh`, `sync-dogfood-claude.sh`, `sync-dogfood-mavis.sh`, `sync-dogfood-opencode.sh`
44
44
  - Drift script: `packages/ai-rules/scripts/check-shared-core-drift.sh`
45
45
  - Orchestrator: when editing presets, load this checklist + twin-sync
@@ -12,5 +12,28 @@
12
12
  "Bash(npx *)",
13
13
  "Bash(pnpm *)"
14
14
  ]
15
+ },
16
+ "hooks": {
17
+ "PreToolUse": [
18
+ {
19
+ "matcher": "Bash",
20
+ "hooks": [
21
+ {
22
+ "type": "command",
23
+ "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-shell-command.sh"
24
+ }
25
+ ]
26
+ }
27
+ ],
28
+ "SubagentStop": [
29
+ {
30
+ "hooks": [
31
+ {
32
+ "type": "command",
33
+ "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/chain-team-phases.sh"
34
+ }
35
+ ]
36
+ }
37
+ ]
15
38
  }
16
39
  }
@@ -9,7 +9,8 @@ See @rules/README.md for the full catalog and loading strategy.
9
9
  ## Conventions
10
10
 
11
11
  - **One topic per file**; for large areas — subfolders under `rules/<topic>/`.
12
- - **Session-start rules** (no `paths:`) — exactly **three**: `nuxt-app-core`, `package-manager`, `code-quality`.
12
+ - **Session-start rules** (no `paths:`) — 3–5: `nuxt-app-core`, `package-manager`, `code-quality`, `ai-local-overlay`.
13
+ - **Local overlay (session-start):** `ai-local-overlay` has no `paths:` and counts in the 3–5 budget. On every turn, probe `ls -la .ai.local`, apply `.ai.local/rules/*.md` and `.ai.local/conventions.md`, and acknowledge `Using .ai.local: <rule-name>`. Guide: `docs/LOCAL-OVERLAY.md`.
13
14
  - **Domain-specific rules** — YAML frontmatter `paths:` (loaded when matching files); `post-change-lint` — requestable (**required after code edits**); orchestrator and code-review — on-demand.
14
15
  - Slash commands — in `commands/`; scenarios — in `skills/`; subagents — in `agents/`.
15
16
 
@@ -49,3 +50,4 @@ Copies `CLAUDE.md`, `rules/**`, `commands/**`, `agents/**`, `hooks/**`, `MCP.md`
49
50
  `git commit/push deny`; JS stacks also `npx jest* deny` and `npm/npx/pnpm/bun`
50
51
  ask). Re-init overwrites the file (consumer can edit afterwards); mirror
51
52
  with root `AGENTS.md` if you change the harness.
53
+ - **Pipeline hooks:** `.claude/settings.json` `hooks` wires `guard-shell-command.sh` (`PreToolUse` / `Bash`, `permissionDecision` `ask` or `allow`) and `chain-team-phases.sh` (`SubagentStop` for kebab-case `agent_type`). See `hooks/README.md`. No `hooks.json`.
@@ -72,4 +72,4 @@ A `.ai.local/` directory MAY exist at the repo root or at any nesting depth in m
72
72
 
73
73
  Plain markdown rules under `.ai.local/rules/*.md` are read by the agent with higher priority than preset rules. Living gotchas live in `.ai.local/conventions.md`.
74
74
 
75
- Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules` package. The `ai-local-overlay` rule (always-on for Cursor, on-demand for Claude) is the mechanism; this `MANDATORY` section is the reinforcement.
75
+ On every turn, probe `ls -la .ai.local`, apply `.ai.local/rules/*.md` and `.ai.local/conventions.md`, and acknowledge `Using .ai.local: <rule-name>`. Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules` package. The `ai-local-overlay` rule is always-on on Cursor and session-start on Claude (no `paths:`). Mavis and OpenCode have no native `alwaysApply`; this section plus the platform entry's essential-rules list is the reinforcement.
@@ -5,10 +5,13 @@
5
5
  | `chain-team-phases.sh` | Pipeline chaining after subagent stop; `skipIf`, parallel, `validation_failed`, `retryAfterFix` |
6
6
  | `guard-shell-command.sh` | Destructive git / package-manager guard |
7
7
 
8
- Wire into Claude Code hooks per project documentation when enabling agent team auto-chain.
8
+ No `hooks.json`. Default chain and shell guard are registered in `.claude/settings.json` (see **Shipped wiring**). Cookbook scripts in `hooks/examples/` stay unwired; keep stack-safe recipes (this preset: **nuxt**).
9
9
 
10
- ## Optional cookbook
10
+ ## Shipped wiring (Claude Code settings)
11
11
 
12
- Example scripts live in `hooks/examples/` (secret-guard, format-edited, test-on-save). They are **not** auto-enabled.
12
+ `.claude/settings.json` `hooks` (https://code.claude.com/docs/en/hooks) registers:
13
13
 
14
- To wire in Claude Code: copy an `.example.sh` into `hooks/`, make executable, and register per [Claude Code hooks](https://code.claude.com/docs/en/hooks) for your project. Keep stack-safe recipes (this preset: **nuxt**). Cursor twin examples under `presets/cursor/nuxt/hooks/examples/` are the same allowlist forks.
14
+ - `PreToolUse` matcher `Bash` → `guard-shell-command.sh` (reads `tool_input.command`; emits `permissionDecision` `ask` or `allow`)
15
+ - `SubagentStop` → `chain-team-phases.sh` (kebab-case `agent_type` maps to `status: completed`; empty or non-kebab types are ignored; `stop_hook_active` does not recurse)
16
+
17
+ There is no `hooks.json`. Cookbook scripts under `hooks/examples/` stay unwired. A hook crash is not a deny (Cursor `failClosed` has no Claude field); `ask` is the supported review decision.
@@ -21,6 +21,24 @@ try {
21
21
  process.exit(0);
22
22
  }
23
23
 
24
+ // Claude Code SubagentStop has hook_event_name / agent_type / stop_hook_active, not status.
25
+ // Kebab-case agent_type (preset roles) is the completed signal. Empty or non-kebab
26
+ // types (Claude internal agents) do not advance the pipeline. stop_hook_active
27
+ // means this hook already continued the turn — do not recurse.
28
+ // Manual pipes of {"status":"completed"} skip this block.
29
+ if (hookInput.hook_event_name === 'SubagentStop') {
30
+ if (hookInput.stop_hook_active === true) {
31
+ process.stdout.write('{}');
32
+ process.exit(0);
33
+ }
34
+ const agentType = typeof hookInput.agent_type === 'string' ? hookInput.agent_type : '';
35
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(agentType)) {
36
+ process.stdout.write('{}');
37
+ process.exit(0);
38
+ }
39
+ if (hookInput.status == null) hookInput.status = 'completed';
40
+ }
41
+
24
42
  if (hookInput.status !== 'completed') {
25
43
  process.stdout.write('{}');
26
44
  process.exit(0);
@@ -10,6 +10,8 @@ Optional scripts under `hooks/examples/`. **Not** referenced from default `hooks
10
10
 
11
11
  ## Wiring (Claude Code)
12
12
 
13
+ Default `.claude/settings.json` already registers `guard-shell-command.sh` on `PreToolUse` (matcher `Bash`) and `chain-team-phases.sh` on `SubagentStop`. Cookbook scripts are not in that default set.
14
+
13
15
  Claude Code has no preset `hooks.json`; hooks are registered in `.claude/settings.json` and fire on events such as `PreToolUse`, `PostToolUse`, and `Stop`.
14
16
 
15
17
  1. Copy an example into `hooks/` (drop `.example` suffix), e.g. `cp hooks/examples/secret-guard.example.sh hooks/secret-guard.sh`.
@@ -17,20 +17,43 @@ try {
17
17
  process.exit(0);
18
18
  }
19
19
 
20
- const command = String(event.command || event.input?.command || '');
21
- if (!command.trim()) {
22
- process.stdout.write('{ "permission": "allow" }');
23
- process.exit(0);
24
- }
20
+ const claudePreTool = event.hook_event_name === 'PreToolUse';
21
+ const command = String(
22
+ event.command
23
+ || (event.input && event.input.command)
24
+ || (event.tool_input && event.tool_input.command)
25
+ || '',
26
+ );
25
27
 
26
- function out(permission, userMessage, agentMessage) {
28
+ function out(permission, userMessage) {
29
+ if (claudePreTool) {
30
+ const decision = permission === 'ask' || permission === 'deny' ? permission : 'allow';
31
+ const hookSpecificOutput = {
32
+ hookEventName: 'PreToolUse',
33
+ permissionDecision: decision,
34
+ };
35
+ if (userMessage && decision !== 'allow') {
36
+ hookSpecificOutput.permissionDecisionReason = userMessage;
37
+ }
38
+ process.stdout.write(JSON.stringify({ hookSpecificOutput }));
39
+ return;
40
+ }
41
+ if (!userMessage) {
42
+ process.stdout.write('{ "permission": "allow" }');
43
+ return;
44
+ }
27
45
  process.stdout.write(JSON.stringify({
28
46
  permission,
29
47
  user_message: userMessage,
30
- agent_message: agentMessage || userMessage,
48
+ agent_message: userMessage,
31
49
  }));
32
50
  }
33
51
 
52
+ if (!command.trim()) {
53
+ out('allow');
54
+ process.exit(0);
55
+ }
56
+
34
57
  const dangerousGit = /\bgit\s+(reset\s+--hard|clean\s+-[^\n]*f|push\s+--force|push\s+-f|checkout\s+--\s+)/;
35
58
  if (dangerousGit.test(command)) {
36
59
  out(
@@ -59,7 +82,7 @@ if (!expected && fs.existsSync('package.json')) {
59
82
  }
60
83
 
61
84
  if (!expected) {
62
- process.stdout.write('{ "permission": "allow" }');
85
+ out('allow');
63
86
  process.exit(0);
64
87
  }
65
88
 
@@ -73,5 +96,5 @@ if (used && used !== expected) {
73
96
  process.exit(0);
74
97
  }
75
98
 
76
- process.stdout.write('{ "permission": "allow" }');
99
+ out('allow');
77
100
  NODE
@@ -14,7 +14,7 @@ In Claude Code all `.md` files under `rules/` are **discovered recursively**. Bo
14
14
 
15
15
  ## Loading strategy
16
16
 
17
- - **Session start (no `paths:`):** 3–5 — `nuxt-app-core`, `package-manager`, `code-quality`
17
+ - **Session start (no `paths:`):** 3–5 — `nuxt-app-core`, `package-manager`, `code-quality`, `ai-local-overlay`
18
18
  - **On-demand (`paths:` or via commands):** `post-change-lint`, `security-nuxt`, architecture, UI, tests, `vue-nuxt-anti-hallucination`, **preset-*** meta, …
19
19
  - **Skills:** `feature-delivery`, `vue-performance`, `code-review`, …
20
20
 
@@ -1,10 +1,5 @@
1
1
  ---
2
2
  description: Local overlay from .ai.local/ (consumer-owned rules with priority over preset rules) — MANDATORY
3
- paths:
4
- - "**/.ai.local/**"
5
- - "**/AGENTS.md"
6
- - "**/CLAUDE.md"
7
- alwaysApply: false
8
3
  impact: CRITICAL
9
4
  ---
10
5
 
@@ -26,7 +26,7 @@ Checklist for PRs that touch `packages/ai-rules/presets/**` (and dogfood `.curso
26
26
  - [ ] **README:** stack `rules/README.md` core→stack mapping / catalog updated if stems added
27
27
  - [ ] **CHANGELOG / package README:** note when public preset paths or install surface change
28
28
  - [ ] **i18n anchors:** kept-marked Cyrillic fragments in `tests-unit.md(c)` stay consistent with their English counterparts. Run `packages/ai-rules/scripts/check-preset-i18n.sh`.
29
- - [ ] **Dogfood:** run `packages/ai-rules/scripts/sync-dogfood-cursor.sh` (and `sync-dogfood-mavis.sh` / `sync-dogfood-opencode.sh` when those platforms changed), or document an intentional skip, when maintaining this monorepo
29
+ - [ ] **Dogfood:** run `packages/ai-rules/scripts/sync-dogfood-cursor.sh`, `sync-dogfood-claude.sh`, `sync-dogfood-mavis.sh`, and `sync-dogfood-opencode.sh` when those platforms changed, or document an intentional skip, when maintaining this monorepo
30
30
  - [ ] **shared-core drift:** for embed-mode stems, run `packages/ai-rules/scripts/check-shared-core-drift.sh` (or document intentional fork)
31
31
 
32
32
  ## Pointers
@@ -36,6 +36,6 @@ Checklist for PRs that touch `packages/ai-rules/presets/**` (and dogfood `.curso
36
36
  - Budget: `preset-token-budget`
37
37
  - Leakage: `preset-no-cross-stack-leakage`
38
38
  - Validation: stack `agents/build-verifier.md` → preset-structure section
39
- - Dogfood scripts: `packages/ai-rules/scripts/sync-dogfood-cursor.sh`, `sync-dogfood-mavis.sh`, `sync-dogfood-opencode.sh`
39
+ - Dogfood scripts: `packages/ai-rules/scripts/sync-dogfood-cursor.sh`, `sync-dogfood-claude.sh`, `sync-dogfood-mavis.sh`, `sync-dogfood-opencode.sh`
40
40
  - Drift script: `packages/ai-rules/scripts/check-shared-core-drift.sh`
41
41
  - Orchestrator: when editing presets, load this checklist + twin-sync
@@ -12,5 +12,28 @@
12
12
  "Bash(npx *)",
13
13
  "Bash(pnpm *)"
14
14
  ]
15
+ },
16
+ "hooks": {
17
+ "PreToolUse": [
18
+ {
19
+ "matcher": "Bash",
20
+ "hooks": [
21
+ {
22
+ "type": "command",
23
+ "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-shell-command.sh"
24
+ }
25
+ ]
26
+ }
27
+ ],
28
+ "SubagentStop": [
29
+ {
30
+ "hooks": [
31
+ {
32
+ "type": "command",
33
+ "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/chain-team-phases.sh"
34
+ }
35
+ ]
36
+ }
37
+ ]
15
38
  }
16
39
  }
@@ -4,7 +4,8 @@ Preset for PHP backends using ports & adapters (PSR / Composer-first).
4
4
 
5
5
  **Repo-root agents:** see [`AGENTS.md`](../../AGENTS.md) at the project root.
6
6
 
7
- - Session-start: `php-app-core`, `architecture/boundaries`, `code-quality` (3–5).
7
+ - Session-start: `php-app-core`, `architecture/boundaries`, `code-quality`, `ai-local-overlay` (3–5).
8
+ - **Local overlay (session-start):** `ai-local-overlay` has no `paths:` and counts in the 3–5 budget. On every turn, probe `ls -la .ai.local`, apply `.ai.local/rules/*.md` and `.ai.local/conventions.md`, and acknowledge `Using .ai.local: <rule-name>`. Guide: `docs/LOCAL-OVERLAY.md`.
8
9
  - Delivery: `architecture/feature-delivery.md` + skill `feature-delivery`.
9
10
  - After PHP edits: `tooling-and-review/post-change-test.md` (+ `php-tooling`).
10
11
  - Integration tests: agents `integration-test-*` + skill `integration-testing` (never Playwright/XCUITest).
@@ -41,3 +42,4 @@ Init: `npx @bonesofspring/ai-rules init claude --preset php-hexagonal` (also cop
41
42
  `git commit/push deny`; JS stacks also `npx jest* deny` and `npm/npx/pnpm/bun`
42
43
  ask). Re-init overwrites the file (consumer can edit afterwards); mirror
43
44
  with root `AGENTS.md` if you change the harness.
45
+ - **Pipeline hooks:** `.claude/settings.json` `hooks` wires `guard-shell-command.sh` (`PreToolUse` / `Bash`, `permissionDecision` `ask` or `allow`) and `chain-team-phases.sh` (`SubagentStop` for kebab-case `agent_type`). See `hooks/README.md`. No `hooks.json`.
@@ -70,4 +70,4 @@ A `.ai.local/` directory MAY exist at the repo root or at any nesting depth in m
70
70
 
71
71
  Plain markdown rules under `.ai.local/rules/*.md` are read by the agent with higher priority than preset rules. Living gotchas live in `.ai.local/conventions.md`.
72
72
 
73
- Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules` package. The `ai-local-overlay` rule (always-on for Cursor, on-demand for Claude) is the mechanism; this `MANDATORY` section is the reinforcement.
73
+ On every turn, probe `ls -la .ai.local`, apply `.ai.local/rules/*.md` and `.ai.local/conventions.md`, and acknowledge `Using .ai.local: <rule-name>`. Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules` package. The `ai-local-overlay` rule is always-on on Cursor and session-start on Claude (no `paths:`). Mavis and OpenCode have no native `alwaysApply`; this section plus the platform entry's essential-rules list is the reinforcement.
@@ -5,12 +5,13 @@
5
5
  | `chain-team-phases.sh` | Pipeline chaining after subagent stop (`TEAM_ROOT=.ai.local/team`) |
6
6
  | `guard-shell-command.sh` | Destructive git / JS package-manager guard; **allows** `composer test / vendor/bin/phpunit` / `compiler/IDE inspections` / `configured static analysis` / `repo static analysis` |
7
7
 
8
- Claude Code may not use Cursor `hooks.json`. Wire scripts per project docs when enabling agent-team auto-chain.
8
+ No `hooks.json`. Default chain and shell guard are registered in `.claude/settings.json` (see **Shipped wiring**). Cookbook scripts in `hooks/examples/` stay unwired; keep stack-safe recipes (this preset: **php-hexagonal**).
9
9
 
10
- **No `hooks.json` in Claude preset** (platform limit — same as next Claude).
10
+ ## Shipped wiring (Claude Code settings)
11
11
 
12
- ## Optional cookbook
12
+ `.claude/settings.json` `hooks` (https://code.claude.com/docs/en/hooks) registers:
13
13
 
14
- Example scripts live in `hooks/examples/` (secret-guard, format-edited, test-on-save). They are **not** auto-enabled.
14
+ - `PreToolUse` matcher `Bash` → `guard-shell-command.sh` (reads `tool_input.command`; emits `permissionDecision` `ask` or `allow`)
15
+ - `SubagentStop` → `chain-team-phases.sh` (kebab-case `agent_type` maps to `status: completed`; empty or non-kebab types are ignored; `stop_hook_active` does not recurse)
15
16
 
16
- To wire in Claude Code: copy an `.example.sh` into `hooks/`, make executable, and register per [Claude Code hooks](https://code.claude.com/docs/en/hooks) for your project. Keep stack-safe recipes (this preset: **php-hexagonal**). Cursor twin examples under `presets/cursor/php-hexagonal/hooks/examples/` are the same allowlist forks.
17
+ There is no `hooks.json`. Cookbook scripts under `hooks/examples/` stay unwired. A hook crash is not a deny (Cursor `failClosed` has no Claude field); `ask` is the supported review decision.
@@ -23,6 +23,24 @@ try {
23
23
  process.exit(0);
24
24
  }
25
25
 
26
+ // Claude Code SubagentStop has hook_event_name / agent_type / stop_hook_active, not status.
27
+ // Kebab-case agent_type (preset roles) is the completed signal. Empty or non-kebab
28
+ // types (Claude internal agents) do not advance the pipeline. stop_hook_active
29
+ // means this hook already continued the turn — do not recurse.
30
+ // Manual pipes of {"status":"completed"} skip this block.
31
+ if (hookInput.hook_event_name === 'SubagentStop') {
32
+ if (hookInput.stop_hook_active === true) {
33
+ process.stdout.write('{}');
34
+ process.exit(0);
35
+ }
36
+ const agentType = typeof hookInput.agent_type === 'string' ? hookInput.agent_type : '';
37
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(agentType)) {
38
+ process.stdout.write('{}');
39
+ process.exit(0);
40
+ }
41
+ if (hookInput.status == null) hookInput.status = 'completed';
42
+ }
43
+
26
44
  if (hookInput.status !== 'completed') {
27
45
  process.stdout.write('{}');
28
46
  process.exit(0);
@@ -10,6 +10,8 @@ Optional scripts under `hooks/examples/`. **Not** referenced from default `hooks
10
10
 
11
11
  ## Wiring (Claude Code)
12
12
 
13
+ Default `.claude/settings.json` already registers `guard-shell-command.sh` on `PreToolUse` (matcher `Bash`) and `chain-team-phases.sh` on `SubagentStop`. Cookbook scripts are not in that default set.
14
+
13
15
  Claude Code has no preset `hooks.json`; hooks are registered in `.claude/settings.json` and fire on events such as `PreToolUse`, `PostToolUse`, and `Stop`.
14
16
 
15
17
  1. Copy an example into `hooks/` (drop `.example` suffix), e.g. `cp hooks/examples/secret-guard.example.sh hooks/secret-guard.sh`.
@@ -17,4 +19,4 @@ Claude Code has no preset `hooks.json`; hooks are registered in `.claude/setting
17
19
  3. Register the command in `.claude/settings.json` (see Claude Code hooks docs for event/matcher syntax).
18
20
  4. Keep cookbook scripts **out** of the default preset when contributing back upstream.
19
21
 
20
- Stack: **go** — recipes must stay stack-safe (no cross-stack lint/test commands).
22
+ Stack: **php-hexagonal** — recipes must stay stack-safe (no cross-stack lint/test commands).
@@ -20,20 +20,43 @@ try {
20
20
  process.exit(0);
21
21
  }
22
22
 
23
- const command = String(event.command || event.input?.command || '');
24
- if (!command.trim()) {
25
- process.stdout.write('{ "permission": "allow" }');
26
- process.exit(0);
27
- }
23
+ const claudePreTool = event.hook_event_name === 'PreToolUse';
24
+ const command = String(
25
+ event.command
26
+ || (event.input && event.input.command)
27
+ || (event.tool_input && event.tool_input.command)
28
+ || '',
29
+ );
28
30
 
29
- function out(permission, userMessage, agentMessage) {
31
+ function out(permission, userMessage) {
32
+ if (claudePreTool) {
33
+ const decision = permission === 'ask' || permission === 'deny' ? permission : 'allow';
34
+ const hookSpecificOutput = {
35
+ hookEventName: 'PreToolUse',
36
+ permissionDecision: decision,
37
+ };
38
+ if (userMessage && decision !== 'allow') {
39
+ hookSpecificOutput.permissionDecisionReason = userMessage;
40
+ }
41
+ process.stdout.write(JSON.stringify({ hookSpecificOutput }));
42
+ return;
43
+ }
44
+ if (!userMessage) {
45
+ process.stdout.write('{ "permission": "allow" }');
46
+ return;
47
+ }
30
48
  process.stdout.write(JSON.stringify({
31
49
  permission,
32
50
  user_message: userMessage,
33
- agent_message: agentMessage || userMessage,
51
+ agent_message: userMessage,
34
52
  }));
35
53
  }
36
54
 
55
+ if (!command.trim()) {
56
+ out('allow');
57
+ process.exit(0);
58
+ }
59
+
37
60
  const dangerousGit = /\bgit\s+(reset\s+--hard|clean\s+-[^\n]*f|push\s+--force|push\s+-f|checkout\s+--\s+)/;
38
61
  if (dangerousGit.test(command)) {
39
62
  out(
@@ -62,7 +85,7 @@ if (!expected && fs.existsSync('package.json')) {
62
85
  }
63
86
 
64
87
  if (!expected) {
65
- process.stdout.write('{ "permission": "allow" }');
88
+ out('allow');
66
89
  process.exit(0);
67
90
  }
68
91
 
@@ -76,5 +99,5 @@ if (used && used !== expected) {
76
99
  process.exit(0);
77
100
  }
78
101
 
79
- process.stdout.write('{ "permission": "allow" }');
102
+ out('allow');
80
103
  NODE
@@ -12,7 +12,7 @@ Claude topic `.md` files are **derived** from Cursor SoT `presets/cursor/php-hex
12
12
 
13
13
  ## Loading budget
14
14
 
15
- - **Session-start (no `paths:`):** 3–5 — `php-app-core`, `boundaries`, `code-quality`
15
+ - **Session-start (no `paths:`):** 3–5 — `php-app-core`, `boundaries`, `code-quality`, `ai-local-overlay`
16
16
  - All others — with `paths:`
17
17
  - **Twin depth:** domain rules target ≥15 body lines; thin aliases: `agent-team-intake`, `technical-retro`; **documented stub** (v1): `api-grpc`; `messaging-adapters` is full — see Cursor `presets/cursor/php-hexagonal/rules/README.md` Catalog (Depth column)
18
18