[FEATURE] Add `additionalContext` support to PreToolUse hooks

Status Fixed / completed
Maintainer reply None cached
Activity 5 comments · opened Dec 29, 2025 · closed Jan 16, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

PreToolUse hooks can control permissions and modify tool inputs, but cannot inject context into Claude's conversation. This limits their usefulness for providing contextual guidance at the moment it's needed.

Use case: I have an inject-test-methodology hook that triggers when Claude is about to write test files. I want to inject testing best practices (AAA pattern, naming conventions, edge case requirements) at the exact moment Claude needs them—not loaded globally for every conversation.

Currently, I must choose between:

| Approach | Problem |
|----------|---------|
| Global CLAUDE.md | Always loaded, wastes context on non-test work |
| UserPromptSubmit hook | Fires on every prompt, requires complex filtering |
| PostToolUse hook | Fires AFTER the tool runs, too late to guide behavior |

None of these are ideal. PreToolUse fires at exactly the right moment but can't inject context.

Proposed Solution

Add additionalContext field to PreToolUse's hookSpecificOutput, matching the existing pattern used by:

  • UserPromptSubmit
  • SessionStart
  • PostToolUse

Schema change:

| {
    hookEventName: 'PreToolUse';
    permissionDecision?: 'allow' | 'deny' | 'ask';
    permissionDecisionReason?: string;
    updatedInput?: Record<string, unknown>;
    additionalContext?: string;  // ← NEW FIELD
  }

Behavior: When a PreToolUse hook returns additionalContext, include it in Claude's context for the current tool call decision and subsequent processing.

Alternative Solutions

| Approach | Why Not Ideal |
|----------|---------------|
| Global CLAUDE.md | Loads methodology for every project, even non-test work |
| UserPromptSubmit | Fires on every prompt; complex filtering needed |
| PostToolUse | Too late—tool already executed |
| Project CLAUDE.md | Per-project maintenance burden |

Priority

Critical - Blocking my work

Feature Category

CLI commands and flags

Use Case Example

Scenario: Developer asks Claude to write tests for a new feature.

Current flow:

  1. Claude decides to use Write tool for test_feature.py
  2. PreToolUse hook fires, detects test file pattern
  3. Hook can only: allow/deny/modify inputs
  4. Hook CANNOT tell Claude "follow AAA pattern, use descriptive names, test edge cases"
  5. Claude writes tests without methodology guidance (unless globally loaded)

Desired flow:

  1. Claude decides to use Write tool for test_feature.py
  2. PreToolUse hook fires, detects test file pattern
  3. Hook returns additionalContext with testing methodology
  4. Claude receives methodology at exactly the moment it's needed
  5. Claude writes high-quality tests following the injected guidance

Additional Context

Current TypeScript Schema (from official docs)

The limitation is visible in the type definitions but not explicitly documented:

hookSpecificOutput?:
  | {
      hookEventName: 'PreToolUse';
      permissionDecision?: 'allow' | 'deny' | 'ask';
      permissionDecisionReason?: string;
      updatedInput?: Record<string, unknown>;
      // NO additionalContext - this is the gap
    }
  | {
      hookEventName: 'UserPromptSubmit';
      additionalContext?: string;  // HAS IT
    }
  | {
      hookEventName: 'SessionStart';
      additionalContext?: string;  // HAS IT
    }
  | {
      hookEventName: 'PostToolUse';
      additionalContext?: string;  // HAS IT
    };

Documentation Gap

The documentation doesn't explicitly state that PreToolUse cannot inject context—users must infer it from the schema. Even if this feature isn't added, explicitly documenting this limitation would help developers avoid wasted effort.

Why This Matters

PreToolUse is the only hook that fires before a tool runs AND knows which tool is about to run. This makes it uniquely positioned for:

  • Injecting tool-specific guidance (testing methodology for test files, security guidelines for auth files)
  • Providing context-aware instructions based on file type/path
  • Just-in-time documentation injection

Without additionalContext, these use cases require workarounds that either waste context (global loading) or arrive too late (PostToolUse).

