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,53 @@
1
+ #!/bin/bash
2
+ # pre-compact-knowledge-save.sh — Save critical context before compaction
3
+ #
4
+ # Solves: Context compaction losing important decisions, file locations,
5
+ # and progress state. After /compact, Claude forgets what it was
6
+ # doing and repeats work or contradicts earlier decisions.
7
+ #
8
+ # How it works: PreCompact hook that saves the current session state
9
+ # to a checkpoint file that survives compaction. The model can read
10
+ # this file after compaction to restore context.
11
+ #
12
+ # The checkpoint includes: current task, recent decisions, modified files.
13
+ #
14
+ # TRIGGER: PreCompact
15
+ # MATCHER: ""
16
+
17
+ set -euo pipefail
18
+
19
+ INPUT=$(cat)
20
+
21
+ CHECKPOINT="${CC_COMPACT_CHECKPOINT:-.claude/pre-compact-checkpoint.md}"
22
+ mkdir -p "$(dirname "$CHECKPOINT")"
23
+
24
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
25
+
26
+ # Gather session state
27
+ GIT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
28
+ MODIFIED=$(git diff --name-only 2>/dev/null | head -10 || echo "none")
29
+ STAGED=$(git diff --cached --name-only 2>/dev/null | head -10 || echo "none")
30
+ RECENT_COMMITS=$(git log --oneline -3 2>/dev/null || echo "none")
31
+
32
+ cat > "$CHECKPOINT" << CHECKPOINT_EOF
33
+ # Pre-Compact Checkpoint
34
+ Generated: ${TIMESTAMP}
35
+ Branch: ${GIT_BRANCH}
36
+
37
+ ## Modified files (not staged)
38
+ ${MODIFIED}
39
+
40
+ ## Staged files
41
+ ${STAGED}
42
+
43
+ ## Recent commits
44
+ ${RECENT_COMMITS}
45
+
46
+ ## Notes
47
+ Read this file after compaction to restore context.
48
+ Check tasks/todo.md for current task progress.
49
+ CHECKPOINT_EOF
50
+
51
+ echo "Pre-compact checkpoint saved to $CHECKPOINT" >&2
52
+
53
+ exit 0
@@ -0,0 +1,85 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # pre-compact-transcript-export.sh — Export conversation before compaction
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # After compaction, the pre-compaction conversation is inaccessible
7
+ # in the TUI. This hook exports the conversation to a human-readable
8
+ # markdown file before compaction happens, so you can review it later.
9
+ #
10
+ # Reads transcript.jsonl and extracts:
11
+ # - User messages (prompts)
12
+ # - Assistant messages (responses)
13
+ # - Tool calls and results (summarized)
14
+ #
15
+ # TRIGGER: PreCompact
16
+ # MATCHER: (none — PreCompact has no matcher)
17
+ #
18
+ # OUTPUT: .claude/conversation-snapshots/TIMESTAMP.md
19
+ #
20
+ # See: https://github.com/anthropics/claude-code/issues/27242
21
+ # ================================================================
22
+
23
+ # Find the current session transcript
24
+ SESSION_DIR="${HOME}/.claude/projects"
25
+ TRANSCRIPT=""
26
+
27
+ # Try to find transcript from input
28
+ INPUT=$(cat)
29
+ TRANSCRIPT=$(echo "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
30
+
31
+ # Fallback: find most recent transcript.jsonl
32
+ if [ -z "$TRANSCRIPT" ] || [ ! -f "$TRANSCRIPT" ]; then
33
+ TRANSCRIPT=$(find "$SESSION_DIR" -name "transcript.jsonl" -newer /tmp/.claude-session-start 2>/dev/null | head -1)
34
+ fi
35
+
36
+ # If still not found, try the current working directory
37
+ if [ -z "$TRANSCRIPT" ] || [ ! -f "$TRANSCRIPT" ]; then
38
+ TRANSCRIPT=$(find "$SESSION_DIR" -name "transcript.jsonl" -mmin -60 2>/dev/null | sort -t/ -k1 | tail -1)
39
+ fi
40
+
41
+ [ -z "$TRANSCRIPT" ] || [ ! -f "$TRANSCRIPT" ] && exit 0
42
+
43
+ # Create snapshot directory
44
+ SNAPSHOT_DIR="${HOME}/.claude/conversation-snapshots"
45
+ mkdir -p "$SNAPSHOT_DIR"
46
+ TIMESTAMP=$(date -u +"%Y%m%d-%H%M%S")
47
+ OUTPUT="$SNAPSHOT_DIR/${TIMESTAMP}.md"
48
+
49
+ # Extract human-readable conversation
50
+ {
51
+ echo "# Conversation Snapshot"
52
+ echo "Exported: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
53
+ echo "Source: $TRANSCRIPT"
54
+ echo ""
55
+ echo "---"
56
+ echo ""
57
+
58
+ # Parse JSONL and extract messages
59
+ while IFS= read -r line; do
60
+ ROLE=$(echo "$line" | jq -r '.message.role // empty' 2>/dev/null)
61
+ case "$ROLE" in
62
+ user)
63
+ CONTENT=$(echo "$line" | jq -r '.message.content // empty' 2>/dev/null)
64
+ if [ -n "$CONTENT" ] && [ "$CONTENT" != "null" ]; then
65
+ echo "## User"
66
+ echo "$CONTENT" | head -20
67
+ echo ""
68
+ fi
69
+ ;;
70
+ assistant)
71
+ TEXT=$(echo "$line" | jq -r '[.message.content[]? | select(.type=="text") | .text] | join("\n")' 2>/dev/null)
72
+ if [ -n "$TEXT" ] && [ "$TEXT" != "null" ]; then
73
+ echo "## Assistant"
74
+ echo "$TEXT" | head -50
75
+ echo ""
76
+ fi
77
+ ;;
78
+ esac
79
+ done < "$TRANSCRIPT"
80
+ } > "$OUTPUT" 2>/dev/null
81
+
82
+ LINES=$(wc -l < "$OUTPUT" 2>/dev/null || echo 0)
83
+ echo "Conversation snapshot saved: $OUTPUT ($LINES lines)" >&2
84
+
85
+ exit 0
@@ -6,6 +6,8 @@
6
6
  # Claude Code has built-in Read, Edit, Grep, Glob tools that are faster and safer
