Skip to main content

Lifecycle Hooks

The HookRegistry lets you attach handlers to team lifecycle events. Hooks are priority-ordered and can block or modify operations.

Hook Events​

EventWhen
PRE_TEAM_STARTBefore a team starts
POST_TEAM_STARTAfter a team starts
PRE_TEAM_STOPBefore a team stops
POST_TEAM_STOPAfter a team stops
PRE_MEMBER_STARTBefore a member starts
POST_MEMBER_STARTAfter a member starts
PRE_MEMBER_STOPBefore a member stops
POST_MEMBER_STOPAfter a member stops
PRE_TASK_ASSIGNBefore a task is assigned
POST_TASK_ASSIGNAfter a task is assigned
PRE_TASK_EXECUTEBefore a task runs
POST_TASK_EXECUTEAfter a task runs
ON_TASK_COMPLETEWhen a task completes successfully
ON_TASK_FAILEDWhen a task fails
ON_MEMBER_ERRORWhen a member encounters an error

Basic Usage​

from agent_teams.hooks import HookRegistry, HookEvent, HookResult

registry = HookRegistry()

# Register a hook with a decorator
@registry.on(HookEvent.PRE_TASK_ASSIGN)
async def validate_task(event, **kwargs):
"""Block tasks that are missing a description."""
task = kwargs.get("task")
if task and not task.get("description"):
return HookResult(allow=False, reason="Task must have a description")
return HookResult(allow=True)

Priority Ordering​

Hooks with lower priority numbers run first:

from agent_teams.hooks import Hook

registry.register(Hook(
event=HookEvent.POST_TEAM_START,
name="log-start",
handler=log_handler,
priority=100, # Runs after...
))

registry.register(Hook(
event=HookEvent.POST_TEAM_START,
name="init-monitoring",
handler=init_handler,
priority=10, # ...this one
))

Blocking Hooks​

PRE_* hooks can block the operation by returning HookResult(allow=False):

@registry.on(HookEvent.PRE_TEAM_START)
async def capacity_check(event, **kwargs):
"""Prevent starting if too many teams are running."""
active_count = get_active_team_count()
if active_count >= 10:
return HookResult(
allow=False,
reason=f"Max team capacity reached ({active_count}/10)",
)
return HookResult(allow=True)

When a hook blocks, subsequent hooks in the chain are not executed.

Modifying Arguments​

Hooks can pass modified arguments to downstream hooks:

@registry.on(HookEvent.PRE_TASK_ASSIGN, priority=1)
async def add_metadata(event, **kwargs):
return HookResult(
allow=True,
modified_args={"priority": "high", "tags": ["urgent"]},
)

Modified args from multiple hooks are merged (later hooks can override earlier ones).

Running Hooks​

# Run all hooks for an event
result = await registry.run(HookEvent.PRE_TASK_ASSIGN, task=my_task)

if not result.allow:
print(f"Blocked: {result.reason}")
else:
# Proceed with the operation
pass

Disabling Hooks​

Individual hooks can be disabled without unregistering them:

# Find and disable
for hook in registry.get_hooks(HookEvent.PRE_TEAM_START):
if hook.name == "capacity_check":
hook.enabled = False

Error Handling​

If a hook raises an exception, it is caught and logged — subsequent hooks still execute:

@registry.on(HookEvent.POST_TASK_EXECUTE)
async def flaky_hook(event, **kwargs):
raise RuntimeError("Something went wrong")
# This won't block other POST_TASK_EXECUTE hooks

Integration with TeamManager​

The TeamManager creates a HookRegistry automatically:

from agent_teams.manager import TeamManager

manager = TeamManager()

# Access the hook registry
@manager.hooks.on(HookEvent.PRE_TASK_ASSIGN)
async def audit_task(event, **kwargs):
log.info(f"Task being assigned: {kwargs}")
return HookResult(allow=True)