0047. The assistant is one agent in ai that acts as the person and changes things only through approvals
Status: accepted, 2026-10-30
Context
The owner decided on the xvii assistant: one server-side agent with the platform's MCP tools in every panel, the
native apps and Telegram (text and voice), acting through approvals. ai already runs chat answers on the server
(they survive a closed tab and resume over SSE), and every operation of the platform becomes an MCP tool through
home's catalog (0028). An agent with those tools reads logs, error
messages, webhook payloads and commit messages that people outside the team can write into, so text it reads can
try to steer it. Approvals (0025) and delegations (0026) already name
the assistant as a requester and a holder, but left its shape to this decision.
Decision
- One agent. The assistant is a conversation kind of ai's chat engine, not a service and not one agent per
panel. Panels (through a few fixed operations their own backend mounts for its session, and a registry sheet; no
frames), the hub and the Mini App (through home), the native apps, Telegram (through notify's bot) and the CLI are
clients of its API; a thread continues from one to another. Its conversations are the person's own: never shared
with a team, never public.
- It is the person. It reads and acts only through the person's assistant delegation, within the ceiling the
person chose when creating it with a passkey; without one it does nothing. It sees and does nothing the person
couldn't, and never more than the credential that asked for the turn: its tokens are narrowed to that caller's
scope, teams and services. Only people drive it (from panels, the apps, the CLI and Telegram), never agents, CI,
API tokens or itself, and from Telegram and the hub it offers nothing critical, as ADR 0033 has it.
- Its tools are the platform's. The MCP tools home's catalog lists for the person, and nothing else: no tools of
its own, no web search, fetching, Python or artifacts in assistant conversations. The general chat keeps those and
gets none of the platform's.
- Changes only through approvals. Reads (risk none) run freely. Every call above risk none runs at the service
that owns the operation under its approvals gate; for via
assistant, confirm from low risk up is a floor in
code, and high and critical need a passkey as the default policy says. A service whose contract doesn't declare
that it gates approvals is read-only to the assistant.
- What it reads is data. Tool results reach the model redacted, within the data boundary
(0048) and fenced as untrusted; nothing in them can
widen what it may do. Answers on chat surfaces don't repeat tool output verbatim.
Consequences
- Every change the assistant makes is an approval record with a summary the owning service wrote, decided by the
person (or the environment's approvers); a prompt-injected assistant can at most propose.
- The approvals design's default matrix changes for
assistant at low (none → confirm), with a floor no setting
lowers; allowances still cover runs of the same action.
- Services that don't gate yet can't be changed through the assistant until they do; contracts declare it.
- Each service's backend mounts the assistant's operations and each panel syncs the sheet: one patch release per
service. A script injected into one panel could then ask, as the person, about what they read elsewhere; panels'
content security policy is what keeps scripts out, and no change happens without an approval the script can't
decide.
- The cost of a turn counts on the person in the conversation's budget team, within ADR 0036's access and the
team's limits.
- Design:
superpowers/specs/2026-10-30-assistant-design.md in this repository.