Pre-hooks and Post-hooks
Execute custom logic before and after agent runs with hooks.
You can use hooks on agents and teams to do work before or after the main execution of the run.
Use cases for hooks include:
- Security guardrails (e.g. PII detection, prompt injection defense)
- Input validation
- Output validation
- Data preprocessing (e.g. normalizing input data)
- Data postprocessing (e.g. adding additional context to the output)
- Logging (e.g. logging the duration of the run)
- Debugging (e.g. debugging the run)
When Hooks Are Triggered
Hooks execute at specific points in the Agent/Team run lifecycle:
-
Pre-hooks: Execute after Agno loads the session and state and resolves dependencies, before it builds the main model context. They can update input, state, or resolved dependencies. Any model or external calls made by a dependency have already happened.
-
Post-hooks: Execute after the main model output is complete. For nonstreaming runs, this is before the run result is returned. Streaming content chunks have already been emitted; post-hooks cannot retract or rewrite those chunks.
Validation failures
Blocking checks raise InputCheckError or OutputCheckError. Agent and Team runs catch these and return a result with status=RunStatus.error; ordinary hook exceptions are logged and execution continues. If a validator must succeed, translate its operational or parsing failures into a check error. See the input validator example.
Inspect the returned status before displaying content. A failed output check can leave the rejected answer in response.content. Streaming consumers receive RunError or TeamRunError events, but may already have received content; buffer it or use nonstreaming execution for validation before display.
Pre-hooks
Pre-hooks inspect or transform the supplied run input before the main model context is built. History, retrieved content, and dependencies need their own checks when they are part of your validation policy.
Use them for input validation, security checks, or any data preprocessing on the input your Agent receives.
Common Use Cases
Security Guardrails
- Detect and prevent PII (Personally Identifiable Information) from reaching the LLM.
- Defend against prompt injection and jailbreak attempts.
- Filter NSFW or inappropriate content.
- See the Guardrails documentation for more details.
Input Validation
- Validate format, length, content or any other property of the input.
- Remove or mask sensitive information.
- Normalize input data.
Data Preprocessing
- Transform input format or structure.
- Enrich input with additional context.
- Apply any other business logic before sending the input to the LLM.
Basic Example
Install agno and openai in a virtual environment and set OPENAI_API_KEY before running an Agent.
A simple pre-hook that validates the input length and raises an error if it's too long:
from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.exceptions import CheckTrigger, InputCheckError
from agno.run.agent import RunInput
# Simple function we will use as a pre-hook
def validate_input_length(
run_input: RunInput,
) -> None:
"""Pre-hook to validate input length."""
max_length = 1000
if len(run_input.input_content) > max_length:
raise InputCheckError(
f"Input too long. Max {max_length} characters allowed",
check_trigger=CheckTrigger.INPUT_NOT_ALLOWED,
)
agent = Agent(
name="My Agent",
model=OpenAIResponses(id="gpt-5.2"),
# Provide the pre-hook to the Agent using the pre_hooks parameter
pre_hooks=[validate_input_length],
)You can see complete examples of pre-hooks in the Examples section.
Pre-hook Parameters
Pre-hooks run automatically during the Agent run and receive the following parameters:
run_input: The input to the Agent run that can be validated or modifiedagent: Reference to the Agent instancesession: The current agent sessionrun_context: The current run context. See the Run Context reference.user_id: The user ID for the run (optional)metadata: The metadata of the current run (optional)debug_mode: Whether debug mode is enabled (optional)
The framework automatically injects only the parameters your hook function accepts, so you can define hooks with just the parameters you need.
See the Pre-hooks reference for the full parameter list.
Post-hooks
Post-hooks validate, transform, or enrich the completed run output. Use a nonstreaming run and check its status before display when validation must finish before the user sees content.
Use them for output filtering, compliance checks, response enrichment, or any other output transformation you need.
Common Use Cases
Output Validation
- Validate response format, length, and content quality.
- Remove sensitive or inappropriate information from responses.
- Ensure compliance with business rules and regulations.
Output Transformation
- Add metadata or additional context to responses.
- Transform output format for different clients or use cases.
- Enrich responses with additional data or formatting.
Basic Example
A simple post-hook that validates the output length and raises an error if it's too long:
from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.exceptions import CheckTrigger, OutputCheckError
from agno.run.agent import RunOutput
# Simple function we will use as a post-hook
def validate_output_length(
run_output: RunOutput,
) -> None:
"""Post-hook to validate output length."""
max_length = 1000
if len(run_output.content) > max_length:
raise OutputCheckError(
f"Output too long. Max {max_length} characters allowed",
check_trigger=CheckTrigger.OUTPUT_NOT_ALLOWED,
)
agent = Agent(
name="My Agent",
model=OpenAIResponses(id="gpt-5.2"),
# Provide the post-hook to the Agent using the post_hooks parameter
post_hooks=[validate_output_length],
)You can see complete examples of post-hooks in the Examples section.
Post-hook Parameters
Post-hooks run automatically during the Agent run and receive the following parameters:
run_output: The output from the Agent run that can be validated or modifiedagent: Reference to the Agent instancesession: The current agent sessionrun_context: The current run context. See the Run Context reference.user_id: The user ID for the run (optional)metadata: The metadata of the current run (optional)debug_mode: Whether debug mode is enabled (optional)
The framework automatically injects only the parameters your hook function accepts, so you can define hooks with just the parameters you need.
See the Post-hooks reference for the full parameter list.
Guardrails
A popular use case for hooks are Guardrails: built-in safeguards for your Agents.
See Guardrails for details.
The @hook Decorator
The @hook decorator allows you to configure individual hook behavior. Currently, it supports marking hooks to run in the background when used with AgentOS.
Background Execution
By default, hooks are either executed synchronously or asynchronously, in an API context they still block the response until they complete. For hooks that perform non-critical tasks (logging, analytics, notifications), you can mark them to run in the background:
from agno.hooks import hook
@hook(run_in_background=True)
async def record_completion(run_output):
"""Record completion after the response when AgentOS schedules this hook."""
print(f"Run finished: {run_output.run_id}")Background scheduling requires AgentOS. Direct runs execute these hooks in the foreground. An async hook requires arun() or aprint_response() and is awaited; a synchronous run() rejects it.
When to Use Background Hooks
Background hooks are ideal for:
- Logging and analytics: Record metrics without affecting response time
- Notifications: Send emails, Slack messages, or webhooks
- Async data storage: Write to external databases or APIs
- Non-critical post-processing: Tasks that don't affect the response
Background hooks should not mutate runtime state. Agno attempts to deep-copy run_input, run_output, and run_context; other objects, including the Agent, Team, and session, can remain shared, and a failed copy falls back to the original reference.
Keep validation in foreground hooks. AgentOS's global background-hook mode keeps BaseGuardrail checks inline, but ordinary validation functions are scheduled like other hooks. Use background hooks for logging or other work that does not decide whether a response is allowed.
For complete documentation on background task execution, see the Background Tasks guide.
For the full decorator API, see the @hook Decorator Reference.