Middleware

Middleware

Middleware wrap your agent's work. They can inspect a tool call before it runs, change what the model sees after it returns, gate a call for approval, skip it entirely, or answer a model call without asking the provider at all. Each one is a small, independent piece of behaviour you turn on per agent, in agent.toml.

Every middleware on this page is off until you turn it on, and enabling one is a single line. A short always-on set rides underneath them; see what runs by default.

Choosing a middleware

I want to...Use
Stop paying for the same question twiceLLM response cache
Cut spend on short, easy requestsModel router
Try a new model on part of my trafficModel router
Stop re-running the same lookup in one conversationTool result cache
Be asked about dangerous calls without being asked about every callRisk-based approval
Stop a confused agent making sweeping changesBlast radius limiter
Fit more of a long session in the model's contextTool output summarizer
See what an agent would do before letting itDry run
Find which tool is slow or failingTool telemetry

Every middleware

MiddlewareSlotWhat it does
Tool telemetryobservePer-tool counts, errors, and latency
Tool output summarizercontextCondenses big tool output for the model
Risk-based approvalpolicyApproval only when arguments look dangerous
Blast radius limiterpolicyCaps writes per run
Dry runpolicySuppresses writes so a run previews only
Model routerresilienceCheaper model or less thinking for small requests; canary a new model
LLM response cacheresilienceServes a repeated model call from a stored turn
Tool result cacheresilienceReuses a repeated read's result

A name AXL does not know, or settings that do not type-check, fails the boot rather than being quietly ignored - including keys under a section you left disabled, so a typo is caught immediately rather than waiting until you switch it on. So does a section that sets keys without an enabled = true to switch on a middleware that ships off, since none of them would apply. Past that, each middleware rejects the settings that would leave it running on every call and never acting: a cache bound of 0, a router with nothing to route to, an empty dry-run notice. What no check can reach is a middleware you enabled and gave nothing to do - risk-based approval with two empty lists boots and gates nothing.

How the stack works

Every agent has a stack, ordered into bands called slots. Outermost first:

SlotWhat belongs there
observeWatches, never changes anything
securityScrubs or blocks content before anything inside sees it
contextShapes what the model sees
policyDecides whether a call may proceed
resilienceAbsorbs tool and provider failures, closest to the call

A request travels outermost to innermost; a result travels back innermost to outermost. The framework fixes the order for two cases: autonomy leads the policy band, so a tool it forbids is refused before anything else can answer for the call, and the model router runs before the LLM cache, so a cached answer is keyed on the model that actually produced it.

What runs by default

tracing, loop_guard, and autonomy are on for every agent, plus audit when you enable it. autonomy and audit cannot be turned off.

diagnostics follows the deployment rather than the agent: with AXL_DIAGNOSTICS_ENABLED=true it joins every agent's stack. It is the only thing that produces the runs, LLM calls, and tool calls the diagnostics boards read, so under a per-agent opt-in, turning collection on would answer every board with an empty list until each agent had been edited. An agent that should not be recorded opts out with [middleware.diagnostics] enabled = false.

Everything in the table above ships off.

Seeing your stack

axl weave print --config axl-config/agents/<your-agent>/agent.toml

This prints the resolved onion for that agent, outermost first, without starting the server. It runs the checks the boot runs, so a name it rejects, a typo it rejects, or a setting that would do nothing all fail here first. It reads AXL_DIAGNOSTICS_ENABLED from your environment, so diagnostics shows up exactly when a server started here would put it on the stack. Two checks need the running platform and so happen only at startup: whether your provider actually serves a model the model router routes to, and any middleware your host registered in Rust - the CLI has no way to see one of those, so it reports a config naming it as unknown.

Next

On this page