# Agents

How an agent reads, how it proposes, what it takes for one to accept — and how you see every time it does.

## Proposals, not writes

An agent with `notes:write` cannot change a note directly. It commits to a sibling suggestion container and you get a reviewable diff. Accepting is a separate transaction — yours, from a signed-in session, or the agent's own, but only under a token you minted with the `turns:accept` scope.

That scope is a grant, not a setting. It is never implied by another scope, never in a CLI's default grant, and only a person can mint a token that carries it. An agent may accept only turns it opened itself, and only prose: proposed links and calendar events wait for you on every path.

The reason the default is propose-only is specific to how Fastpad syncs. An edit committed to a note is durable and on every one of your devices immediately. If a poisoned web page or a malicious note steered the agent, the injected text would be everywhere before anyone saw a diff — and no interface can retract bytes that are already on a second device. Granting accept is you deciding that risk is worth it for that token, by name, and the trail below is what you get in return.

## Reviewing a proposal

A proposal arrives in your inbox and at a URL of its own. You see a per-block diff: what the agent read, what it wants to change it to, and which blocks it says it drew from.

1. Accept — the change is applied, marked as reviewed by you, and the sources it cited become real links.
2. Accept some — the rest stay pending.
3. Reject or abandon — nothing was ever applied, so there is nothing to undo.
4. Revert, later — undoes the whole proposal as one unit, keeping any edit you made on top of it.

> **Note:** If you edited the text while the proposal was waiting, accept refuses to overwrite you. You get a three-way merge instead — your version is never discarded silently.

When an agent accepts its own proposal, you see it afterwards instead of before. The Agent activity page, at `/agent-activity` in the app, lists every turn that reached a note on an agent's authority — accepted under `turns:accept`, or auto-applied — with who did it, which notes it touched, and how many blocks. Each accept is also written to the audit log under the agent and the token that made it.

- Mark reviewed — the blocks the agent accepted are promoted to reviewed-by-you, the same state a proposal you accepted yourself gets. Auto-applied blocks stay unreviewed; the turn still leaves the queue.
- Revert — undoes the whole turn as one unit, keeping any edit you made on top. Reverting is yours alone: no token of any scope can do it.
- Open the diff — the same per-block view a pending proposal has.

## What a token can reach

A token resolves to a concrete set of notes when it is created, never to a live tag query. Otherwise an agent holding `notes:write` could widen its own reach simply by tagging a note it wanted to read.

| Scope | Grants |
| --- | --- |
| `notes:read` | read note bodies |
| `notes:propose` | create proposals — never apply them |
| `notes:write` | write note content directly (properties, types, comments) |
| `notes:delete` | move to trash and restore |
| `search:read` | search, and titles and snippets with it |
| `graph:read` | traverse links |
| `schema:write` | define note types and their properties |
| `export` | pull the whole workspace as Markdown |
| `turns:accept` | accept its own proposals; every accept is listed for you to review |

Accepting is on that list, and nothing else on it implies it: a token holding every other scope still cannot accept. What is not on the list, and cannot be, is reverting, reviewing, publishing and verifying — those need a signed-in person.

## Trust is two questions, not one

Every piece of content carries where it came from and whether a person ratified it. Those are separate axes, and keeping them separate is what makes “an agent wrote this and I read the diff” different from “an agent wrote this and nobody looked”.

| Origin | Means |
| --- | --- |
| `human_typed` | a person typed it, or a terminal they were holding did |
| `agent_written` | an agent authored it |
| `inbound_untrusted` | it arrived from outside a keystroke — a capture, an import, an email |

By default an agent searching your workspace sees only content a human authored. Agent-written text nobody reviewed is excluded, and so is anything untrusted. An agent has to ask for a lower floor explicitly.

A block an agent accepted under `turns:accept` carries the review state `agent_accepted`. That is not treated as human-reviewed: every trust floor above the lowest excludes it exactly as it excludes unreviewed agent text, so an agent cannot ratify its own work into what the next agent is told is established fact. It becomes `human_accepted` only when you mark the turn reviewed.

## Autonomy, for the cases that earn it

A token can be given auto-apply, scoped to its note set or to the workspace. Its edits then land without review — and stay marked unreviewed forever, so the cost of that decision is visible in the data rather than only in a settings page.

Auto-apply and accept are different grants. Auto-apply skips the proposal entirely; accept ratifies one that was made. Neither turns a token into a person: an accept is marked as an agent's, an auto-applied write is marked unreviewed, both land on the Agent activity page, and reverting either is yours.
