Never From a 6-Inch Screen: Write a Remote-Approval Policy

A remote approval policy for coding agents: what a phone may approve, what never goes remote, and a presence-marker hook plus a monthly drill to hold the line.

Remote approval policy: a phone showing an approval card on one side, a desk on the other, and a boundary line between them marking which approvals may crossRemote approval policy: a phone showing an approval card on one side, a desk on the other, and a boundary line between them marking which approvals may cross
Small screen, small decisions. Anything standing, paid or irreversible waits for the desk.

An Approve button on a lock screen carries the same authority as the Enter key at your desk, with a fraction of the context. The agent is waiting on a shell command longer than the screen is wide, and every coding agent with remote control will let you tap that button from wherever you are.

That is the feature working as designed, and it is why you need a remote approval policy. Claude Code forwards permission prompts to your phone and keeps them open until you answer, and Codex, Antigravity and Kimi Code all accept approvals from a phone or a browser. What none of them documents is a way for an admin to say which actions may be approved from a small screen and which must wait for the desk. That line is yours to draw.

By Tuesday you want three things. A small-screen matrix that sorts every action class into allowed remotely or never remote. Three enforcement layers, each written on the assumption that the other two failed. And a monthly drill in which you try to break the policy from your own phone.

Where the transcript of those approvals ends up is a separate question with its own runbook: what each vendor’s remote control stores.

Four vendors now forward agent approvals to a phone or a browser

Anthropic’s Remote Control docs are the most detailed. “Claude Code keeps permission prompts and AskUserQuestion questions open until you answer them.” From the phone or the web you can also run /model, /effort, /fast, /color and /rename with a value; from the Claude phone app, /config takes key=value to change a setting. /mcp can reconnect, enable or disable servers, while /plugin and /resume stay local.

Anthropic also keeps two money prompts off the phone on purpose. “On Team and Enterprise, /usage-credits from mobile or web doesn’t send a usage-credits request to your admin. Sending requires a confirmation that appears only in the interactive CLI.” The Fable usage-credits consent prompt isn’t forwarded at all, and the turn ends unsent if nobody answers at the machine. Remote Control itself “is off by default on Team and Enterprise plans.”

OpenAI’s Codex Remote page opens with “Follow progress, approve actions, and send instructions from your phone.” Its prose lists “Approve commands and other actions.” The page’s illustration of an approval shows two buttons, Approve and Always approve, and nothing on the page says what the second one persists, for how long, or where. The remote connections page adds the reassuring half: “The sandboxing settings, security controls, and action approvals still apply to the connected session.”

Google’s Antigravity docs cover Antigravity 2.0 and the CLI. Tool confirmations (y/n) and clarifying questions can be answered “from either your local terminal or the remote UI.” Then comes a line Anthropic doesn’t draw: “You cannot toggle settings in the settings panel from the remote web interface; to change settings, use the CLI.”

Google Antigravity Docs Remote Control page, showing the feature available on Antigravity 2.0 and Antigravity CLI and described as driving desktop sessions and CLI instances from any web browser, above the steps for enabling it in Settings Screenshot: Google Antigravity Docs, “Remote Control | Google Antigravity Docs” (undated page), captured Sep 28, 2026.

Kimi Code went furthest in the other direction. Its 0.42.0 release on Sep 9 removed the experimental flag, and its Remote Control guide lets a remote page “approve or deny file edits, Shell execution, and other confirmation requests right in the web page”. The guide shows no setting that restricts what may be approved there, and it warns that anyone who has the link “may control your sessions and files.”

Put the four pages side by side and one row is empty everywhere. No vendor documents a way for an admin to choose which actions may be approved remotely. The documented levers are surface switches: on or off for an org, a workspace, a device or an account. Not documented is not the same as impossible, but it means the per-action line has to live somewhere you control.

Why a tap on a phone is a different approval from a keypress at the desk