7
7
  # than bash equivalents. But Claude often reaches for sed, grep, cat instead.
8
8
  # This hook denies those commands with a pointer to the correct built-in tool.
9
+ #
10
+ # TRIGGER: PermissionRequest MATCHER: ""
9
11
 
10
12
  INPUT=$(cat)
11
13
  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: "Edit|Write"
2
4
  CONTENT=$(cat | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
3
5
  [ -z "$CONTENT" ] && exit 0
4
6
  echo "$CONTENT" | grep -qE "^\s*let\s+\w+\s*=" && echo "NOTE: Consider const if not reassigned" >&2
@@ -0,0 +1,55 @@
1
+ #!/bin/bash
2
+ # prefer-dedicated-tools.sh — Force use of dedicated tools instead of Bash equivalents
3
+ #
4
+ # Solves: Claude uses Bash cat/grep/head/tail instead of dedicated Read/Grep
5
+ # tools, wasting tokens on shell overhead and losing structured output
6
+ # (#39979). The system prompt says to use dedicated tools, but the
7
+ # model ignores it.
8
+ #
9
+ # How it works: PreToolUse hook on Bash that detects file-reading commands
10
+ # and blocks them with a suggestion to use the dedicated tool instead.
11
+ #
12
+ # TRIGGER: PreToolUse
13
+ # MATCHER: "Bash"
14
+ #
15
+ # Usage:
16
+ # {
17
+ # "hooks": {
18
+ # "PreToolUse": [{
19
+ # "matcher": "Bash",
20
+ # "hooks": [{ "type": "command", "command": "~/.claude/hooks/prefer-dedicated-tools.sh" }]
21
+ # }]
22
+ # }
23
+ # }
24
+
25
+ INPUT=$(cat)
26
+ CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
27
+ [ -z "$CMD" ] && exit 0
28
+
29
+ # Detect cat used for reading files (not piped)
30
+ if echo "$CMD" | grep -qE '^\s*cat\s+[^|]+$'; then
31
+ echo "BLOCKED: Use the Read tool instead of 'cat' for reading files." >&2
32
+ exit 2
33
+ fi
34
+
35
+ # Detect head/tail used for reading files
36
+ if echo "$CMD" | grep -qE '^\s*(head|tail)\s+(-[0-9]+\s+)?[^|]+$'; then
37
+ echo "BLOCKED: Use the Read tool (with offset/limit) instead of head/tail." >&2
38
+ exit 2
39
+ fi
40
+
41
+ # Detect grep used for searching (not piped)
42
+ if echo "$CMD" | grep -qE '^\s*grep\s+(-[a-zA-Z]*\s+)*[^|]+$' && ! echo "$CMD" | grep -qE '\|'; then
43
+ echo "BLOCKED: Use the Grep tool instead of 'grep' for searching files." >&2
44
+ exit 2
45
+ fi
46
+
47
+ # Detect find used for file discovery
48
+ if echo "$CMD" | grep -qE '^\s*find\s+\S+\s+-name\s'; then
49
+ echo "BLOCKED: Use the Glob tool instead of 'find' for file discovery." >&2
50
+ exit 2
51
+ fi
52
+
53
+ # Allow piped commands (cat file | grep pattern is a valid use case)
54
+ # Allow other legitimate bash usage
55
+ exit 0
@@ -1,4 +1,6 @@
1
1
  #!/bin/bash
2
+ #
3
+ # TRIGGER: PreToolUse MATCHER: "Edit|Write"
2
4
  CONTENT=$(cat | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
3
5
  [ -z "$CONTENT" ] && exit 0
4
6
  echo "$CONTENT" | grep -qE "\w+\s*&&\s*\w+\.\w+" && echo "NOTE: Consider optional chaining (?.) instead" >&2
@@ -16,6 +16,8 @@
16
16
  # }
17
17
  # }
18
18
  # ================================================================
19
+ #
20
+ # TRIGGER: PreToolUse MATCHER: "Bash"
19
21
 
20
22
  INPUT=$(cat)
21
23
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -8,6 +8,8 @@
8
8
  # (API, shared sessions, automated pipelines).
9
9
  #
10
10
  # See: https://github.com/anthropics/claude-code/issues/34895
11
+ #
12
+ # TRIGGER: PreToolUse MATCHER: "Bash"
11
13
 
12
14
  INPUT=$(cat)
13
15
  PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null)
@@ -6,6 +6,8 @@
6
6
  # Warns when a user prompt exceeds a character threshold.
7
7
  # Very long prompts can consume excessive context and tokens.
8
8
  # Adjust THRESHOLD to match your comfort level.
9
+ #
10
+ # TRIGGER: PreToolUse MATCHER: "Bash"
9
11
 
10
12
  INPUT=$(cat)
11
13
  PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null)
