|
| 1 | +# Claude Code Hooks for Safe Scientific Development |
| 2 | + |
| 3 | +This directory contains hooks that provide technical enforcement of safety requirements for the `non_local_detector` project. |
| 4 | + |
| 5 | +## Hook Overview |
| 6 | + |
| 7 | +Hooks automatically intercept commands and verify safety requirements before execution. They provide the first layer of defense in the three-layer system (hooks + skills + documentation). |
| 8 | + |
| 9 | +## Available Hooks |
| 10 | + |
| 11 | +### pre-tool-use.sh |
| 12 | +**Triggers:** Before every Bash tool execution |
| 13 | + |
| 14 | +**Enforces:** |
| 15 | +1. **Conda environment validation** |
| 16 | + - Warns if Python commands run outside `non_local_detector` environment |
| 17 | + - Suggests activation command |
| 18 | + - Auto-prepends activation to commands |
| 19 | + |
| 20 | +2. **Test-before-commit** |
| 21 | + - Checks if tests have run recently before allowing commits |
| 22 | + - Warns if no test cache found |
| 23 | + - Recommends running test suite |
| 24 | + |
| 25 | +3. **Snapshot update protection** |
| 26 | + - Blocks `--snapshot-update` without approval flag |
| 27 | + - Requires full analysis before approval |
| 28 | + - Clears approval flag after use |
| 29 | + |
| 30 | +**Exit codes:** |
| 31 | +- `0`: Command allowed (may include warnings) |
| 32 | +- `1`: Command blocked (e.g., snapshot update without approval) |
| 33 | + |
| 34 | +--- |
| 35 | + |
| 36 | +### user-prompt-submit.sh |
| 37 | +**Triggers:** After user submits a prompt |
| 38 | + |
| 39 | +**Detects:** |
| 40 | +- Snapshot file changes (`.ambr` files) |
| 41 | +- Recent snapshot test runs |
| 42 | + |
| 43 | +**Actions:** |
| 44 | +- Reports modified snapshot files |
| 45 | +- Reminds Claude to provide full analysis |
| 46 | +- Lists requirements for snapshot update approval |
| 47 | + |
| 48 | +**Exit codes:** |
| 49 | +- Always `0` (informational only, never blocks) |
| 50 | + |
| 51 | +--- |
| 52 | + |
| 53 | +## Utility Libraries |
| 54 | + |
| 55 | +### lib/env_check.sh |
| 56 | +**Functions:** |
| 57 | +- `check_conda_env()`: Verify conda environment active |
| 58 | +- `get_activation_cmd()`: Return activation command string |
| 59 | +- `prepend_activation()`: Auto-prepend activation to command |
| 60 | +- `needs_conda()`: Check if command requires conda environment |
| 61 | + |
| 62 | +### lib/numerical_validation.sh |
| 63 | +**Functions:** |
| 64 | +- `check_invariants()`: Scan test output for NaN/Inf |
| 65 | +- `has_snapshot_changes()`: Detect modified snapshot files |
| 66 | +- `has_snapshot_approval()`: Check if approval flag set |
| 67 | +- `set_snapshot_approval()`: Create approval flag file |
| 68 | +- `clear_snapshot_approval()`: Remove approval flag file |
| 69 | + |
| 70 | +--- |
| 71 | + |
| 72 | +## Hook Environment Variables |
| 73 | + |
| 74 | +Hooks receive these environment variables from Claude Code: |
| 75 | + |
| 76 | +- `CLAUDE_TOOL_NAME`: Name of tool being invoked (e.g., "Bash") |
| 77 | +- `CLAUDE_TOOL_COMMAND`: Full command string being executed |
| 78 | +- `CONDA_DEFAULT_ENV`: Current conda environment name |
| 79 | + |
| 80 | +--- |
| 81 | + |
| 82 | +## Testing Hooks |
| 83 | + |
| 84 | +### Manual testing |
| 85 | + |
| 86 | +```bash |
| 87 | +# Test environment check |
| 88 | +export CLAUDE_TOOL_NAME="Bash" |
| 89 | +export CLAUDE_TOOL_COMMAND="pytest --version" |
| 90 | +.claude/hooks/pre-tool-use.sh |
| 91 | +echo "Exit code: $?" |
| 92 | + |
| 93 | +# Test snapshot protection (should block) |
| 94 | +export CLAUDE_TOOL_COMMAND="pytest --snapshot-update" |
| 95 | +.claude/hooks/pre-tool-use.sh |
| 96 | +echo "Exit code: $?" # Should be 1 |
| 97 | + |
| 98 | +# Test with approval |
| 99 | +source .claude/hooks/lib/numerical_validation.sh |
| 100 | +set_snapshot_approval |
| 101 | +.claude/hooks/pre-tool-use.sh |
| 102 | +echo "Exit code: $?" # Should be 0 |
| 103 | +``` |
| 104 | + |
| 105 | +### Expected behavior |
| 106 | + |
| 107 | +| Scenario | Hook | Expected Result | |
| 108 | +|----------|------|-----------------| |
| 109 | +| Python command, wrong env | pre-tool-use | Warning (exit 0) | |
| 110 | +| Commit without recent tests | pre-tool-use | Warning (exit 0) | |
| 111 | +| Snapshot update, no approval | pre-tool-use | Blocked (exit 1) | |
| 112 | +| Snapshot update, with approval | pre-tool-use | Allowed, flag cleared (exit 0) | |
| 113 | +| Snapshot files modified | user-prompt-submit | Info message (exit 0) | |
| 114 | + |
| 115 | +--- |
| 116 | + |
| 117 | +## Integration with Skills |
| 118 | + |
| 119 | +Hooks work together with skills: |
| 120 | + |
| 121 | +1. **Skills** (layer 2) guide Claude through workflows |
| 122 | +2. **Hooks** (layer 1) enforce critical requirements |
| 123 | +3. **Documentation** (layer 3) explains the "why" |
| 124 | + |
| 125 | +Example flow: |
| 126 | +``` |
| 127 | +Claude uses scientific-tdd skill |
| 128 | + ↓ |
| 129 | +Skill says: "Run tests" |
| 130 | + ↓ |
| 131 | +Claude executes: pytest command |
| 132 | + ↓ |
| 133 | +pre-tool-use hook checks conda env |
| 134 | + ↓ |
| 135 | +Hook passes or warns |
| 136 | + ↓ |
| 137 | +Command executes |
| 138 | +``` |
| 139 | + |
| 140 | +--- |
| 141 | + |
| 142 | +## Debugging Hooks |
| 143 | + |
| 144 | +If hooks misbehave: |
| 145 | + |
| 146 | +1. **Check hook permissions:** |
| 147 | + ```bash |
| 148 | + ls -l .claude/hooks/*.sh |
| 149 | + # Should show -rwxr-xr-x |
| 150 | + ``` |
| 151 | + |
| 152 | +2. **Test utilities directly:** |
| 153 | + ```bash |
| 154 | + source .claude/hooks/lib/env_check.sh |
| 155 | + check_conda_env && echo "OK" || echo "FAIL" |
| 156 | + ``` |
| 157 | + |
| 158 | +3. **Run hook with debug output:** |
| 159 | + ```bash |
| 160 | + bash -x .claude/hooks/pre-tool-use.sh |
| 161 | + ``` |
| 162 | + |
| 163 | +4. **Check environment variables:** |
| 164 | + ```bash |
| 165 | + echo "Tool: $CLAUDE_TOOL_NAME" |
| 166 | + echo "Command: $CLAUDE_TOOL_COMMAND" |
| 167 | + echo "Conda: $CONDA_DEFAULT_ENV" |
| 168 | + ``` |
| 169 | + |
| 170 | +--- |
| 171 | + |
| 172 | +## Maintenance |
| 173 | + |
| 174 | +### When to update hooks: |
| 175 | + |
| 176 | +- Conda environment name changes |
| 177 | +- New tools need environment checking |
| 178 | +- Validation requirements change |
| 179 | +- New safety checks needed |
| 180 | + |
| 181 | +### Best practices: |
| 182 | + |
| 183 | +- Keep hooks fast (< 100ms) |
| 184 | +- Always exit with appropriate code (0 or 1) |
| 185 | +- Provide helpful error messages |
| 186 | +- Source utilities from `lib/` directory |
| 187 | +- Test thoroughly before deployment |
| 188 | + |
| 189 | +--- |
| 190 | + |
| 191 | +## Related Documentation |
| 192 | + |
| 193 | +- **CLAUDE.md**: Project operational rules |
| 194 | +- **Skills**: Workflow enforcement |
| 195 | +- **Testing Plan**: Coverage improvement strategy |
0 commit comments