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.
  • claude CLI installed and logged in (test with claude --version). The runner shells out to whichever claude is on PATH — or point at a specific one with CLAUDE_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-bin pointed at different sandboxes).
  • Routing per LAN (home vs office tags).
  • 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/healthz should 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 600 by default.
  • ~/.claude-scheduler/state/<name>.pid — daemon pid.
  • ~/.claude-scheduler/state/<name>.log — daemon log. Tail with claude-runner daemon logs <name> -f.