@@ -16,6 +16,8 @@
16
16
  # }]
17
17
  # }
18
18
  # }
19
+ #
20
+ # TRIGGER: PreToolUse MATCHER: "Bash"
19
21
 
20
22
  INPUT=$(cat)
21
23
  TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
@@ -0,0 +1,58 @@
1
+ #!/bin/bash
2
+ # public-repo-push-guard.sh — Block pushing proprietary code to public repos
3
+ #
4
+ # Solves: Accidental exposure of private code to public repositories (#29225).
5
+ # Claude pushes code containing internal paths, strategy files, or
6
+ # proprietary patterns to a public GitHub repo.
7
+ #
8
+ # How it works: PreToolUse hook on Bash that detects git push commands,
9
+ # checks if the remote repo is public via gh API, then scans staged
10
+ # files against a configurable blocklist.
11
+ #
12
+ # Configuration: CC_PRIVATE_PATTERNS (colon-separated glob patterns)
13
+ # Default: "internal/:strategies/:*.secret.*:*.private.*"
14
+ #
15
+ # TRIGGER: PreToolUse
16
+ # MATCHER: "Bash"
17
+
18
+ set -uo pipefail
19
+
20
+ INPUT=$(cat)
21
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
22
+ [ -z "$COMMAND" ] && exit 0
23
+
24
+ # Only check git push
25
+ if ! echo "$COMMAND" | grep -qE '^\s*git\s+push\b'; then
26
+ exit 0
27
+ fi
28
+
29
+ # Get remote URL
30
+ REMOTE=$(git remote get-url origin 2>/dev/null || echo "")
31
+ [ -z "$REMOTE" ] && exit 0
32
+
33
+ # Extract owner/repo from URL
34
+ REPO=$(echo "$REMOTE" | sed -E 's|.*github\.com[:/]||; s|\.git$||')
35
+ [ -z "$REPO" ] && exit 0
36
+
37
+ # Check visibility (requires gh CLI)
38
+ if command -v gh &>/dev/null; then
39
+ VISIBILITY=$(gh repo view "$REPO" --json visibility --jq '.visibility' 2>/dev/null || echo "UNKNOWN")
40
+ if [ "$VISIBILITY" = "PUBLIC" ]; then
41
+ # Check staged files against private patterns
42
+ PATTERNS="${CC_PRIVATE_PATTERNS:-internal/:strategies/:*.secret.*:*.private.*}"
43
+ STAGED=$(git diff --cached --name-only 2>/dev/null || echo "")
44
+
45
+ IFS=':' read -ra PATS <<< "$PATTERNS"
46
+ for pat in "${PATS[@]}"; do
47
+ MATCH=$(echo "$STAGED" | grep -E "$pat" | head -1)
48
+ if [ -n "$MATCH" ]; then
49
+ echo "BLOCKED: Pushing to PUBLIC repo '$REPO' with private file pattern." >&2
50
+ echo "File: $MATCH matches pattern: $pat" >&2
51
+ echo "Remove private files from staging or push to a private repo." >&2
52
+ exit 2
53
+ fi
54
+ done
55
+ fi
56
+ fi
57
+
58
+ exit 0
@@ -5,6 +5,8 @@
5
5
  # The PreToolUse companion then checks this record before allowing git push.
