Skip to content
Navigation

Security validation rails with priority ordering and cross-rail state sharing. Rails are lifecycle guards that intercept agent execution at hook points and return actions to control flow.

RailAction

python
class RailAction(enum.StrEnum):
    CONTINUE = "continue"  # Proceed to next rail or guarded operation
    SKIP = "skip"          # Skip the guarded operation entirely
    RETRY = "retry"        # Retry the guarded operation
    ABORT = "abort"        # Abort the agent run immediately

Rail (ABC)

Abstract base class for agent rails. Rails are run in ascending priority order (lower numbers run first).

python
from exo.rail import Rail, RailAction

class BlockDangerousTool(Rail):
    async def handle(self, ctx):
        if ctx.inputs.tool_name == "rm_rf":
            return RailAction.ABORT
        return RailAction.CONTINUE

rail = BlockDangerousTool(name="block_dangerous", priority=10)

Constructor

ParameterTypeDefaultDescription
namestrrequiredUnique identifier for this rail
priorityint50Execution order (lower = earlier)

Methods

MethodReturnsDescription
handle(ctx)RailAction | NoneInspect and act on a lifecycle event. Return None to continue.

RailContext

The ctx parameter passed to handle() contains:

AttributeTypeDescription
agentAgentThe agent being guarded
eventHookPointThe lifecycle hook point
inputsInvokeInputs | ModelCallInputs | ToolCallInputsTyped inputs for the event
extradict[str, Any]Shared state across rails in the same invocation

RailManager

Manages rails with priority ordering and cross-rail state sharing.

python
from exo.rail import RailManager, RailAction
from exo.hooks import HookPoint

manager = RailManager()
manager.add(my_safety_rail)
action = await manager.run(HookPoint.PRE_LLM_CALL, agent=agent, messages=msgs)

Methods

MethodReturnsDescription
add(rail)NoneAdd a rail to the manager
remove(rail)NoneRemove a rail (raises ValueError if not found)
clear()NoneRemove all rails
run(event, **data)RailActionRun all rails in priority order, return first non-CONTINUE action
hook_for(event)HookCreate a hook callable for use with HookManager

Integration with Agent

Pass rails directly to the Agent constructor:

python
from exo import Agent
from exo.rail import Rail, RailAction

class ContentFilter(Rail):
    async def handle(self, ctx):
        # Check content before LLM call
        return RailAction.CONTINUE

agent = Agent(
    name="safe_agent",
    rails=[ContentFilter(name="content_filter", priority=10)],
)

RetryRequest

Parameters for a RETRY action. Attach to the rail’s return context when returning RailAction.RETRY.

FieldTypeDefaultDescription
delayfloat0.0Seconds to wait before retrying
max_retriesint1Maximum retry attempts
reasonstr""Human-readable explanation

RailAbortError

Raised when a rail returns RailAction.ABORT. Inherits from ExoError.

AttributeTypeDescription
rail_namestrName of the rail that triggered the abort
reasonstrHuman-readable reason