horus-runtime
Plugin SystemMiddleware

Middleware Domains

Middleware Domains

Each middleware root receives a different context object. Those context models define what a middleware can inspect or mutate.

Task Middleware

@dataclass
class TaskMiddlewareContext:
    task: BaseTask

Entered by BaseTask.run().

The task's per-invocation working directory is created at the innermost point of this chain, immediately before _run(). Every middleware's before hook has therefore already run by the time the directory exists.

That ordering is what makes retargeting possible. A middleware may repoint context.task.target in before — an orchestrator re-anchoring a task the engine added mid-run, for instance, such as a horus_map clone or an inlined subworkflow body — and the directory is then created under the new target. If it were created before the chain were entered, the retarget would land too late: the directory would exist at the old path and the executor would launch with a cwd that was never created.

No built-in middleware relies on the directory existing during before. If yours does, create it yourself rather than assuming.

Workflow Middleware

@dataclass
class WorkflowMiddlewareContext:
    workflow: BaseWorkflow

Entered by BaseWorkflow.run().

Runtime Middleware

@dataclass
class RuntimeMiddlewareContext:
    runtime: BaseRuntime
    task: BaseTask

Entered by BaseRuntime.setup_runtime().

Executor Middleware

@dataclass
class ExecutorMiddlewareContext:
    executor: BaseExecutor
    task: BaseTask

Entered by BaseExecutor.execute().

Target Middleware

@dataclass
class TargetMiddlewareContext:
    target: BaseTarget
    task: BaseTask

Entered by BaseTarget.dispatch().

Transfer Middleware

@dataclass
class TransferMiddlewareContext:
    transfer_strategy: BaseTransferStrategy[Any, Any]
    artifact: BaseArtifact
    source: BaseTarget
    destination: BaseTarget

Entered by BaseTransferStrategy.transfer().

Interaction Middleware

@dataclass
class InteractionMiddlewareContext:
    transport: BaseInteractionTransport
    interaction: BaseInteraction
    renderer: BaseInteractionRenderer[Any, Any]
    attempt: int

Entered by BaseInteractionTransport.ask() once per render attempt.

This context is intentionally mutable. Middleware can replace the transport, interaction, or renderer before the render call happens.

Built-in Middleware

Horus currently ships two built-in middleware implementations:

  • TaskTimeMiddleware
  • WorkflowTimeMiddleware

Both record elapsed wall-clock time and emit timing information on the event bus after execution completes.

On this page