6
6
  #
7
7
  # Detected test commands: npm test, pytest, cargo test, go test, make test, etc.
8
+ #
9
+ # TRIGGER: PreToolUse MATCHER: "Bash"
8
10
 
9
11
  INPUT=$(cat)
10
12
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -24,6 +24,8 @@
24
24
  # }]
25
25
  # }
26
26
  # }
27
+ #
28
+ # TRIGGER: PreToolUse MATCHER: "Bash"
27
29
 
28
30
  INPUT=$(cat)
29
31
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -16,6 +16,8 @@
16
16
  # }
17
17
  # }
18
18
  # ================================================================
19
+ #
20
+ # TRIGGER: PreToolUse MATCHER: "Bash"
19
21
 
20
22
  INPUT=$(cat)
21
23
  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
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
4
6
  CONTENT=$(echo "$INPUT" | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
@@ -0,0 +1,51 @@
1
+ #!/bin/bash
2
+ # read-all-files-enforcer.sh — Track which files have been read in a directory
3
+ #
4
+ # Solves: Agent skips files when told to "read every file" (#40389).
5
+ # Claude delegates to subagents, summarizes instead of reading,
6
+ # or substitutes its own judgment about what needs reading.
7
+ #
8
+ # How it works: PostToolUse hook on Read that logs read files.
9
+ # Paired with a manual check: after the user says "read all files in X",
10
+ # compare the log against actual directory contents.
11
+ #
12
+ # Usage: Set CC_READ_TRACK_DIR to the target directory.
13
+ # export CC_READ_TRACK_DIR="docs/"
14
+ # After the task, check: diff <(ls docs/) <(cat /tmp/claude-read-log-*)
15
+ #
16
+ # TRIGGER: PostToolUse
17
+ # MATCHER: "Read"
18
+
19
+ set -euo pipefail
20
+
21
+ INPUT=$(cat)
22
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
23
+ [ "$TOOL" = "Read" ] || exit 0
24
+
25
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
26
+ [ -z "$FILE" ] && exit 0
27
+
28
+ TRACK_DIR="${CC_READ_TRACK_DIR:-}"
29
+ [ -n "$TRACK_DIR" ] || exit 0
30
+
31
+ # Check if the read file is in the tracked directory
32
+ case "$FILE" in
33
+ ${TRACK_DIR}*)
34
+ # Log the read
35
+ LOG_FILE="/tmp/claude-read-track-${PPID:-0}"
36
+ echo "$FILE" >> "$LOG_FILE"
37
+
38
+ # Count total files in directory vs read files
39
+ TOTAL=$(find "$TRACK_DIR" -type f 2>/dev/null | wc -l)
40
+ READ_COUNT=$(sort -u "$LOG_FILE" 2>/dev/null | wc -l)
41
+
42
+ if [ "$READ_COUNT" -lt "$TOTAL" ]; then
43
+ REMAINING=$((TOTAL - READ_COUNT))
44
+ echo "Progress: $READ_COUNT/$TOTAL files read in $TRACK_DIR ($REMAINING remaining)" >&2
45
+ else
46
+ echo "All $TOTAL files in $TRACK_DIR have been read." >&2
47
+ fi
48
+ ;;
49
+ esac
50
+
51
+ exit 0
@@ -1,4 +1,6 @@
1
1
  #!/bin/bash
