← Work

Autonomy earned per action shape, then revoked live

ProjectGreenlight
RoleSole builder
DatesJuly 2026
Statuspublic repo
StackNext.js, TypeScript, Prisma, AI SDK v7, Claude
Codegithub.com/parth012001/greenlight

An employee asks for access in chat. An agent resolves it end to end. Every consequential action passes through a policy engine, an approval queue, and a hash-chained audit log. Flip a policy toggle and the agent's behaviour changes instantly, because policy lives in the action layer, not in the model. And trust is earned per action shape: after a track record of clean approvals the system proposes promoting that exact shape to auto-approve, then revokes it the moment an autonomous run goes wrong.

I built Greenlight in July 2026 as a working answer to the question every team deploying agents against a real system of record has to answer: how much do you let the agent do on its own, how does it prove it earned that, and how do you guarantee it cannot do anything else.

The action layer

Every tool that touches the world routes through one function. Policy check, then execute, queue for approval, or deny. There is no code path where a tool call reaches a connector without passing the gate. The model's tools are physically incapable of bypassing it.

Policy is deliberately simple: first match wins, default closed. Anything the system has no opinion about goes to a human. That is the opposite default from most agent demos, which try it when unsure.

Two details that separate this from an if-statement:

  • Identity comes from the session, never the model. Tools are built per request and scoped to the authenticated persona. There is no user-id parameter for the model to lie about.
  • Input is validated at the trust boundary. App id and access level come from the model. Before anything persists, the action layer checks the app exists and the level is real for that app. A hallucinated id fails cleanly with a hint, not a 500 and not a silently accepted garbage value reaching the connector.

Earned autonomy

Trust attaches to a shape: the exact tuple of action kind, app, level, and requester role. Granting Airtable editor to a contractor is a different trust record from the same grant to a full-time employee.

  • Every human-resolved approval increments the shape's streak. A denial or a failed execution resets it to zero.
  • Thresholds are per action kind and calibrated to risk. Three clean approvals for grants, licenses, and password resets. Five for revocations.
  • Crossing the threshold drafts a graduation proposal inside the same transaction that bumped the streak, so the two cannot race apart. The promotion claim is an atomic guarded update, so a duplicate is structurally impossible.
  • A proposal is a real diff: the exact policy row that will be added, plus a replay of the last 50 real actions showing that only this shape flips outcome. A human reads that and accepts or declines.
  • Autonomy is lost in one bad run. A genuine fault under a graduated rule disables that rule on the spot. The shape falls back to full supervision with zero fast lane and re-earns the whole streak.

The subtlety that matters in the field: a full seat pool is a business condition, not a fault. It interrupts the run without revoking trust. Only outages and upstream rejections demote. Getting that line right per customer is the difference between earned autonomy and trust that collapses on noise.

Discovered autonomy

The streak engine only counts approvals it watched happen. Real history has patterns nobody tracked. A pattern miner sweeps 30 days of terminal actions for shapes that recurred cleanly, had zero denials or failures, and still route to a human. Promoting a mined suggestion drafts the same proposal the streak path drafts. Same diff, same replay, same human accept. One gate, two ways to arrive at it. There is intentionally no second, weaker bar for "discovered" trust.

The decision I would defend

No auto-widening. Graduation only ever produces a single-shape rule. There is no "promote the whole role" or "promote the whole app" path, because that trades away the thing that makes earned autonomy safe. And no calendar promotion. Nothing becomes trusted after 30 days. Promotion is evidence-driven or it does not happen.

The bug a review caught

Before merge, a review found the agent reporting success on an HTTP 200 that had executed nothing. The UI animated a green check for an action that never happened. That is the single worst thing an approval-gated system can do, and it is invisible in a transcript. Fixed on main before it shipped. I would rather show this than pretend the first version was right.

The mechanism as a business number

The same tables every action writes also feed an insights view: auto-resolution rate (about 70% on the seeded week), hours saved with the minutes-per-action assumption printed on the tile, autonomous success rate under graduated rules, latency medians. Trigger the outage demotion and the success rate visibly drops. No projections. One assumption, printed where the number is.

What I deliberately did not build

  • Realtime push. The console polls every 2.5 seconds. Honest for a demo; the first production upgrade.
  • A second model to "double-check" the agent. Safety here comes from the deterministic action layer. A reviewer model would blur where trust lives.
  • A real Okta connector. Sandbox connectors ship behind an interface with realistic latency and a failure-injection path. A real one drops in without touching the agent or the approval flow.

Built with an AI coding agent doing most of the typing. The action-layer design, the session-identity rule, the choice to evaluate the guardrails rather than the generations, the counterfactual replay before any rule widens, and every review were mine.

Figures

1Supervisedhuman approves each request · streak +1 clean, reset on denial or failure
2Threshold3 clean (grants) / 5 (revokes) · in the same transaction that bumped the streak
3Proposalexact policy row + a replay of the last 50 actions showing only this shape flips · a human accepts
4Autonomousthe same shape runs without approval · every run recorded
↺ demotion · one genuine fault disables the rule and the shape re-earns the whole streak · a full seat pool and other business conditions do not demote
shape = (kind, appId, level, role)
Trust is earned per action shape, proposed only as a single-shape rule, and revoked on one bad run. There is no auto-widening and no calendar promotion; a pattern miner reaches the same proposal from 30 days of history.