This hook auto-claims files in lain before Codex CLI edits them. Codex's
hook config lives in ~/.codex/config.toml (TOML, with [[hooks.PreToolUse]]
arrays). Codex also accepts ~/.codex/hooks.json for the same purpose; the
TOML form is canonical on this host.
~/.codex/config.toml— TOML with a top-level[[hooks.PreToolUse]]array. Each entry hasmatcherand a nested[[hooks.PreToolUse.hooks]]array of{type, command, timeout}entries.~/.codex/hooks.json— alternative JSON form: a top-levelhooks.PreToolUsearray of{matcher, hooks:[{type, command, timeout}]}entries.
- Make sure
lainis on$PATHand alain serveris running with HTTP transport. - Set
LAIN_URLif lain is not onhttp://localhost:9999(bare URL; the MCP/mcppath is appended automatically). - Append to
~/.codex/config.toml(preserving existing content):
# lain: claim files before edit
[[hooks.PreToolUse]]
matcher = "edit_file|apply_patch|create_file"
[[hooks.PreToolUse.hooks]]
type = "command"
command = "/path/to/hooks/codex/pre-edit.sh"
timeout = 10Replace /path/to/hooks/... with the absolute path in this repo. Adjust
the matcher to the actual write/edit tool names exposed by your Codex
version (e.g. edit_file, write_file, apply_patch, create_file).
If you prefer JSON, write ~/.codex/hooks.json instead:
{
"hooks": {
"PreToolUse": [
{ "matcher": "edit_file|apply_patch|create_file",
"hooks": [{ "type": "command", "command": "/path/to/hooks/codex/pre-edit.sh", "timeout": 10 }] }
]
}
}- pre-edit.sh: Calls
lain hooks claimto register Codex as an agent and claim the file. Conflicts are surfaced to Codex on stderr. Lain unreachable → exit 0 (don't break Codex's workflow).
--agent-name=codex--agent-kind=codex
All Codex sessions share the same agent name (codex) and persistent
session token. 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.