At the desk, an approval arrives with context: the whole command, the diff, the scrollback, the other terminal where the tests just failed. On a phone it arrives as a summary and a button, usually while you are doing something else. The action is identical. The decision is not, because the evidence you decide on has shrunk to whatever fits.

Some remote taps also outlive the moment. A /model <name> sent from a device to an interactive session “also sets your default for new sessions” in Claude Code v2.1.238 and later, while a model picked from the device’s own model control is session-only. Codex’s Always approve button, going by its label, covers more than one action, and its docs don’t say how much more. Forwarded dialogs that aren’t approvals expire after five minutes by default (dialogExpiry, v2.1.224 and later) and continue with the no-action default, so a missed buzz can make a choice for you.

Chatbots suggest; agents act, and an approval is the moment an agent’s action gets your name on it. A remote approval policy decides how much evidence your name requires.

Step 1: Keep your consequence tiers, and add a surface column

You probably already tier agent actions by consequence, from read-only up to production and secrets. Keep those tiers exactly as they are; approval queue hygiene covers how to build them. The remote approval policy adds one column to that table, headed “from a phone?”, and one test for filling it in.

An action may be approved remotely only if it passes all four checks:

  1. One-shot. It grants this action once, not a class of actions from now on.
  2. Fully visible. The whole command, the whole diff or the whole question fits on the small screen without truncation.
  3. Reversible. A revert, a re-run or a branch delete undoes it.
  4. Lower tier. It sits below whatever tier you reserve for production, money and credentials.

Fail any one and the action is never remote. The checks are deliberately blunt, because the moment you apply them is the moment you have the least context. Permission-mode switches fail check 1 by design; unified permission modes explains why a mode is a standing approval with a friendlier name.

Step 2: Write the small-screen matrix

Run every action class through the four checks and write the result down. This is the matrix most fleets end up with; adjust the examples, not the logic.

Action class Examples From a phone Check it fails
Answer a clarifying question AskUserQuestion, Antigravity clarifying questions Allowed None; the agent still acts at its own tier
One-shot read or test command git status, the test suite inside the sandbox Allowed None
One-shot edit on a feature branch A single file edit whose diff fits the screen Allowed None, if the diff fits
Session cosmetics /rename, /color Allowed None
Standing approvals Always approve, allowlist edits, permission-mode changes Never One-shot
Mode and settings changes /config key=value, /effort, /model <name> Never One-shot; /model sets the default for new sessions
Paid meters /fast, usage-credit requests, model upgrades Never Lower tier: spends money you can’t see from the phone
Deploys and production Deploy scripts, production database commands Never Reversible, lower tier
Secrets Reading or writing credentials and key files Never Lower tier
Force-push Rewriting shared branch history Never Reversible
MCP auth Authorizing or enabling an MCP server, /mcp enable Never One-shot: new tools and new credentials in one tap

The paid-meter row has vendor precedent. Anthropic already refuses to send a Team or Enterprise usage-credits request from a phone, and it keeps the Fable consent prompt at the machine. It still lets /fast run from the phone, and per its fast mode docs that speed tier draws on usage credits.

The vendor drew half the line. Your matrix draws the rest, and the speed budget runbook sets what /fast may cost when it is approved at the desk.

Step 3: Map the matrix onto what each vendor actually lets a phone do

The matrix is your policy. Each vendor’s remote surface is what that policy has to survive. Line them up, using only what the docs say today, and the gaps you need to close yourself become obvious.

