# Authority Boundary

> Pattern 08 · Standing authority · part of Agent Consent Patterns.
> Human page: https://agentconsent.dev/patterns/authority-boundary/

Standing authority accretes one prompt at a time until nobody can say what the agent is actually allowed to do unattended. Give it a single home: one surface that answers, per capability, what the agent may do on its own and what it must always ask about.

## Problem

Every standing grant an agent accumulates was reasonable when it was made. "Yes, you can archive these." "Sure, remember that." "Allow always." But those decisions happened in a dozen different contexts, days or weeks apart, and nothing ever gathers them in one place. So the question that matters most about an agent, *what can this thing do without me?*, has no answer surface. The authority is real. It is just invisible, distributed across settings pages, past prompts, and remembered choices no one can list.

You can't review what you can't see, and you can't revoke what you can't find. An agent's autonomy needs a boundary the user can actually look at: a single place where the full extent of standing authority is legible, and adjustable, in one sitting.

## Solution

Give the agent's authority one home. List every capability, and put each on an explicit level: the user can see the whole boundary at once and move any capability across it.

- **Automatic.** The agent may do this unattended. Reserve it for the reversible and the low-stakes.
- **Ask first.** The agent may propose it, but every instance goes through a confirmation. This is the safe resting level.
- **Never.** The agent may not do this at all, full stop.

A running summary tallies how much is automatic versus gated, so the *amount* of standing authority is a number the user can see, not something they'd have to reconstruct. A capability can also forbid a level: permanent deletion simply can't be set to Automatic, so the surface refuses to grant standing authority to the irreversible.

> **Live demo** — an interactive Authority Boundary demo runs on the page: https://agentconsent.dev/patterns/authority-boundary/

The demo is the `AuthorityBoundary` component from `@agentconsent/react`. Move "Send email" to Automatic and watch the summary re-tally; note that "Permanently delete" won't accept Automatic at all.

## Anatomy

> **Anatomy** — a labeled breakdown of the Authority Boundary component's parts is shown on the interactive page: https://agentconsent.dev/patterns/authority-boundary/

## When to use it

- **Any agent with more than a couple of standing permissions.** Once autonomy is spread across several capabilities, users need one place to see and shape the whole boundary.
- **As the home the in-task prompts defer to.** A [Consent Memory](/patterns/consent-memory/) choice made in a prompt should land here, where it can be reviewed later out of the heat of the task.
- **Where levels genuinely differ by capability.** The pattern earns its keep when "read" and "delete" *should* sit at different authority levels, which is almost always.

## When not to use it

- **A single permission.** One capability with one grant is a [Scoped Grant](/patterns/scoped-grant/) or a [Connection Card](/patterns/connection-card/), not a boundary surface.
- **A momentary, in-flow decision.** Don't make the user open a full settings panel to answer one prompt. Capture that inline with [Consent Memory](/patterns/consent-memory/) and let it flow here afterward.
- **Numeric guardrails.** "Automatic up to $50, ask above" is a spend limit, not a level. Pair this surface with dedicated [Spend & Rate Limits](/patterns/spend-rate-limits/) rather than trying to encode thresholds as authority levels.

## Real-world examples

- **Claude Code permission modes.** Named operating levels (plan-only, ask-per-action, auto-accept edits, full bypass) plus per-tool allow/deny rules. The boundary is explicit, inspectable, and adjustable mid-session, and the mode name is always visible while the agent works.
- **ChatGPT agent mode.** Sensitivity-tiered autonomy in one product: routine browsing runs autonomously, consequential actions require confirmation, and on sensitive sites the agent drops to a supervised watch mode. Different categories of action live at different standing levels, not one global dial.
- **Mobile OS permission screens and cloud IAM.** The per-app settings page (each capability set to Never / Ask / While Using / Always) is the household-name version of a per-category boundary; AWS IAM permission boundaries are the infrastructure version. A hard cap on what a role can ever do, regardless of what other policies grant.

*Annotated screenshots of these flows are being collected. Products are credited, annotations follow the site-wide callout conventions, and any screenshot is removed on request. See [About](/about/).*

## Accessibility

- The surface is a `role="group"` labelled by its title, so assistive tech announces the whole boundary as one named region.
- **Each capability's level is a real radio group.** Every row is a `fieldset` with a screen-reader legend naming the capability ("Authority for Send email"), so the three levels are an independent, labelled single-choice control, not an ambiguous cluster of buttons.
- **The summary is a polite live region.** Changing any capability's level updates the tally without moving focus, so a non-visual user always knows how much standing authority is in force.
- **Forbidden levels are genuinely disabled.** A barred level (e.g. Automatic on a permanent delete) is a `disabled` radio, announced as unavailable, not a styled-inert label a screen reader would still offer as selectable.
- Levels are conveyed with **text** (Automatic / Ask first / Never) and layout, in addition to color, and the access of each capability is a text badge. The boundary never depends on color to be read.

## Anti-patterns

- **Scattered authority.** Permissions spread across five settings pages and a history of prompts, with no surface that sums them up. If the user can't see the whole boundary in one place, they don't really have one.
- **Automatic as the default.** Shipping capabilities pre-set to Automatic "for convenience" makes the powerful choice the resting state. Default to Ask first; make the user reach for autonomy.
- **No "never."** A boundary that can only widen (where every capability is Automatic or Ask, with no way to take something off the table) isn't a boundary. Some things the user must be able to forbid outright.
- **Autonomy for the irreversible.** Letting a permanent-delete or money-moving capability be set to Automatic hands standing authority to exactly the actions that most deserve a per-instance gate. Forbid it structurally.
- **A summary that lies.** A tally that counts what's *listed* rather than what's *in force*, or that omits the capabilities defaulting to a level, understates the real authority. Count what's actually granted.
- **A boundary that escalates.** Treating Automatic as *new* power rather than a ceiling on rights the user already holds. An agent running unattended is still bounded by what its principal may do. The boundary can only narrow that intersection, never widen past it.

## Code

```tsx
import { AuthorityBoundary } from "@agentconsent/react";
import "@agentconsent/react/theme.css";

<AuthorityBoundary.Root
  value={levels}                        // { [id]: "auto" | "ask" | "never" }
  onValueChange={setLevels}
>
  <AuthorityBoundary.Header>
    <AuthorityBoundary.Icon>⚖</AuthorityBoundary.Icon>
    <AuthorityBoundary.Title>
      What can Inbox Assistant do on its own?
    </AuthorityBoundary.Title>
  </AuthorityBoundary.Header>

  <AuthorityBoundary.Summary>
    {({ auto, ask, never }) =>
      `${auto} automatic · ${ask} ask first · ${never} off-limits`}
  </AuthorityBoundary.Summary>

  <AuthorityBoundary.List>
    <AuthorityBoundary.Capability
      id="read-inbox"
      access="read"
      label="Read your inbox"
      description="Scan messages to draft replies."
    />
    <AuthorityBoundary.Capability
      id="send-email"
      access="write"
      label="Send email"
      description="Send a message you have not reviewed."
    />
    <AuthorityBoundary.Capability
      id="delete-thread"
      access="delete"
      label="Permanently delete"
      description="Irreversibly remove a conversation."
      disallow={["auto"]}        // standing autonomy barred for the irreversible
    />
  </AuthorityBoundary.List>
</AuthorityBoundary.Root>
```

The level map (`value` / `defaultValue`) is the single source of truth: give
every capability an entry so the summary counts what's actually in force. Use
`disallow` to bar a level a capability should never hold. All parts are unstyled
primitives with `data-acp` attributes; skip `theme.css` and style them yourself,
or override the `--acp-*` tokens to retheme.
