The system
How the system worksThe DirectoryDispatchThe LedgerAI modelsAI agentsYour installationThe appThe research libraryWhat changes for your businessUse it from your softwareEverything it can do
Messaging
iMessageWhatsApp
Ads and leads
AdsCreativeLeads
Devices
Devices
Industries
RealtorsRestaurantsHome services
Explore
How it worksPermissions and limitsCompareSet upQuestionsText me

Unified dispatch: one runner for the terminal, browser, phone and cloud, and tokens that lend out exactly part of it

Every capability of this system, from a shell command on a Mac to a browser session, an iMessage line, a cloud container and 1,500 web services, is one row called through one runner with one call shape. That single authority is then lent out in pieces: a scoped token, built on the macaroon construction, carries its own readable limits, can be narrowed by whoever holds it, can never be widened, and leaves a record of every use and every refusal. This is the design, the cryptography, the recorded proof and the honest edges.

The problem: an agent that can think but cannot reach

An assistant can know exactly what to do and still have no way to do it. Reading a web page, editing a file, driving a browser, sending a text from a real phone number and running a job in the cloud are five different interfaces with five different credentials in five different places. Most agent systems solve this one integration at a time, and every integration is another place where a call can be made without a limit and without a record.

Unified dispatch is the alternative this system is built on. There is one runner. Every capability, whatever it touches, is a row in the Directory, and every row is called the same way:

json
{ "tool": "NAME", "args": { ... } }
Line 1, Column 1JSON

The runner looks up the row, reads its contract, makes the real call to wherever the capability lives, and records the exchange on the Ledger. The caller never learns the upstream interface. A shell command on the owner's Mac and a REST call to a lead database are the same call with different names.

That gives the system one place to put two things that are usually scattered: a permission check and a record. Because every action crosses the same runner, a limit enforced there is enforced everywhere, and a record written there is complete. The second half of this article is about the token that carries those limits. The first half is about how much the runner reaches.

What one runner reaches

SurfaceWhat the rows connect to
TerminalCommands on the owner's Mac through the Mac command runner (LOCAL_EXEC, the CLI_* tools, AppleScript and Shortcuts)
BrowserBrowser actions through the BROWSER_* tools, PLAYWRIGHT, and the COMPUTER tool's isolated persistent browser
Phone and messagingiPhone operations through PHONE_, iMessage through IMSG_ and the sign-in line, Shortcuts that run on the device
CloudCLOUD_EXEC, container agents and Workers
ServicesEvery web or API service whose contract is a Directory row: search, mail, ads, leads, patents, Cloudflare, Google, Stripe, Shopify

These environments stay different underneath. A browser action still needs a browser to be available; a phone operation still needs the device to be connected; a service still needs a valid credential. What unifies them is the request and the result: one call shape in, one recorded exchange out. A script, an assistant, a Shortcut or a person pasting a link can look up a capability, open its contract and call the runner without being rewritten around each tool's native interface.

The useful consequence is that the execution surface can grow while the calling pattern stays fixed. Adding a capability is adding a row. Nothing that calls the runner has to change.

One call, thirty wrappers

The contracts page renders every form of the canonical call for a given tool and states, for each, the only three things that vary: where it is sent, where the credential goes, and how the name and arguments are wrapped. Twenty-six forms are rendered for every tool: the build's REST door, a one-line URL, MCP over HTTP, an MCP client configuration, two command-line clients, a webhook, an Apple Shortcut, JavaScript and Python, an SDK method, a direct function call, MCP over stdio, WebSocket, server-sent events, GraphQL, SSH, a model's function call as the model would write it, and the OIP dispatch door with its dry-run form. A live scoped token adds three credential-free links. An upstream service adds its own call, made exactly as written.

Three of those forms (GraphQL, WebSocket, server-sent events) have no route yet; four (the SDK import, the direct function call, MCP over stdio, SSH) run only on the owner's machine. The contracts are generated from the row; they describe the call, not a promise that every transport is wired.