From a phone or browser Claude Code Codex Antigravity Kimi Code
Approve tool or permission prompts Yes; prompts wait until answered Yes: “Approve commands and other actions” Yes: y/n confirmations Yes: file edits, shell and other confirmations
Standing approval Not documented Always approve button shown; what it persists is not documented Not documented Not documented
Change settings Yes: /config key=value from the phone app Not documented No: settings are CLI-only Not documented
Paid meters /fast works; the Team and Enterprise /usage-credits send is CLI-only Not documented Not documented Not documented
Switch the model /model <name> also sets the default for new sessions Not documented Not documented Not documented
Admin scoping of remote-approvable actions Not documented Not documented Not documented Not documented
Surface off-switch Org toggle, off by default on Team and Enterprise; disableRemoteControl per device Workspace admin enablement; sign-out Account or organization policy flag None documented
Device binding Trusted Devices (beta): enrolled device, sign-in under 18 hours old QR pairing per phone, per host The same Google Account About three devices; the link itself grants control

Chart of what a phone may do in four coding agents per their docs on Sep 28, 2026: all four approve tool prompts remotely, Claude Code also changes settings and toggles fast mode, Antigravity refuses remote settings changes, Codex shows an unexplained Always approve button, and no vendor documents admin scoping of remote approvalsChart of what a phone may do in four coding agents per their docs on Sep 28, 2026: all four approve tool prompts remotely, Claude Code also changes settings and toggles fast mode, Antigravity refuses remote settings changes, Codex shows an unexplained Always approve button, and no vendor documents admin scoping of remote approvals Documented capabilities only, read Sep 28, 2026. The bold row is the one this policy exists to fill.

Three patterns fall out. Claude Code gives the phone the most power and the most controls, including the only requirement in the group for a recent sign-in on a known device. Antigravity is the one vendor that keeps settings off the remote surface by design. Codex and Kimi Code document approvals and little else: Codex adds admin enablement on top of its existing sandbox and approval settings, and Kimi Code documents no admin controls.

Step 4: Enforce the line in three layers, each assuming the others failed

No single control covers the matrix. The vendors’ switches work at the level of the surface (on or off), and your matrix works at the level of the action. You need both, plus a check that lives on the desk where the phone can’t reach it.

Layer 1: turn remote control off on top-tier lanes

Some lanes exist to do never-remote work: the one with deploy keys, the one attached to the production database, the one that manages secrets. On those lanes the phone should not connect at all. In Claude Code that is disableRemoteControl in managed settings, applied per device and independent of the organization toggle; the residency runbook has the managed-setting shape and what it misses. For the other vendors, use their surface switches from the table and keep top-tier work off lanes that have none.

This layer fails open in one predictable way: a personal device outside your management. The wall behind it is where the credentials live. A lane that never holds deploy keys can’t deploy, whoever approves.

Layer 2: bind remote access to known devices

Codex pairs each phone to each host, and Kimi Code caps you at about three devices, but only Claude Code’s Trusted Devices setting adds a recent sign-in to the device check. Per the Trusted Devices docs, “It ties Remote Control access to a known device and a recent authentication, not just a signed-in account.” A Team or Enterprise Owner turns on Require trusted devices under Organization settings, Capabilities, Remote sessions; Pro and Max users turn it on for themselves. The member’s sign-in “must be no more than 18 hours old,” refreshed by Face ID, Touch ID, Windows Hello or a passkey, and enrolled devices can be listed and revoked.

Claude Code Docs Remote Control page, Trusted Devices section, with the steps to turn on Require trusted devices for an organization and the note that the setting applies to every member, is not retroactive, and cannot be scoped per team or per project Screenshot: Claude Code Docs, “Continue local sessions from any device with Remote Control - Claude Code Docs” (undated page), captured Sep 28, 2026.

Read the limits before you rely on it. Trusted Devices is in beta and off by default on every plan. It applies to every member of the organization: “Per-team or per-project scoping is not available.”

That sentence is about the Trusted Devices setting, not about remote permissions, and it means you can’t require stricter devices for the payments team alone. And sessions already running when you flip it “are not retroactively protected and continue without the device requirement until they end.” Turn it on, then restart the long-running sessions.

Layer 3: a desk-presence check before top-tier tool calls