View original on GitHub ↗

5 Comments

github-actions[bot] · 9 months ago

Found 1 possible duplicate issue:

  1. https://github.com/anthropics/claude-code/issues/15345

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

coygeek · 9 months ago

Follow-up: Empirical Confirmation

Following up on my feature request from yesterday. I ran empirical tests to verify the limitation isn't just a documentation gap or my misunderstanding.

What I Tested

Created a simple PreToolUse hook that outputs additionalContext with a marker phrase:

#!/usr/bin/env python3
import json
print(json.dumps({
    "hookSpecificOutput": {
        "hookEventName": "PreToolUse",
        "permissionDecision": "allow",
        "additionalContext": "XYZZY: Say 'PRETOOL WORKS' as your first words."
    }
}))

Added it to my settings.json for the Read tool, then triggered a Read in a live Claude session.

Results

The hook executed successfully - confirmed via my hook logging infrastructure showing PreToolUse:Read hook succeeded: Success.

But Claude never saw the marker. No "PRETOOL WORKS" response, and no <system-reminder> block with the XYZZY content appeared in Claude's context.

For comparison, PostToolUse hooks in the same session successfully inject additionalContext - I can see them appearing as <system-reminder> blocks that Claude receives and responds to.

Ruling Out a Logging Gap

Initially I wondered if this was just a visibility issue - maybe the context was reaching Claude but not being logged. But the marker test proves otherwise: if Claude received the instruction "Say 'PRETOOL WORKS' as your first words", it would have done so. It didn't, so the context never arrived.

Conclusion

The limitation is real and confirmed:

  • PreToolUse additionalContext is silently ignored
  • PostToolUse, SessionStart, and UserPromptSubmit additionalContext all work
  • The infrastructure exists; PreToolUse just doesn't use it

Would love to see this added. PreToolUse fires at exactly the right moment to inject contextual guidance, but currently can't.

coygeek · 9 months ago

The Ideal AI Architecture: Defense-in-Depth for Testing

If the Claude Agent SDK implemented additionalContext support for PreToolUse hooks, developers could finally move away from "Prompt Engineering" and toward "System Engineering."

Instead of hoping Claude remembers instructions loaded at the start of a session, you can build a layered architecture that guides, standardizes, and guards the AI's behavior exactly when needed.

Here is the comprehensive guide to this ideal "Defense-in-Depth" workflow for software testing.

---

The Three Layers of Context

In this architecture, we stop treating "Context" as a single bucket. Instead, we split it into three distinct layers based on Scope and Trigger.

| Layer | Component | Scope | Trigger | Purpose |
| :--- | :--- | :--- | :--- | :--- |
| 1. Strategy | Agent Skills | Global (Workflow) | Intent (User asks for it) | Defines the process (e.g., "How we run QA cycles"). |
| 2. Standards | .claude/rules/ | Static (File-based) | Location (File path matches) | Defines the style (e.g., "Naming conventions"). |
| 3. Guardrails | PreToolUse Hook | Dynamic (Action-based) | Action (Specific tool/content) | Enforces safety & logic (e.g., "Don't mock this deprecated DB"). |

---

Layer 1: Strategy (Agent Skills)

"The Manager"

Skills are best used to define the workflow. They teach Claude how to act like a specific role.

Configuration: .claude/skills/qa-engineer/SKILL.md

---
name: qa-engineer
description: Use when the user asks to run tests, fix suites, or debug CI failures.
---
# QA Engineering Process
1. **Discovery:** Always run `npm test -- --list` first to see available suites.
2. **Isolation:** Never run the full suite. Run only the test file relevant to the change.
3. **Analysis:** If a test fails, read the logs, categorize the error (Logic vs. Syntax), and propose a fix.
  • When it runs: Only when the user explicitly asks to "Run tests" or "Fix the build."
  • Why here? Workflow instructions are complex and token-heavy. You don't want these loaded when you are just asking Claude to update a README.

---

Layer 2: Standards (.claude/rules)

