Add composable multi-language linting and formatting system

PostToolUse hook auto-formats files after Edit/Write/MultiEdit with
git-blob checkpoints for safe revert. Pre-commit hook for staged files.
Canonical formatter scripts for py, sh, ts, sql, json (+ symlinks for
js, yaml, md). Install and setup scripts for project opt-in.

Includes best-practices/linting.md, HOOKS.md docs, README.md, and
session log.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Paul O'Reilly
2026-03-13 11:50:36 +13:00
parent a463dc0793
commit d3a92326de
18 changed files with 700 additions and 5 deletions

View File

@@ -7,6 +7,32 @@ Claude Code hooks that run automatically in response to events. Source of truth
| Hook | Event | File |
|------|-------|------|
| Pre-compact backup | PreCompact (auto + manual) | `hooks/pre-compact-backup.sh` |
| Post-edit lint | PostToolUse (Edit/Write/MultiEdit) | `hooks/post-edit-lint.sh` |
| Pre-commit lint | Git pre-commit | `hooks/pre-commit-lint.sh` |
## Post-edit Lint
Formats and lints files after every Edit/Write/MultiEdit. Dispatches to project-local `formatters/` directory (symlinks to `claude-foundations/formatters/`).
**Flow:**
1. Extracts `file_path` and `cwd` from stdin JSON
2. Walks up from `cwd` to find `formatters/` directory
3. Creates a `git hash-object` checkpoint (`.pre-lint` file with blob SHA)
4. Runs the matching formatter script
5. On clean pass: removes checkpoint, exits 0 (silent)
6. On lint errors: keeps checkpoint, exits 2 (feeds errors back to Claude via stderr)
**Requires:** `python3` (for JSON parsing from stdin). Formatter tools are optional — missing tools silently pass.
**Revert:** `git cat-file blob $(cat <file>.pre-lint) > <file>`
## Pre-commit Lint
Git pre-commit hook that runs project formatters on staged files. Reuses the same formatter scripts.
**Flow:** iterates staged files → runs matching formatter → re-stages formatted files → exits non-zero if lint errors remain (blocks commit).
**Install:** symlink `.git/hooks/pre-commit``pre-commit-lint.sh`, or use `scripts/setup-formatters.sh`.
## Pre-compact Backup
@@ -18,10 +44,23 @@ Saves a copy of the session transcript before context compaction so no conversat
## Installation
The easiest way is to run the install script:
```bash
cd ~/dev/claude/projects/claude-foundations
scripts/install-hooks.sh
```
This symlinks all hooks into `~/.claude/hooks/` and prints the `settings.json` config to add.
### Manual installation
1. Symlink each hook into `~/.claude/hooks/`:
```bash
mkdir -p ~/.claude/hooks
ln -sf "$(pwd)/hooks/pre-compact-backup.sh" ~/.claude/hooks/pre-compact-backup.sh
ln -sf "$(pwd)/hooks/post-edit-lint.sh" ~/.claude/hooks/post-edit-lint.sh
ln -sf "$(pwd)/hooks/pre-commit-lint.sh" ~/.claude/hooks/pre-commit-lint.sh
```
2. Add the hook configuration to `~/.claude/settings.json`:
@@ -31,17 +70,28 @@ Saves a copy of the session transcript before context compaction so no conversat
"PreCompact": [
{
"matcher": "auto",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/pre-compact-backup.sh", "timeout": 15 }]
"hooks": [{ "type": "command", "command": "~/.claude/hooks/pre-compact-backup.sh", "timeout": 15, "statusMessage": "Backing up transcript before compaction..." }]
},
{
"matcher": "manual",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/pre-compact-backup.sh", "timeout": 15 }]
"hooks": [{ "type": "command", "command": "~/.claude/hooks/pre-compact-backup.sh", "timeout": 15, "statusMessage": "Backing up transcript before compaction..." }]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/post-edit-lint.sh", "timeout": 30, "statusMessage": "Formatting and linting..." }]
}
]
}
}
```
3. For per-project formatters, run:
```bash
scripts/setup-formatters.sh <project-dir> <ext> [<ext> ...]
```
## Adding New Hooks
1. Create the script in `hooks/`