Install a runner
The runner is a small Node 20+ daemon. It opens an outbound HTTPS connection to claude-scheduler, claims due jobs, and runs them locally as claude -p. Nothing inbound, no port to open.
It works anywhere the Claude CLI works: macOS, Linux, WSL. One process per runner profile, ~30 MB RAM idle. The runner is open source (MIT) — audit it before you install.
Prerequisites
- Node 20+. Install via
brew install node, nodejs.org, or nvm. claudeCLI installed and logged in (test withclaude --version). The runner shells out to whicheverclaudeis onPATH— or point at a specific one withCLAUDE_BIN.
Install
a) One-line installer (recommended)
curl -fsSL https://cronforclaude.com/install.sh | sh -s -- \ --profile=my-mac \ --token=csr_live_… \ --tags=mac,gpu
npm-installs claude-scheduler-runner globally, configures the profile, and prints the next command. Re-running it upgrades to the latest published version.
Omit --token to just install the binary without configuring anything — you can run claude-runner add afterwards.
b) npm
npm install -g claude-scheduler-runner
Then configure a profile with the interactive wizard or a flag-only invocation:
# wizard claude-runner add my-mac # one-shot claude-runner add my-mac \ --token=csr_live_… \ --tags=mac,gpu \ --non-interactive
c) From source
git clone https://github.com/HK2-AI/claude-scheduler-runner cd claude-scheduler-runner pnpm install --frozen-lockfile pnpm build node dist/index.js add my-mac
The same claude-runner binary is the one published to npm. Build-from-source is the right path if you want to inspect or fork.
Run it
# foreground — handy to confirm it connects on first run claude-runner run my-mac # detached daemon, pid + log under ~/.claude-scheduler/state/ claude-runner daemon start my-mac claude-runner daemon status claude-runner daemon logs my-mac -f claude-runner daemon restart my-mac claude-runner daemon stop my-mac
Multiple runners on one machine
A profile is a named runner identity stored as ~/.claude-scheduler/runners/<name>.env. One install hosts as many as you want — no per-runner directory needed.
claude-runner add work --token=csr_live_… --tags=work claude-runner add personal --token=csr_live_… --tags=personal claude-runner daemon start work claude-runner daemon start personal claude-runner ls # personal # work claude-runner daemon status # 2 runner instance(s) detected: # profile=personal pgid=… [tracked] # profile=work pgid=… [tracked]
Common use cases:
- Two Claude accounts on one machine (e.g.
--claude-binpointed at different sandboxes). - Routing per LAN (
homevsofficetags). - Beefy box for GPU work + light box for everything else.
Run as a systemd service
Template-unit pattern — one file serves every profile:
# /etc/systemd/system/[email protected] [Unit] Description=claude-scheduler runner (%i) After=network-online.target [Service] Type=simple User=youruser ExecStart=/usr/bin/claude-runner run %i Restart=always RestartSec=10 [Install] WantedBy=multi-user.target
sudo systemctl daemon-reload sudo systemctl enable --now claude-runner@my-mac sudo systemctl enable --now claude-runner@work sudo journalctl -u 'claude-runner@*' -f
Verifying
Reload the Runners page. Your runner should show online within ~15 seconds. If it's still offline:
- Run
claude-runner run <profile>in the foreground — the first line tells you exactly what failed (wrong token, network blocked, claude binary missing). - Tokens can't be recovered. If you lost it, delete the runner row in the dashboard and create a new one.
- Outbound sanity:
curl -fsS https://cronforclaude.com/api/healthzshould return{"ok":true}.
Runner tags
Tags are routing labels you make up. A schedule with runnerTags = ["gpu"] only lands on runners whose tag list contains gpu. A schedule with no tags goes to any online runner.
Upgrading
# upgrade via npm npm install -g claude-scheduler-runner@latest # or rerun the one-line installer — it pulls the latest published version curl -fsSL https://cronforclaude.com/install.sh | sh # state survives upgrades claude-runner daemon restart my-mac
Where things live
~/.claude-scheduler/runners/<name>.env— profile config (token, URL, tags, etc.).chmod 600by default.~/.claude-scheduler/state/<name>.pid— daemon pid.~/.claude-scheduler/state/<name>.log— daemon log. Tail withclaude-runner daemon logs <name> -f.