cc-safe-setup 29.6.32 → 29.6.33

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 (384) hide show
  1. package/COOKBOOK.md +70 -0
  2. package/README.md +6 -2
  3. package/examples/absolute-rule-enforcer.sh +42 -0
  4. package/examples/allow-claude-settings.sh +2 -0
  5. package/examples/allow-git-hooks-dir.sh +2 -0
  6. package/examples/allow-protected-dirs.sh +2 -0
  7. package/examples/allowlist.sh +2 -0
  8. package/examples/ansible-vault-guard.sh +2 -0
  9. package/examples/auto-approve-build.sh +2 -0
  10. package/examples/auto-approve-compound-git.sh +2 -0
  11. package/examples/auto-approve-docker.sh +2 -0
  12. package/examples/auto-approve-git-read.sh +2 -0
  13. package/examples/auto-approve-python.sh +2 -0
  14. package/examples/auto-approve-readonly-tools.sh +2 -0
  15. package/examples/auto-approve-ssh.sh +2 -0
  16. package/examples/auto-approve-test.sh +2 -0
  17. package/examples/auto-checkpoint.sh +2 -0
  18. package/examples/auto-git-checkpoint.sh +2 -0
  19. package/examples/auto-mode-safe-commands.sh +2 -0
  20. package/examples/auto-snapshot.sh +2 -0
  21. package/examples/backup-before-refactor.sh +2 -0
  22. package/examples/banned-command-guard.sh +3 -3
  23. package/examples/bash-domain-allowlist.sh +72 -0
  24. package/examples/bash-safety-auto-deny.sh +56 -0
  25. package/examples/bash-secret-output-detector.sh +68 -0
  26. package/examples/bash-timeout-guard.sh +2 -0
  27. package/examples/bashrc-safety-check.sh +59 -0
  28. package/examples/bg-task-cooldown-guard.sh +46 -0
  29. package/examples/block-database-wipe.sh +2 -0
  30. package/examples/branch-name-check.sh +2 -0
  31. package/examples/branch-naming-convention.sh +2 -0
  32. package/examples/cargo-publish-guard.sh +2 -0
  33. package/examples/check-abort-controller.sh +2 -0
  34. package/examples/check-accessibility.sh +2 -0
  35. package/examples/check-aria-labels.sh +2 -0
  36. package/examples/check-async-await-consistency.sh +2 -0
  37. package/examples/check-before-act-enforcer.sh +47 -0
  38. package/examples/check-charset-meta.sh +2 -0
  39. package/examples/check-cleanup-effect.sh +2 -0
  40. package/examples/check-content-type.sh +2 -0
  41. package/examples/check-controlled-input.sh +2 -0
  42. package/examples/check-cookie-flags.sh +2 -0
  43. package/examples/check-cors-config.sh +2 -0
  44. package/examples/check-csp-headers.sh +2 -0
  45. package/examples/check-csrf-protection.sh +2 -0
  46. package/examples/check-debounce.sh +2 -0
  47. package/examples/check-dependency-age.sh +2 -0
  48. package/examples/check-dependency-license.sh +2 -0
  49. package/examples/check-dockerfile-best-practice.sh +2 -0
  50. package/examples/check-error-boundaries.sh +2 -0
  51. package/examples/check-error-class.sh +2 -0
  52. package/examples/check-error-handling.sh +2 -0
  53. package/examples/check-error-logging.sh +2 -0
  54. package/examples/check-error-message.sh +2 -0
  55. package/examples/check-error-page.sh +2 -0
  56. package/examples/check-error-stack.sh +2 -0
  57. package/examples/check-favicon.sh +2 -0
  58. package/examples/check-form-validation.sh +2 -0
  59. package/examples/check-git-hooks-compat.sh +2 -0
  60. package/examples/check-https-redirect.sh +2 -0
  61. package/examples/check-image-optimization.sh +2 -0
  62. package/examples/check-input-validation.sh +2 -0
  63. package/examples/check-key-prop.sh +2 -0
  64. package/examples/check-lang-attribute.sh +2 -0
  65. package/examples/check-lazy-loading.sh +2 -0
  66. package/examples/check-loading-state.sh +2 -0
  67. package/examples/check-memo-deps.sh +2 -0
  68. package/examples/check-meta-description.sh +2 -0
  69. package/examples/check-npm-scripts-exist.sh +2 -0
  70. package/examples/check-null-check.sh +2 -0
  71. package/examples/check-package-size.sh +2 -0
  72. package/examples/check-pagination.sh +2 -0
  73. package/examples/check-port-availability.sh +2 -0
  74. package/examples/check-promise-all.sh +2 -0
  75. package/examples/check-prop-types.sh +2 -0
  76. package/examples/check-rate-limiting.sh +2 -0
  77. package/examples/check-responsive-design.sh +2 -0
  78. package/examples/check-retry-logic.sh +2 -0
  79. package/examples/check-return-types.sh +2 -0
  80. package/examples/check-semantic-html.sh +2 -0
  81. package/examples/check-semantic-versioning.sh +2 -0
  82. package/examples/check-suspense-fallback.sh +2 -0
  83. package/examples/check-test-naming.sh +2 -0
  84. package/examples/check-timeout-cleanup.sh +2 -0
  85. package/examples/check-tls-version.sh +2 -0
  86. package/examples/check-type-coercion.sh +2 -0
  87. package/examples/check-unsubscribe.sh +2 -0
  88. package/examples/check-viewport-meta.sh +2 -0
  89. package/examples/check-worker-terminate.sh +2 -0
  90. package/examples/checkpoint-tamper-guard.sh +2 -0
  91. package/examples/chmod-guard.sh +2 -0
  92. package/examples/chown-guard.sh +2 -0
  93. package/examples/ci-workflow-guard.sh +59 -0
  94. package/examples/classifier-fallback-allow.sh +2 -0
  95. package/examples/claude-cache-gc.sh +15 -0
  96. package/examples/claudeignore-enforce-guard.sh +60 -0
  97. package/examples/claudemd-enforcer.sh +2 -0
  98. package/examples/commit-message-check.sh +2 -0
  99. package/examples/compact-blocker.sh +25 -0
  100. package/examples/composer-guard.sh +2 -0
  101. package/examples/compound-command-allow.sh +2 -0
  102. package/examples/consecutive-failure-circuit-breaker.sh +49 -0
  103. package/examples/console-log-count.sh +2 -0
  104. package/examples/context-compact-advisor.sh +16 -0
  105. package/examples/cors-star-warn.sh +2 -0
  106. package/examples/credential-exfil-guard.sh +2 -0
  107. package/examples/credential-file-cat-guard.sh +2 -0
  108. package/examples/cron-modification-guard.sh +40 -0
  109. package/examples/cwd-project-boundary-guard.sh +50 -0
  110. package/examples/denied-action-retry-guard.sh +41 -0
  111. package/examples/dependency-install-guard.sh +2 -0
  112. package/examples/deploy-guard.sh +2 -0
  113. package/examples/deploy-path-verify-guard.sh +62 -0
  114. package/examples/django-migrate-guard.sh +2 -0
  115. package/examples/docker-volume-guard.sh +2 -0
  116. package/examples/dockerfile-latest-guard.sh +2 -0
  117. package/examples/dotenv-commit-guard.sh +44 -0
  118. package/examples/dotenv-example-sync.sh +55 -0
  119. package/examples/dotnet-build-on-edit.sh +2 -0
  120. package/examples/drizzle-migrate-guard.sh +2 -0
  121. package/examples/edit-counter-test-gate.sh +44 -0
  122. package/examples/edit-error-counter.sh +2 -0
  123. package/examples/edit-guard.sh +2 -0
  124. package/examples/edit-retry-loop-guard.sh +2 -0
  125. package/examples/edit-verify.sh +2 -0
  126. package/examples/enforce-tests.sh +2 -0
  127. package/examples/env-inherit-guard.sh +2 -0
  128. package/examples/env-inline-secret-guard.sh +36 -0
  129. package/examples/env-prod-guard.sh +2 -0
  130. package/examples/env-required-check.sh +2 -0
  131. package/examples/env-var-check.sh +2 -0
  132. package/examples/expo-eject-guard.sh +2 -0
  133. package/examples/export-overwrite-guard.sh +29 -0
  134. package/examples/file-change-tracker.sh +2 -0
  135. package/examples/file-change-undo-tracker.sh +46 -0
  136. package/examples/file-recycle-bin.sh +48 -0
  137. package/examples/file-size-limit.sh +2 -0
  138. package/examples/five-hundred-milestone.sh +2 -0
  139. package/examples/flask-debug-guard.sh +2 -0
  140. package/examples/gem-push-guard.sh +2 -0
  141. package/examples/git-checkout-safety-guard.sh +2 -0
  142. package/examples/git-config-guard.sh +2 -0
  143. package/examples/git-hook-bypass-guard.sh +2 -0
  144. package/examples/git-merge-conflict-prevent.sh +2 -0
  145. package/examples/git-message-length.sh +2 -0
  146. package/examples/git-show-flag-sanitizer.sh +41 -0
  147. package/examples/git-stash-before-danger.sh +2 -0
  148. package/examples/git-submodule-guard.sh +2 -0
  149. package/examples/git-tag-guard.sh +2 -0
  150. package/examples/github-actions-secret-guard.sh +59 -0
  151. package/examples/gitignore-check.sh +2 -0
  152. package/examples/gitops-drift-guard.sh +53 -0
  153. package/examples/go-mod-tidy-warn.sh +2 -0
  154. package/examples/hallucination-url-check.sh +2 -0
  155. package/examples/hardcoded-ip-guard.sh +2 -0
  156. package/examples/headless-empty-result-guard.sh +46 -0
  157. package/examples/headless-stop-guard.sh +43 -0
  158. package/examples/helm-install-guard.sh +2 -0
  159. package/examples/issue-draft-redact-guard.sh +45 -0
  160. package/examples/java-compile-on-edit.sh +2 -0
  161. package/examples/k8s-production-guard.sh +77 -0
  162. package/examples/laravel-artisan-guard.sh +2 -0
  163. package/examples/large-file-guard.sh +2 -0
  164. package/examples/log-level-guard.sh +2 -0
  165. package/examples/magic-number-warn.sh +2 -0
  166. package/examples/max-edit-size-guard.sh +2 -0
  167. package/examples/max-file-count-guard.sh +2 -0
  168. package/examples/max-file-delete-count.sh +2 -0
  169. package/examples/max-function-length.sh +2 -0
  170. package/examples/max-import-count.sh +2 -0
  171. package/examples/max-subagent-count.sh +2 -0
  172. package/examples/mcp-orphan-process-guard.sh +39 -0
  173. package/examples/mcp-server-allowlist.sh +45 -0
  174. package/examples/mcp-tool-audit-log.sh +41 -0
  175. package/examples/mcp-tool-guard.sh +2 -0
  176. package/examples/migration-verify-guard.sh +44 -0
  177. package/examples/monorepo-scope-guard.sh +2 -0
  178. package/examples/network-exfil-guard.sh +61 -0
  179. package/examples/network-guard.sh +2 -0
  180. package/examples/nextjs-env-guard.sh +2 -0
  181. package/examples/no-absolute-import.sh +2 -0
  182. package/examples/no-alert-confirm-prompt.sh +2 -0
  183. package/examples/no-any-type.sh +2 -0
  184. package/examples/no-any-typescript.sh +2 -0
  185. package/examples/no-assignment-in-condition.sh +2 -0
  186. package/examples/no-callback-hell.sh +2 -0
  187. package/examples/no-catch-all-route.sh +2 -0
  188. package/examples/no-circular-dependency.sh +2 -0
  189. package/examples/no-class-in-functional.sh +2 -0
  190. package/examples/no-cleartext-storage.sh +2 -0
  191. package/examples/no-commented-code.sh +2 -0
  192. package/examples/no-commit-fixup.sh +2 -0
  193. package/examples/no-console-assert.sh +2 -0
  194. package/examples/no-console-error-swallow.sh +2 -0
  195. package/examples/no-console-in-prod.sh +2 -0
  196. package/examples/no-console-log.sh +2 -0
  197. package/examples/no-console-time.sh +2 -0
  198. package/examples/no-cors-wildcard.sh +2 -0
  199. package/examples/no-curl-upload.sh +2 -0
  200. package/examples/no-dangerouslySetInnerHTML.sh +2 -0
  201. package/examples/no-dangling-await.sh +2 -0
  202. package/examples/no-debug-in-commit.sh +2 -0
  203. package/examples/no-deep-nesting.sh +2 -0
  204. package/examples/no-deep-relative-import.sh +2 -0
  205. package/examples/no-default-credentials.sh +2 -0
  206. package/examples/no-deprecated-api.sh +2 -0
  207. package/examples/no-direct-dom-manipulation.sh +2 -0
  208. package/examples/no-disabled-test.sh +2 -0
  209. package/examples/no-document-cookie.sh +2 -0
  210. package/examples/no-document-write.sh +2 -0
  211. package/examples/no-empty-function.sh +2 -0
  212. package/examples/no-eval-in-template.sh +2 -0
  213. package/examples/no-eval-template.sh +2 -0
  214. package/examples/no-eval.sh +2 -0
  215. package/examples/no-exec-user-input.sh +2 -0
  216. package/examples/no-expose-internal-ids.sh +2 -0
  217. package/examples/no-floating-promises.sh +2 -0
  218. package/examples/no-force-install.sh +2 -0
  219. package/examples/no-git-rebase-public.sh +2 -0
  220. package/examples/no-global-state.sh +2 -0
  221. package/examples/no-hardcoded-port.sh +2 -0
  222. package/examples/no-hardcoded-url.sh +2 -0
  223. package/examples/no-helmet-missing.sh +2 -0
  224. package/examples/no-http-url.sh +2 -0
  225. package/examples/no-http-without-https.sh +2 -0
  226. package/examples/no-index-as-key.sh +2 -0
  227. package/examples/no-infinite-scroll-mem.sh +2 -0
  228. package/examples/no-inline-event-handler.sh +2 -0
  229. package/examples/no-inline-handler.sh +2 -0
  230. package/examples/no-inline-style.sh +2 -0
  231. package/examples/no-inline-styles.sh +2 -0
  232. package/examples/no-innerhtml.sh +2 -0
  233. package/examples/no-install-global.sh +2 -0
  234. package/examples/no-jwt-in-url.sh +2 -0
  235. package/examples/no-large-commit.sh +2 -0
  236. package/examples/no-localhost-expose.sh +2 -0
  237. package/examples/no-long-switch.sh +2 -0
  238. package/examples/no-magic-number.sh +2 -0
  239. package/examples/no-md5-sha1.sh +2 -0
  240. package/examples/no-memory-leak-interval.sh +2 -0
  241. package/examples/no-mixed-line-endings.sh +2 -0
  242. package/examples/no-mutation-in-reducer.sh +2 -0
  243. package/examples/no-mutation-observer-leak.sh +2 -0
  244. package/examples/no-nested-subscribe.sh +2 -0
  245. package/examples/no-nested-ternary.sh +2 -0
  246. package/examples/no-network-exfil.sh +2 -0
  247. package/examples/no-new-array-fill.sh +2 -0
  248. package/examples/no-object-freeze-mutation.sh +2 -0
  249. package/examples/no-open-redirect.sh +2 -0
  250. package/examples/no-output-truncation.sh +44 -0
  251. package/examples/no-package-downgrade.sh +2 -0
  252. package/examples/no-package-lock-edit.sh +2 -0
  253. package/examples/no-path-join-user-input.sh +2 -0
  254. package/examples/no-port-bind.sh +2 -0
  255. package/examples/no-process-exit.sh +2 -0
  256. package/examples/no-prototype-pollution.sh +2 -0
  257. package/examples/no-push-without-ci.sh +2 -0
  258. package/examples/no-raw-ref.sh +2 -0
  259. package/examples/no-redundant-fragment.sh +2 -0
  260. package/examples/no-render-in-loop.sh +2 -0
  261. package/examples/no-root-user-docker.sh +2 -0
  262. package/examples/no-root-write.sh +2 -0
  263. package/examples/no-secrets-in-args.sh +2 -0
  264. package/examples/no-secrets-in-logs.sh +2 -0
  265. package/examples/no-sensitive-log.sh +2 -0
  266. package/examples/no-side-effects-in-render.sh +2 -0
  267. package/examples/no-sleep-in-hooks.sh +2 -0
  268. package/examples/no-star-import-python.sh +2 -0
  269. package/examples/no-string-concat-sql.sh +2 -0
  270. package/examples/no-sudo-guard.sh +2 -0
  271. package/examples/no-sync-external-call.sh +2 -0
  272. package/examples/no-sync-fs.sh +2 -0
  273. package/examples/no-table-layout.sh +2 -0
  274. package/examples/no-throw-string.sh +2 -0
  275. package/examples/no-todo-in-merge.sh +2 -0
  276. package/examples/no-todo-in-production.sh +2 -0
  277. package/examples/no-todo-without-issue.sh +2 -0
  278. package/examples/no-triple-slash-ref.sh +2 -0
  279. package/examples/no-unreachable-code.sh +2 -0
  280. package/examples/no-unused-import.sh +2 -0
  281. package/examples/no-unused-state.sh +2 -0
  282. package/examples/no-var-keyword.sh +2 -0
  283. package/examples/no-wildcard-cors.sh +2 -0
  284. package/examples/no-wildcard-import.sh +2 -0
  285. package/examples/no-window-location.sh +2 -0
  286. package/examples/no-with-statement.sh +2 -0
  287. package/examples/no-write-outside-src.sh +2 -0
  288. package/examples/no-xml-external-entity.sh +2 -0
  289. package/examples/notify-waiting.sh +2 -0
  290. package/examples/npm-audit-warn.sh +2 -0
  291. package/examples/npm-publish-guard.sh +2 -0
  292. package/examples/npm-script-injection.sh +2 -0
  293. package/examples/npm-supply-chain-guard.sh +92 -0
  294. package/examples/nuxt-config-guard.sh +2 -0
  295. package/examples/output-secret-mask.sh +2 -0
  296. package/examples/package-json-guard.sh +2 -0
  297. package/examples/parallel-session-guard.sh +2 -0
  298. package/examples/path-traversal-guard.sh +2 -0
  299. package/examples/permission-audit-log.sh +2 -0
  300. package/examples/permission-entry-validator.sh +48 -0
  301. package/examples/php-lint-on-edit.sh +2 -0
  302. package/examples/pip-publish-guard.sh +2 -0
  303. package/examples/plain-language-danger-warn.sh +37 -0
  304. package/examples/plan-mode-enforcer.sh +2 -0
  305. package/examples/plugin-process-cleanup.sh +50 -0
  306. package/examples/polyglot-rm-guard.sh +59 -0
  307. package/examples/pr-description-check.sh +2 -0
  308. package/examples/pre-compact-knowledge-save.sh +53 -0
  309. package/examples/pre-compact-transcript-export.sh +85 -0
  310. package/examples/prefer-builtin-tools.sh +2 -0
  311. package/examples/prefer-const.sh +2 -0
  312. package/examples/prefer-dedicated-tools.sh +55 -0
  313. package/examples/prefer-optional-chaining.sh +2 -0
  314. package/examples/prisma-migrate-guard.sh +2 -0
  315. package/examples/prompt-injection-detector.sh +2 -0
  316. package/examples/prompt-length-guard.sh +2 -0
  317. package/examples/protect-dotfiles.sh +2 -0
  318. package/examples/public-repo-push-guard.sh +58 -0
  319. package/examples/push-requires-test-pass-record.sh +2 -0
  320. package/examples/push-requires-test-pass.sh +2 -0
  321. package/examples/rails-migration-guard.sh +2 -0
  322. package/examples/rate-limit-guard.sh +2 -0
  323. package/examples/read-all-files-enforcer.sh +51 -0
  324. package/examples/readme-exists-check.sh +2 -0
  325. package/examples/redis-flushall-guard.sh +2 -0
  326. package/examples/rm-safety-net.sh +2 -0
  327. package/examples/role-tool-guard.sh +69 -0
  328. package/examples/ruby-lint-on-edit.sh +2 -0
  329. package/examples/schema-migration-guard.sh +57 -0
  330. package/examples/scope-guard.sh +2 -0
  331. package/examples/secret-file-read-guard.sh +74 -0
  332. package/examples/self-modify-bypass-guard.sh +54 -0
  333. package/examples/sensitive-log-guard.sh +2 -0
  334. package/examples/session-checkpoint.sh +2 -0
  335. package/examples/session-end-logger.sh +57 -0
  336. package/examples/session-error-rate-monitor.sh +65 -0
  337. package/examples/session-health-monitor.sh +61 -0
  338. package/examples/session-memory-watchdog.sh +17 -0
  339. package/examples/session-permission-reset-guard.sh +39 -0
  340. package/examples/session-resume-env-fix.sh +49 -0
  341. package/examples/session-state-saver.sh +2 -0
  342. package/examples/session-summary-stop.sh +2 -0
  343. package/examples/session-summary.sh +2 -0
  344. package/examples/session-token-counter.sh +2 -0
  345. package/examples/shell-wrapper-guard.sh +2 -0
  346. package/examples/skill-gate.sh +2 -0
  347. package/examples/skill-injection-detector.sh +41 -0
  348. package/examples/spec-file-scope-guard.sh +69 -0
  349. package/examples/spring-profile-guard.sh +2 -0
  350. package/examples/sql-injection-detect.sh +2 -0
  351. package/examples/subagent-budget-guard.sh +2 -0
  352. package/examples/subagent-claudemd-inject.sh +45 -0
  353. package/examples/subagent-tool-call-limiter.sh +48 -0
  354. package/examples/svelte-lint-on-edit.sh +2 -0
  355. package/examples/swift-build-on-edit.sh +2 -0
  356. package/examples/system-message-workaround.sh +44 -0
  357. package/examples/system-package-guard.sh +2 -0
  358. package/examples/temp-file-cleanup.sh +2 -0
  359. package/examples/terminal-state-restore.sh +23 -0
  360. package/examples/test-after-edit.sh +2 -0
  361. package/examples/test-before-commit.sh +2 -0
  362. package/examples/test-before-push.sh +2 -0
  363. package/examples/test-exit-code-verify.sh +2 -0
  364. package/examples/timeout-guard.sh +2 -0
  365. package/examples/timezone-guard.sh +2 -0
  366. package/examples/tmp-output-size-guard.sh +46 -0
  367. package/examples/todo-check.sh +2 -0
  368. package/examples/todo-deadline-warn.sh +48 -0
  369. package/examples/token-budget-per-task.sh +55 -0
  370. package/examples/token-usage-tracker.sh +14 -0
  371. package/examples/turbo-cache-guard.sh +2 -0
  372. package/examples/uncommitted-changes-stop.sh +2 -0
  373. package/examples/uncommitted-work-shield.sh +37 -0
  374. package/examples/usage-warn.sh +2 -0
  375. package/examples/verify-before-commit.sh +2 -0
  376. package/examples/vue-lint-on-edit.sh +2 -0
  377. package/examples/webfetch-domain-allow.sh +96 -0
  378. package/examples/worktree-memory-guard.sh +47 -0
  379. package/examples/worktree-project-unify.sh +19 -0
  380. package/examples/worktree-unmerged-guard.sh +2 -0
  381. package/examples/write-overwrite-confirm.sh +40 -0
  382. package/examples/write-secret-guard.sh +2 -0
  383. package/examples/write-test-ratio.sh +2 -0
  384. package/package.json +2 -2
