hooks
Extensible hook system for entity lifecycle events
HookDispatcher is a platform primitive that enables components to extend behavior without tight coupling. Hooks run at defined points (before_create, after_update, etc.) and can: Veto to reject operations, Patch to modify entity fields, or request SideEffects like notifications. Hooks execute in priority order with deterministic merging of patches.
0
Ports
5
Schemas
6
Hooks
4
Events
01
Ports
Adapters Provided
- HookDispatcher
02
Schemas
Uses
No external schemas used
03
Hooks
- before_create_task
- after_create_task
- before_update_task
- after_update_task
- before_complete_task
- after_complete_task
04
Events
- HookRegistered v1
- HookUnregistered v1
- HookDispatched v1
- HookVetoed v1
05
Stories
06
Examples
from psp.platform.hooks import HookDispatcher, HookPoint, HookContext, Patch
dispatcher = HookDispatcher()
def auto_tag_emails(ctx: HookContext) -> Patch | None:
"""Add 'email' tag if title contains 'email'."""
title = ctx.entity_data.get("title", "").lower()
if "email" in title:
return Patch(add_items={"tags": ["email", "communication"]})
return None
dispatcher.register(
HookPoint.BEFORE_CREATE_TASK,
auto_tag_emails,
priority=50,
name="auto_tag_emails",
)
Add auto-tagging before task creation.
from psp.platform.hooks import HookContext, Veto
def block_empty_titles(ctx: HookContext) -> Veto | None:
"""Reject tasks with empty titles."""
title = ctx.entity_data.get("title", "").strip()
if not title:
return Veto(reason="Task title cannot be empty")
return None
dispatcher.register(HookPoint.BEFORE_CREATE_TASK, block_empty_titles)
Reject task creation based on business rules.
from psp.platform.hooks import HookContext, SideEffectRequest
def notify_on_complete(ctx: HookContext) -> SideEffectRequest:
"""Send notification when task is completed."""
return SideEffectRequest(
kind="send_notification",
payload={
"channel": "email",
"recipient": ctx.entity_data.get("owner_id"),
"message": f"Task '{ctx.entity_data.get('title')}' completed!",
},
)
dispatcher.register(HookPoint.AFTER_COMPLETE_TASK, notify_on_complete)
Schedule notifications after task completion.
async def execute(self, input: CreateTaskInput) -> CreateTaskOutput:
# Build hook context
ctx = HookContext(
hook_point=HookPoint.BEFORE_CREATE_TASK,
entity_type="Task",
entity_id=None,
entity_data={"title": input.title, "tags": input.tags},
)
# Dispatch and check for veto
result = self._dispatcher.dispatch(ctx)
if result.vetoed:
raise ValidationError(result.veto_reason)
# Apply patches from hooks
tags = input.tags + result.merged_patch.add_items.get("tags", [])
# Create task with modified data
task = Task(title=input.title, tags=tags)
await self._repo.add(task)
# Execute side effects
for side_effect in result.side_effects:
await self._executor.run(side_effect)
Execute hooks and handle results.
API Reference
This component mounts routes under /v1/hooks.
View OpenAPI specification