For the forms that do run, the order is fixed: the permission checker sits in front of the runner. A token's limits are therefore applied at the one point every interface passes through, which is the property that makes the limits worth having.

Data and execution are one grammar

The original design note for this system draws two pipelines side by side:

text
DATA       TARGET → FILTER → SELECT → ORDER → PAGE → AGGREGATE → RETURN WHAT WAS ASKED FOR
EXECUTION  TARGET → ARGS   → DEPEND ON → RUN → PROJECT → RECEIPT
Line 2, Column 1Plain Text

Reading a table and running a tool look different, but both end the same way: the caller should get back what it asked for, and the system should keep the whole result in case the caller asks a second question. A model that receives a warehouse when it asked for three rows wastes its context; a model that re-runs a tool to see a field it was not shown repeats a side effect.

The general envelope that unifies the two, one object with target, op, where or args, select, with, order, page, control and want for every capability and every data read, is written as a design and is not implemented as a single door. What is implemented is the projection half, inside the tools where it matters most:

  • The catalog projects to names. Every tool with its description is 817,371 bytes; every tool name alone is 41,663 bytes, 19.6 times smaller (measured 9 October 2026). A model reads names, then opens one row.
  • Results project on the way back. The CODE, ARTICLE, COMPUTER and RESULT tools take return.select (dot paths into the result), return.max_bytes and return.mode (selected, full or reference). The whole result is stored before it is reduced, and the answer carries a reference to it. Asking for the reference returns the stored result; it does not run the tool again. A budget cut is made at whole records or whole fields, never mid-field, and every answer states how large the whole payload was.

The invariant that matters, and the one most systems get wrong: projection shapes what the model sees, never what the system keeps. Nothing is silently truncated, nothing has to be re-run to be re-read, and a reviewer can always retrieve the part the model was not shown.

Scoped tokens: lending out part of the authority

A runner that reaches a terminal, a browser, a phone and the cloud holds a great deal of authority. The build key opens all of it, which is the right key for the owner and the wrong key for everyone and everything else: a helper agent, a client, a model doing one task, a stranger who should see one search result. The principle is old; least privilege is practiced by forcing a process to run with only those privileges required by the task. The problem has always been making it cheap enough to actually do.

A scoped token is a separate credential whose limits are written into it in plain text, checked by the runner before anything executes. Each limit is a caveat, one line a person can read:

text
tools = EXA_SEARCH
ways = rest,mcp
uses <= 3
expires < 2026-10-10T00:00:00.000Z
Line 4, Column 1Plain Text

That token lets its holder run one search tool, from a program or an MCP client, at most three times, until midnight on 10 October. An attempt to send mail is refused before anything is sent, because EMAIL_SEND is not on the list. A fourth search is refused. The holder can read exactly what the token allows, and so can anyone they hand it to.

The holder can also make it smaller. Appending uses <= 1 and handing the copy to a helper gives the helper one search. The helper's use also counts against the original three. Making ten copies creates no additional allowance. Distributing work no longer requires distributing the key, and a narrower copy never resets its parent's limits.

The cryptography: a chain that only grows

The token is three parts:

text
g1.<payload>.<signature>
payload   = base64url of {"i": "<id>", "c": ["<caveat>", "<caveat>", …]}
signature = 43 characters: the last link of an HMAC-SHA256 chain, one link per caveat
Line 3, Column 1Plain Text

The construction is the one from Google's 2014 paper on macaroons, credentials that embed caveats that attenuate and contextually confine when, where, by who, and for what purpose a target service should authorize requests. The mechanism is nested, chained MACs: each signature becomes the key that signs the next caveat.

