From fc999d0449fbcc895336234a801b965329e9a57a Mon Sep 17 00:00:00 2001 From: GenWave Radio Date: Sun, 13 Sep 2026 10:07:09 -0600 Subject: [PATCH] fix(toolkit): live .env guard hook and the no-trailers rule (gh-#750, gh-#752) The example hooks read $CLAUDE_FILE_PATHS, which Claude Code never exports, so the .env guard and the formatter had never run. Hook input is JSON on stdin; the guard now reads .tool_input.file_path with jq and exits 2 on *.env files. The formatter hook is dropped: admin-ui has no prettier (CI runs eslint) and per-edit dotnet format is too slow for a builder loop. CLAUDE.md gains the rule that no session trailers, co-author lines, or claude.ai/code links go into commits, PRs, issues, or releases, so every subagent sees it without relying on memory. Refs gh-#750, gh-#752 --- .claude/settings.example.json | 25 +++---------------------- CLAUDE.md | 1 + 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/.claude/settings.example.json b/.claude/settings.example.json index 48ff22c5..85039a8e 100644 --- a/.claude/settings.example.json +++ b/.claude/settings.example.json @@ -1,6 +1,5 @@ { - "$comment": "Rename to settings.json (project-shared) or settings.local.json (personal, gitignored). Hooks below are examples — uncomment to enable. See https://docs.claude.com/claude-code/hooks for the full schema.", - + "$comment": "Rename to settings.json (project-shared) or settings.local.json (personal, gitignored). Hooks below are live examples. See https://docs.claude.com/claude-code/hooks for the full schema.", "permissions": { "$comment": "Pre-approve common safe commands so you stop seeing prompts.", "allow": [ @@ -33,40 +32,22 @@ "Bash(curl * | bash)" ] }, - "env": { "$comment": "Project-wide env hints for the AI. Real secrets go in .env (gitignored)." }, - "hooks": { - "$comment_PostToolUse": "Run after each Edit/Write — uncomment to auto-format on save (dotnet format for .cs, prettier for TS/JS).", - "PostToolUse": [ - { - "matcher": "Edit|Write", - "hooks": [ - { - "type": "command", - "command": "case \"$CLAUDE_FILE_PATHS\" in *.cs) dotnet format --include \"$CLAUDE_FILE_PATHS\" 2>/dev/null || true ;; *.ts|*.tsx|*.js|*.jsx) test -f package.json && bunx prettier --write \"$CLAUDE_FILE_PATHS\" 2>/dev/null || true ;; esac" - } - ] - } - ], - - "$comment_PreToolUse": "Block edits to sensitive files. Uncomment to enable.", + "$comment": "Hook input arrives as JSON on stdin (.tool_input.file_path / .tool_input.command). There is no $CLAUDE_FILE_PATHS. Exit 2 blocks the tool call and feeds stderr back to the model. No formatter hook: admin-ui has no prettier and CI runs eslint; dotnet format per edit is too slow.", "PreToolUse": [ { - "$comment": "Example: refuse to edit .env files.", "matcher": "Edit|Write", "hooks": [ { "type": "command", - "command": "echo \"$CLAUDE_FILE_PATHS\" | grep -qE '\\.env(\\..*)?$' && { echo 'refuse: do not edit .env files'; exit 2; } || exit 0" + "command": "f=$(jq -r '.tool_input.file_path // empty'); case \"$f\" in *.env|*.env.*) echo \"refuse: $f is an env file\" >&2; exit 2;; esac; exit 0" } ] } ], - - "$comment_Stop": "Run on session end — uncomment to print a summary or trigger CI.", "Stop": [] } } diff --git a/CLAUDE.md b/CLAUDE.md index a1794be2..04dad165 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,6 +9,7 @@ Self-hosted internet radio station for a small private community. A C# .NET 10 c - Use emoji for markdown documents for readability. - Get to the point, be terse, do not over explain. Tokens are water, we're in the desert. - Never install a package by editing the manifest — always use `dotnet add package`. +- Never add `Claude-Session:` trailers, `Co-Authored-By` lines, or claude.ai/code links to commits, PRs, issues, or releases. ## Stack