# Always-on Remote Control Reference copy of a machine setup: Claude Code Remote Control running as its own system user `claude-rc`, so my projects' read-only MCP servers (now: negsplit, ens-forecast) can be used from the Claude app on the phone. One user and one session (`data`) for all projects. The user holds only read-only database logins; Bash runs sandboxed without network and can't read them (only the MCP servers, which run outside the sandbox, do). Nothing secret in this folder: the ntfy topic lives only in `/etc/claude-rc-notify.env`. Needs `claude-code`, `bubblewrap`, `socat` and each project's MCP server installed. Per project: - negsplit: the installed `negsplit` (with `python-mcp`) and the `garmin_ro` grants from its `sql/garmin_ro_grants.sql`. A per-user query limit is a useful safety net (the session can lift it): ``` mariadb -u root -p -e "ALTER USER 'garmin_ro'@'localhost' WITH MAX_STATEMENT_TIME 30;" ``` - ens-forecast: the installed `ens-forecast-mcp` (with `python-mcp` and `python-mysqlclient`) and the `weather_ro` grant from its `sql/weather_grants.sql`; the same safety net: ``` mariadb -u root -p -e "ALTER USER 'weather_ro'@'localhost' WITH MAX_STATEMENT_TIME 30;" ``` ## Setup Run from this folder. User and folders: ``` doas useradd --system --create-home --home-dir /var/lib/claude-rc --shell /usr/bin/nologin claude-rc doas chmod 700 /var/lib/claude-rc doas install -d -o claude-rc -g claude-rc -m 700 /var/lib/claude-rc/.config /var/lib/claude-rc/.claude /var/lib/claude-rc/data /var/lib/claude-rc/data/.claude doas install -o claude-rc -g claude-rc -m 644 mcp.json /var/lib/claude-rc/data/.mcp.json doas install -o claude-rc -g claude-rc -m 644 project-settings.json /var/lib/claude-rc/data/.claude/settings.json doas install -o claude-rc -g claude-rc -m 644 user-settings.json /var/lib/claude-rc/.claude/settings.json ``` `strictAllowlist` must stay in the user settings: in project settings it has no effect. Each project's config holds only a `[readonly]` section. negsplit (`garmin_ro`): ``` doas install -d -o claude-rc -g claude-rc -m 700 /var/lib/claude-rc/.config/negsplit doas install -o claude-rc -g claude-rc -m 600 config.toml /var/lib/claude-rc/.config/negsplit/config.toml ``` ens-forecast (`weather_ro`): only the `[readonly]` section of my own config, so the password never shows: ``` doas install -d -o claude-rc -g claude-rc -m 700 /var/lib/claude-rc/.config/ens-forecast awk '/^\[/ { keep = ($0 == "[readonly]") } keep' ~/.config/ens-forecast/config.toml | doas install -o claude-rc -g claude-rc -m 600 /dev/stdin /var/lib/claude-rc/.config/ens-forecast/config.toml ``` Log in, trust the folder and enable Remote Control once, interactively: ``` doas -u claude-rc sh -c 'cd /var/lib/claude-rc/data && exec claude auth login' doas -u claude-rc sh -c 'cd /var/lib/claude-rc/data && exec claude' doas -u claude-rc sh -c 'cd /var/lib/claude-rc/data && exec claude remote-control --name data --spawn session' ``` ntfy topic for the failure alert (subscribe to it on ntfy.sh), then the units: ``` doas sh -c 'umask 077; printf "NTFY_TOPIC=claude-rc-%s\n" "$(openssl rand -hex 16)" > /etc/claude-rc-notify.env' doas install -m 644 claude-rc.service claude-rc-notify.service claude-rc-recover.service claude-rc-recover.timer -t /etc/systemd/system/ doas systemctl daemon-reload doas systemctl enable --now claude-rc.service claude-rc-recover.timer ``` The service restarts with a growing delay (30 s to 10 min); after about 50 minutes of failures it gives up and sends the alert. The timer restarts it every 3 hours if it gave up, so a long network outage doesn't stop it for good. After upgrading a project's MCP server, or changing `mcp.json` or the settings, restart `claude-rc.service` so phone sessions use the new version. ## Adding a project Add its server to `mcp.json` and `mcp__` to the `allow` list in `project-settings.json` (plus a `Read` rule for its chart folder, if any), install its `[readonly]` config as above, reinstall the changed files and restart the service. ## Dead login ``` doas systemctl stop claude-rc.service doas -u claude-rc sh -c 'cd /var/lib/claude-rc/data && exec claude auth login' doas systemctl reset-failed claude-rc.service doas systemctl start claude-rc.service ```