2
+ #
3
+ # TRIGGER: PreToolUse MATCHER: "Bash"
2
4
  CONTENT=$(cat | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
3
5
  [ -z "$CONTENT" ] && exit 0
4
6
  COMMAND=$(cat | jq -r ".tool_input.command // empty" 2>/dev/null); echo "$COMMAND" | grep -qE "git\s+commit" && [ ! -f "README.md" ] && echo "NOTE: No README.md in project" >&2
@@ -1,3 +1,5 @@
1
+ #
2
+ # TRIGGER: PreToolUse MATCHER: "Bash"
1
3
  INPUT=$(cat)
2
4
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
3
5
  [[ -z "$COMMAND" ]] && exit 0
@@ -30,6 +30,8 @@
30
30
  #
31
31
  # Note: This hook checks rm, find -delete, and shred. Do NOT add an "if" field
32
32
  # (v2.1.85) because "if" only supports one pattern and would miss the others.
33
+ #
34
+ # TRIGGER: PreToolUse MATCHER: "Bash"
33
35
 
34
36
  INPUT=$(cat)
35
37
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -0,0 +1,69 @@
1
+ #!/bin/bash
2
+ # role-tool-guard.sh — Restrict tools based on current agent role
3
+ #
4
+ # Solves: Agent team workflows where PM writes code instead of delegating (#40425).
5
+ # When using structured team roles (PM → Architect → Developer),
6
+ # each role should only access tools appropriate to its function.
7
+ # CLAUDE.md rules are advisory and get ignored under context pressure.
8
+ #
9
+ # How it works: Reads current role from a scope file, then blocks tools
10
+ # that don't match the role's allowed tool set.
11
+ #
12
+ # Setup:
13
+ # echo "pm" > .claude/current-role.txt
14
+ # Roles: pm, architect, developer, reviewer (customizable)
15
+ #
16
+ # TRIGGER: PreToolUse
17
+ # MATCHER: "Bash|Edit|Write|NotebookEdit|Agent"
18
+
19
+ set -euo pipefail
20
+
21
+ INPUT=$(cat)
22
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
23
+ [ -z "$TOOL" ] && exit 0
24
+
25
+ # Read current role
26
+ ROLE_FILE=".claude/current-role.txt"
27
+ [ -f "$ROLE_FILE" ] || exit 0
28
+
29
+ ROLE=$(head -1 "$ROLE_FILE" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')
30
+ [ -z "$ROLE" ] && exit 0
31
+
32
+ # Define allowed tools per role (customizable via env)
33
+ case "$ROLE" in
34
+ pm|"product-manager"|"project-manager")
35
+ # PM can read, search, and delegate — not write code
36
+ BLOCKED_TOOLS="Edit|Write|Bash|NotebookEdit"
37
+ ROLE_DESC="PM (read/delegate only)"
38
+ ;;
39
+ architect|"system-architect")
40
+ # Architect can read and write docs, not execute
41
+ BLOCKED_TOOLS="Bash|NotebookEdit"
42
+ ROLE_DESC="Architect (design only, no execution)"
43
+ ;;
44
+ reviewer|"code-reviewer")
45
+ # Reviewer can read and comment, not modify
46
+ BLOCKED_TOOLS="Edit|Write|NotebookEdit"
47
+ ROLE_DESC="Reviewer (read-only)"
48
+ ;;
49
+ developer|"dev")
50
+ # Developer has full access
51
+ exit 0
52
+ ;;
53
+ *)
54
+ # Unknown role — allow by default
55
+ exit 0
56
+ ;;
57
+ esac
58
+
59
+ # Check if current tool is blocked for this role
60
+ if echo "$TOOL" | grep -qE "^($BLOCKED_TOOLS)$"; then
61
+ echo "BLOCKED: Role '$ROLE' cannot use $TOOL." >&2
62
+ echo "Current role: $ROLE_DESC" >&2
63
+ echo "" >&2
64
+ echo "To change role: echo 'developer' > .claude/current-role.txt" >&2
65
+ echo "Or delegate this task to the appropriate agent." >&2
66
+ exit 2
67
+ fi
68
+
69
+ 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)
@@ -0,0 +1,57 @@
1
+ #!/bin/bash
2
+ # schema-migration-guard.sh — Warn on database schema migrations without backup
3
+ #
4
+ # Solves: Claude running destructive schema migrations (DROP COLUMN,
5
+ # ALTER TABLE, DROP INDEX) without first creating a backup or
6
+ # generating a rollback migration.
7
+ #
8
+ # How it works: PreToolUse hook on Bash that detects migration commands
9
+ # (Rails, Django, Prisma, Flyway, Liquibase, raw SQL) and warns if
10
+ # they contain destructive operations.
11
+ #
12
+ # TRIGGER: PreToolUse
13
+ # MATCHER: "Bash"
14
+
15
+ set -euo pipefail
16
+
17
+ INPUT=$(cat)
18
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
19
+ [ -z "$COMMAND" ] && exit 0
20
+
21
+ # Detect migration commands
22
+ IS_MIGRATION=false
23
+ case "$COMMAND" in
24
+ *"migrate"*|*"migration"*|*"db:migrate"*|*"prisma migrate"*|*"alembic"*|*"flyway"*|*"liquibase"*)
25
+ IS_MIGRATION=true ;;
26
+ esac
27
+
28
+ # Also check for raw SQL with destructive operations
29
+ if echo "$COMMAND" | grep -qEi '(DROP\s+(TABLE|COLUMN|INDEX|DATABASE|SCHEMA)|ALTER\s+TABLE.*DROP|TRUNCATE\s+TABLE|DELETE\s+FROM.*WHERE\s+1)'; then
30
+ IS_MIGRATION=true
31
+ fi
32
+
33
+ $IS_MIGRATION || exit 0
34
+
35
+ # Check for destructive patterns
36
+ DESTRUCT=""
37
+ if echo "$COMMAND" | grep -qEi 'DROP\s+(TABLE|COLUMN|INDEX|DATABASE)'; then
38
+ DESTRUCT="${DESTRUCT}DROP operation detected. "
39
+ fi
40
+ if echo "$COMMAND" | grep -qEi 'TRUNCATE'; then
41
+ DESTRUCT="${DESTRUCT}TRUNCATE detected. "
42
+ fi
43
+ if echo "$COMMAND" | grep -qEi -- '--force|--no-check|--skip-validation'; then
44
+ DESTRUCT="${DESTRUCT}Safety bypass flag detected. "
45
+ fi
46
+
47
+ if [ -n "$DESTRUCT" ]; then
48
+ echo "WARNING: Destructive database migration detected." >&2
49
+ echo " Command: $COMMAND" >&2
50
+ echo " Issues: $DESTRUCT" >&2
51
+ echo " Before running:" >&2
52
+ echo " 1. Create a database backup" >&2
53
+ echo " 2. Generate a rollback migration" >&2
54
+ echo " 3. Test on staging first" >&2
55
+ fi
56
+
57
+ exit 0
@@ -14,6 +14,8 @@
14
14
  # }]
