Middleware & Policy Gates

Deterministic hooks around agent loops: phase enforcement, policy gates, error handling, cost tracking, and circuit breakers.

Overview

Middleware is the safety layer between the LLM and the real world. While the LLM proposes actions, middleware deterministically enforces rules, catches errors, and enforces budgets. Open SWE's middleware system is one of its most important architectural decisions — and one we are extending significantly for xCoder.

Hook Types

Agent middleware operates at multiple interception points:

HookWhen It RunsUse Cases
before_modelBefore each LLM callInject messages, check budgets, enforce step limits
wrap_model_callAround LLM invocationFallback models, retry logic, response sanitization
wrap_tool_callAround tool executionError handling, sandbox recovery, input sanitization
before_tool_callBefore tool executionPhase gates, policy enforcement, allow/deny decisions
after_tool_callAfter tool executionActivity logging, cost tracking, result observation
after_agentAfter agent loop completesNotifications, cleanup, circuit breaker checks

Open SWE Middleware

Open SWE ships with a curated set of middleware:

  • ToolErrorMiddleware — Catches exceptions and converts them to error ToolMessages so the LLM can self-correct.
  • ModelFallbackMiddleware — Retries with a fallback model on transient errors (5xx, 429, timeouts).
  • SandboxCircuitBreakerMiddleware — Stops runs after repeated sandbox failures to prevent infinite loops.
  • SanitizeToolInputsMiddleware — Cleans tool inputs to prevent injection attacks.
  • check_message_queue_before_model — Injects follow-up messages (Slack/Linear) before the next model call.
  • notify_step_limit_reached — Posts to Slack when the agent hits its step limit.

xCoder Extensions

xCoder adds several middleware stacks that Open SWE does not have:

  • PhaseGate — Blocks tool calls that are not allowed in the current FlowEngine phase. E.g., you cannot call git commit during the spec phase.
  • PolicyGate — Enforces team policies: branch naming conventions, required tests, commit message formats, PR templates.
  • ActivityLogger — Durable logging of every tool call, model response, and phase transition to PostgreSQL.
  • CostTracker — Per-session cost tracking and budget enforcement with real-time alerts.
  • ApprovalGate — Requires human approval for high-impact operations (production deploys, schema changes, auth modifications).
  • SecurityScanner — Scans tool inputs and outputs for secrets, SQL injection, and other security issues.

Implementation Patterns

Middleware can be implemented in multiple languages depending on performance requirements:

LanguageBest ForExample
TypeScriptBusiness logic, orchestration, async I/OPhaseGate, ActivityLogger
Rust (WASM)Hot-path policy enforcement, deterministic checksPolicyGate, SecurityScanner
Rust (native)High-throughput tool execution, sandbox controlCostTracker (stream processing)

Middleware Ordering

Order matters. xCoder uses this default stack (outermost first):

  1. SecurityScanner (catches malicious input first)
  2. ApprovalGate (human approval for dangerous ops)
  3. PhaseGate (enforce flow discipline)
  4. PolicyGate (team policy enforcement)
  5. CostTracker (budget enforcement)
  6. ModelFallbackMiddleware (model resilience)
  7. ToolErrorMiddleware (error normalization)
  8. ActivityLogger (audit trail)
  9. SandboxCircuitBreaker (stop dead sandboxes)

Design principle

Middleware should be composable and order-independent where possible. Each middleware is a pure function of (state, request) → (result, modified_state). This makes testing deterministic and enables middleware reuse across different agent configurations.