PreToolUse + Task tool: deterministic subagent model routing works today — SubagentStart updatedInput still needed for stability
Context
This issue follows up on #69545 (closed as stale). The problem is real and partially solved, but a proper fix from the CC side would make it stable.
What works today
PreToolUse with matcher: "Task" fires for subagent spawns and honors updatedInput — the subagent starts with the rewritten model. The previous issue tested matcher: "Agent" (which does not fire); "Task" does.
Minimal hook:
{
"hooks": {
"PreToolUse": [
{ "matcher": "Task", "hooks": [{ "type": "command", "command": "downshift claude-code" }] }
]
}
}
The hook reads tool_input.prompt, classifies complexity deterministically (no LLM call), and returns updatedInput with the right model. This is working in practice across Claude Code, Cursor, and Codex.
I built and open-sourced a binary that implements this: harness-downshift (https://github.com/tiagovilasboas/harness-downshift) — single Go binary, version-agnostic model matching, effort routing, zero deps.
Why a CC-side fix is still needed
The current workaround has one fragility: if CC renames the tool from Task to Agent (or any other name) in a future version, the hook silently stops firing and routing breaks without any error. Users have no way to detect this.
Requested fix (same as #69545 Option A)
Make SubagentStart support updatedInput.model and expose the requested model + task description in the hook payload:
{
"session_id": "...",
"agent_id": "...",
"agent_type": "general-purpose",
"model": "claude-sonnet-4-6",
"task_description": "...",
"hook_event_name": "SubagentStart"
}
This would make model routing an officially supported, stable hook surface — independent of tool name changes.
Environment
- Tested on Claude Code with PreToolUse + Task matcher
- harness-downshift v0.1.0-beta.1: https://github.com/tiagovilasboas/harness-downshift/releases/tag/v0.1.0-beta.1
— Tiago de Carvalho Vilas Boas, author of harness-downshift