Policy

Your rules decide what the agent may do on its own, what waits for your click, and what is refused outright. They live in the app as plain sentences, a pure engine enforces them with no model in the path, and no proposal reaches execution without either your click or an allow inside limits you wrote. This page explains the rules, the click threshold, the click that follows a web page, how a rule changes, and why the gate has no off switch.

The rules#

A fresh install ships with four rules:

Refuse any single transaction above $10,000.
Refuse more than $25,000 in any 24 hours.
Ask me before anything above $100.
Ask me once auto-approved moves pass $500 in 24 hours.

The first two are hard caps: nothing above them runs, click or no click. The third is the click threshold. The fourth is a daily ceiling on what runs without you: once the moves the policy approved on its own pass $500 in a day, the next one waits for a click however small it is.

Three more kinds of rule exist and appear only once you set them: a cap on how much of your holdings one stablecoin issuer may hold ("Tether may not exceed 30% of holdings"), a cap on how much may be freezable by an issuer ("No more than 20% of holdings may be freezable"), and a list of issuers the app may never move funds into. These judge the state a move would leave behind, so a portfolio already past a cap cannot make further moves until you change the rule or the breach clears.

The last line, when it shows, is the brake: "KILL SWITCH ON: all writes refused." That is Freeze everything in the top bar, see Getting started.

The click threshold#

The click threshold splits every write into two kinds. At or below it, the policy engine decides alone and the move may execute at once, with no click and, on a Touch ID wallet, no Touch ID, as long as the vault is open. Above it, nothing happens until you click. The Vault tab's Policies row says it as Asks you above $100: "Anything above this waits for your click."

This convenience applies only to money that stays in your own custody: a swap inside NEAR Intents, funding the Hyperliquid account, arming a trade. Four moves wait for a click at any size, and the policy engine never executes them on its own:

  • A send, because the money leaves for somebody else. See Money.
  • A withdrawal from Hyperliquid. See Money.
  • A top-up from your vault, once it is on Touch ID. See Money.
  • A policy change, because a rule the human did not click is how every other guarantee gets removed.

Three more cases wait for a click whatever their size: a swap the app cannot measure, because it spends a coin the app cannot price, one whose listed price nothing in the quote can check, a coin 1Click puts no dollar figure on, or a price from the solver relay it could not check against a quote 1Click signed (see Money); a swap while an earlier swap of the same coin may still go through; and every move an agent proposes after it read text from outside Phosphor (see below). Once your vault is on Touch ID, a move that spends more than your allowance holds waits for a click too.

A move that waits is one card in the chat that says Needs your OK. It shows what leaves and what arrives at least, its Details say why it asks, and it has two buttons: Cancel and Approve. On a Touch ID wallet Approve then asks for Touch ID, and the card says Confirm on your Mac until you answer.

If a hostile process running as you is in your threat model, lower the threshold in the Vault tab, or ask your assistant to set it to zero: at zero every move waits for a person. Security says why that is the one exposure that remains.

After a web page#

Once the agent in the chat has searched the web, read a page, or read a stranger's words through Phosphor (news headlines, token names and memos on a chain, or a venue's own words that Phosphor does not know: an error from 1Click, the solver relay, Hyperliquid or a chain's node, a refund reason or status word off the venue's list, the NEAR Intents status page's title), every money move it proposes in that chat waits for your click, whatever its size, until the chat starts a new session (the agent restarts, or you start a new chat). The card says why under its head: "This chat read text from outside Phosphor, so this move waits for your OK." A chart label, a plan note or a highlight the agent writes after a web read carries the same mark, and an agent that later reads one is marked too. So do a board post and a worker's report, and a worker that a marked agent starts begins marked. A move that would have been refused is still refused; the mark only turns a move that would have run on its own into one that asks. Security says why.

An ordinary refusal Phosphor knows (too little margin, an order under the venue's minimum, a price too far from the market, an amount under a route's minimum) reaches the agent in Phosphor's own words and changes nothing; the card still shows the venue's exact words.

An agent you started outside Phosphor#

An agent in your terminal or in another app attaches with a secret the app writes into its data folder, and any program running as you can read that folder. So the first time one uses Phosphor, the window asks whether to let it in ("Claude Code wants to use Phosphor"), and until you allow it, every money move it proposes waits for your click, whatever its size. The card says under its head: "This agent was started outside Phosphor and is not allowed yet, so this move waits for your OK." Allow lets its next moves run under these rules like the chat's own agent, and a move it already asked for still waits; Ask each time keeps every one waiting, and its row in the conversation keeps a Change that asks again. An Allow holds for that one connection: restart the agent and the window asks again. Phosphor cannot see what such an agent reads with its own tools, so a read it makes through Phosphor (news, a chain read) still marks it as above, and the card says to allow only an agent you started yourself. It cannot read a page through Phosphor: web_read opens only an address a search in the chat returned or you typed in the chat.

