101 lines
3.8 KiB
Markdown
101 lines
3.8 KiB
Markdown
# claude-rc
|
|
|
|
Run **Claude Code Remote Control** (`claude rc`) servers so projects are
|
|
drivable from [claude.ai/code](https://claude.ai/code) and the Claude mobile app
|
|
— either as always-on, reboot-surviving services, or as ad-hoc throwaways.
|
|
|
|
Two tools:
|
|
|
|
| Tool | Purpose | Persistence |
|
|
|------|---------|-------------|
|
|
| `claude-rc` | central **manager** of always-on servers, supervised by `systemd --user` from a registry | survives reboot (linger) + crash (`Restart=always`) |
|
|
| `crc` | **ad-hoc** headless launcher for one dir on one host | survives terminal drops; dies on reboot |
|
|
|
|
Both run `claude rc` **headless** — detached, logged, with `--spawn` and
|
|
`--permission-mode` preset so it never blocks on the interactive spawn-mode
|
|
prompt.
|
|
|
|
## Why no tmux
|
|
|
|
The obvious approach — park `claude rc` in a tmux session — is a trap: a shared
|
|
user tmux server can be restarted out from under you (e.g. by another
|
|
supervisor) and your sessions vanish. `claude rc` needs no TTY (it connects fine
|
|
with stdin closed), so **systemd alone** gives boot-persistence + crash-restart,
|
|
and `crc` uses a plain logged background process. No tmux anywhere.
|
|
|
|
## Install
|
|
|
|
```sh
|
|
./install.sh # symlink bin/*, install the unit, seed registry
|
|
sudo loginctl enable-linger "$USER" # once, so units start at boot (Linux)
|
|
claude-rc sync # bring up everything in the registry
|
|
```
|
|
|
|
Requires `claude` (Claude Code) on `$PATH` and a logged-in subscription account.
|
|
|
|
## Manager — `claude-rc`
|
|
|
|
Registry (`~/.config/claude-rc/projects`) is the single source of truth:
|
|
|
|
```
|
|
name=dir # dir relative to $HOME, or absolute, or ~/...
|
|
```
|
|
|
|
Each entry → a systemd template instance `claude-rc@<name>.service` running
|
|
`claude rc --name <name>` in `<dir>`.
|
|
|
|
```sh
|
|
claude-rc list # registry + unit state + dir
|
|
claude-rc status [name] # state + claude.ai/code URL
|
|
claude-rc url <name> # just the URL
|
|
claude-rc add <name> <dir> # register + enable --now
|
|
claude-rc rm <name> # disable + unregister
|
|
claude-rc sync # reconcile units to the registry
|
|
claude-rc logs <name> [-f] # journal
|
|
claude-rc restart|stop|start <name>
|
|
claude-rc envs # account-wide environment list (all hosts)
|
|
```
|
|
|
|
## Account-wide view — `claude-rc-envs`
|
|
|
|
`claude-rc list`/`status` only know about *this host's* units. To see every
|
|
Remote Control environment across all hosts (exactly what the claude.ai/code
|
|
picker shows — including orphans and cloud envs), query the API:
|
|
|
|
```sh
|
|
crc status # or: crc envs / claude-rc envs / rc envs
|
|
claude-rc-envs # state, host, project, env id, dir
|
|
claude-rc-envs --json
|
|
claude-rc-envs rm <env_id> # delete an environment (e.g. an orphan)
|
|
claude-rc-envs archive <env_id>
|
|
```
|
|
|
|
Reads the OAuth token from the macOS Keychain or `~/.claude/.credentials.json`
|
|
and hits `GET https://api.anthropic.com/v1/environments`
|
|
(`anthropic-beta: environments-2025-11-01`).
|
|
|
|
Defaults (override via env in a unit drop-in):
|
|
- `CLAUDE_RC_SPAWN=worktree` — isolated git worktree per spawned session.
|
|
- `CLAUDE_RC_PERM=bypassPermissions` — spawned sessions skip permission prompts.
|
|
|
|
## Ad-hoc — `crc`
|
|
|
|
```sh
|
|
crc <host> <dir> # launch headless; prints the URL. host=local for here
|
|
crc <host> <dir> --status | --log | --stop
|
|
crc <host> <dir> --spawn same-dir --perm default -- <extra claude rc args>
|
|
```
|
|
|
|
`host` is any ssh target, or `local`. State lives under
|
|
`~/.local/state/claude-rc/` on the target. Re-running reports the existing
|
|
server instead of duplicating it.
|
|
|
|
## Layout
|
|
|
|
```
|
|
bin/claude-rc manager (runs on the host; drive remotely over ssh)
|
|
bin/crc ad-hoc headless launcher
|
|
units/claude-rc@.service systemd --user template
|
|
projects.example registry seed
|
|
install.sh symlinks + unit install + registry seed
|
|
```
|