Skip to main content

Hooks & Lifecycle Events

3.5 Hooks & Lifecycle Events​

The SDK provides a hook system that allows external code to observe and react to simulation lifecycle events without modifying model code. Hooks are the mechanism through which output recording, guardrail enforcement, checkpointing, and telemetry are wired into the simulation --- they are not ad-hoc callbacks but a structured extensibility layer.

HookEvent​

Eleven lifecycle events are defined:

EventFired WhenTypical Use
BEFORE_SETUPBefore setup(config) is calledValidate config, initialise external resources
AFTER_SETUPAfter setup(config) completesLog initial state, start timers
BEFORE_STEPBefore each step() callInject external data, pre-step guardrail checks
AFTER_STEPAfter each step() completesRecord output, checkpointing, post-step guardrails
BEFORE_ACTIONBefore each Action executesFine-grained tracing, action-level timing
AFTER_ACTIONAfter each Action completesAction-level metrics, message counting
ON_MESSAGE_SENDWhen an agent calls send() or broadcast()Message logging, rate limiting
ON_MESSAGE_RECEIVEWhen messages are delivered to an inboxMessage inspection, anomaly detection
ON_AGENT_CREATEWhen a new agent is createdAgent registration, initial state logging
ON_AGENT_STOPWhen agent.stop() is calledAgent removal tracking, cascade detection
ON_ERRORWhen an unhandled exception occursError logging, graceful degradation

Hooks are registered on the model's HookRegistry:

from simudyne.engine.hooks import HookEvent

def my_after_step_hook(context):
print(f"Step {context.tick} complete, {context.model.agent_count()} agents")

model.hooks.on(HookEvent.AFTER_STEP, my_after_step_hook)

The HookContext object passed to every callback provides access to the current event, the model, the current agent (for agent-level events), the current action (for action-level events), the tick number, a data dictionary for arbitrary metadata, and the exception object (for ON_ERROR).

The SimulationRecorder (Section 4) attaches itself via AFTER_STEP to capture multi-level output. The CheckpointManager uses AFTER_STEP for auto-checkpointing. The GuardrailRegistry uses AFTER_STEP to enforce runtime invariants. OpenTelemetry uses BEFORE_STEP/AFTER_STEP for span timing. This hook-based architecture means that all cross-cutting concerns are pluggable and composable without modifying model code.