The last layer is ours, not a vendor’s. A local PreToolUse hook runs before each tool call, classifies it against the matrix, and refuses a top-tier call unless a presence marker on the desk machine was touched in the last few minutes. The marker is a file that only a desk-side action updates, such as a keyboard shortcut or a screen-unlock script, and never a command the agent can run. Approve a deploy from the train and the hook blocks it with a message; approve it at the desk and it runs.

Don’t confuse this with Claude Code’s own CLAUDE_CLIENT_PRESENCE_FILE. That variable points at a real vendor presence marker, but it only suppresses push notifications while the file exists. It does not gate approvals.

Flow diagram of our illustrative presence-marker hook for a remote approval policy: a tool call goes to a PreToolUse hook that classifies it; lower-tier calls get a normal approval that a phone may give; top-tier calls run only if the desk presence marker is fresh and are blocked otherwise; any hook error or unreadable input also blocksFlow diagram of our illustrative presence-marker hook for a remote approval policy: a tool call goes to a PreToolUse hook that classifies it; lower-tier calls get a normal approval that a phone may give; top-tier calls run only if the desk presence marker is fresh and are blocked otherwise; any hook error or unreadable input also blocks Our pattern, illustrative only. The hook fails closed: an error blocks the call rather than waving it through.

The config and script below are an illustrative sketch of that pattern, not vendor documentation; check your harness’s hook contract for the exact settings shape and blocking exit code before you rely on it.

// settings (illustrative): run the presence check before shell and file tools
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Edit|Write",
        "hooks": [{ "type": "command", "command": "~/.fleet/hooks/require-presence.sh" }]
      }
    ]
  }
}
#!/usr/bin/env bash
# require-presence.sh: illustrative sketch of our pattern, not a vendor feature
set -u
MARKER="$HOME/.fleet/at-desk"   # touched only by a desk-side shortcut; deny the agent write access to it
MAX_AGE=600                     # seconds since the last touch
TOP_TIER='deploy|terraform apply|kubectl|prod|push (-f|--force)|\.env|secret|mcp (add|auth|enable)'

input="$(cat)" || exit 2                                     # unreadable input: fail closed
target="$(printf '%s' "$input" | jq -r '.tool_input.command // .tool_input.file_path // empty')" || exit 2

printf '%s' "$target" | grep -q 'at-desk' && { echo "The presence marker is desk-only." >&2; exit 2; }
printf '%s' "$target" | grep -Eq "$TOP_TIER" || exit 0      # lower tier: normal approval, phone allowed

touched=$(stat -c %Y "$MARKER" 2>/dev/null || echo 0)       # GNU stat; use stat -f %m on macOS
age=$(( $(date +%s) - touched ))
printf '%s\t%s\t%s\n' "$(date -u +%FT%TZ)" "$age" "$target" >> "$HOME/.fleet/top-tier.log"
[ "$age" -le "$MAX_AGE" ] && exit 0
echo "Top-tier action: approve it at the desk. Presence marker is ${age}s old." >&2
exit 2                                                       # block

Three honest limits. First, a PreToolUse hook sees tool calls, not slash commands, so it cannot stop /config, /fast or /model sent from a phone; on lanes where those matter, only Layer 1 helps. Second, a pattern list is a guardrail, not a boundary: a determined command can dodge a regex, which is why top-tier credentials stay off lanes that allow remote control at all. Third, the log line is the only record of whether an approval happened with someone at the desk, because no vendor documents an audit field for which surface answered a prompt.

Step 5: Drill it monthly from your own phone

A policy nobody has tried to break is a hope with a heading. Once a month, leave the desk, pick up the phone, and attempt one never-remote action per lane. Use canaries rather than real deploys: a harmless command that matches your top-tier pattern, such as an echo that contains the word “deploy”, exercises the hook without touching anything.

