Middleware¶
Middleware wraps dispatch around the normalized payload and the selected transport.
Why It Exists¶
Middleware is the right place for behavior that should run before route logic, such as:
- auto-allow policy checks
- custom policy enforcement
- telemetry or structured audit capture
- response short-circuiting
Middleware Order¶
Agent Hooks runs middleware in this order:
- provider middleware
- app middleware registered with
@app.middleware() - the final route dispatch or default processor
That ordering lets provider behavior stay close to protocol details while leaving room for app-level customization.
Example¶
from __future__ import annotations
from agent_hooks import AgentHook, HookResponse
from agent_hooks.models import HookProcessingResult
app = AgentHook(fallback_to_default_processor=False)
@app.middleware()
def block_specific_bash(context, call_next):
if context.payload.tool_name == "Bash" and context.payload.tool_input.command == "rm -rf /":
return HookProcessingResult(display=None, transport_result=None, response=HookResponse())
return call_next(context)
@app.permission()
def permission_handler():
return HookResponse()
Codex Built-in Middleware¶
The current codebase includes provider middleware for Codex execpolicy.
For Codex PreToolUse events:
- only
Bashtool requests are checked - the command string is tokenized with
shlex.split codex execpolicy checkis run against the configured rules file- top-level
allowshort-circuits dispatch and returns an empty response
Short-Circuiting¶
Middleware can return a HookProcessingResult immediately instead of calling call_next.
That is how the built-in Codex policy shortcut avoids opening a dialog for already-allowed commands.
Limitation¶
Middleware receives normalized payloads. If you need the full provider raw structure, use context.payload.raw.