Skip to main content
MindStudio
Pricing
Blog About
My Workspace

How to Use Session Start Hooks to Force Context Into Every Claude Code Session

Session start hooks deterministically push context into your conversation window every time—unlike claude.md files, which Claude can choose to ignore.

MindStudio Team RSS
How to Use Session Start Hooks to Force Context Into Every Claude Code Session

Why Your CLAUDE.md File Isn’t Actually Doing What You Think

If you’ve been using Claude Code for any serious project work, you’ve probably set up a CLAUDE.md file. You added your coding conventions, your team’s architecture decisions, your testing requirements. And then you watched Claude ignore half of them mid-session.

This isn’t a bug. It’s how large language models work. Claude reads CLAUDE.md as part of its context, but attention isn’t uniform — the model weighs different parts of the input differently, and that weighting shifts as the conversation grows. Session start hooks solve this problem by deterministically pushing context into the conversation window before any reasoning happens, rather than hoping the model pays attention to a file it read at startup.

This guide covers exactly how to configure session start hooks in Claude Code, why they work better than CLAUDE.md for mandatory context, and practical patterns you can use today.


The Reliability Problem with CLAUDE.md

CLAUDE.md is a useful tool. Claude does read it, and for loosely held preferences — “prefer named functions over arrow functions” or “we use Tailwind, not vanilla CSS” — it works fine.

The problem shows up with non-negotiable requirements.

Other agents start typing. Remy starts asking.

YOU SAID "Build me a sales CRM."
01 DESIGN Should it feel like Linear, or Salesforce?
02 UX How do reps move deals — drag, or dropdown?
03 ARCH Single team, or multi-org with permissions?

Scoping, trade-offs, edge cases — the real work. Before a line of code.

When you write “always run tests before committing” or “never modify files outside the /src directory” in a CLAUDE.md file, those instructions go into Claude’s context as text. But as the session grows longer and the conversation fills with code, output, and back-and-forth messages, earlier context gets deprioritized. Claude isn’t ignoring you on purpose — it’s just that long contexts with lots of recent, salient content tend to overshadow instructions that were read at the beginning.

There are a few specific failure modes worth knowing:

  • Recency bias — Recent messages and tool outputs carry more weight than earlier instructions.
  • Instruction drift — Multi-step tasks cause Claude to focus on the immediate subtask, not the meta-rules.
  • File content vs. message content — Content injected as a message (which hooks can do) is processed differently than content read from a file.

The result is a Claude Code session that starts well and gradually stops following your requirements as the session deepens.


What Session Start Hooks Actually Do

Claude Code’s hooks system lets you run shell commands at specific lifecycle events. When those commands write to stdout, that output gets captured and injected into the conversation as content Claude must process — not as a file it optionally reads, but as actual input to the model.

A session start hook fires once, at the beginning of a session, before Claude takes any action. What makes this different from CLAUDE.md:

  • It’s a message, not a file — The injected content appears in the conversation window as a discrete message, which means it’s treated with the same weight as user input.
  • It’s deterministic — The hook runs regardless of what CLAUDE.md says or whether Claude decides to “refer back” to project documentation.
  • It’s dynamic — The shell command can pull context from anywhere: Git status, environment variables, other files, API calls, or runtime state.

This distinction matters a lot. When Claude Code processes a hook’s output as injected content, it doesn’t have the option to deprioritize it the way it can deprioritize a file it read before the session started.


Setting Up Your First Session Start Hook

Prerequisites

You need Claude Code installed and working. If you haven’t set it up yet, Anthropic’s Claude Code documentation covers the installation process. You’ll also want basic familiarity with your shell and JSON.

Step 1: Locate or Create Your Settings File

Claude Code looks for hook configuration in two places:

  • Global settings: ~/.claude/settings.json — applies to all Claude Code sessions
  • Project settings: .claude/settings.json — applies only to sessions in that project directory

For context you want in every session regardless of project, use the global file. For project-specific requirements, use the project file. Both can coexist.

Create the file if it doesn’t exist:

mkdir -p ~/.claude
touch ~/.claude/settings.json

Step 2: Write the Hook Configuration

Open ~/.claude/settings.json and add a hook that fires at session start. Here’s the minimal working structure:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": ".*",
        "hooks": [
          {
            "type": "command",
            "command": "cat ~/.claude/session-context.md"
          }
        ]
      }
    ]
  }
}

This configuration runs cat ~/.claude/session-context.md before Claude uses any tool for the first time in a session. The output of that command gets injected into the conversation.

Step 3: Create Your Context File

Now create the file the hook reads:

touch ~/.claude/session-context.md

Write your mandatory context into it. Be specific and direct — this is not a style guide, it’s a set of hard requirements:

## Session Context