After a move that did not go through#

When a move your agent proposed does not go through, the app wakes the agent to tell you in one line, without waiting for your next message. Nobody typed that turn, so every money move the agent proposes in it waits for your click, whatever its size. The card says under its head: "Your agent asked for this on its own after a move did not go through, so it waits for your OK." The mark ends with that turn, and a move that would have been refused is still refused.

Policy as sentences#

The policy is stored as a file but read as English. The sentences are rendered from the file by a pure function, so what you read is what the engine enforces, and there is no second version anywhere. You see them in three places. Policies on the Pro tab draws three of them as dials (Asks you above, Never more in one move, and what ran on its own today), with the daily cap under them. The Policies row in the Vault tab lists every rule that is set: Asks you above, Largest move, In any 24 hours, Without asking, and where money may go. Policies on the Basic tab takes you there. And the policy_show tool gives your assistant the sentences themselves.

Limits that mean something at their default always render. Opt-in restrictions render only once set, because "no issuer may exceed 100%" says nothing. The kill switch line always renders last.

Changing a rule#

Besides Freeze, the click threshold is the one rule you can change in the window. In the Vault tab, press Change beside Asks you above, type an amount or pick $25, $100, $500 or $1,000, and press Save. That is your own click, and the audit log records it as a human change. The amount must be above $0 and under the per-transaction cap, or it is refused with the reason.

Every other rule, and a threshold of zero, changes through your assistant. It proposes the change with propose_policy_change, carrying the patch and a sentence that says what it means, and the card is headed Change your limits. It always lands as something to click, however small the change.

The engine holds a patch to these rules before it ever reaches you:

  • The kill switch, the file version and the rendered sentences cannot be patched at all.
  • A patch is checked against the schema, and an unknown field refuses it. A patch that names no rule is refused as nothing to change.
  • No click can set a limit above $1,000,000 per transaction or $10,000,000 per day or session. Going higher is an edit to policy.json by a person, not a patch.
  • The click threshold must sit strictly under the transaction cap, or nothing would ever wait for you. A patch that moves one past the other is refused and told to carry both.
  • A patch may add a destination, a forbidden issuer or an issuer cap, and may move a cap that stays. Removing one is refused: that is a decision for the policy file, not a click.
  • The sentence must say what the patch does, on one line, with every figure it moves. A patch whose sentence names a different number, or leaves one out, is refused. An accepted change carries before and after for every limit it touches, and the card shows both.

One click moves a limit to what the sentence says. There is no longer a ten-times-per-step rule: the walls above are what hold a patch, and the click is what accepts it.

The three verdicts#

The engine returns exactly one of three verdicts, and there is no fourth:

  • Refuse: nothing happens. The refusal names the rule and the reasons, and both are logged.
  • Needs approval: the proposal is saved as pending and drawn as a card in the chat with its simulation. It executes only after your click.
  • Allow: inside every cap and at or below the threshold, so the app executes it and logs the verdict that let it.

The chain runs in a fixed order and stops at the first refusal: the policy file is unreadable, the kill switch is on, the move is not a rail this app runs, the amount the app priced is not a positive number, the venue or the account the money lands in is not allowed (a send is the exception: its receiver is yours to check, and the click stands in for a list), the per-transaction cap, the rolling 24 hour cap, then the composition rules. What is left is judged against the click threshold and the daily ceiling, and only then allowed. Every rail then simulates before anything is signed, and a simulation that fails is a refusal, never a pending card you could click.

There is no override argument, no force flag and no "the user said it was fine" field anywhere in the tool surface. An agent that dislikes a refusal has one recourse: propose a rule change, which waits for your click.

Why the gate has no off switch#

There used to be one. A setting turned the gate off so a rail could be exercised without a click on every proposal, and it was the one deliberate hole in the model. It is gone. There is no flag, no environment variable, no proposal kind and no configuration that reaches execution without either your click or a policy allow inside limits you wrote.

The audit log records who decided every executed move: human for a click, policy for an allow. Only a click is recorded as human, and a click needs the window token the agent never holds, see Security. A pending card cannot be dismissed from the chat: if the agent disconnects, the card is still there and still yours to decide.