DESIGN GUIDE

L0 to L4: designing autonomy levels a product can actually enforce

An autonomy ladder is worthless if it lives in a system prompt. The mechanic that makes it real is a permission check that returns a downgrade.

Authority 11 min read Key figure · 5 levels, enforced server-side All posts

Almost every agent platform has an autonomy ladder in a slide deck. Very few have one in the code path. The difference is whether the level is something the agent is told, or something the product checks.

This is a design guide for the second kind. It is the model we run our carrier on, including the parts we got wrong first.

The ladder

Five levels, defined by what happens when the agent asks — not by what the agent is capable of.

LevelMeaningExample capabilityHuman involvement
L0 Read only. The agent can observe but cannot change anything. Look up a policy, read a claim file None needed
L1 Draft. Produces something a person must accept before it exists. Draft a quote, prepare a document pack Accepts or discards
L2 Act within a bound. Writes for real, below a threshold. Post a reserve under $250k, settle under $50k None below the bound
L3 Act with notification. Writes, and a human is told after the fact. Issue an endorsement, publish a cession Reviews afterwards
L4 Act with delegation. Can grant a narrower authority to another actor. Assign a claim to an adjuster with a limit Sets the policy, not the instance

Two things about this list are deliberate.

First, the levels are attached to (actor, capability) pairs, not to actors. The same adjuster is L2 for settlements, L3 for correspondence and L0 for underwriting. An actor with a single global level is not expressive enough to describe any real job.

Second, there is no L5 for "unrestricted". Every capability has a ceiling, even if the ceiling is high. An unbounded level is a decision to stop thinking about the ceiling, and the ceiling is where the incidents happen.

The mechanic that makes it real

A level in a system prompt is a preference. A level in a permission check is a control. The difference in code is small and the difference in behaviour is total.

flowchart TD
    A["Agent requests capability
settle_claim, $58,000"] --> C["policy.check_tool(actor, capability, args)"] C --> D{"Level held
vs level required"} D -->|held >= required| ALLOW["allow
proceed"] D -->|held < required,
route exists| DOWN["downgrade_to = escalate
agent gets a legal next move"] D -->|held < required,
no route| REFUSE["refuse with reason
a result, not an exception"] ALLOW --> W["Write + business event"] DOWN --> ESC["Approval raised to L3"] ESC --> H["Human decides"] H --> W REFUSE --> REC["Recorded, run continues"] ALLOW -.-> REC2["Authority record written
in every branch"] DOWN -.-> REC2 REFUSE -.-> REC2 style C fill:#efecfe,stroke:#4b34e0 style D fill:#efecfe,stroke:#4b34e0 style DOWN fill:#fbede3,stroke:#b4531b style REFUSE fill:#fbede3,stroke:#b4531b style REC2 fill:#e2f5f9,stroke:#0e97b0
Three outcomes, one of them not a failure. The key branch is the middle one: a downgrade gives the agent a legitimate route forward, which is what stops it retrying or reaching for a worse tool. Every branch writes an authority record.
# The signature that matters. Note it returns a decision -- it does not raise. def check_tool(actor, capability, args) -> Decision: required = authority_required_for(capability, args) # amount-aware held = authority_of(actor, capability) if held >= required: return Decision(allowed=True) route = escalation_route(actor, capability, required) return Decision( allowed=False, reason="exceeds_actor_authority", authority_held=held, authority_required=required, downgrade_to="escalate" if route else None, escalated_to=route, )

Three mistakes we made

1. Raising instead of returning

Our first implementation raised PermissionError. It enforced correctly, so the control worked — but the refusal went into a generic error handler, got logged as a stack trace, counted in the error rate, and was thrown away at log rotation. We had a working control with no evidence that it had ever fired.

Refusal is a normal business outcome. Model it as a returned value and it becomes a record. Model it as an exception and it becomes noise.

2. Making the level actor-wide

We started with one level per actor. It survived about a week of real work before we needed an adjuster who could correspond freely but settle narrowly. Retrofitting per-capability levels touched every call site. Start with the pair.

3. Checking authority in the harness

This one is subtle and important. It is tempting to have the agent harness check permissions before dispatching the tool — it is one place, it is tidy, it keeps the products simple.

It is also wrong, because it means the control only exists on the agent path. The moment anything else calls the same API — a script, a migration, an integration, a human's UI — the check is not there. We moved enforcement into the products, where it applies to every caller, and left the harness to interpret the decision.

If your authority check lives in the agent framework, you have not secured a capability. You have secured one path to it.

Amount-aware requirements

A capability's required level often depends on its arguments. Settling a claim is not one capability with one level; it is a capability whose required level is a function of amount.

# Thresholds are configuration, versioned, with an effective date -- # never constants in code, because they change and you need to know # which threshold applied when. settle_claim: - up_to: 50_000 requires: L2 - up_to: 250_000 requires: L3 - above: 250_000 requires: L4

Versioning the thresholds matters more than it looks. When an auditor asks why a $58,000 settlement needed approval in March but not in September, "the limit changed in June" is only an answer if you can show the two schedules and their effective dates.

Choosing levels for a new capability

The question we ask is not "how confident are we in the agent". It is "what does it cost to be wrong, and how quickly would we notice".

  • Cheap to reverse, noticed immediately → L2 or L3. A draft that is wrong gets rejected; a notification that is wrong gets corrected.
  • Expensive to reverse, noticed immediately → L2 with a tight bound. The bound is what limits the damage while you learn the real distribution.
  • Cheap to reverse, noticed late → L3 with a real review queue. Something nobody reads is not a review.
  • Expensive to reverse, noticed late → L1. This is the money-moving, legally-binding, hard-to-unwind category, and a person should be in it. Payments live here.

Notice that model quality does not appear. A better model does not change the cost of being wrong or the time to detection; it changes the frequency. Frequency is worth optimising, but it is not what should set a limit.

What this looks like in InsightLense

A ladder that lives in configuration needs a view that shows what it is actually doing. InsightLense renders the authority matrix per actor and capability, alongside the two metrics that tell you whether the levels are set correctly.

Authority matrix role = adjuster 1 capability never fired
CapabilityLevelInvocationsEscalatedApprovedReading
read_claimL01,9400read only, as designed
post_reserveL27754193%healthy
settle_claimL21711100%approves everything — limit too low?
close_claimL36120zero gates in 90 days — check it is wired
Both highlighted rows are questions, not failures. A capability approving 100% of escalations is spending supervisor attention on nothing. A capability with zero gates in ninety days is either genuinely trivial or not connected — and those look identical from a dashboard.

That last row is how InsightLense surfaces the computed-but-never-enforced defect as a matter of routine rather than as an investigation. A control that has never produced a record is flagged, every time, because the product knows the capability exists and can count how often it fired.

Watching the ladder in production

Two metrics tell you whether your levels are set correctly, and both come out of the authority records.

Escalation rate per capability. Too high on routine work means your bounds are too tight and you are spending supervisor attention on nothing. Zero means either the capability is genuinely trivial or — far more often — the check is not wired up.

Approval rate at escalation. If supervisors approve 99% of escalations without comment, the escalation is theatre and the limit is in the wrong place. If they reject 40%, the agent is systematically reaching too far and that is a prompt or a data problem worth fixing at source.

Both of these are only available if refusals are records. Which brings the design back to where it started: the ladder is worth building because of what it lets you write down, not because of what it prevents.

Where do your agents already act on real records?

Tell us that, and what you would need to prove about those actions to an auditor. We will set up a hands-on walkthrough within two weeks.

Request a demo →