PreToolUse hooks need a way to detect subagent vs main session context

Resolved 💬 3 comments Opened Feb 18, 2026 by acushner-rippling Closed Feb 21, 2026

Problem

There's no way within a PreToolUse hook to determine whether the tool call is happening in the main conversation or inside a subagent (spawned via the Task tool).

I want to block certain expensive MCP tools (datadog, snowflake, atlassian, etc.) from being called directly in the main conversation — they should only be callable from subagents to avoid context bloat. A PreToolUse hook is the natural enforcement mechanism, but the hook input is identical in both contexts:

  • session_id — same in main and subagent
  • transcript_path — same in main and subagent (no /subagents/ path segment)
  • Process tree (PPID) — same parent process
  • Environment variables — identical, no CLAUDE_SUBAGENT or similar

I verified all of this with debug logging in the hook script.

Proposed Solutions (either would work)

Option A: Add field to hook input

Add an is_subagent boolean or agent_depth integer to the PreToolUse (and PostToolUse) hook input JSON:

{
  "session_id": "abc123",
  "hook_event_name": "PreToolUse",
  "is_subagent": true,
  "tool_name": "mcp__datadog__search_logs",
  ...
}

Option B: Hook configuration option

Add a context field to hook definitions in settings.json:

{
  "matcher": "mcp__datadog__.*",
  "context": "main-only",
  "hooks": [{ "type": "command", "command": "./block-direct-mcp.sh" }]
}

Values could be "main-only", "subagent-only", or "all" (default).

Use Case

Expensive/slow MCP servers (datadog, snowflake, atlassian, slack, etc.) should always be delegated to subagents. CLAUDE.md instructions asking for this are unreliable — the model frequently ignores them and calls MCPs directly, bloating the main conversation context. A hard enforcement mechanism via hooks is needed.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