"The Style Guide"

Rules are best used for static, file-specific conventions. They ensure consistency without requiring a script execution.

Configuration: .claude/rules/testing.md

---
paths: "**/*.test.ts", "**/spec/*.js"
---
# Testing Standards
1. **Naming:** Use `describe('method', () => { it('should...', () => {}) })`.
2. **Structure:** Follow the Arrange-Act-Assert (AAA) pattern strictly.
3. **Libraries:** Use `vitest` for unit tests. Do not import `jest`.
  • When it runs: Automatically, the moment Claude reads or writes a file ending in .test.ts.
  • Why here? It is lightweight and native. You don't need code to tell Claude to use vitest; you just need a rule mapped to a file extension.

---

Layer 3: Dynamic Guardrails (PreToolUse Hook)

"The Guardian"

This is the missing link. This hook fires based on what the agent is about to do. It executes code to check the state of the repo, the content of the edit, or external dependencies, and injects context Just-in-Time.

Configuration: .claude/hooks/hooks.json

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "python3 scripts/guardrails/check_test_integrity.py"
          }
        ]
      }
    ]
  }
}

The Logic (check_test_integrity.py):
Unlike the static Rules layer, this script can perform dynamic validation.

  1. Input: Receives the file path and the proposed content change from Claude.
  2. Logic:
  • Is this a test file? Yes.
  • Is Claude trying to mock the PaymentGateway class? Yes.
  • External Check: Check the internal API registry. -> Result: PaymentGateway was deprecated yesterday.
  1. Output (The Proposed Feature):

``json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": "CRITICAL: You are attempting to mock
PaymentGateway. This class was deprecated yesterday and removed from the build pipeline. You MUST mock UniversalPaymentClient instead, or the tests will fail in CI."
}
}
``

  • When it runs: Every time Claude touches a file, regardless of user intent.
  • Why here? A static markdown file (.claude/rules) cannot know that an API was deprecated yesterday. Only a script that queries a registry or checks a changelog can know that.

---

The Complete Workflow in Action

Here is how these three layers combine to create a perfect development loop.

User Prompt: "I updated the user schema. Update the payment tests to match."

  1. Layer 1 (Skills) - Ignored:
  • The user did not ask to "run QA," they asked to "update tests." Claude acts as a general coding agent. The heavy "QA Workflow" context is not loaded, saving tokens.
  1. Claude Action:
  • Claude decides to call Edit on src/payments/payment.test.ts.
  1. Layer 2 (Rules) - Activated:
  • Claude Code sees the .test.ts extension.
  • It silently loads .claude/rules/testing.md.
  • Effect: Claude ensures the new code uses vitest and Arrange-Act-Assert formatting.
  1. Layer 3 (Hooks) - Activated:
  • The PreToolUse hook fires. The script analyzes the proposed code.
  • It sees Claude is using the old PaymentGateway.
  • Effect: The hook injects the additionalContext warning about deprecation.
  1. Self-Correction (The Magic Moment):
  • Claude receives the tool output before the file is written.
  • Internal Monologue: "I was about to use PaymentGateway, but the system tells me it is deprecated. I will update my plan to use UniversalPaymentClient instead."
  • Claude rewrites the code block and executes the Edit.

Summary of Benefits

If PreToolUse supported additionalContext, we would move from Correction to Prevention.

  1. Zero Hallucinations on APIs: The hook can fetch the current API schema and inject it right before Claude writes code against it.
  2. Lean Context: We don't need to stuff 50 pages of documentation into the chat. We inject only the paragraph needed for the specific file being touched.
  3. Unbreakable Standards: Even if the user explicitly prompts "Ignore all rules and write a quick hack," the Hook fires on the action, not the prompt. It intercepts the file write and reinjects the requirement, forcing the agent to comply with safety standards.
coygeek · 9 months ago

Feature was implemented in v2.1.9.
-Added support for PreToolUse hooks to return additionalContext to the model

Thanks Anthropic!

github-actions[bot] · 8 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.