**Critical requirements for this session:**
- Never modify files outside the project root unless explicitly asked
- Run `npm test` before marking any task complete
- All new functions require JSDoc comments
- Check `package.json` before installing any new dependency

**Current environment:**
- Node.js project using TypeScript
- Tests are in `/tests`, source in `/src`
- Use conventional commits format

Hire a contractor. Not another power tool.

Cursor, Bolt, Lovable, v0 are tools. You still run the project.
With Remy, the project runs itself.

Step 4: Test the Configuration

Start a new Claude Code session and give it a task. Before Claude takes any action, it should process your hook output. You can verify this is working by asking Claude to describe its current session requirements — it should be able to articulate the constraints you set.


Practical Hook Configurations

Dynamic Git Context

Static files are fine for persistent rules, but one of the real advantages of hooks is pulling live context. This hook injects the current branch name, recent commit messages, and any uncommitted changes:

#!/bin/bash
echo "## Current Git Context"
echo "Branch: $(git branch --show-current)"
echo ""
echo "Recent commits:"
git log --oneline -5
echo ""
echo "Uncommitted changes:"
git status --short

Save this as ~/.claude/hooks/git-context.sh, make it executable (chmod +x), and reference it in your settings:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": ".*",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/git-context.sh"
          }
        ]
      }
    ]
  }
}

Now Claude starts every session knowing exactly where the codebase stands.

Environment-Aware Context

Different environments need different guardrails. This hook reads an environment variable to inject context conditionally:

#!/bin/bash
ENV=${CLAUDE_ENV:-development}

if [ "$ENV" = "production" ]; then
  echo "⚠️ PRODUCTION ENVIRONMENT"
  echo "Do NOT run migrations without explicit confirmation."
  echo "Do NOT modify environment variables."
  echo "All changes require a PR — do not push directly."
else
  echo "Environment: $ENV (development)"
  echo "Standard development rules apply."
fi

Project-Specific Rules from a Config File

For teams, storing context rules in the repo makes sense. This hook reads from a .claude-requirements file in the project root if it exists, falling back to a global default:

#!/bin/bash
PROJECT_RULES="./.claude-requirements"
GLOBAL_RULES="$HOME/.claude/global-requirements.md"

if [ -f "$PROJECT_RULES" ]; then
  echo "## Project Requirements"
  cat "$PROJECT_RULES"
elif [ -f "$GLOBAL_RULES" ]; then
  echo "## Global Requirements"
  cat "$GLOBAL_RULES"
fi

Advanced Patterns

Combining Multiple Hooks

You can run multiple hooks in sequence. They all execute before the matched tool use, and their outputs are injected in order:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": ".*",
        "hooks": [
          {
            "type": "command",
            "command": "cat ~/.claude/global-rules.md"
          },
          {
            "type": "command",
            "command": "~/.claude/hooks/git-context.sh"
          },
          {
            "type": "command",
            "command": "~/.claude/hooks/environment-check.sh"
          }
        ]
      }
    ]
  }
}

Keep the total output concise. Injecting thousands of tokens defeats the purpose — Claude will deprioritize long injected content just as it deprioritizes long files. Aim for 200–500 tokens of genuinely essential context.

Tool-Specific Context Injection

Hooks support regex matching on tool names. This means you can inject context only when Claude is about to use specific tools:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Before running bash commands: always check the working directory with pwd first.'"
          }
        ]
      },
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "cat ~/.claude/file-modification-rules.md"
          }
        ]
      }
    ]
  }
}

This is more targeted than a blanket session start — you’re injecting relevant context right when Claude needs it, not flooding the session with everything at once.

Using PostToolUse Hooks for Consistency Checks

Remy doesn't build the plumbing. It inherits it.

Other agents wire up auth, databases, models, and integrations from scratch every time you ask them to build something.

200+
AI MODELS
GPT · Claude · Gemini · Llama
1,000+
INTEGRATIONS
Slack · Stripe · Notion · HubSpot
MANAGED DB
AUTH
PAYMENTS
CRONS

Remy ships with all of it from MindStudio — so every cycle goes into the app you actually want.

Session start hooks handle initialization, but you can extend the pattern. PostToolUse hooks fire after tool execution and can verify Claude followed your rules, then reinject reminders:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'File written. Reminder: run tests before marking this task complete.'"
          }
        ]
      }
    ]
  }
}

Common Mistakes and How to Avoid Them

Overloading the Hook Output

The most common mistake is treating the hook like a comprehensive documentation dump. If your hook outputs 3,000 tokens of context, you’ve just recreated the CLAUDE.md problem in a different format.

Be ruthless about what goes in the hook. If a rule isn’t non-negotiable, it doesn’t belong in the session start injection. Put guidelines and preferences in CLAUDE.md. Put hard requirements in hooks.

