rdmsm4x-changelog-20260825-1319-claude-remote-control-boot-service
Claude Code Remote Control now runs as an always-on LaunchAgent on rdmsm4x, so a session is reachable from claude.ai/code and the Claude mobile app with nobody at the terminal. Installed, self-heal tested, and verified end to end.
- Scope: rdmsm4x only. Researched and driven from rdmbair15m5 over SSH.
- Started: 2026-08-25 13:00 EDT (research) · Service live: 13:15 EDT · Closed: 13:19 EDT
What changed on rdmsm4x
| Path | Change |
|---|---|
~/scripts/claude_rc_service.sh |
NEW v1.1.1, mode 755. Self-contained:
install / status / restart /
uninstall / logs + internal run
(launchd entry point). |
~/Library/LaunchAgents/net.dataroo.claude-rc.plist |
NEW. RunAtLoad,
KeepAlive, ThrottleInterval 60,
WorkingDirectory ~/dev. |
~/Library/Logs/claude-rc/ |
NEW. claude-rc.log (rotates at 4 MB,
one .1 kept) + tiny launchd.log. |
~/dataroo.net/wiki/claude-remote-control-service-research.html |
NEW. Published research/design page, v0.2. |
~/Desktop/claude_remote_research_ver0.2_20260825.html |
NEW. Copy for Rich. v0.1 removed. |
Not changed, deliberately:
~/.claude/settings.json was NOT touched.
permissions.defaultMode stays
bypassPermissions — that key is Rich's alone and no agent
writes it. No credential was written to disk and no long-lived token was
created.
Service definition
claude remote-control \
--remote-control-session-name-prefix rdmsm4x \
--spawn same-dir \
--capacity 4
Run from ~/dev. The wrapper unsets
ANTHROPIC_BASE_URL, ANTHROPIC_API_KEY,
DISABLE_TELEMETRY, DO_NOT_TRACK,
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC and
DISABLE_GROWTHBOOK — each silently disables Remote Control
and a LaunchAgent can inherit them. --verbose is
deliberately omitted: it dumps entire SessionStart hook payloads as
JSON.
Why a LaunchAgent and not a LaunchDaemon
Claude Code on macOS keeps its live OAuth
credentials in the login keychain — verified by
watching
security find-generic-password -s "Claude Code-credentials"
refresh its mdat on use (rdmbair15m5 2026-08-25 16:58Z,
rdmsm4x 11:31Z). ~/.claude/.credentials.json is a
stale leftover on both hosts (rdmsm4x copy mtime Aug 24
07:36, its token already expired Aug 24 15:36) and must not be designed
around. The login keychain is locked until a GUI login, so a
system-domain daemon cannot authenticate. That, not launchd, was the
real pre-login blocker.
Verification evidence
| Check | Command | Result |
|---|---|---|
| Server mode runs headless | launched with stdin a pipe, stdout a file, no TTY | Registered, printed a session URL. No tmux/pty needed. |
| Install preflight | bash claude_rc_service.sh install |
binary, execute bit, workdir, workspace trust, RC consent all PASS |
| Registers a session | log scrape | session_01VLWyy76x9A9G9G3xzFUrBe |
| Self-heals | kill -9 80639, wait 75s |
new pid 81711, runs = 3,
state = running |
| Restart does not orphan | compared session URL before/after kill | same session reattached (~4h recovery window) |
| Reachable cross-host | listed + messaged from rdmbair15m5 | appears as rdmsm4x-ethereal-squirrel |
| End to end | asked the session to run 4 commands | replied rdmsm4x / /Users/richh/dev /
13:18:49 EDT / pid = 81711 |
Decisions Rich made (2026-08-25)
- Boot resilience: keep FileVault, use a LaunchAgent.
Accepted trade — a cold boot needs a human at the unlock screen. Use
sudo fdesetup authrestartfor planned reboots. - Topology:
~/devwith--spawn same-dir.~/devis trusted but is NOT a git repo, so--spawn worktreewas unavailable there. - Permissions: inherit
bypassPermissions. - Concurrency:
--capacity 4(default is 32; the box hit load 71 during a build).
Outstanding / known limits
- Cold boot still needs a human. FileVault On + no
auto-login (macOS refuses auto-login while FileVault is on).
fdesetup authrestartcovers planned reboots; power loss and kernel panics do not have a software answer. A UPS is the cheapest way to close that gap without dropping encryption — not purchased, Rich's call. - The service inherits
bypassPermissions, so an always-on phone-reachable session rooted at~/devcan act without prompting. Deliberate, and narrowable at the service level later without touching the global setting. - rdmsm4x was at load 15–71 on 16 cores during this work. Capacity 4 was chosen with that in mind.
Post-install fix: log volume (v1.1.1, 13:39 EDT)
The first run produced a 471 KB log in 20 minutes
with no --verbose. Cause: server mode repaints its status
block roughly once a second. On a TTY that repaints in place; to a FILE
every repaint is appended. Measured 1099 copies of "space to show QR
code" in 20 minutes, ~1.2 MB/hour of noise burying anything
diagnostic.
Two things made naive fixes fail, both caught by testing before deploying:
- macOS
/usr/bin/awkis BWK awk and has nostrftime()— the first filter died on every line. Rewritten in python3. - Consecutive-dedup is insufficient. With two sessions live the status block lists each on its own line, so the lines ALTERNATE and no two identical lines are ever adjacent. Replaced with time-windowed suppression (300s TTL, reports how many repeats were swallowed).
- Session ids live inside OSC-8 hyperlinks, so stripping OSC removed the id too and the filter reported zero session URLs. Fixed by matching the id on the RAW line first.
Regression-tested against two real captures before shipping: 3387 lines -> 11, and the alternating two-session case 128 lines -> 11.
Result measured in production: 454 bytes in 90
seconds, versus 471 KB for a comparable window before.
status still finds the session URL, which is what it greps
for.
Also changed: the wrapper no longer execs claude, so it
survives to log the child's exit status
(claude exited rc=N). launchd still restarts on wrapper
exit via KeepAlive.
How to undo
bash ~/scripts/claude_rc_service.sh uninstall # bootout + remove the plist
rm -f ~/scripts/claude_rc_service.sh
rm -rf ~/Library/Logs/claude-rc
rm -f ~/dataroo.net/wiki/claude-remote-control-service-research.html
Nothing else was modified; there is no other state to reverse.
Related
- Published page:
https://dev.dataroo.net/claude-remote-control-service-research.html(Basic-auth gated; served from~/dataroo.net/wikivia the nginx container on 127.0.0.1:8787 behind cloudflared) - Fleet bus request to
claude@rdmsm4xfor a canonical to-do/intake folder: message20260825-131046-EC786538, topicfleet-todo-intake-folder