Skip to content

[Feature] Add PreToolUse hook event to enable command rewriting before execution #188

@luc-olivera

Description

@luc-olivera

Add PreToolUse hook event to enable command rewriting before execution

Feature description

Add a PreToolUse hook event that fires before a tool executes, with the ability to modify the tool input — not just audit or block. This would complement the existing Stop and PostToolUse hooks, completing the tool execution lifecycle:

Model returns tool_use → [PreToolUse hook] → Execute tool → [PostToolUse hook] → Return result

Today only PostToolUse (after execution) and Stop (before response) exist. The missing PreToolUse step would allow intercepting and rewriting tool inputs before they run — a pattern already proven by Claude Code, Cursor, Copilot, and 10+ other AI coding tools.

Use case

Primary: Token optimization with RTK (55k+ GitHub stars)

RTK is a CLI proxy that reduces LLM token consumption by 60-90% on common dev commands. It rewrites commands like git statusrtk git status via a PreToolUse hook, compressing the output before it reaches the context window. Typical savings in a 30-minute session:

Operation Standard tokens With RTK Savings
git status (10x) 3,000 600 -80%
cat / read (20x) 40,000 12,000 -70%
cargo test / npm test (5x) 25,000 2,500 -90%
Total (~94 commands) ~118,000 ~23,900 -80%

RTK already integrates with 13 AI coding tools through their PreToolUse hooks, but cannot work with Azure SRE Agent because no PreToolUse event exists.

Secondary use cases:

  • Input validation — validate/sanitize tool inputs before execution (stronger than post-hoc blocking via PostToolUse)
  • Input enrichment — inject additional parameters or context before a tool runs
  • Conditional routing — redirect tool calls to alternative implementations

Current workaround

There is no workaround. The PostToolUse hook fires after the tool has already executed, so it cannot rewrite inputs or reduce token consumption from verbose command outputs. The only option today is to manually prefix commands with rtk in agent instructions, which is fragile and doesn't cover all tool calls.

Proposed approach

Mirror the existing PostToolUse configuration, adding a modifiedInput field to the response format:

hooks:
  PreToolUse:
    - type: command
      matcher: "Bash|RunInTerminal"
      timeout: 10
      failMode: allow
      script: |
        #!/bin/bash
        CONTEXT=$(cat)
        COMMAND=$(echo "$CONTEXT" | jq -r '.tool_input.command // empty')
        
        # Rewrite command through RTK
        if command -v rtk &>/dev/null; then
          REWRITTEN=$(rtk rewrite "$COMMAND" 2>/dev/null)
          if [ $? -eq 0 ] && [ -n "$REWRITTEN" ]; then
            echo "{\"decision\": \"allow\", \"modifiedInput\": {\"command\": \"$REWRITTEN\"}}"
            exit 0
          fi
        fi
        echo "{\"decision\": \"allow\"}"

Response format extension:

{"decision": "allow"}                                                    // No changes
{"decision": "allow", "modifiedInput": {"command": "rtk git status"}}    // Rewrite input
{"decision": "block", "reason": "Command not allowed by policy"}         // Block before execution

Context schema — same as PostToolUse but without tool_result/tool_succeeded (tool hasn't run yet):

{
  "hook_event_name": "PreToolUse",
  "agent_name": "my_agent",
  "tool_name": "RunInTerminal",
  "tool_input": {"command": "git status"},
  "current_turn": 5,
  "execution_summary": "/path/to/transcript.txt"
}

References:

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions