> ## Documentation Index
> Fetch the complete documentation index at: https://comis-feature-matrix-channel.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Autonomy

> Named autonomy profiles, the zero-config default, and the honest, legible degrade

**What it does.** Decides how much an agent can do on its own -- spawn
sub-agents, run scheduled jobs, write to its workspace, browse the web -- and
makes that decision **legible**. You pick a named profile (or accept the
default); Comis resolves it into a concrete set of capabilities and guard
rails, logs exactly what it turned on, and tells you the one field to change
it. Smart defaults must never surprise you.

<Note>
  **Autonomy vs. capabilities.** A *profile* is the operator-facing dial. It
  resolves to a set of **capabilities** (the `orch:*` permission tokens an agent
  holds) plus guard rails (budget ceiling, spawn-rate limit, message quota).
  Capabilities are enforced by a single gate on every privileged action -- see
  the [Capability Model](/security/capability-model) for the enforcement side.
  This page is about choosing and reading the posture.
</Note>

## The Zero-Config Default

If you set no `autonomy` block at all, every agent resolves to the **`standard`**
profile. That is the great-out-of-the-box posture: the agent can orchestrate
(spawn sub-agents, author cron jobs, run execution graphs, use skills, read and
analyze content, write to its jailed workspace) under always-on guard rails, and
it messages only its own channel under an hourly quota.

```yaml title="~/.comis/config.yaml -- nothing to set; standard is the default" theme={}
agents:
  default:
    model: gpt-5.1
    # No autonomy block -> resolves to the `standard` profile.
```

There is no un-gated path to orchestration: an agent with no autonomy config
resolves to `standard` and holds exactly those surfaces, capability-gated. It
is an explicit grant via a named profile, not a compatibility shim.

## Named Profiles

Set `autonomy.profile` to pick a posture. There are four:

| Profile                | Orchestration                                                                               | Guard rails                                                                | When to use                                                                                                     |
| ---------------------- | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `assistant`            | **Off** -- zero orchestration surfaces, the agent only replies                              | n/a                                                                        | A pure conversational agent; or the safe floor Comis downshifts to when the jail cannot be built                |
| `standard` *(default)* | The nine floor capabilities (read, web, write, analyze, spawn, graph, cron, skill, message) | Budget ceiling, spawn-rate limit, concurrency cap, message quota -- all on | The default for almost everyone                                                                                 |
| `unattended`           | Same nine floor capabilities as `standard` (the cap set is clamped -- no over-grant)        | Standard guard rails **plus** the never-hang mode behaviors (below)        | Long-running, no-human-present operation: the run never stalls on a human and never retry-loops the budget away |
| `max`                  | Same as `standard` in this release                                                          | Same                                                                       | Reserved for the fullest coordinator posture (ships later)                                                      |