Attempt from the phone Expected result If it succeeds
Approve a top-tier canary command with the marker stale Hook blocks it with the desk message Fix the pattern list or the hook’s exit path
Connect to a top-tier lane at all No connection: remote control is disabled there Push the managed setting again; find the device that lacks it
Connect from a phone that isn’t enrolled Refused under Trusted Devices Check the org setting and restart sessions older than it
Send /fast on or a /config change to an ordinary lane It works; that is the documented gap Move the lane’s paid or sensitive work behind Layer 1
Tap Always approve where offered Your runbook says never; the product won’t stop you Revoke the standing grant, then retrain the habit
Break the hook on purpose, such as a missing jq Top-tier calls block Make every error path exit as a block

Write the results into the same log the hook writes, with the date and the phone used. Then revoke what the drill turns up: devices belonging to people who left, stale pairings, and any Kimi Code link that has travelled further than you meant it to.

Remote approval policy failure modes, and the signal for each

The standing grant from the train. Someone taps Always approve or approves an allowlist edit from the phone, and a class of actions stops asking. Signal: a prompt you used to see on that lane no longer appears. Fix: review standing grants on a schedule, and make the matrix row “never” in the runbook, not just in your head.

The default that moved. A /model <name> sent from the phone changed the default for every new session. Signal: new sessions start on a model nobody configured. Fix: put /model in the never-remote row, and check the default as part of the drill.

The session older than the rule. Trusted Devices went on last Tuesday, and a session started last Monday is still running without it. Signal: long-lived sessions whose start time predates the setting. Fix: restart them.

The dialog that answered itself. A forwarded dialog that isn’t an approval expired after five minutes and took its no-action default. Signal: a choice in the transcript nobody remembers making. Fix: learn each dialog’s no-action default, and keep decisions that matter in permission prompts, which wait.

The hook that fails open. A missing dependency or a parse error lets the script exit cleanly. Signal: the drill’s broken-hook row succeeds. Fix: every error path exits as a block, and the credentials stay off lanes where the hook is the only wall.

The link that is a key. A Kimi Code remote link pasted into a ticket gives its reader control of the sessions and files behind it. Signal: link strings in chat exports. Fix: stop Remote Control on that machine and treat the link as leaked until Kimi ships its revocation UI.

A remote approval policy is fleet policy, not a phone setting

Every vendor now ships the approval surface, and none ships the line. So the line gets written once, in the matrix, and enforced per lane with whatever each vendor allows: a managed setting here, a policy flag there, a device check where one exists, and the same desk-side hook wherever the harness runs hooks. That is fleet policy in the sense of restricted mode as fleet policy: one rule, many harnesses, checked on a schedule rather than trusted.

It also sits beside the other rules a user can’t override from wherever they happen to be. Non-overridable agent permissions covers the deny rules that should hold no matter who approves, and the admin-toggle sweep keeps the vendors’ own remote switches from flipping under you. The phone is a fine place to answer a question. It is a bad place to change what the fleet is allowed to do.

FAQ

Is it safe to approve agent actions from my phone?

For one-shot, fully visible, reversible, low-tier actions, yes: answering a question or approving a test run is fine. Never approve standing grants, settings or mode changes, paid meters, deploys, secrets, force-pushes or MCP authorization from a phone. Enforce that with off-switches on top-tier lanes, device binding and a desk-presence check.

Can admins restrict which actions are approved remotely in Claude Code?

Not per action. Anthropic documents an organization toggle, the per-device disableRemoteControl setting and Trusted Devices, which applies to every member and can’t be scoped per team or project. As of Sep 28, 2026, no vendor documents admin scoping of remote-approvable actions, so the per-action line needs your own hook.

What does Claude Code’s Trusted Devices setting require?

An enrolled device and a sign-in no more than 18 hours old, refreshed with Face ID, Touch ID, Windows Hello or a passkey. It is in beta and off by default on every plan. Owners enable it for Team and Enterprise; Pro and Max users enable it themselves. Running sessions aren’t retroactively protected.

Sources

YOU'RE THROUGH THIS ONE.

Keep connecting the dots.

Back to the library