@@ -0,0 +1,54 @@
1
+ #!/bin/bash
2
+ # self-modify-bypass-guard.sh — Auto-allow .claude/ writes in bypass mode
3
+ #
4
+ # Solves: Self-modification guard prompts for .claude/ writes even when
5
+ # bypassPermissions is active (#40463). The guard fires before
6
+ # hooks/permissions are evaluated.
7
+ #
8
+ # How it works: PermissionRequest hook that detects .claude/ write prompts
9
+ # and auto-allows them when the project uses bypassPermissions mode.
10
+ # Exempts security-sensitive paths (settings.json, CLAUDE.md).
11
+ #
12
+ # TRIGGER: PermissionRequest
13
+ # MATCHER: ""
14
+
15
+ set -euo pipefail
16
+
17
+ INPUT=$(cat)
18
+
19
+ # Extract the permission request details
20
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
21
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
22
+
23
+ # Only handle Edit/Write to .claude/ paths
24
+ case "$TOOL" in
25
+ Edit|Write) ;;
26
+ *) exit 0 ;;
27
+ esac
28
+
29
+ case "$FILE" in
30
+ .claude/*|*/.claude/*) ;;
31
+ *) exit 0 ;;
32
+ esac
33
+
34
+ # Security-sensitive files: always prompt (don't auto-allow)
35
+ BASENAME=$(basename "$FILE")
36
+ case "$BASENAME" in
37
+ settings.json|settings.local.json|CLAUDE.md)
38
+ # Let the default prompt handle these
39
+ exit 0 ;;
40
+ esac
41
+
42
+ # Check if bypassPermissions is configured
43
+ SETTINGS=".claude/settings.json"
44
+ if [ -f "$SETTINGS" ]; then
45
+ MODE=$(jq -r '.defaultMode // empty' "$SETTINGS" 2>/dev/null)
46
+ if [ "$MODE" = "bypassPermissions" ]; then
47
+ # Auto-allow: output hookSpecificOutput to approve
48
+ echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","allow":true}}'
49
+ exit 0
50
+ fi
51
+ fi
52
+
53
+ # Not in bypass mode — let default prompt handle it
54
+ exit 0
@@ -1,3 +1,5 @@
1
+ #
2
+ # TRIGGER: PreToolUse MATCHER: "Edit|Write"
1
3
  INPUT=$(cat)
2
4
  FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
3
5
  [[ -z "$FILE" ]] && exit 0
@@ -19,6 +19,8 @@
19
19
  #
20
20
  # Recovery: Add to CLAUDE.md:
21
21
  # "If ~/.claude/checkpoints/ has a file for this project, read it first."
22
+ #
23
+ # TRIGGER: Stop MATCHER: ""
22
24
 
23
25
  INPUT=$(cat)
24
26
  REASON=$(echo "$INPUT" | jq -r '.stop_reason // empty' 2>/dev/null)
@@ -0,0 +1,57 @@
1
+ #!/bin/bash
2
+ # session-end-logger.sh — Log session activity at exit
3
+ #
4
+ # Solves: No built-in session audit trail. When a session ends,
5
+ # there's no record of what was done unless you manually check
6
+ # git log or conversation history (#40010).
7
+ #
8
+ # How it works: SessionEnd hook that captures recent git commits,
9
+ # modified files, and session metadata into a structured log file.
10
+ #
11
+ # TRIGGER: SessionEnd
12
+ # MATCHER: ""
13
+ #
14
+ # Usage:
15
+ # {
16
+ # "hooks": {
17
+ # "SessionEnd": [{
18
+ # "hooks": [{ "type": "command", "command": "~/.claude/hooks/session-end-logger.sh" }]
19
+ # }]
20
+ # }
21
+ # }
22
+
23
+ INPUT=$(cat)
24
+ SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"' 2>/dev/null)
25
+
26
+ LOG_DIR=".claude/session-logs"
27
+ mkdir -p "$LOG_DIR"
28
+ LOG_FILE="$LOG_DIR/$(date '+%Y-%m-%d').md"
29
+
30
+ {
31
+ echo ""
32
+ echo "## Session $SESSION_ID — $(date '+%H:%M')"
33
+ echo ""
34
+
35
+ # Recent git activity
36
+ if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
37
+ COMMITS=$(git log --oneline --since="1 hour ago" 2>/dev/null)
38
+ if [ -n "$COMMITS" ]; then
39
+ echo "### Commits"
40
+ echo '```'
41
+ echo "$COMMITS"
42
+ echo '```'
43
+ fi
44
+
45
+ CHANGED=$(git diff --name-only HEAD~5..HEAD 2>/dev/null | head -20)
46
+ if [ -n "$CHANGED" ]; then
47
+ echo "### Changed files"
48
+ echo '```'
49
+ echo "$CHANGED"
50
+ echo '```'
51
+ fi
52
+ fi
53
+
54
+ echo ""
55
+ } >> "$LOG_FILE"
56
+
57
+ exit 0
@@ -0,0 +1,65 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # session-error-rate-monitor.sh — Detect session quality degradation
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # Long sessions (6+ hours) show quality decay: more errors,
7
+ # ignored instructions, and destructive actions. This hook
8
+ # tracks the error rate over a rolling window and warns when
9
+ # it exceeds a threshold, suggesting a session restart.
10
+ #
11
+ # How it works:
12
+ # - Counts tool calls and errors (exit code != 0) in a state file
13
+ # - Calculates error rate over last N tool calls
14
+ # - Warns (stderr) when error rate exceeds threshold
15
+ # - Does NOT block — purely advisory (exit 0 always)
16
+ #
17
+ # TRIGGER: PostToolUse
18
+ # MATCHER: "Bash"
19
+ #
20
+ # CONFIG:
21
+ # CC_ERROR_RATE_WINDOW=20 (rolling window size)
22
+ # CC_ERROR_RATE_THRESHOLD=40 (% error rate to trigger warning)
23
+ #
24
+ # See: https://github.com/anthropics/claude-code/issues/32963
25
+ # ================================================================
26
+
27
+ INPUT=$(cat)
28
+ EXIT_CODE=$(echo "$INPUT" | jq -r '.tool_result.exit_code // "0"' 2>/dev/null)
29
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
30
+
31
+ # Only track Bash tool calls
32
+ [[ "$TOOL" != "Bash" ]] && exit 0
33
+
34
+ WINDOW=${CC_ERROR_RATE_WINDOW:-20}
35
+ THRESHOLD=${CC_ERROR_RATE_THRESHOLD:-40}
36
+ STATE_DIR="${HOME}/.claude/state"
37
+ mkdir -p "$STATE_DIR"
38
+ STATE_FILE="$STATE_DIR/error-rate-history.log"
39
+
40
+ # Record result: 0=success, 1=error
41
+ if [ "$EXIT_CODE" = "0" ]; then
42
+ echo "0" >> "$STATE_FILE"
43
+ else
44
+ echo "1" >> "$STATE_FILE"
45
+ fi
46
+
47
+ # Keep only last N entries
48
+ TOTAL=$(wc -l < "$STATE_FILE" 2>/dev/null || echo "0")
49
+ if [ "$TOTAL" -gt "$WINDOW" ]; then
50
+ tail -n "$WINDOW" "$STATE_FILE" > "$STATE_FILE.tmp"
51
+ mv "$STATE_FILE.tmp" "$STATE_FILE"
52
+ fi
53
+
54
+ # Calculate error rate
55
+ if [ "$TOTAL" -ge "$WINDOW" ]; then
56
+ ERRORS=$(tail -n "$WINDOW" "$STATE_FILE" | grep -c "^1$" || echo "0")
57
+ RATE=$(( ERRORS * 100 / WINDOW ))
58
+
59
+ if [ "$RATE" -ge "$THRESHOLD" ]; then
60
+ echo "⚠ Session quality alert: ${RATE}% error rate over last ${WINDOW} commands (threshold: ${THRESHOLD}%)" >&2
61
+ echo " Consider: /compact or starting a fresh session" >&2
62
+ fi
63
+ fi
64
+
65
+ exit 0
@@ -0,0 +1,61 @@
1
+ #!/bin/bash
2
+ # session-health-monitor.sh — Monitor session health metrics
3
+ #
4
+ # Solves: Long-running sessions degrade silently — context fills up,
5
+ # tool calls slow down, errors accumulate. No visibility into
6
+ # session health until it's too late.
7
+ #
8
+ # How it works: PreToolUse hook that tracks session metrics:
9
+ # - Tool call count (proxy for context usage)
10
+ # - Error rate (consecutive failures)
11
+ # - Session duration
12
+ # Warns at configurable thresholds.
13
+ #
14
+ # TRIGGER: PreToolUse
15
+ # MATCHER: ""
16
+ #
17
+ # Usage:
18
+ # {
19
+ # "hooks": {
20
+ # "PreToolUse": [{
21
+ # "hooks": [{ "type": "command", "command": "~/.claude/hooks/session-health-monitor.sh" }]
22
+ # }]
23
+ # }
24
+ # }
25
+
26
+ STATE="/tmp/cc-health-$$"
27
+
28
+ # Initialize on first call
29
+ if [ ! -f "$STATE" ]; then
30
+ echo "start=$(date +%s) calls=0 errors=0" > "$STATE"
31
+ fi
32
+
33
+ # Read current state
34
+ eval $(cat "$STATE")
35
+ calls=$((calls + 1))
36
+
37
+ # Update state
38
+ echo "start=$start calls=$calls errors=$errors" > "$STATE"
39
+
40
+ # Check thresholds
41
+ DURATION=$(( ($(date +%s) - start) / 60 ))
42
+
43
+ if [ "$calls" -eq 50 ]; then
44
+ echo "ℹ Session health: 50 tool calls, ${DURATION}m elapsed." >&2
45
+ fi
46
+
47
+ if [ "$calls" -eq 150 ]; then
48
+ echo "⚠ Session health: 150 tool calls, ${DURATION}m elapsed. Context may be getting full." >&2
49
+ echo "Consider saving state and starting a fresh session." >&2
50
+ fi
51
+
52
+ if [ "$calls" -ge 250 ] && [ $((calls % 50)) -eq 0 ]; then
53
+ echo "🔴 Session health: $calls tool calls, ${DURATION}m elapsed. Performance may be degraded." >&2
54
+ fi
55
+
56
+ # Duration warning
57
+ if [ "$DURATION" -ge 120 ] && [ $((calls % 100)) -eq 0 ]; then
58
+ echo "⏰ Session running for ${DURATION}m. Long sessions accumulate context drift." >&2
59
+ fi
60
+
61
+ exit 0
@@ -0,0 +1,17 @@
1
+ MAX_RSS_MB="${CC_MAX_RSS_MB:-4096}"
2
+ CHECK_INTERVAL=300
3
+ (
4
+ while true; do
5
+ sleep "$CHECK_INTERVAL"
6
+ pgrep -f "claude" | while read pid; do
7
+ RSS_KB=$(ps -o rss= -p "$pid" 2>/dev/null | tr -d ' ')
8
+ [ -z "$RSS_KB" ] && continue
9
+ RSS_MB=$((RSS_KB / 1024))
10
+ if [ "$RSS_MB" -gt "$MAX_RSS_MB" ]; then
11
+ echo "[$(date -Iseconds)] PID $pid: ${RSS_MB}MB > ${MAX_RSS_MB}MB limit" >> ~/.claude/memory-watchdog.log
12
+ kill -15 "$pid" 2>/dev/null
13
+ fi
14
+ done
15
+ done
16
+ ) &
17
+ exit 0
@@ -0,0 +1,39 @@
1
+ #!/bin/bash
2
+ # session-permission-reset-guard.sh — Override session-cached permissions
3
+ #
4
+ # Solves: Sandbox mode caching session-level permissions (#40384).
5
+ # After approving a command once, sandbox caches the approval
6
+ # for the entire session, bypassing the allow list.
7
+ #
8
+ # How it works: PreToolUse hook that enforces per-invocation checks
9
+ # for specified commands, regardless of session cache state.
10
+ # Acts as a secondary permission layer outside the caching system.
11
+ #
12
+ # CONFIG:
13
+ # CC_ALWAYS_CHECK_COMMANDS="git commit:git push:npm publish:cargo install"
14
+ #
15
+ # TRIGGER: PreToolUse
16
+ # MATCHER: "Bash"
17
+
18
+ INPUT=$(cat)
19
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
20
+ [ -z "$COMMAND" ] && exit 0
21
+
22
+ # Commands that should always require hook-level check
23
+ ALWAYS_CHECK="${CC_ALWAYS_CHECK_COMMANDS:-git commit:git push:npm publish:cargo install:pip install}"
24
+
25
+ IFS=':' read -ra PATTERNS <<< "$ALWAYS_CHECK"
26
+ for pattern in "${PATTERNS[@]}"; do
27
+ # Match the pattern anywhere in the command (including chained commands)
28
+ if echo "$COMMAND" | grep -qiF "$pattern"; then
29
+ echo "HOOK CHECK: '$pattern' detected — hook-level review." >&2
30
+ echo "Command: $COMMAND" >&2
31
+ echo "" >&2
32
+ echo "This hook enforces per-invocation checks regardless of" >&2
33
+ echo "session permission caching. To allow, remove this pattern" >&2
34
+ echo "from CC_ALWAYS_CHECK_COMMANDS." >&2
35
+ exit 2
36
+ fi
37
+ done
38
+
39
+ exit 0
@@ -0,0 +1,49 @@
1
+ #!/bin/bash
2
+ # session-resume-env-fix.sh — Fix CLAUDE_ENV_FILE path on session resume
3
+ #
4
+ # Solves: CLAUDE_ENV_FILE points to startup session directory, but Bash
5
+ # tool loads from resumed session directory (#40391, #24775).
6
+ # Environment variables written by SessionStart hooks are lost.
7
+ #
8
+ # How it works: SessionStart hook that detects resume (source="resume")
9
+ # and copies/symlinks env files from the startup session directory
10
+ # to the resumed session directory.
11
+ #
12
+ # TRIGGER: SessionStart
13
+ # MATCHER: ""
14
+
15
+ set -euo pipefail
16
+
17
+ INPUT=$(cat)
18
+ SOURCE=$(echo "$INPUT" | jq -r '.source // empty' 2>/dev/null)
19
+ SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
20
+
21
+ # Only act on resume events
22
+ [ "$SOURCE" = "resume" ] || exit 0
23
+ [ -n "$SESSION_ID" ] || exit 0
24
+ [ -n "${CLAUDE_ENV_FILE:-}" ] || exit 0
25
+
26
+ # Extract the startup session directory from CLAUDE_ENV_FILE
27
+ STARTUP_DIR=$(dirname "$CLAUDE_ENV_FILE")
28
+ ENV_BASE=$(dirname "$STARTUP_DIR")
29
+
30
+ # Construct the resumed session directory
31
+ RESUME_DIR="${ENV_BASE}/${SESSION_ID}"
32
+
33
+ # If they're the same, no fix needed
34
+ [ "$STARTUP_DIR" != "$RESUME_DIR" ] || exit 0
35
+
36
+ # Create resumed session directory if missing
37
+ mkdir -p "$RESUME_DIR"
38
+
39
+ # Copy all env files from startup dir to resumed dir
40
+ for envfile in "$STARTUP_DIR"/*.sh; do
41
+ [ -f "$envfile" ] || continue
42
+ BASENAME=$(basename "$envfile")
43
+ if [ ! -f "$RESUME_DIR/$BASENAME" ]; then
44
+ cp "$envfile" "$RESUME_DIR/$BASENAME"
45
+ echo "Copied env file to resumed session: $BASENAME" >&2
46
+ fi
47
+ done
48
+
49
+ exit 0
@@ -1,4 +1,6 @@
1
1
  #!/bin/bash
2
+ #
3
+ # TRIGGER: PreToolUse MATCHER: "Bash"
2
4
  INPUT=$(cat)
3
5
  TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
4
6
  STATE_DIR="${HOME}/.claude"
@@ -17,6 +17,8 @@
17
17
  # }]
18
18
  # }
19
19
  # }
20
+ #
21
+ # TRIGGER: PreToolUse MATCHER: "Bash"
20
22
 
21
23
  INPUT=$(cat)
22
24
 
@@ -1,4 +1,6 @@
1
1
  #!/bin/bash
2
+ #
3
+ # TRIGGER: PreToolUse MATCHER: "Bash"
2
4
  echo "" >&2
3
5
  echo "=== Session Summary ===" >&2
4
6
  BRANCH=$(git branch --show-current 2>/dev/null)
@@ -24,6 +24,8 @@
24
24
  # CC_TOOL_WARN_100 — threshold 1 (default: 100)
25
25
  # CC_TOOL_WARN_200 — threshold 2 (default: 200)
26
26
  # CC_TOOL_WARN_500 — threshold 3 (default: 500)
27
+ #
28
+ # TRIGGER: PreToolUse MATCHER: "Bash"
27
29
 
28
30
  INPUT=$(cat)
29
31
  TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
@@ -13,6 +13,8 @@
13
13
  # This hook unwraps interpreter one-liners and checks the inner command.
14
14
  #
15
15
  # Usage: PreToolUse hook on "Bash"
16
+ #
17
+ # TRIGGER: PreToolUse MATCHER: "Bash"
16
18
 
17
19
  INPUT=$(cat)
18
20
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -1,4 +1,6 @@
1
1
  #!/bin/bash
2
+ #
3
+ # TRIGGER: PreToolUse MATCHER: "Bash"
2
4
  INPUT=$(cat)
3
5
  TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
4
6
  [[ "$TOOL" != "Skill" ]] && exit 0
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ # skill-injection-detector.sh — Detect silently injected skills/plugins
3
+ #
4
+ # Solves: Skills and plugins from claude.ai silently injected into Claude Code
5
+ # sessions (#39686). External tool definitions bloat context and
6
+ # can override local behavior without user awareness.
7
+ #
8
+ # How it works: Notification hook that monitors for unexpected skill/plugin
9
+ # loading messages. Warns when tools are loaded from external sources.
10
+ # Also checks MCP config for unexpected servers.
11
+ #
12
+ # TRIGGER: PreToolUse
13
+ # MATCHER: ""
14
+
15
+ set -euo pipefail
16
+
17
+ INPUT=$(cat)
18
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
19
+
20
+ # Check MCP tool calls for unexpected servers
21
+ if [ "$TOOL" = "Bash" ]; then
22
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
23
+ # Detect MCP server addition
24
+ if echo "$COMMAND" | grep -qE 'claude\s+mcp\s+add'; then
25
+ echo "WARNING: MCP server addition detected." >&2
26
+ echo "Command: $COMMAND" >&2
27
+ echo "Verify this server is expected before proceeding." >&2
28
+ fi
29
+ fi
30
+
31
+ # Check for skill/plugin invocation from unexpected sources
32
+ if echo "$INPUT" | jq -e '.tool_input.skill // empty' 2>/dev/null | grep -qv '^$'; then
33
+ SKILL=$(echo "$INPUT" | jq -r '.tool_input.skill' 2>/dev/null)
34
+ # Check if skill is local
35
+ if [ ! -f ".claude/skills/${SKILL}/SKILL.md" ] && [ ! -f ".claude/skills/${SKILL}.md" ]; then
36
+ echo "WARNING: Skill '$SKILL' invoked but not found locally." >&2
37
+ echo "This may be an externally injected skill." >&2
38
+ fi
39
+ fi
40
+
41
+ exit 0
@@ -0,0 +1,69 @@
1
+ #!/bin/bash
2
+ # spec-file-scope-guard.sh — Restrict edits to files mentioned in a spec document
3
+ #
4
+ # Solves: Agent ignoring specification across multiple sessions (#40383).
5
+ # Claude modifies files not mentioned in the spec, introduces
6
+ # fabricated data, and drifts from the stated objective.
7
+ #
8
+ # How it works: Reads a spec/requirements file, extracts file paths and
9
+ # directory names mentioned in it, then blocks Edit/Write to files
10
+ # outside that scope.
11
+ #
12
+ # Setup:
13
+ # echo "spec.md" > .claude/spec-file.txt
14
+ # # Or set CC_SPEC_FILE=spec.md
15
+ #
16
+ # TRIGGER: PreToolUse
17
+ # MATCHER: "Edit|Write"
18
+
19
+ set -euo pipefail
20
+
21
+ INPUT=$(cat)
22
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
23
+
24
+ case "$TOOL" in
25
+ Edit|Write) ;;
26
+ *) exit 0 ;;
27
+ esac
28
+
29
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
30
+ [ -z "$FILE" ] && exit 0
31
+
32
+ # Find spec file
33
+ SPEC_FILE="${CC_SPEC_FILE:-}"
34
+ if [ -z "$SPEC_FILE" ] && [ -f ".claude/spec-file.txt" ]; then
35
+ SPEC_FILE=$(head -1 ".claude/spec-file.txt" | tr -d '\n')
36
+ fi
37
+ [ -z "$SPEC_FILE" ] && exit 0
38
+ [ -f "$SPEC_FILE" ] || exit 0
39
+
40
+ # Extract paths/directories mentioned in spec
41
+ # Matches: path/to/file.ext, src/components/, ./config.ts, etc.
42
+ MENTIONED=$(grep -oE '(\.?/?[a-zA-Z0-9_-]+/)+[a-zA-Z0-9_.-]*' "$SPEC_FILE" | sort -u || true)
43
+
44
+ if [ -z "$MENTIONED" ]; then
45
+ # No paths found in spec — don't restrict
46
+ exit 0
47
+ fi
48
+
49
+ # Check if the target file matches any mentioned path
50
+ BASENAME=$(basename "$FILE")
51
+ DIRNAME=$(dirname "$FILE")
52
+
53
+ for path in $MENTIONED; do
54
+ # Match if file path contains the spec path
55
+ if echo "$FILE" | grep -qF "$path"; then
56
+ exit 0
57
+ fi
58
+ # Match if basename matches
59
+ if echo "$BASENAME" | grep -qF "$path"; then
60
+ exit 0
61
+ fi
62
+ done
63
+
64
+ echo "WARNING: Editing file not mentioned in spec ($SPEC_FILE):" >&2
65
+ echo " File: $FILE" >&2
66
+ echo " Spec mentions: $(echo "$MENTIONED" | head -5 | tr '\n' ', ')" >&2
67
+ echo " Stay focused on the specification." >&2
68
+ # Warning only — change to exit 2 to block
69
+ exit 0
@@ -1,3 +1,5 @@
1
+ #
2
+ # TRIGGER: PreToolUse MATCHER: "Edit|Write"
1
3
  INPUT=$(cat)
2
4
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
3
5
  [[ -z "$COMMAND" ]] && exit 0
@@ -1,4 +1,6 @@
1
1
  #!/bin/bash
2
+ #
3
+ # TRIGGER: PreToolUse MATCHER: "Edit|Write"
2
4
  INPUT=$(cat)
3
5
  CONTENT=$(echo "$INPUT" | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
4
6
  [ -z "$CONTENT" ] && exit 0
@@ -1,4 +1,6 @@
1
1
  #!/bin/bash
2
+ #
3
+ # TRIGGER: PreToolUse MATCHER: "Bash"
2
4
  INPUT=$(cat)
3
5
  TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
4
6
  [[ "$TOOL" != "Agent" ]] && exit 0
@@ -0,0 +1,45 @@
1
+ #!/bin/bash
2
+ # subagent-claudemd-inject.sh — Inject CLAUDE.md rules into subagent prompts
3
+ #
4
+ # Solves: Subagents lose CLAUDE.md context since v2.1.84 (#40459).
5
+ # omitClaudeMd:true strips project instructions from Explore/Plan agents,
6
+ # causing them to ignore language preferences, environment config, etc.
7
+ #
8
+ # How it works: PreToolUse hook on Agent that appends key CLAUDE.md rules
9
+ # to the subagent's prompt. Extracts critical rules (marked with SUBAGENT:
10
+ # prefix in CLAUDE.md) and injects them into the agent description/prompt.
11
+ #
12
+ # Setup: Mark critical rules in CLAUDE.md with "SUBAGENT:" prefix:
13
+ # ## SUBAGENT: Always respond in Japanese
14
+ # ## SUBAGENT: Use DEV environment for testing
15
+ #
16
+ # TRIGGER: PreToolUse
17
+ # MATCHER: "Agent"
18
+
19
+ set -euo pipefail
20
+
21
+ INPUT=$(cat)
22
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
23
+ [ "$TOOL" = "Agent" ] || exit 0
24
+
25
+ # Find CLAUDE.md
26
+ CLAUDEMD=""
27
+ for candidate in "CLAUDE.md" "../CLAUDE.md" "../../CLAUDE.md"; do
28
+ if [ -f "$candidate" ]; then
29
+ CLAUDEMD="$candidate"
30
+ break
31
+ fi
32
+ done
33
+ [ -n "$CLAUDEMD" ] || exit 0
34
+
35
+ # Extract SUBAGENT-tagged rules
36
+ RULES=$(grep -iE '^##?\s*SUBAGENT:' "$CLAUDEMD" 2>/dev/null | sed 's/^##\?\s*SUBAGENT:\s*//' | head -10 || true)
37
+ [ -z "$RULES" ] && exit 0
38
+
39
+ # Inject rules as a system message warning
40
+ echo "REMINDER: Project rules from CLAUDE.md (apply to all subagents):" >&2
41
+ echo "$RULES" | while IFS= read -r rule; do
42
+ echo " - $rule" >&2
43
+ done
44
+
45
+ exit 0
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+ # subagent-tool-call-limiter.sh — Limit total tool calls per session
3
+ #
4
+ # Solves: Subagents making unbounded tool calls (#36727).
5
+ # One user reported 234 tool calls in 1.5 hours from a single subagent.
6
+ # Existing rate limiters check frequency, not total count.
7
+ #
8
+ # How it works: PreToolUse hook (all tools) that increments a counter file.
9
+ # When CC_MAX_TOOL_CALLS (default 200) is reached, blocks further calls.
10
+ #
11
+ # TRIGGER: PreToolUse
12
+ # MATCHER: ""
13
+
14
+ set -euo pipefail
15
+
16
+ MAX_CALLS="${CC_MAX_TOOL_CALLS:-200}"
17
+ COUNTER_FILE="/tmp/claude-tool-call-counter-$$"
18
+
19
+ # Use session-based counter (PID of parent process)
20
+ PPID_FILE="/tmp/claude-tool-call-counter-${PPID:-0}"
21
+ [ -f "$PPID_FILE" ] && COUNTER_FILE="$PPID_FILE"
22
+
23
+ # Initialize or read counter
24
+ if [ -f "$COUNTER_FILE" ]; then
25
+ COUNT=$(cat "$COUNTER_FILE" 2>/dev/null || echo 0)
26
+ else
27
+ COUNT=0
28
+ COUNTER_FILE="$PPID_FILE"
29
+ fi
30
+
31
+ COUNT=$((COUNT + 1))
32
+ echo "$COUNT" > "$COUNTER_FILE"
33
+
34
+ # Check limit
35
+ if [ "$COUNT" -gt "$MAX_CALLS" ]; then
36
+ echo "BLOCKED: Tool call limit reached ($COUNT/$MAX_CALLS)." >&2
37
+ echo "This session has made $COUNT tool calls (limit: $MAX_CALLS)." >&2
38
+ echo "Consider starting a new session or increasing CC_MAX_TOOL_CALLS." >&2
39
+ exit 2
40
+ fi
41
+
42
+ # Warn at 80%
43
+ WARN_AT=$((MAX_CALLS * 80 / 100))
44
+ if [ "$COUNT" -eq "$WARN_AT" ]; then
45
+ echo "WARNING: $COUNT/$MAX_CALLS tool calls used (80%). Consider wrapping up." >&2
46
+ fi
47
+
48
+ exit 0
@@ -1,3 +1,5 @@
1
+ #
2
+ # TRIGGER: PostToolUse MATCHER: "Edit|Write"
1
3
  INPUT=$(cat)
2
4
  FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
3
5
  [[ -z "$FILE" ]] && exit 0
@@ -17,6 +17,8 @@
17
17
  # }
18
18
  # }
19
19
  # ================================================================
20
+ #
21
+ # TRIGGER: PreToolUse MATCHER: "Bash"
20
22
 
21
23
  INPUT=$(cat)
22
24
  FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)