Using Relative Paths in Commands

Hooks run from the project directory, but their execution environment can vary. Always use absolute paths for files referenced in hook commands:

# Bad
cat ./session-context.md

# Good
cat "$HOME/.claude/session-context.md"

Forgetting to Make Scripts Executable

If your hook command is a shell script, it needs execute permission. A hook that fails silently means your context never gets injected:

chmod +x ~/.claude/hooks/your-hook-script.sh

Not Testing After Configuration Changes

Always start a fresh Claude Code session after modifying settings.json. Changes don’t apply to sessions already in progress.


Extending This Pattern with Automated Workflows

Session start hooks are powerful for injecting static or semi-static context, but some use cases require dynamic context pulled from external systems. What if your session context should include open tickets from your project management tool? Or the current deployment status from a CI/CD pipeline? Or structured data from a database that defines how your domain objects work?

This is where MindStudio’s Agent Skills Plugin becomes useful. The @mindstudio-ai/agent npm SDK lets Claude Code call 120+ typed capabilities as simple method calls — things like agent.searchGoogle(), agent.runWorkflow(), or custom workflows you’ve built in MindStudio.

You can hook this into your session start script. Before Claude Code boots up, a shell script could call a MindStudio workflow that pulls your current sprint’s open issues, formats them as context, and pipes them into the session. Instead of static rules, you get live context from your actual tooling.

For teams using Claude Code across multiple engineers, this pattern makes session context consistent without requiring everyone to maintain their own local config files. One MindStudio workflow generates the context; every engineer’s session start hook calls it.

You can start building those kinds of workflows free at mindstudio.ai — no API keys or separate model accounts required.


Frequently Asked Questions

What’s the difference between CLAUDE.md and session start hooks?

CLAUDE.md is a markdown file that Claude reads as part of its initial context. It works well for loose conventions and background information, but because it’s file content rather than a message in the conversation, Claude can deprioritize it as sessions grow longer.

Session start hooks run shell commands at lifecycle events and inject their output as actual conversation content. This means the context is treated with the same weight as user input — it can’t be selectively ignored the way file content can.

Can session start hooks slow down Claude Code sessions?

Yes, if your hooks do expensive work. A hook that makes an API call, runs tests, or processes large files will add latency before Claude can start. Keep hook commands fast — under 1–2 seconds. For heavier context generation, consider running it as a background process and writing the output to a file your hook reads synchronously.

Where should I put my settings.json — global or project level?

Use the global file (~/.claude/settings.json) for rules that apply regardless of project: your general coding standards, safety rails you always want active, and anything about how you want Claude to behave fundamentally.

Use project-level settings (.claude/settings.json) for project-specific requirements: architecture decisions, framework-specific rules, team conventions specific to that codebase. Commit the project-level file to version control so the whole team benefits.

Do hooks run on every tool use or just the first one?

By default, a hook configured on PreToolUse with a ".*" matcher fires before every tool use in the session. If you only want the context injected once at the start, you’ll need to handle that in your hook script — for example, by writing a flag file when the hook runs and checking for it on subsequent invocations:

#!/bin/bash
FLAG="$HOME/.claude/.session-initialized"
if [ ! -f "$FLAG" ]; then
  cat "$HOME/.claude/session-context.md"
  touch "$FLAG"
fi

Clean up the flag file as part of your session teardown or shell configuration.

Can I use hooks to prevent Claude from taking certain actions?

Yes. If a hook exits with a non-zero status code or returns specific JSON, Claude Code can treat that as a blocking signal. This is useful for safety guardrails — for example, a hook that checks whether a file being written to is in a protected directory and blocks the operation if so.

Does this work with the Claude Code VS Code extension?

Hook configuration in settings.json applies to Claude Code regardless of how you’re invoking it, including through the VS Code extension. The extension respects both global and project-level settings files.


Key Takeaways

  • CLAUDE.md files are useful but not reliable for mandatory context — Claude can deprioritize their content as sessions grow.
  • Session start hooks inject content as actual conversation messages, making them deterministic rather than advisory.
  • Configure hooks in ~/.claude/settings.json (global) or .claude/settings.json (project-level).
  • Keep hook output concise — 200–500 tokens of genuine requirements, not documentation dumps.
  • Dynamic hooks that pull live context (Git state, environment, external tools) are more powerful than static files.
  • Use tool-specific matchers to inject relevant context at the moment Claude needs it, not just at session start.
  • For teams, centralizing context generation in an automated workflow keeps everyone’s sessions consistent without individual config maintenance.

If you’re already building with Claude Code, session start hooks are one of the higher-leverage configuration changes you can make. The improvement in consistency — especially on long sessions with complex requirements — is immediately noticeable.

Presented by MindStudio

No spam. Unsubscribe anytime.