Agent door
Capabilities & grants
A grant lists the exact capabilities an agent may exercise. Capabilities are the door's first authority layer; row-level security is the independent second.
Every tool the door exposes names a capability — a dotted
resource.verb string — that a caller's grant must hold. A workspace admin
issues a capability grant listing exactly which capabilities an agent may
exercise. The capability gate is the first authority layer; row-level security on
ctx.db is a second, independent one, so a bug in either cannot read or write a
row the other forbids.
The capability namespace
The grantable capabilities are derived from the live tool registry — a capability is
grantable if, and only if, some tool actually gates on it, with the one exception of
diagnostic.start (below). There are twenty today — they back
twenty-three of the twenty-five tools in the Tools reference, because
three capabilities each back two tools: action_item.update backs the write
(update_action_item) and its read-only status poll
(get_approval_status), portfolio.read backs
list_portfolio and get_portfolio_changes, and
diagnostic.read backs get_diagnostic and get_run_status.
Of the other two, describe_yellowhead describes Yellowhead and its plans, reads no
account data and gates on no capability, and start_diagnostic gates on
diagnostic.start, which is never issued in a capability grant (see below).
| Capability | Kind | Grants access to |
|---|---|---|
diagnostic.list | read | List diagnostics |
diagnostic.read | read | Read a diagnostic |
report.read | read | Read a completed Diagnostic report |
action_item.list | read | List action items |
action_item.read | read | Read an action item |
action_item.update | write | Request an action-item update (held for approval), and poll its status |
action_item.comment | write | Request a comment on an action item's activity timeline (held for approval) |
diagnostic.run | write | Request a re-run of an existing diagnostic, optionally with different numeric inputs (always held for approval; metered against the organization's wallet). Limited availability — see below |
usage.read | read | Read workspace usage / quota |
strategic_assessment.list | read | List published strategic assessments |
strategic_assessment.read | read | Read a published strategic assessment |
infrastructure_audit.list | read | List published infrastructure audits |
infrastructure_audit.read | read | Read a published infrastructure audit |
citation_scan.list | read | List the organization's Citation Scans |
citation_scan.read | read | Read a Citation Scan and, once completed, its results |
crawlability_scan.list | read | List the organization's Crawlability Scans |
crawlability_scan.read | read | Read a Crawlability Scan and, once completed, its run summary |
accessibility_scan.list | read | List the organization's Accessibility Scans |
accessibility_scan.read | read | Read an Accessibility Scan and, once completed, its results |
portfolio.read | read | List the organization's client workspaces with their latest scores and open high-priority items, and which moved since a date. Team accounts on an Agency plan, Business Enterprise or a custom plan |
Each capability maps to one or more tools in the Tools reference, which is generated from the same registry.
Reads: verb wildcards
For read tools, the gate honours a verb wildcard: a grant holding
diagnostic.* satisfies both diagnostic.list and
diagnostic.read. The wildcard is a convenience for read scopes only.
Writes: exact match, opt-in, never default
The write capabilities — action_item.update,
action_item.comment and diagnostic.run — are
exact-match: a verb wildcard never
unlocks one. Holding action_item.* for reads does not grant either
action-item write, and neither implies the other: changing an item's state and posting to its
timeline are separate authorities, grantable separately. Likewise
diagnostic.* reads never reach diagnostic.run — reading the
diagnostics and spending the workspace's wallet are not the same authority. A workspace opts
into a write deliberately,
one capability at a time, and no code path adds a write capability to a grant
automatically. The approval poll (get_approval_status) is exact-match too — any
write capability admits it, so an agent can always see the outcome of a write it was allowed
to request, while a read-only or wildcard grant can never even see the write queue.
Even with the write capability granted, the write itself is held for a human by default — see Write approvals.
Limited availability: diagnostic.run
diagnostic.run is the one capability that costs money per use — it asks us to
run a fresh Diagnostic, which is metered against the workspace's wallet at its plan rate. It
carries two extra constraints the other writes do not. It is always held
for a human: unlike every other write, no auto-approve setting can make it apply directly.
And it is not generally available — it can only be granted to organizations
we have explicitly enabled for agent-initiated runs, so a grant request that includes it is
refused for everyone else. Both constraints are enforced in code, not in policy.
The target is never the agent's to choose. A re-run replays an existing
diagnostic's stored intake, and the business, website URL and account always come from that
stored run — there is no argument that names, moves or redirects any of them. What an agent
may vary is the run's numeric inputs: the per-pillar self-assessment
(side_a_scores, whole numbers 1–10) and the monthly spend figures. Those merge
over the stored intake per field, so anything omitted keeps the earlier run's value, and every
override is frozen onto the approval and shown to the approving admin next to the value it
replaces. Numbers are the whole reason that half is open: the fixed target and the fixed
field list are what keep an agent from pointing a billed audit somewhere new.
Given at sign-in only: diagnostic.start
diagnostic.start backs start_diagnostic, which starts a free
Diagnostic from inside an AI assistant's conversation. It is never issued in a capability
grant: grant management refuses it by name. A connection receives it only when a person
connects an AI assistant through its sign-in and approves the consent screen, on every plan,
and the run is that person's, as if they had started it in the app. Like a write capability
it is exact-match, so diagnostic.* never reaches it. It is not held for approval:
the first call returns a preview and starts nothing, and only a second call with the preview's
confirmation token starts the run. It uses only the account's included monthly Diagnostics and
never the wallet; when none are left, nothing is charged. The run is recorded with the same
five choices as the app (the person's own business, a client, a competitor, research or a
prospect) and filed by the same workspace rules: a competitor or research run of a website no
workspace holds is filed in no workspace and creates none.
What the consent screen says it may do follows the account's plan. On a plan with workspaces, it can file the run in one of them. On an Agency plan (Consultant, Studio or Firm) or a custom plan, it can also create a new prospect or client workspace for the business when the person asks for one, provided that person is an owner or admin of the team account.
Grants are org-scoped
A grant authorises exactly one organization. Every tool binds its query to that org in addition to row-level security, so a grant issued for one workspace can never reach another's rows — even if the underlying identity happened to have membership elsewhere.