Feature Request: claude remote-control --headless — daemonizable remote control without TTY dependency

Status Open
Maintainer reply None cached
Activity 7 comments · opened Mar 3, 2026

Summary

Remote control and headless mode are two powerful capabilities that solve complementary problems. Combining them would unlock a new class of deployment: always-on, remotely-accessible Claude Code instances on headless servers — no terminal multiplexer required.

The Architectural Insight

Today, three pieces exist independently:

| Capability | What it proves |
|---|---|
| Headless mode (claude -p) | The execution engine runs without a TTY |
| Remote control (claude remote-control) | The UI can live entirely on another device (phone, browser) |
| Remote control networking | Outbound-only HTTPS polling — no inbound ports, no local UI interaction needed |

When using remote control, the local terminal is rendering a mirror of what the remote client (claude.ai/code, iOS/Android app) already displays. The local TUI is redundant — the user is on their phone or browser, not looking at the server terminal.

Proposal

A --headless flag (or --daemon) for remote control:

claude remote-control --headless

Behavior:

  • Starts the execution engine + HTTPS polling loop as a plain process (no PTY required)
  • Prints the session URL/token to stdout, then runs as a background-friendly process
  • No local terminal rendering — all UI interaction happens on the remote client
  • Compatible with nohup, systemd, supervisord, Docker, or any process manager

Permission Handling — Remote Client as the Permission UI

In current remote control, permission prompts are already forwarded to the remote client (iOS app, claude.ai/code). In headless mode, this becomes the primary permission interface — the remote client isn't just mirroring a terminal, it's the only UI.

| Scenario | Approach |
|---|---|
| Interactive remote (typical) | Permission prompts appear on iOS / claude.ai/code. User approves from phone/browser. |
| Unattended / sandboxed | --dangerously-skip-permissions or --permission-mode for environments where no human is watching. |
| Semi-trusted | --allowedTools to pre-approve specific tools, prompt for everything else via remote client. |

This means the iOS app and claude.ai/code effectively become the permission controller for a headless instance — no local terminal needed for any part of the workflow.

Flag Compatibility

Existing CLI flags should compose naturally with headless remote control:

| Flag | Why it matters for headless RC |
|---|---|
| -r / --resume | Essential. Reconnect to an existing session after a process restart, server reboot, or crash. Without this, a daemon that restarts generates a new session URL every time. |
| --dangerously-skip-permissions | Unattended operation for sandboxed/trusted environments where the remote client may not be connected when a permission is needed. |
| --permission-mode | Finer-grained alternative — e.g., --permission-mode acceptEdits for semi-trusted setups. |
| --allowedTools | Scope what the headless instance can do (e.g., only Bash(git:*), Read, Edit), with remaining prompts forwarded to the remote client. |

Use Cases

Always-on dev server (systemd):

[Service]
ExecStart=/usr/local/bin/claude remote-control --headless
Restart=on-failure

Resilient daemon with resume:

# First launch: prints session URL
claude remote-control --headless \
  --session-id 550e8400-e29b-41d4-a716-446655440000 \
  > ~/rc-session.txt 2>&1

# After restart: reconnect to same session
claude remote-control --headless \
  --resume 550e8400-e29b-41d4-a716-446655440000

Quick background process:

nohup claude remote-control --headless > ~/rc-session.txt 2>&1 &
cat ~/rc-session.txt  # grab session URL, open on phone

Docker / cloud dev environments:

CMD ["claude", "remote-control", "--headless", "--permission-mode", "acceptEdits"]

SSH fire-and-forget:

ssh devbox 'nohup claude remote-control --headless > /tmp/session.txt 2>&1 &'
ssh devbox 'cat /tmp/session.txt'  # get URL, open on phone

Why This Is Not a TTY Bug

This is not about fixing stty ioctl errors when a TTY is absent (see #15428). This is a feature request for a new mode of operation where the local terminal rendering is intentionally removed because the remote client is the only UI. The execution engine and networking already work without a terminal — they just need to be offered as a first-class headless option.

Impact

Remote control is currently limited to machines where you can maintain an interactive terminal session (directly or via tmux/screen). This is ironic — remote control is designed to free you from being at your machine, but it still requires your machine to have an active terminal. A headless mode, combined with --resume for crash recovery and the remote client as the permission UI, would make remote control a true always-on development service.

View original on GitHub ↗

4 Comments

JOduMonT · 4 months ago

I'm all for this
But I'm also wondering if this isn't against their TOS.

attempting to automate context retention or session continuity.

Otherwise did you tried remote-control server-mode
https://code.claude.com/docs/en/remote-control#server-mode

fabiolr · 3 months ago

Use case: always-on coding daemon on a dedicated machine (Mac Studio)

I run Claude Code on a dedicated Mac Studio at my office and access it remotely while traveling internationally. The machine is always on and always connected. I want Claude to keep working on long-running tasks while I'm in transit, on a plane, or simply away from my laptop.

The current setup requires tmux to provide a TTY, which works but has two problems:

  1. It can't survive a reboot without manual SSH intervention to restart the tmux session and relaunch claude
  2. It's an unnecessary layer of complexity for what is fundamentally a daemon use case

A --headless flag for claude remote-control would let me run it as a proper launchd service on macOS — boot-persistent, auto-restarting on crash, no TTY dependency. I spent several hours trying to make launchd + tmux work reliably and hit the TTY wall every time.

The interaction model already supports headless perfectly: when using remote control, I'm on my phone or browser — not looking at the local terminal. The local TUI is rendering for nobody. The execution engine and the remote control networking clearly work without a terminal; the TTY requirement is the only blocker.

This is a real production workflow: dedicated always-on machine + remote supervision via mobile app. --headless would make it work properly.

fabiolr · 3 months ago
I'm all for this But I'm also wondering if this isn't against their TOS. > attempting to automate context retention or session continuity. Otherwise did you tried remote-control server-mode https://code.claude.com/docs/en/remote-control#server-mode

requires a TTY, the whole point of this request is to avoid that and make it truly headless.

Snailflyer · 3 months ago

The headless request makes sense, but I would keep one distinction explicit: removing the local TTY is different from preserving a durable session authority. The remote client should not become the authority by accident; it should attach to one host-side runtime that owns cwd, permissions, tool state, and receipts.

I have been testing the opposite conservative tradeoff in Faryo: keep the host CLI inside tmux as the live-process authority, then let phone/browser do compact output, short input, interrupt, and handoff into that same process. Redacted walkthrough: https://github.com/Snailflyer/faryo/releases/download/v1.0.7/faryo-public-redacted-same-session-handoff-walkthrough-20260528-0120.gif

For remote-control --headless, the acceptance test I would want is not just "the daemon stays up". It is:

  • after process restart/resume, the remote client is still bound to the intended session id;
  • permission prompts show host/session/cwd and return applied/rejected/stale;
  • an interrupt from mobile has an explicit applied/failed receipt;
  • if the runtime cannot preserve the same session, it says so instead of silently creating a new one.

Showing cached comments. Read the full discussion on GitHub ↗