@roko-app/kokoshi-worker
v0.2.11
Published
Run the Kokoshi coding agent on your own machine for your Roko projects — listens for your tasks and opens a PR for each, on your own Claude subscription.
Readme
@roko-app/kokoshi-worker
Run Kokoshi — Roko's autonomous coding agent — on your own machine, for your own repos, on your own Claude subscription.
The worker signs in with your Roko account, listens for tasks you (or your collaborators) assign to Kokoshi across all your projects, and opens a pull request for each one. It holds no Roko secrets — every privileged action goes through Roko's API, authenticated with your personal token. The GitHub token used to push is minted server-side per job and never touches your machine beyond the run.
Prerequisites
claudeinstalled and signed in (the worker runs on your subscription).gitand theghCLI on yourPATH.- Node 18+.
- The Roko GitHub App installed on the repositories Kokoshi should work on (Roko app → Settings → Integrations).
Setup
# 1. Get your worker token from the Roko app → Kokoshi → "Get your worker token"
# (it's a personal access token, roko_pat_…; revoke it any time in Settings).
npx @roko-app/kokoshi-worker login --token <your roko_pat_…>
# 2a. Start the worker in the foreground (good for a first run). Ctrl-C to stop.
npx @roko-app/kokoshi-worker start
# 2b. …or install it once as a background service — it then starts on login,
# runs headless, and auto-restarts, so you never babysit a terminal.
npx @roko-app/kokoshi-worker installlogin saves the token + API host to ~/.roko/worker.json (mode 0600). You
can skip it and pass everything by env instead:
ROKO_USER_TOKEN=roko_pat_… npx @roko-app/kokoshi-worker startWhat a run does
- poll — claim your next pending job (FIFO across your projects).
- github-token — fetch a short-lived installation token for the job's repo.
- clone the repo (token stripped from the remote afterward), check out the
server-reserved branch, install deps (
--ignore-scripts). - run
claudeon the task prompt (your subscription). The agent only commits — it's given no GitHub credential. - the worker pushes the branch and opens the PR (GitHub ground truth); a no-change run is a clean completion, not a failure.
- result — report back; Roko moves the task to To Merge / Failed and posts Kokoshi's comment. Merging the PR moves the task to done.
Config (env)
| Var | Default | Meaning |
| ----------------------------------- | ------------------------- | ------------------------------------------------ |
| ROKO_USER_TOKEN | — | Your worker token (overrides the stored one) |
| ROKO_API_URL | https://www.rokohub.com | Roko API host |
| ROKO_WORK_ROOT | ~/.roko/coding-jobs | Where repos are cloned |
| CLAUDE_PATH | claude | Path to the Claude CLI |
| ROKO_MAX_CONCURRENT_RUNS | 2 | Max simultaneous runs (parallel across projects) |
| ROKO_POLL_INTERVAL_MS | 5000 | Poll cadence when idle |
| ROKO_NOTIFY_URL | — | Public wake URL for instant job pickup (below) |
| ROKO_NOTIFY_PORT | URL port, else 8745 | Local port the wake listener binds |
| ROKO_CONTROL_PORT | 8765 | Loopback port for the control channel (below) |
| ROKO_CONTROL_DISABLE | — | 1 to skip the control channel (pure headless) |
| ROKO_WORKER_SANDBOX | native | native / docker / off (see below) |
| ROKO_WORKER_SANDBOX_ALLOW_DOMAINS | — | Extra domains the sandboxed agent may reach |
| ROKO_WORKER_SANDBOX_IMAGE | kokoshi-sandbox:latest | Image used when sandbox is docker |
| ROKO_ALLOW_ROOT | — | 1 to allow running as root (refused otherwise) |
Concurrent runs (optional)
The worker runs several tasks at once: parallel across projects (each gets
its own clone + claude process) but serial within a project (two runs on
one repo would clash on the same working tree, so same-project tasks queue).
ROKO_MAX_CONCURRENT_RUNS (default 2) caps how many different projects run
simultaneously — raise it on a beefy box, lower it to 1 for one-at-a-time.
Each concurrent run is its own Claude session, so the cap is also your main
cost control: N runs ≈ N× simultaneous API/subscription usage. Tasks beyond
the cap (or behind a busy project) queue and start as slots free up;
get_worker_status shows live "N/M slots active".
Instant job pickup (optional)
By default the worker discovers a new job on its next poll (up to
ROKO_POLL_INTERVAL_MS later). If your machine is reachable from the
internet (a VPS, or a reverse-proxied box), set ROKO_NOTIFY_URL to a
public URL that routes to the worker — the worker advertises it on every
poll, listens on ROKO_NOTIFY_PORT, and Roko POSTs a content-free
"poll now" ping there the instant one of your tasks is assigned, so the run
starts immediately. The ping carries no data and triggers nothing but an
authenticated poll, so the endpoint needs no secret; a worker behind NAT
simply leaves this unset and keeps the normal poll cadence.
Run as a background service
kokoshi-worker install registers the worker with your OS so it runs headless,
starts on login, and restarts if it crashes — no terminal to babysit:
- macOS → a per-user launchd LaunchAgent
(
~/Library/LaunchAgents/com.rokohub.kokoshi-worker.plist). - Linux → a systemd user unit
(
~/.config/systemd/user/kokoshi-worker.service; runloginctl enable-lingerto keep it running while logged out). - Windows → a Task Scheduler task (
KokoshiWorker, runs at logon).
install prints exactly what it wrote and ran, so you can reproduce it by hand.
uninstall reverses it. Run login first — the service needs your saved token.
Control channel (tray app / web panel)
A running worker exposes a tiny localhost-only HTTP control channel
(127.0.0.1:8765) so the desktop tray app — and, later, the web "Run Kokoshi on
your machine" panel — can show what it's doing and steer it without spawning a
process. From the terminal:
kokoshi-worker status # live: online · model · effort, current run, recent runs
kokoshi-worker pause # stop claiming new tasks (a run already in flight finishes)
kokoshi-worker resume # start claiming againIt's bound to loopback only (never the network), every request needs a bearer
token generated on first start and stored 0600 in ~/.roko/control.json, and
the Host header is pinned to localhost — a stray web page can't pause or stop
your worker. Set ROKO_CONTROL_DISABLE=1 on a box that should expose no local
port at all.
Security & sandboxing
The worker runs an LLM agent on untrusted repo + task content, so it's
hardened: the agent gets no GitHub credential (git's keychain helper is
neutralized, the clone's token is stripped), dependency installs run with
--ignore-scripts, secrets are scrubbed from the progress stream, and it
refuses to run as root (override with ROKO_ALLOW_ROOT=1).
Sandboxing is on by default (ROKO_WORKER_SANDBOX=native) — it uses Claude
Code's built-in OS sandbox so the agent's commands can read + write only the
clone and reach only git + the common package registries. Everything else
(~/.ssh, your other repos, the worker's own token) is invisible.
- macOS — uses Seatbelt, nothing to install.
- Linux / WSL2 — needs
bubblewrap(apt-get install bubblewrap); if it's missing it warns and runs unsandboxed rather than breaking. - Add domains the agent legitimately needs with
ROKO_WORKER_SANDBOX_ALLOW_DOMAINS=a.com,b.com.
Set ROKO_WORKER_SANDBOX=docker for the strongest isolation (a container
that also firewalls network) — you supply the image (ROKO_WORKER_SANDBOX_IMAGE,
with claude + git). Set off to disable isolation entirely.
Commands
login [--token <t>] [--api <url>]— save your token.start— run the poll loop in the foreground (Ctrl-C to stop).install/uninstall— register/remove the background service.pause/resume— stop/start claiming new tasks on a running worker.status— live worker status (falls back to login state when offline).help— usage.
Maintainers: this directory is also the trusted, admin-token Kokoshi worker (
src/index.ts) and the privateroko-mcpstdio server. Those run server-side only and are not part of the published CLI (bin→dist/cli.js). SeeCLAUDE.md.
