# Autonomy ladder

Give each agent an autonomy level (shadow, draft, exceptions, autonomous). It is promoted by a person on measured evidence, demoted automatically when the evidence turns bad, and its unapproved work is randomly sampled for independent review.

Autonomy is earned. The ladder gives each agent one of four levels. Each level only ever tightens what the agent's MCP server postures already allow. A `deny` or `require_approval` posture, or a posture rule, still holds at every level.

| Level | What happens to the agent's writes |
| --- | --- |
| `shadow` | Never sent. Each write is recorded as a shadow action for a person to review, and the agent is told it was not sent. |
| `draft` | Every write waits for a person, even on a server whose posture lets agents write. |
| `exceptions` | Routine writes run. A write whose risk score reaches `autonomy_exception_risk` (default 35) waits for a person. A share of the writes that ran is sampled for audit (`autonomy_sample_rate`, default 10%). |
| `autonomous` | The server postures alone decide. A smaller share is still sampled (`autonomy_sample_rate_autonomous`, default 5%). |

Reads are never affected.

An **action type** (`server/tool`) can have a level of its own, which wins over the agent's for that action: an agent can be autonomous on ticket comments and still drafting on refunds. Send `action_type` with `PUT /api/governance/autonomy/{agent}`, and evaluate one with `GET /api/governance/autonomy/{agent}?action_type=jira/add_comment`.

## Existing agents keep running unchanged

The ladder is opt-in. An agent with no ladder record behaves exactly as it did before. Nothing new holds Liya in Teams, the copilot, scheduled runs or any other live agent.

To bring a live agent under measurement without changing what it does, **adopt** it: `POST /api/governance/autonomy/{agent}/adopt`, or `POST /api/governance/autonomy:adopt-all` for every agent you may update. An adopted agent is seeded at `autonomous`, which is what it already does. Adopt-all first receipts the approval history decided before the ledger existed, and each agent's history so far is kept as the evidence it was seeded on. Adoption never demotes and never adds a human step; from then on its unapproved writes are sampled.

## Promotion is a person's decision

`GET /api/governance/autonomy/{agent}` returns the agent's record since it reached its current level and the recommendation it supports. The record is read only from the [trust ledger](/docs/govern/trust-ledger), so every outcome it counts is a receipt an auditor can verify. It counts:

- receipted approvals of its held writes: approved as asked and run (good), approved after an edit (neutral, but it lowers the good rate), run but failed or not found by the read-back (bad), rejected (bad);
- receipted independent verdicts on its sampled and shadow work: `ok` (good), `wrong` (bad), `unsafe` (bad, and it demotes at once).

A receipt that no longer verifies against its chain hash is not counted, and the record reports how many were `tampered`.

| From | Needed to suggest the next level |
| --- | --- |
| `shadow` | 20 outcomes, at least 90% good, none unsafe |
| `draft` | 30 outcomes, at least 90% good, none unsafe |
| `exceptions` | 50 outcomes, at least 97% good, none unsafe |

A periodic pass records a suggestion and audits `agent.autonomy.promotion_suggested`. It never promotes. A person raises the level with `PUT /api/governance/autonomy/{agent}` (`agents.update` and Cedar `update`), one step at a time. Raising without the evidence, or by more than one step, is refused (409). To do it anyway, send `override: true` with a `reason`, which is audited.

## Demotion is automatic

One `unsafe` verdict, or a bad-outcome rate above 15% over at least 10 outcomes, steps the agent down one level at once and audits `agent.autonomy.demoted`. This applies only to agents someone put on the ladder or adopted. Set `TICKETIQ_AUTONOMY_AUTO_DEMOTE=false` to turn the step-down into a recommendation only.

## Independent review of sampled work

`GET /api/governance/samples?status=pending` lists the audit queue. `POST /api/governance/samples/{id}/verdict` with `ok`, `wrong` or `unsafe` records a verdict (`agents.approve` and Cedar `approve` on the agent). With `autonomy_independent_review` on (the default), one of the agent's own owners may not review its samples (403, audited as `agent.autonomy.sample.refused`). Samples are drawn with a cryptographic random source, so which work is audited cannot be predicted.

## Audit events

`agent.autonomy.set`, `agent.autonomy.set.refused`, `agent.autonomy.seeded`, `agent.autonomy.cleared`, `agent.autonomy.shadowed`, `agent.autonomy.sampled`, `agent.autonomy.sample.reviewed`, `agent.autonomy.sample.refused`, `agent.autonomy.sample.dropped`, `agent.autonomy.promotion_suggested`, `agent.autonomy.demoted`.

## Settings

| Setting | Default | Meaning |
| --- | --- | --- |
| `TICKETIQ_AUTONOMY_EXCEPTION_RISK` | `35` | Risk score at or above which an `exceptions` write waits for a person |
| `TICKETIQ_AUTONOMY_SAMPLE_RATE` | `0.10` | Share of `exceptions` writes sampled |
| `TICKETIQ_AUTONOMY_SAMPLE_RATE_AUTONOMOUS` | `0.05` | Share of `autonomous` writes sampled |
| `TICKETIQ_AUTONOMY_AUTO_DEMOTE` | `true` | Step an agent down at once on bad evidence |
| `TICKETIQ_AUTONOMY_INDEPENDENT_REVIEW` | `true` | Refuse a sample verdict from one of the agent's owners |
