Claude Code Setup Hooks
Run a deterministic setup script, then hand the output to an agent for diagnosis. One command, three modes, zero drifted docs.
The quality of an engineering team shows up in one number: how long it takes a new hire to get the project running on their machine.
Great teams need one link, one doc, a few commands. Most teams eat a day or two of pairing, Slack threads, dusty wiki pages, and back and forth over why something broke.
Agents make this solvable.
Getting a codebase up has always been a choice between three bad shapes:
Pure scripts are predictable but fragile. They run the same commands every time and freeze the moment reality shifts. A missing dependency or a downed database, and the script just dies.
Pure agents are clever but unreliable. You cannot plug one into a CI/CD pipeline and expect the exact same output across every run.
Pure docs are flexible but human-dependent. Nobody reads them, and they go stale inside a few weeks.
What works is braiding all three together. Scripts handle the execution. Agents watch over them. You end up with a living document that executes.
Setup hooks landed in Claude Code on January 25th, 2026. They're a dedicated hook type that fires before your session spins up. When you run:
claude --initThe setup hook goes first, then Claude starts. The hook can install packages, seed the database, and prep your environment. By the time Claude boots, it already knows what happened.
This is where things get interesting. You can tack a prompt onto the init flag:
claude --init "/install"Now the hook runs, and the /install command fires right after. The agent reads the log files, works out what happened, and reports back in plain language.
claude --init "/install true"Three setups fall out of this:
┌─────────────────────────────────────────────────────────┐
│ DETERMINISTIC AGENTIC INTERACTIVE │
│ (hooks only) (hooks + prompt) (hooks + Qs) │
│ │
│ claude --init /install /install true │
│ │
│ - Fast - Supervised - Asks Qs │
│ - Predictable - Diagnostic - Adapts │
│ - CI-friendly - Reports status - Context- │
│ aware │
└─────────────────────────────────────────────────────────┘Deterministic mode: Script only. Fast, repeatable, perfect for CI/CD where every run has to match.
Agentic mode: Script first, then an agent reads the results. It scans log files, parses errors, and tells you in plain language what went right or wrong.
Interactive mode: Script first, then the agent pulls you into a short Q&A. "Fresh database or keep the old one? Full install or minimal? Want me to check prerequisites first?"
The script is always the source of truth. Hooks and prompts call the same script every time. What changes is whether an agent supervises, and whether it asks you questions up front.
Just is a tiny command runner, and it pairs nicely with setup hooks. Treat it as a launchpad for your engineering work. Instead of memorizing flags, you type just and see every available command:
just # See all commands
just cldi # Deterministic setup
just cldii # Agentic setup (with reporting)
just cldit # Interactive setup (asks questions)The justfile itself stays simple:
# Deterministic codebase setup
cldi:
claude --init
# Agentic codebase setup
cldii:
claude --init "/install"
# Interactive setup (asks questions)
cldit:
claude --init "/install true"
# Deterministic maintenance
cldm:
claude --maintenance
# Agentic maintenance (with reporting)
cldmm:
claude --maintenance "/maintenance"Teammates and agents never have to memorize flags twice. They run just cldii and things work.
| Scenario | Mode | Command |
|---|---|---|
| CI/CD pipeline | Deterministic | claude --init-only |
| Quick local setup | Deterministic | just cldi |
| Setup failed, need diagnosis | Agentic | just cldii |
| New engineer, unfamiliar codebase | Interactive | just cldit |
| Weekly dependency updates | Agentic | just cldmm |
--init-only is the pipeline flag. It runs the hook, returns an exit code, and shuts down. No interactive session attached.
Onboarding is where this shines. A new engineer types just cldit and the agent walks them through it:
Agent: How should I handle the database?
┌─ Database Setup ─────────────────────────────────┐
│ ○ Fresh database (Recommended) │
│ ○ Keep existing │
│ ○ Skip database setup │
└──────────────────────────────────────────────────┘The agent asks about install mode, env variables, and whether to verify prerequisites first. It adapts to the answers and runs only the steps that match.
Scripts cannot do this. They play the same tape every time. Agents can stop mid-run, ask a clarifying question, and branch on the answer.
Setup hooks are one of 12 lifecycle events in the hook system. Configuration lives in .claude/settings.json:
{
"hooks": {
"Setup": [
{
"matcher": "init",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/setup_init.py",
"timeout": 120
}
]
},
{
"matcher": "maintenance",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/setup_maintenance.py",
"timeout": 60
}
]
}
]
}
}The hook script runs your commands and logs the whole thing:
def main():
# Install backend dependencies
run(["uv", "sync"], cwd="apps/backend")
# Install frontend dependencies
run(["npm", "install"], cwd="apps/frontend")
# Initialize database
run(["uv", "run", "python", "init_db.py"], cwd="apps/backend")
# Tell Claude what happened
print(json.dumps({
"hookSpecificOutput": {
"hookEventName": "Setup",
"additionalContext": "Setup complete. Run 'just be' and 'just fe' to start."
}
}))The /install slash command picks up the log and writes up the results:
---
description: Run setup and report installation results
---
## Workflow
1. Run /prime to understand the codebase
2. Read the log file at .claude/hooks/setup.init.log
3. Analyze for successes and failures
4. Write results to app_docs/install_results.md
5. Report to userWhen something breaks, the agent already has the context to diagnose it. List the usual failure modes inside the prompt, and the agent will walk the fix playbook on its own.
Think about onboarding time against the pace you want your team to grow. Could one prompt handle setup and installation for a new hire? Could it make each step clear by asking before it acts?
Yes, on both counts. Agents are good enough for this. The missing piece is standardization.
Determinism preserved: The hook fires the same script each time. Zero LLM variance during execution. The agent only looks at results after the deterministic work finishes.
CI compatible: GitHub Actions runs claude --init-only and gets back a clean exit code.
Interactive when it matters: New hires get guided through setup. Everyone else runs the fast version.
A living document that executes: Your install process now lives in natural language, tucked into prompts that agents follow. Updates happen by editing the prompt.
Start simple. Write a .claude/hooks/setup_init.py script that installs your dependencies, wire it up in .claude/settings.json, then add an /install command that reads the log and reports back. Wrap the whole thing in a justfile so your team runs just install and stops thinking about it.
Need something lighter? If you only want to load different context per session type, a slash command is usually enough. No install script required.
Setup hooks pay off most when you want one command that installs the world, diagnoses the failures, and walks new engineers through each step. Scripts supply the certainty. Agents supply the judgment. If your team hops across Windows, Linux, and macOS, read the cross-platform hook patterns so the same setup runs on every OS.
Stop configuring. Start building.