These hooks auto-claim files in lain before Claude Code edits them, and release after.
- Make sure
lainis on$PATHand alain serveris running with HTTP transport. - Set
LAIN_URL(default:http://localhost:9999). The MCP/mcppath is appended automatically by the CLI; passinghttp://localhost:9999/mcpalso still works. - Add to
~/.claude/settings.json(project or user):
{
"hooks": {
"PreToolUse": [
{ "matcher": "Edit|Write|MultiEdit", "hooks": [{ "type": "command", "command": "/path/to/hooks/claude-code/pre-edit.sh" }] }
],
"PostToolUse": [
{ "matcher": "Edit|Write|MultiEdit", "hooks": [{ "type": "command", "command": "/path/to/hooks/claude-code/post-edit.sh" }] }
]
}
}Replace /path/to/hooks/... with the absolute path in this repo.
- pre-edit.sh: Calls
lain hooks claimto register Claude Code as an agent and claim the file. If lain reports conflicts, the script writes the conflict JSON to stderr — Claude Code surfaces it in the conversation. - post-edit.sh: Calls
lain hooks releaseafter the edit. If lain is unreachable, the script silently exits 0 (don't break Claude's workflow).
Edit a file with Claude Code and run curl http://localhost:9999/mcp -d '...list_active_agents...' to see Claude Code's session.
All Claude Code sessions share the same agent name (claude-code) and session token. They appear as ONE agent in lain. If you need per-window tracking, set LAIN_AGENT_NAME differently per shell.
An empty get_blast_radius means no static edges found, not no impact. Before mutating any symbol whose blast radius is empty, run all three:
get_coupling_radaron the touched paths (git co-change partners).find_anchorson the file to surface nearby high-fan-in hubs.- Check
docs/dynamic-boundaries.mdin the repo for documented dispatch points (message buses, DI containers, schema-driven routers).
If the file is not in dynamic-boundaries.md and all three queries are empty, proceed with the smoke command. Otherwise treat the result as evidence insufficient and require a broader smoke run before the mutation lands on disk.
You can also call explain_dispatch <symbol> for a single-shot synthesis with a verdict field — insufficient_evidence is the explicit "do not assume safe" signal.
Full reference: docs/dynamic-dispatch.md in the lain repo.