Remote Control — drive a box from your phone
Claude Code has a native Remote Control (/remote-control <name>): the session keeps running on its box while you drive it from the Claude app › Code tab or claude.ai/code on any device — terminal, phone and browser share one live session.
Use it to stand up a backup-chief: a standby chief on a fleet box you reach when your main machine is closed. The box stays drivable locally over claude-fleet too — same parity.
The one gotcha — it needs a full-scope login
Remote Control refuses the fleet's headless setup-token (what claude-fleet reauth deploys) — that token is inference-only by design. The box needs a real claude auth login (subscription OAuth).
A remote-control box is a full-login box. Never
claude-fleet reauthit — that redeploys the inference-only token and silently re-breaks Remote Control. (See claude-fleet's README › A note on auth.)⚠️ Never
claude-fleet restartit either.restartrelaunches a plainclaude, dropping the--remote-control <name>flag — the device silently vanishes from the Claude app (the login stays fine, but RC is off). To restart an RC box, go through its unit:systemctl --user restart claude-tmux(carries the flag) → thenclaude-fleet up <host>to clear the bypass gate.
Enable it on a box (over claude-fleet/ssh — the parity)
- Swap to a full-scope login — only if the box is on a setup-token (
claude auth statusshowsauthMethod: oauth_token):- Disable the inference override claude-fleet injected (it exports
CLAUDE_CODE_OAUTH_TOKEN, which overrides any login):mv ~/.config/claude-fleet/env ~/.config/claude-fleet/env.disabled. - Log in via the headless paste-code flow — in a throwaway tmux window:
unset CLAUDE_CODE_OAUTH_TOKEN; claude auth login --claudeai. It prints a URL → the user opens it (signed into claude.ai), approves, and hands back the code → feed the code into the prompt.claude auth statusflips toauthMethod: claude.ai.
- Disable the inference override claude-fleet injected (it exports
- Restart the session onto the new login:
systemctl --user restart claude-tmux(on the box), thenclaude-fleet up <host>(from the command center) →ready. - Enable it:
claude-fleet send <host> "/remote-control <name>", then accept the Enable Remote Control menu (Enter). The pane shows/remote-control is active+ aclaude.ai/code/session_…URL. - Connect & verify: the user opens Claude app › Code — the session appears under
<name>. Record the box's full-login status in the fleet ledger (fleet.md) so it never getsreauth'd.
Durability caveats (state them honestly)
- Automate it via the launch flag. Bake
--remote-control <name>into the persistent unit's launch command (ExecStart=… exec claude --remote-control <name>), and it re-arms on every boot and restart with no manual/remote-controlstep.- After the unit (re)starts, run
claude-fleet up <host>to clear the bypass gate →ready. - The one catch: a plain relaunch — including
claude-fleet restart, see the warning above — bypasses the unit and drops the flag. Always restart through the unit.
- After the unit (re)starts, run
- Pair it with
--continueso the chief keeps its memory across crashes. Unit launch command:claude --continue --remote-control <name> || exec claude --remote-control <name>.- Every boot and restart resumes the existing conversation instead of starting blank; the
||fallback covers a box with no prior conversation. - A large resumed session pauses at a "resume from summary / full as-is" menu. Accept summary — full re-ingests the whole transcript against plan limits — and it is one Enter, or one
claude-fleet up <host>, away.
- Every boot and restart resumes the existing conversation instead of starting blank; the
- Reattach beats re-enable. On relaunch the session reattaches to its existing remote session and un-archives it server-side — the app shows the same
<name>entry, not a new one.- If the app shows it disconnected after an outage, restart through the unit and refresh the Code tab; check the archived list too.
- Never paste
/remote-controlinto a running session via tmux — it reaches the model as a prompt, not the TUI.
A slash command sent through the remote channel arrives as plain text
A /goal driven from the app does not become a contract. It lands as an ordinary message whose
text happens to begin with a slash, so the session reads it and does not bind to it.
- Dispatch a contract through tmux, never through the app.
- From a phone, send an instruction rather than a contract — plain text works on either channel.