Back to catalogue
ValidationPostToolUse· Write|Edit
Pyright type checking
Python type errors caught right after an edit
Runs pyright via uv on the modified .py file and reports type errors to the agent so they are fixed within the same loop.
What does the Pyright type checking hook do?
Pyright type checking is a Claude Code PostToolUse hook matching Write|Edit. It fires automatically at that lifecycle event — outside the model, so it can't be skipped or forgotten. Python type errors caught right after an edit.
As a PostToolUse hook it runs after the action, reacting to what just happened rather than blocking it. Because it is a deterministic Node.js script, it executes on every matching event without relying on the model to remember — the guarantee that makes agentic workflows safe to automate.
Use cases
- Strict typing in Python projects with pyright
- Catch type mismatches immediately after an edit
- Pair with ruff for a complete Python quality pipeline
Tags
#validation#pyright#typecheck#python#quality
settings.json fragment
{
"hooks": {
"PostToolUse": [
{
"hooks": [
{
"command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/pyright-check.mjs",
"type": "command"
}
],
"matcher": "Write|Edit"
}
]
}
}Script · .claude/hooks/pyright-check.mjs
#!/usr/bin/env node
// @hookstack post-edit-pyright
import { execSync } from "node:child_process";
// @hookstack post-edit-pyright
// Vérifie les types Python avec pyright après édition (PostToolUse Write|Edit)
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
function defaultExec(cmd) {
return execSync(cmd, { encoding: "utf8", stdio: "pipe", timeout: 30_000 });
}
export function run(input, { exec = defaultExec } = {}) {
const filePath = input.tool_input?.file_path ?? input.tool_input?.path ?? "";
if (!filePath.endsWith(".py")) return null;
try {
exec(`uv run pyright "${filePath}"`);
return null;
} catch (err) {
const output = err.stdout?.toString() ?? "";
return output ? { message: `[pyright] ${output.trim()}\n` } : null;
}
}
/* v8 ignore next 5 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const input = JSON.parse(readFileSync(0, "utf8"));
const result = run(input);
if (result?.message) process.stderr.write(result.message);
}