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: BaseTaskEntered 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: BaseWorkflowEntered by BaseWorkflow.run().
Runtime Middleware
@dataclass
class RuntimeMiddlewareContext:
runtime: BaseRuntime
task: BaseTaskEntered by BaseRuntime.setup_runtime().
Executor Middleware
@dataclass
class ExecutorMiddlewareContext:
executor: BaseExecutor
task: BaseTaskEntered by BaseExecutor.execute().
Target Middleware
@dataclass
class TargetMiddlewareContext:
target: BaseTarget
task: BaseTaskEntered by BaseTarget.dispatch().
Transfer Middleware
@dataclass
class TransferMiddlewareContext:
transfer_strategy: BaseTransferStrategy[Any, Any]
artifact: BaseArtifact
source: BaseTarget
destination: BaseTargetEntered by BaseTransferStrategy.transfer().
Interaction Middleware
@dataclass
class InteractionMiddlewareContext:
transport: BaseInteractionTransport
interaction: BaseInteraction
renderer: BaseInteractionRenderer[Any, Any]
attempt: intEntered 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:
TaskTimeMiddlewareWorkflowTimeMiddleware
Both record elapsed wall-clock time and emit timing information on the event bus after execution completes.