15
15
  # }
16
16
  # }
17
+ #
18
+ # TRIGGER: PreToolUse MATCHER: "Bash"
17
19
 
18
20
  INPUT=$(cat)
19
21
  TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
@@ -0,0 +1,74 @@
1
+ #!/bin/bash
2
+ # secret-file-read-guard.sh — Block Read/Grep of files containing secrets
3
+ #
4
+ # Solves: Sensitive data (API keys, credentials, PII) is sent to the
5
+ # LLM provider when Read/Grep tools access configuration files
6
+ # (#39882). This hook blocks reads of known-sensitive files.
7
+ #
8
+ # How it works: PreToolUse hook that checks if Read/Grep targets a
9
+ # file that commonly contains secrets (.env, credentials, keys, etc.)
10
+ # and blocks the operation before file contents enter the context.
11
+ #
12
+ # TRIGGER: PreToolUse
13
+ # MATCHER: "Read|Grep"
14
+ #
15
+ # Usage:
16
+ # {
17
+ # "hooks": {
18
+ # "PreToolUse": [{
19
+ # "matcher": "Read|Grep",
20
+ # "hooks": [{ "type": "command", "command": "~/.claude/hooks/secret-file-read-guard.sh" }]
21
+ # }]
22
+ # }
23
+ # }
24
+
25
+ INPUT=$(cat)
26
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
27
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty' 2>/dev/null)
28
+
29
+ [[ "$TOOL" != "Read" && "$TOOL" != "Grep" ]] && exit 0
30
+ [ -z "$FILE" ] && exit 0
31
+
32
+ # Expand ~ to $HOME
33
+ FILE=$(echo "$FILE" | sed "s|^~|$HOME|")
34
+
35
+ # ============================================
36
+ # BLOCKED FILE PATTERNS — customize as needed
37
+ # ============================================
38
+ BLOCKED_PATTERNS=(
39
+ '\.env$'
40
+ '\.env\.'
41
+ 'credentials'
42
+ '\.pem$'
43
+ '\.key$'
44
+ '\.p12$'
45
+ '\.jks$'
46
+ '\.keystore$'
47
+ 'id_rsa'
48
+ 'id_ed25519'
49
+ '\.ssh/config$'
50
+ '\.aws/credentials$'
51
+ '\.aws/config$'
52
+ '\.npmrc$'
53
+ '\.pypirc$'
54
+ '\.docker/config\.json$'
55
+ '\.kube/config$'
56
+ 'secrets\.ya?ml$'
57
+ 'vault\.ya?ml$'
58
+ '\.htpasswd$'
59
+ 'shadow$'
60
+ 'master\.key$'
61
+ 'service[-_]account.*\.json$'
62
+ )
63
+
64
+ BASENAME=$(basename "$FILE")
65
+ for pattern in "${BLOCKED_PATTERNS[@]}"; do
66
+ if echo "$FILE" | grep -qE "$pattern" || echo "$BASENAME" | grep -qE "$pattern"; then
67
+ echo "BLOCKED: Cannot read file that may contain secrets: $FILE" >&2
68
+ echo "This file matches pattern: $pattern" >&2
69
+ echo "If you need this file's contents, describe what you need and the user can provide it." >&2
70
+ exit 2
71
+ fi
72
+ done
73
+
74
+ exit 0