<Info>
  **`unattended` is active; `max` ships later.** `unattended`'s capability **set**
  stays `standard`-equivalent (the structural floor still bounds every cap -- no
  over-grant), but its **mode behaviors are on in this release**: a run that would
  ask a human resolves to **deny + escalate** (never a blocking prompt), a
  **denial breaker** aborts a run that keeps hitting a floor block, and an operator
  can **evict** an in-flight run back to `default` -- see
  [The `unattended` profile](#the-unattended-profile) below. `max`'s extra surface
  (sandbox auto-allow) is **not** in this release: selecting it resolves to
  `standard`'s capability set and attaches a not-yet-available notice (logged at
  boot). Comis **never silently grants** a capability whose
  enforcement floor is not yet built, so you are told rather than over-granted.
  (**Durable runs** are not one of the deferred surfaces -- they ship as an opt-in
  knob orthogonal to the profile; see [Durability & Resume](#durability-resume)
  below.)
</Info>

### The `unattended` profile

`unattended` is for a run with **no human present** -- a long-lived cron pipeline,
an overnight batch, a background coordinator. Its capability **set** is exactly
`standard`'s (the structural floor bounds every cap; there is no over-grant), but
its **mode** changes how the run behaves when it reaches a decision a human would
normally make. The whole point is that such a run **never stalls waiting on a
person** and **never burns its budget retry-looping** a thing it is not allowed to
do.

* **Never-hang: a would-ask becomes deny + escalate.** Under `standard`, an action
  that needs approval pauses for a human. Under `unattended` there is no human to
  pause for, so that same action **does not block** -- it resolves to a denial and
  the platform **escalates it to your operator** out-of-band. The run keeps going
  on what it *is* allowed to do; it does not sit on a prompt forever.
* **Outward actions still escalate, never auto-send.** `unattended` does **not**
  loosen the outward floor. A send to a new channel, a browser action, any
  hard-to-reverse outward step is still **proposed** for approval, never
  auto-decided -- exactly as under `standard`. Never-hang changes *waiting* into
  *escalation*; it does not change *propose* into *send*.
* **The denial breaker stops a retry-loop.** A run that keeps trying a blocked
  capability would otherwise spin -- each attempt denied, the budget draining for
  nothing. After [`denialBreakerN`](/reference/config-yaml#autonomy-agents-autonomy)
  consecutive floor blocks (default **5**) on one run, the **denial breaker** trips:
  the run is aborted (an `execution:aborted` with reason `denial_breaker`) and the
  operator is told, rather than letting it retry-loop the budget away. An actual
  allowed step in between resets the counter, so a single stray denial inside
  productive work never accumulates to a trip.
* **An operator can evict an in-flight run to `default`.** If an `unattended` run
  misbehaves, an admin can call
  [`autonomy.evict`](/reference/json-rpc#autonomy-evict) with its `rootRunId`. This
  is **demote-but-continue**: the run is **not** killed -- it keeps running, but
  **under `default`** from its next gated decision onward (so it reverts to the
  conservative posture mid-flight, no waiting for a restart or the next spawn).
  This is distinct from `lease.revoke` (cooperative stop) and `run.kill` (hard
  stop).
* **Fail-closed: an unresolvable mode is treated as `default`.** Mode resolution is
  fail-closed. If the run's autonomy mode cannot be determined for any reason, it
  is treated as `default` (the safe profile) -- **never** something broader. This
  posture is controlled by
  [`evictOnPolicyUnreachable`](/reference/config-yaml#autonomy-agents-autonomy)
  (default **true**), and it is the same safe target the `autonomy.evict` demotion
  lands on.

The two `unattended` knobs are `denialBreakerN` (default `5`) and
`evictOnPolicyUnreachable` (default `true`); both live in the
[`autonomy.*` config table](/reference/config-yaml#autonomy-agents-autonomy) and
apply to every profile, but they are the dials that matter most for a no-human run.

### What `standard` turns on

The `standard` profile resolves these nine floor capabilities:

| Capability     | What it permits                                                                                           |
| -------------- | --------------------------------------------------------------------------------------------------------- |
| `orch:read`    | Read content and workspace files                                                                          |
| `orch:web`     | Fetch untrusted external web content                                                                      |
| `orch:write`   | Write to the agent's jailed workspace                                                                     |
| `orch:analyze` | Cost-bearing media analysis (behind the budget)                                                           |
| `orch:spawn`   | Spawn sub-agents                                                                                          |
| `orch:graph`   | Run execution graphs                                                                                      |
| `orch:cron`    | Author and run scheduled jobs                                                                             |
| `orch:skill`   | Invoke skills                                                                                             |
| `orch:message` | Send a message to the agent's **own origin channel** (the channel it was spoken to) under an hourly quota |

`orch:message` is on by default but scoped to the agent's **origin channel
only** -- it answers where it was spoken to. The cap covers the genuinely-outward
send subset (`message.send`/`reply`/`react`); editing, deleting, fetching, and
attaching stay admin-only. A send to a **new** channel always escalates for
approval (it is never auto-decided), configured via `message.channels`.

Two surfaces are **off** in every default profile because they are outward and
hard to reverse: `orch:browse` (a real browser) and messaging a **new** channel
(beyond the agent's own). Opt into the browser explicitly with `browse: true`;
even then it always escalates for approval -- it is never auto-decided.

### Learned procedures stay advisory

When an agent solves a task with an [`orchestrate`](/agent-tools/orchestrate) run and that
approach proves out across verified successes, the learning layer distils it into an **advisory
procedure doc** -- a learned skill that records the run's tool footprint. It surfaces into the
agent's `<available_skills>` listing like any other learned skill, bounded by a **per-agent
budget** ([`learning.reflect.maxProcedureDocsSurfaced`](/agents/memory-config#the-one-learning-reflection-engine),
default `10`) that, when exceeded, keeps the **most-corroborated** procedure docs in a stable
listing order, so a burst of procedures can never bloat every prompt. Crucially, surfacing a
procedure doc grants **no new capability and no new execution path**: it is guidance the model
**re-authors** into a fresh `orchestrate` script, run under the **same** capability gate and jail
as any other run. A learned procedure can never widen the agent's autonomy posture -- the profile
and its guard rails still bound every tool the re-authored script may touch.

## Overriding Individual Knobs (Progressive Disclosure)

Most operators set only `profile:` (or nothing). When you need a single
adjustment, set just that field -- an explicit field **overrides** the profile,
so you do not have to restate the whole posture.

```yaml title="~/.comis/config.yaml -- standard, but with a tighter budget and the browser on" theme={}
agents:
  default:
    autonomy:
      profile: standard
      aggregateBudgetUsd: 5      # override just the spawn-tree $ ceiling
      browse: true               # opt into orch:browse (still always escalates)
```

The per-surface toggles (`web`, `analyze`, `write`, `browse`) each map to the
matching `orch:*` capability. The scalar guard rails (`aggregateBudgetUsd`,
`maxConcurrentSelfAgents`, `maxSelfSpawnRatePerMin`, `cronSelfMax`), the
`lease.leaseMaxTtlMin` renewal ceiling (in minutes -- the maximum a jailed-surface
capability lease can renew up to, so revoke actually stops renewal), and the
`message` block (`channels`, `maxPerHour`) are all individually overridable.

The always-on bounds are also exposed as nested blocks for finer control, each
defaulting safe so a runaway agent is bounded out of the box:

* `budget.{ aggregateUsd, tokens, wallClockMs }` -- the per-root-run ceiling.
  `aggregateUsd` is the priced $limb (the `aggregateBudgetUsd` field is its
  alias); `tokens` and `wallClockMs` bound a loop even on an unknown-priced
  (subscription /$0) model the \$ limb would count as free.
* `rate.{ perRootCallsPerSec, perSocketCallsPerSec, connectionChurnPerMin }` --
  the call-rate ceiling that bounds a call storm without tripping a legitimate
  burst.
* `spawn.{ maxConcurrentSelfAgents, maxSpawnDepth, maxChildrenPerAgent }` -- the
  tree-wide spawn shape (`maxConcurrentSelfAgents` is the alias of the flat field;
  depth defaults to 3, fan-out to 5).
* `outward.{ originOnly, perTargetGrants, volumeCap }` -- outward-send governance.
  `originOnly` keeps sends to the agent's own channel by default; a new target
  needs an explicit `perTargetGrants` entry; `volumeCap` bounds a mass-recipient
  send.

See the full field list in the [config reference](/reference/config-yaml#autonomy-agents-autonomy).

## Connected MCP Tools

The [`orch:mcp`](/security/capability-model#connected-mcp-tools-orch-mcp)
capability -- which lets a jailed [`orchestrate`](/agent-tools/orchestrate)
script reach connected MCP server tools -- is a **floor capability** held by
default on the autonomy-bearing profiles (standard/unattended/max), like
`orch:write`. Holding the cap opens **no** server, though: reachability is gated
by the per-server `autonomy.mcp.allow` allowlist, which is **empty by default**.
So a fresh agent holds `orch:mcp` yet reaches no MCP tool until you allowlist the
exact `{server -> tools}` it may call.

```yaml title="~/.comis/config.yaml -- expose two allowlisted MCP tools to one agent" theme={}
agents:
  research:
    autonomy:
      profile: standard
      mcp:
        # `enabled` is NOT required on standard/unattended/max -- orch:mcp is
        # floor-granted there. Set it only for the `assistant` profile opt-in.
        allow:
          weather-server:
            tools: [forecast, current]   # explicit tool names -- no wildcard
            classification: safe         # inbound tier: safe | permission-gated
```

`autonomy.mcp` defaults to `{ enabled: false, allow: {} }`. On standard/unattended/max
the `orch:mcp` cap is floor-held regardless of `enabled`, so a fresh agent's MCP
surface is dark at exactly **one** operative layer -- the empty allowlist. Setting
`allow` is the only step needed to make a tool reachable:

* **`allow`** is the per-server inbound allowlist -- **the operative gate**. Each
  key is a connected server's name; its `tools` is the **explicit** list of tool
  names reachable on that server (there is no `*` wildcard -- you name each tool),
  and `classification` is the inbound tier. Absent from `allow` ⇒ denied by
  absence.
* **`enabled`** grants `orch:mcp` to the `assistant` profile (which has autonomy
  off and no floor caps) as an explicit opt-in. On standard/unattended/max the cap
  is already floor-held, so `enabled` is not required there (it is a harmless
  no-op for the grant). There is no separate boolean `mcp:` toggle beside
  `web`/`analyze`/`write`/`browse`; the nested block's own `enabled` field is the
  assistant-opt-in signal, mirroring `durability.enabled`.

The `classification` is a **three-tier inbound gate**:

| Tier               | Meaning                                                                                        |
| ------------------ | ---------------------------------------------------------------------------------------------- |
| `safe`             | The allowlisted tool is reachable directly.                                                    |
| `permission-gated` | The tool is reachable, but each call fires the [approval workflow](/security/approvals) first. |
| *absent*           | **Unreachable.** A server with no `classification` is denied -- the default-deny safety net.   |

Reachability is thus **unlisted ⇒ unreachable** at every step: an unlisted
server, an unlisted tool on a listed server, or a listed server with no inbound
classification are all denied. Enforcement is the daemon's, at the capability
socket -- the config only ever *widens* from the dark default, and never past
what the operator explicitly names. The connected MCP tool runs **daemon-side**
so the jail stays `--unshare-net`, and the management plane (connecting or
authenticating a server) is never reachable from a jailed script. This inbound
allowlist is a **separate** control from the outbound `/mcp/v1` export policy
that governs which of *this* daemon's tools are exposed to external MCP clients;
turning one on never affects the other.

## One-shot auto-repair

When an [`orchestrate`](/agent-tools/orchestrate) script fails on a **recoverable**
error -- a bad import, a misused `comis_tools` call, or a `TypeError` -- the runner
does **one** utility-model re-prompt that regenerates the script and re-runs it
**once**. It turns a small model's near-miss into a working run in the same turn,
without bouncing the failure back to the main model for another inference turn.

This is **class-gated off the model's capability class** -- it is not a profile knob
and there is no config toggle:

| Capability class  | Auto-repair                                 |
| ----------------- | ------------------------------------------- |
| `small`, `nano`   | **On** -- the weaker models it helps most   |
| `mid`, `frontier` | **Off** -- a stronger model rarely needs it |

The class is resolved from the agent's model (an operator capability-class override on
the provider, otherwise the provider family). There is **no `autonomy.autorepair`
field** to set: the model tier is the whole control, so there is no dead toggle to
drift out of sync. When the class is absent or unresolved it defaults to the
repair-eligible side (`small`), so an unknown-tier or keyless local deployment still
self-repairs rather than silently not.

The repair is bounded to **exactly one attempt** -- a repaired script that fails again
surfaces the original error, never a retry loop. It runs on a cheap utility model (the
same keyless-safe path other utility passes use) and **rides normal spend/budget
accounting**, so the agent's budget bounds it like any other call. The regenerated
script re-runs in the **identical** jail, capability, and lease envelope as the
original -- it gains no new privilege.

## Durability & Resume

By default an in-flight autonomy run lives only in the daemon's memory: kill the
daemon mid-pipeline and that run is gone. Turn on
[`autonomy.durability.enabled`](/reference/config-yaml#autonomy-agents-autonomy)
(**off by default** -- a default install builds no durable stores and is
byte-identical) and a long-running run becomes **resumable across a restart**,
with an **exactly-once** guarantee on everything it sends outward.

```yaml title="~/.comis/config.yaml -- make a cron-fired pipeline survive a restart" theme={}
agents:
  default:
    autonomy:
      profile: standard
      durability:
        enabled: true          # opt-in; off by default
```

**What it gives you:**

* **Resume or honest orphan -- never a silent vanish.** As a run advances it
  stamps a checkpoint (its spawn tree, the consumed budget, a heartbeat) to
  `memory.db`. On restart the daemon scans the live runs (after channels are up)
  and **resumes** each one, or -- if its record cannot be trusted -- **orphans**
  it and **notifies the operator** out-of-band. A run is never left in limbo. A
  daemon-wide watchdog sweeps any run whose heartbeat has lapsed past
  `staleHeartbeatMs` (the same fate: resume or orphan-and-notify).
* **Exactly-once outward sends -- a crash never re-DMs or re-posts.** Every
  agent-originated outward send is wrapped in a durable three-state ledger
  (`send_attempt_started` → `unknown_after_send` → `committed`) keyed on a unique
  `(rootRunId, step-index)` pair. A send that already committed is a no-op on
  replay; a send that crashed *between* the attempt and the platform
  acknowledgement is **reconciled** on recovery -- the owning channel is asked
  "did this actually send?" -- rather than blind-replayed. This is security
  invariant #12: **a restart mid-pipeline never double-sends.** It covers **both**
  the direct [`message.send`/`reply`/`react`](/reference/json-rpc#message-send)
  path **and** the sub-agent completion-announcement path -- the announcement
  dead-letter queue consults the same ledger on restart, so a recovered
  announcement is never delivered twice. The typed
  [`comis_tools.message_send`/`reply`/`react`](/agent-tools/orchestrate#the-typed-mutation-surface-write-and-message)
  outward methods dispatch that same `message.*` path, so they ride the same
  ledger. **This dedup is active only under durability.** With durability off
  (the default), an outward send is a best-effort pass-through -- still delivered,
  just not deduped across a crash; the exactly-once guarantee attaches only once
  `autonomy.durability.enabled` is on.
* **A resumed run never broadens its authority.** On resume the lease is
  re-minted from the run's **persisted, already-attenuated** capabilities -- never
  re-attenuated from a live parent (which could be broader), and never a superset
  of what the run originally held. A [`lease.revoke` / `run.kill`](/reference/json-rpc#lease-revoke)
  **poisons** the persisted record (flips it to `revoked`), so a later boot can
  never resurrect pre-revoke capabilities -- a revoked record is orphaned on
  resume, not re-minted.
* **DAGs resume at node-boundary granularity.** A cron-fired multi-node
  execution graph interrupted by a restart resumes its **incomplete** nodes;
  already-completed nodes are **not** re-run, and any outward send a re-run node
  repeats is deduped by the same ledger. (Intra-node LLM/tool state is not
  checkpointed -- resume is per node, not mid-node.)

**The config knobs** (all under `autonomy.durability`):

| Field              | Default  | What it does                                                                                                                                                                                                                  |
| ------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`          | `false`  | Master switch. Off → no durable stores, no watchdog, byte-identical install.                                                                                                                                                  |
| `keepAliveMs`      | `30000`  | How often a live run stamps its heartbeat (independent of step/spawn completion, so a long child never looks stale).                                                                                                          |
| `staleHeartbeatMs` | `120000` | A run whose heartbeat is older than this is treated as crashed and orphan-swept. Default is 4× `keepAliveMs` -- the conservative ratio that keeps a transiently-slow run from being falsely failed (and its work duplicated). |
| `recoveryBudgetMs` | `30000`  | Wall-clock budget for one recovery pass. A backlog larger than the budget is partially recovered and the remainder deferred to the next pass -- no thundering herd on a large crash backlog.                                  |

<Note>
  **Honest per-channel coverage of the exactly-once guarantee.** The "was this
  actually sent?" reconciliation needs a channel that can be **queried** for its
  recent sends. **Discord** and **Slack** can (they fetch recent history and match
  the bot's message), so a crashed-mid-send on those resolves cleanly to
  *sent* (acknowledge once, no replay) or *not-sent* (replay once). **iMessage,
  IRC, and Email cannot** be queried for their sent history -- so a crashed-mid-send
  on those resolves to **unresolved**, which Comis handles by **parking the send
  and escalating to the operator** rather than guessing. That is the safe,
  surfaced outcome: never a silent double-send, and never a silent drop -- you are
  told to decide. This is the truthful shape of invariant #12: the guarantee is
  *full and automatic* on queryable channels, and *parked-and-surfaced* on the
  ones that cannot answer.
</Note>

<Note>
  **Resume scope.** A resumed run is re-anchored under the bounded-autonomy
  meter (bounded, killable, and with its outward ledger reconciled across the
  restart) from its persisted checkpoint -- it is **not** re-entered into the agent
  loop from the exact step it was on. Resuming the model turn itself from a
  mid-run step needs a wider checkpoint and is a later enhancement; today's
  guarantee is "the run survives, stays bounded, and never double-sends," not "the
  model picks up its half-finished thought."
</Note>

## Legible Boot Logging

At startup Comis logs **one INFO line per agent** stating the resolved posture,
so you can read what every agent was granted -- and how to change it -- from the
boot logs alone, without turning on debug logging:

```json theme={}
{
  "level": 30,
  "submodule": "autonomy",
  "agentId": "default",
  "profile": "standard",
  "capabilities": ["orch:read", "orch:web", "orch:write", "orch:analyze", "orch:spawn", "orch:graph", "orch:cron", "orch:skill"],
  "aggregateBudgetUsd": 200,
  "changeField": "autonomy.profile",
  "msg": "Resolved agent autonomy profile"
}
```

The `changeField` names the one config field that changes all of the above:
`autonomy.profile`. The line also carries an `m1Notice` whose text is
profile-specific: for an `unattended` agent it states that the never-hang mode
behaviors are **active** (deny + escalate, the denial breaker, operator evict) and
that the capability set stays `standard`-equivalent; for a `max` agent it states
that the extra surface (sandbox auto-allow) is not yet available.

## Honest, Legible Degrade

Autonomy needs a jail to run its orchestration surfaces safely. On Linux, that
jail is built from an unprivileged user namespace. If the host preflight for
that namespace **fails**, Comis does **not** quietly run the agent unjailed.
Instead it downshifts that agent to the **`assistant`** profile (no orchestration
surfaces, the agent only replies) and says so, two ways:

1. A **WARN** at boot naming the downshift, with an actionable hint and
   `errorKind: "precondition"`.
2. A **doctor finding** an operator can read, naming the same remediation.

```json theme={}
{
  "level": 40,
  "submodule": "autonomy",
  "errorKind": "precondition",
  "hint": "Autonomy needs an unprivileged user namespace ... downshifted to the 'assistant' profile. Enable unprivileged user namespaces ... or set autonomy.profile: assistant to silence this.",
  "msg": "Agent autonomy downshifted to the 'assistant' profile: the namespace preflight failed ..."
}
```

To resolve it, enable unprivileged user namespaces on the host (for example,
`sysctl kernel.unprivileged_userns_clone=1`, and on AppArmor-restricted distros
`kernel.apparmor_restrict_unprivileged_userns=0`) and restart. If you intend to
run an assistant-only agent, set `autonomy.profile: assistant` explicitly to
silence the warning.

<Warning>
  **There is never a silent unjailed fallback.** A failed precondition always
  lands on the `assistant` posture (orchestration disabled) -- the agent stays
  safe and you are told. The actual host probe that produces the preflight result
  ships with the sandbox jail; the downshift path and its logging are wired
  independently, so the behavior is legible the moment the probe lands.
</Warning>

## Related

<Note>
  **The agent reads its own copy of this guidance.** A bundled `autonomy` skill
  (`packages/daemon/bundled-skills/autonomy/`) auto-seeds into every agent's
  workspace and is surfaced to the model: it is the on-demand, model-facing
  decision guide for *when* to reach for an orchestration surface and *how* to
  route a multi-step task through [`orchestrate`](/agent-tools/orchestrate). A
  one-paragraph always-on doctrine carrying the same contract and routing rule
  also rides every run's system prompt, so the floor applies even when the model
  never opens the skill.
</Note>

<CardGroup cols={2}>
  <Card title="Capability Model" icon="key" href="/security/capability-model">
    How capabilities are enforced by a single gate, and why no capability ever
    implies admin access.
  </Card>

  <Card title="Safety" icon="shield-check" href="/agents/safety">
    The budget cap, circuit breaker, and rate limits that bound an autonomous
    agent.
  </Card>

  <Card title="Config Reference" icon="file-code" href="/reference/config-yaml#autonomy-agents-autonomy">
    Every `autonomy.*` field, its type, and its default.
  </Card>

  <Card title="Security Model" icon="lock" href="/reference/security-model">
    The orthogonal capability axis and the deny-by-origin control-plane boundary.
  </Card>
</CardGroup>
