Dashboard/Phase 4: Integrations
📖 Concept7 min10 XP

Lesson 27: Hooks: Deterministic Automation

Day 27 of 50 · ~7 min read · Phase 4: Integrations


The Opening Question

You've spent the last few lessons learning how Claude Code can think through problems, make decisions, and act on your codebase. It's powerful stuff.

But here's a harder question: what if you don't want Claude to think?

Not because Claude is unreliable — but because some tasks shouldn't depend on judgment at all. They should just happen, every single time, the same way, no exceptions.

Think about linting. Every time you modify a file, you probably want it linted. But should Claude decide whether to lint? Should it reason about when linting is necessary? Or should it just... always lint, automatically, without asking?

That's the difference between automation and intelligence. Sometimes you want automation.


Discovery

Question 1: What if a task is 100% deterministic?

Let me ask you: when you finish editing a file, do you want Claude to choose whether to run your linter? Or do you want the linter to always run?

Pause and think. What's the problem with leaving it to Claude's judgment?

Here's the issue: if Claude decides whether to lint, you've introduced variability. Maybe today it lints, maybe tomorrow it forgets. Maybe it thinks "this file is already formatted well" and skips it. Now you have inconsistency.

But some things should never vary. Linting. Formatting. Running pre-commit hooks. Logging. Security checks. These aren't judgment calls — they're rules.

Question 2: So what's a hook?

In Claude Code, a hook is a deterministic script that runs automatically at specific points in your workflow — always, without Claude needing to decide.

Think of hooks like event listeners in JavaScript. They're tied to specific moments:

  • PreToolUse: Before Claude uses a tool (edit, bash, etc.)
  • PostToolUse: After Claude uses a tool
  • SessionStart: When you start a Claude Code session
  • SessionEnd: When you end a session

What should happen at each of these moments? It's up to you to define.

What's the advantage of having these run automatically, instead of Claude choosing?

Question 3: How do hooks differ from skills?

You learned about skills in earlier lessons — custom slash commands that Claude Code can invoke. If you want to run a linter, couldn't you just ask Claude to invoke a /lint skill?

You could. But there's a crucial difference:

Skills are AI-driven. Claude must decide to invoke them. "Should I run the linter now? Let me think..." — and sometimes it might forget, or decide it's not necessary.

Hooks are deterministic. They run automatically, 100% of the time, based on a trigger event. No decision. No variability. Pure automation.

One is reactive (Claude chooses). One is automatic (you choose, once, and it's locked in forever).

Question 4: What should hooks actually do?

Here are real examples:

  • Post-edit hook: After Claude edits a file, automatically run the formatter
  • Pre-commit hook: Before Claude creates a commit, run tests
  • Session-start hook: When you start a session, log the timestamp and session ID
  • Post-command hook: After any tool runs, validate that it succeeded

What do these have in common? They're not creative. They're not decisions. They're just "execute this script, no thinking required."


The Insight

Hooks are the part of Claude Code that should never think. They're deterministic automation — scripts that run at specific moments in your workflow, always the same way, no judgment. They're how you enforce consistency and safety without burdening Claude with decision-making.

The mental model: Hooks are like laws in a system. You don't re-decide the laws every day — they just apply, automatically. "Whenever Claude edits a file, the file must be linted afterward." Done. No negotiation.


Try It

Let's configure your first hook. You'll create a simple one that logs every session start.

  1. Create the hook directory:

    mkdir -p ~/.claude/hooks
    
  2. Create a hook script (~/.claude/hooks/session-start.sh):

    #!/bin/bash
    echo "Session started at $(date)" >> ~/.claude/session-log.txt
    echo "Working directory: $(pwd)" >> ~/.claude/session-log.txt
    
  3. Make it executable:

    chmod +x ~/.claude/hooks/session-start.sh
    
  4. Start a new Claude Code session and check the log:

    tail ~/.claude/session-log.txt
    

You should see your timestamp. That's a hook working. No decision, no slack — just execution.

  1. Create a more useful hook. Add a post-edit hook that automatically formats Python files:

    Create ~/.claude/hooks/post-edit.sh:

    #!/bin/bash
    # Auto-format Python files after editing
    if [[ "$EDITED_FILE" == *.py ]]; then
      black "$EDITED_FILE" 2>/dev/null || true
    fi
    
  2. Test it. Have Claude edit a Python file. Your hook should automatically format it.


Key Concepts Introduced

ConceptDefinition
HookA deterministic script that runs automatically at specific workflow moments (pre/post-tool, session start/end)
Deterministic automationTasks that should run 100% consistently, without AI judgment, based on fixed rules
PreToolUse / PostToolUseHooks that trigger before and after Claude uses any tool (edit, bash, etc.)
SessionStart / SessionEndHooks that trigger when a Claude Code session begins or ends
Hook chainingMultiple hooks that work together to enforce a complete workflow

Bridge to Lesson 28

Now you've seen how to enforce consistency without asking Claude to think. But hooks are just one kind of safety net.

Tomorrow's question: How do you actually know the code Claude writes is correct?

We'll tackle testing — the most powerful way to validate Claude's work before it ever reaches your users. And you'll see how to make testing automatic, too.


← Back to Curriculum · Lesson 28 →