text
root = HMAC(the build's access key, "misc-sheets grants v1")
s0   = HMAC(root, id)
s_k  = HMAC(s_(k-1), caveat_k)
the token carries s_n
Line 4, Column 1Plain Text

Four properties follow from that arithmetic, and the checker enforces each:

  1. Only this build can start a chain. The first link needs the root; the root needs the build's access key. Rotating the key ends every token at once.
  2. Anyone can narrow a token without asking the build. The holder appends a caveat and computes the next link from the signature they already have. The result is a valid, smaller token. This is attenuation in the object-capability sense: given one reference, create another with certain security restrictions, except that here it needs no server round trip and no storage. delegate = no stops further narrowing.
  3. Nobody can widen one. Removing, changing or reordering a caveat would require computing a link backwards through HMAC. The checker recomputes the whole chain from the root and compares the last link in constant time.
  4. An unknown caveat refuses the call. Caveats are joined by AND. A line the checker cannot parse is a refusal, never a pass. A system that passed on unknown limits would be a system whose limits could be bypassed by typo.

The payload is readable JSON, so the token is also its own documentation: the holder page at /g?t=<token> simply prints the caveats in plain words, then shows each of the token's doors filled in and ready to run.

Eleven limits, read from one list in the code

The checker, the Console's token builder and the public scoped access page all read one array of limits in the source. None of them can name a limit the others do not enforce, which is how the documentation stays true by construction.

LimitCaveatWhat it does
Toolstools = EXA_SEARCH,LEADS_*Which Directory rows may run; a trailing * covers a prefix
Waysways = link,rest,mcp,chat,proofWhich doors the token opens
Expiresexpires < <ISO time>When it stops
Usesuses <= NTool runs and chat messages; counted along the chain
Tasktask = T-0207Files every run under one task; stops when the task is done
Areasarea = /prefix/Every path-named argument must start with one of these prefixes
Argument rulesarg EMAIL_SEND.to glob *@acme.comOne argument of one tool must match =, prefix, glob, in, <= or >=
Personperson = p_…Only that person, signed in by text from their phone, may use it from a browser
Whose keyskeys = p_…Tools run with that person's own credentials (their Gmail, their iMessage line), never the build's
Modelmodel = <model id>The model the holder talks to in the chat door
Hand ondelegate = noNothing may be appended after it

Two of these carry design decisions worth knowing.

Uses are counted per link. Each uses caveat is charged against the link of the chain it sits on. A limit of 20 on a token covers every narrower copy made from it; a copy's own limit of 2 covers only that copy. Spending a use is an atomic compare-and-swap on the token's record, retried on conflict, so two concurrent runs cannot both take the last use.

Whose keys can only be set at mint. A narrowing that could add keys = <someone else> would move the token onto another person's accounts, which is a widening dressed as a caveat. The checker refuses a keys caveat that was not in the record written when the token was made. When a token carries keys, a tool that needs a credential the person has not stored is refused, and the refusal names the missing key.

Five doors, one check, one record

DoorAddressFor
LinkGET /g/run/<TOOL>?args=…&t=<token>A browser, a Shortcut, a model whose only tool is opening a page
RESTPOST /g/run, Authorization: Bearer <token>Any program
MCPPOST /g/mcp, same headerClaude, Codex, Cursor or any MCP client; it is shown only the tools the token allows
Chat/g/chat?t=<token>A page where the holder talks to a model that can run only the token's tools
Proof/w/<TASK>?t=<token>The read-only record of one task; runs nothing

Every door that runs a tool goes through the same seven steps: parse the token (a malformed string is refused); recompute the chain and compare the last link; read the token's record (never minted, turned off, or narrowed from a turned-off link are all refusals); check every caveat in the order the token carries them; spend one use on every uses caveat in the chain, atomically; run the tool through the same runner the build key uses; write the call to the token's log and a grant used row to the Ledger with the token id, chain link, caveats, tool, door, arguments, status and duration. The runner records the tool's answer under the same call id.

A refusal writes a grant refused row with the caveat that refused it. The tool is not executed. One honest edge: refusal and durable recording are separate outcomes, so a storage failure during a refusal can leave a gap in the record even though the call was correctly stopped.

What needs the build and what does not: narrowing needs nothing from the build. Checking needs the root key and one read of the token's record. That one read buys three things a bare macaroon cannot do: counting uses, turning a token off, and seeing which narrower copies have been used. Turning off a token turns off every copy narrowed from it; turning off one copy leaves the token it came from working.

A recorded run: the check made when this shipped

On 3 October 2026 a task was written with one purpose: prove a task-bound token end to end on the live build. Its completion condition, as written: two runs on the task's proof page, a refused run refused, and the token stopping when the task is marked done. A token was minted for it with tools = WIKIPEDIA_SUMMARY,HTTP_ECHO_HEADERS, ways = rest,mcp, uses <= 10 and task = T-0229.

T-0229, as its proof page records it
JSONT-0229, as its proof page records it
5 keys
"task""T-0229"
"date""2026-10-03"
"token_caveats" 5 items
"tools = WIKIPEDIA_SUMMARY,HTTP_ECHO_HEADERS"
"ways = rest,mcp"
"expires < 2026-10-03T22:41:13.648Z"
"uses <= 10"
"task = T-0229"
"calls" 3 items
4 keys
"at""2026-10-03T21:41:18.679Z"
"tool""WIKIPEDIA_SUMMARY"
"result""answered"
"ms"2321
4 keys
"at""2026-10-03T21:41:23.646Z"
"tool""HTTP_ECHO_HEADERS"
"result""answered"
"ms"1351
5 keys
"at""2026-10-03T22:02:42.146Z"
"tool""WIKIPEDIA_SUMMARY"
"result""refused before it ran"
"caveat""task = T-0229"
"reason""its task T-0229 is done"
"read_from""the proof page /w/T-0229, opened with the owner key on 9 October 2026"

Two runs answered, at 2321 ms and 1351 ms. The task was marked done. Twenty-one minutes later a third run never left the build: the checker refused it on task = T-0229 with the reason "its task T-0229 is done", and the proof page shows the refusal with the caveat beside it. The page is drawn from the checker's call log, not from anything the worker wrote. That is the whole point of the design in one small record: the worker could not leave a call out, because it could not act without the token, and it could not add one, because the build writes the record.

Why this is a containment primitive, not just a permission system

Put the pieces together and a specific property appears. What an agent may do is checked by code outside the model. How its actions execute is decided by the runner, not improvised by the model. What record is kept is written by the runtime, at the boundary, before and after every call. On none of those three questions is the model consulted. A model that is wrong, manipulated, or working against its operator has nothing to lie to and nothing to lie with.

That makes unified dispatch plus scoped tokens a candidate control plane for the places where agent behaviour has to be bounded and then audited: a development sandbox, tool use during training, an evaluation harness, a deployment. A rollout can run under a token whose tools, arguments, paths, uses and lifetime are fixed in advance, and the record of what it did and every point where it tried to exceed its grant is produced independently of its own transcript. Authority outside the model states that claim carefully, including what it would take to make it fully true.

What is true today is narrower, and worth saying exactly. The permission checker is implemented and live: eleven caveats, uses counted atomically along the chain, every use and refusal recorded with the caveat that refused it. No running agent of this build has been switched to scoped tokens; they still hold the build key, so the checker constrains only the holders it is given to. Containment would further require every agent switched, the build key withdrawn from them, no route around the runner, network egress forced through it, and an adversarial test of that boundary. None of those is done. The mechanism is built; the enclosure is not.

Where the design stops

  • area checks arguments that name a path. The text of a shell command is not a path argument, so an area restriction does not confine a shell tool. Do not give shell tools to a token you limit by area.
  • A token is a bearer credential unless it carries person. Whoever holds the string can use it within its limits.
  • Caveats are first-party only. The macaroon paper's third-party caveats, discharged by another service, are not implemented.
  • The checker reads tasks from the document the task list was kept in before it moved to a database table. A token bound to a task created since the move is refused as "does not exist" until the checker is pointed at the table.
  • GraphQL, WebSocket and server-sent-event forms are rendered but have no route; four forms run only on the owner's machine.
  • The general want envelope is a design. Projection runs today inside four tools, not at one door.

Prior work

The signature chain is the construction in Macaroons: Cookies with Contextual Caveats for Decentralized Authorization in the Cloud (Birgisson, Politz, Erlingsson, Taly, Vrable and Lentczner, NDSS 2014), over HMAC as specified in RFC 2104, with the payload in the URL-safe base64 alphabet of RFC 4648. The attenuation property is the object-capability pattern. What this implementation adds is the binding: every caveat is checked against a concrete tool call in one runner, uses and refusals enter one Ledger, and a task caveat turns those records into a page a third party can be shown. The MCP door exposes the result to any client that speaks the Model Context Protocol, which sees only the tools the token allows.

The rest of the series

  • The Directory and the Ledger: the catalog of rows that hold their own calls, and the append-only record of exact bytes that the runner writes to.
  • Atomic tooling: the tools behind the runner that keep orchestration out of the model, and the return budgeting described above.
  • Task provenance: what the task caveat produces, in full, and the article a task can become.
Related pages
References (18)
  1. Scoped access: the page the build writes from its own code — miscsubjects“Every capability of this build runs through one dispatch authority. A scoped token is a link-sized string that carries its own limits: which tools, by which doors, how many times, until when, for which task, inside which folders, for whom.”
  2. Scoped access: the chain — miscsubjects“The chain is the whole idea, borrowed from macaroons.”
  3. Scoped access: checking a token — miscsubjects“To check a token, the build recomputes the chain from its root and compares the last link. Change, reorder or remove any caveat and the chain no longer matches. A new build key changes the root and ends every token at once.”
  4. Scoped access: every limit — miscsubjects“A caveat this build does not know is a refusal, never a pass. A refusal says which caveat refused it, and is itself a Ledger row.”
  5. Scoped access: handing a token on, smaller — miscsubjects“They cannot remove a caveat, because they cannot compute a link backwards. So a model can give a helper agent exactly the part of its own access the helper needs.”
  6. Scoped access: what a use is — miscsubjects“A use is one tool run or one chat message; opening a page is not a use”
  7. Scoped access: turning a token off — miscsubjects“Turning off a token turns off every copy narrowed from it; turning off one copy leaves the token it came from working.”
  8. Scoped access: the proof page — miscsubjects“The worker could not leave a call out, because it could not act without the token, and it could not add one, because the build writes the record.”
  9. Scoped access: what is not yet switched — miscsubjects“No running agent of this build has been switched to scoped tokens”
  10. Scoped access: the MCP door — miscsubjects“and see only the tools the token allows.”
  11. Macaroons: Cookies with Contextual Caveats for Decentralized Authorization in the Cloud (NDSS 2014) — Google Research“macaroons embed caveats that attenuate and contextually confine when, where, by who, and for what purpose a target service should authorize requests”
  12. Macaroons: the construction — Google Research“Macaroons are based on a construction that uses nested, chained MACs (e.g., HMACs) in a manner that is highly efficient, easy to deploy, and widely applicable.”
  13. RFC 2104: HMAC — IETF“This document describes HMAC, a mechanism for message authentication using cryptographic hash functions.”
  14. RFC 4648: Base64 with URL and filename safe alphabet — IETF“This encoding is technically identical to the previous one, except for the 62:nd and 63:rd alphabet character”
  15. Object-capability model: attenuation — Wikipedia“given one reference of an object, create another reference for a proxy object with certain security restrictions, such as only permitting read-only access or allowing revocation.”
  16. Principle of least privilege — Wikipedia“least privilege is practiced by forcing a process to run with only those privileges required by the task”
  17. Model Context Protocol: a tool is a name — Model Context Protocol“Each tool is uniquely identified by a name and includes metadata describing its schema.”
  18. Authority outside the model — miscsubjects“In this build a model does not set its own authority”