@firefunc-agent/runner
v0.7.1
Published
FireFunc self-hosted runner — an always-on daemon that runs YOUR local coding agent (Claude Code, Codex, Gemini CLI, Cursor CLI) on work FireFunc routes to it, opens pull requests, and reports back. Your machine, your subscriptions.
Maintainers
Readme
firefunc-runner
Run your own coding agent — Claude Code, OpenAI Codex, Gemini CLI or Cursor CLI — on work FireFunc routes to you, and open PRs automatically.
This is the self-hosted runner for FireFunc's Claude Code Channel engine. It's a tiny always-on daemon on your machine (laptop, dev box, CI host) that:
- long-polls FireFunc (outbound only — works behind NAT/VPN, no inbound ports),
- claims a bug FireFunc dispatched to your project,
- runs your local coding agent (
claude -p,codex exec,gemini, orcursor-agent— whichever the work is routed to) in an isolated git worktree off a clean base branch, - opens a draft PR and reports the result back.
Why this and not the cloud Routine? No ~15/day cap (it uses your Claude subscription's limits), your code never leaves your machine, and it has your full local context — running app, AWS creds, gh/git auth, MCP servers, CLAUDE.md.
Requirements
- Node ≥ 20
- Claude Code installed and signed in (
claudeon your PATH) gitand the GitHub CLI (gh) signed in, with push access to the repos- A local checkout of each repo FireFunc will fix
Quick start
# 1. Install the package. Use -g, not npx — see the note below.
npm install -g @firefunc-agent/runner
# 2. In FireFunc: Engines → "Add a machine". Copy the WHOLE command it shows —
# it already contains your one-time token (ffr_…) and your API URL:
firefunc-runner connect ffr_xxxxx --api https://your-firefunc-host --repos-dir ~/code
# (or map a repo exactly: --repo acme/api=/Users/me/code/api)
# 3. Go online — starts at login/sign-in and survives reboot:
firefunc-runner installnpm install -g, not npx. npx runs the package from a throwaway cache
(~/.npm/_npx/<hash>/…) that npm is free to delete. A background service has to
point at a path that still exists after a reboot, so firefunc-runner install
refuses to run from there and tells you this. Everything else — connect,
start, status, logs — works fine under npx if you prefer.
--api is required: this package has no hard-coded FireFunc host, so it only
ever talks to the deployment you point it at.
That's it. When your QA files a bug (labeled for FireFunc), it appears here within seconds, gets fixed, and a draft PR shows up — all visible in the FireFunc dashboard.
Safety
- Works in a throwaway git worktree off a clean base — it never touches your working tree or current branch.
- Opens a PR only when there's a real diff (no phantom PRs).
- Pushes a deterministic branch with
--force-with-lease, so a duplicate dispatch converges to one PR. - Runs Claude with
--permission-mode acceptEdits(autonomous file edits) without--dangerously-skip-permissions(which hangs non-interactive daemons). - A per-job timeout (default 20 min) prevents a stuck run from hanging the daemon.
Commands
| Command | What it does |
| ----------------------------------------- | ------------------------------------------------------------------------- |
| firefunc-runner connect <token> [flags] | Save your token + settings (~/.firefunc-runner/config.json, mode 0600) |
| firefunc-runner install | Install as a background service — starts at login/boot, restarts on crash |
| firefunc-runner start | Run in THIS terminal (stops when you close it) — for watching it work |
| firefunc-runner stop | Stop the background service (stays stopped) |
| firefunc-runner start-service | Start the background service again |
| firefunc-runner logs | Recent runner output |
| firefunc-runner uninstall | Remove the background service |
| firefunc-runner status | Saved config and whether the service is installed + running |
connect flags
| Flag | Default | Meaning |
| --------------------------- | ---------------- | -------------------------------------------------------------- |
| --api <url> | — (required) | Your FireFunc API URL — the copied command fills this in |
| --name <name> | hostname | Friendly runner name (shown in the dashboard) |
| --repos-dir <dir> | — | Base dir; repos are matched by name (acme/api → <dir>/api) |
| --repo <owner/repo=/path> | — | Map one repo to an exact checkout (repeatable) |
| --claude-bin <bin> | claude | Claude Code binary |
Always-on
firefunc-runner start runs in the foreground: it dies with the terminal and does
not come back after a reboot. That matters more than it sounds, because
FireFunc's queue is pull — nothing is pushed to your machine, the runner asks
for work every few seconds. A runner that is not running is not a slow runner;
it is an absent one, and work waits for a machine that will never ask again.
So install it once:
firefunc-runner install- macOS — a launchd LaunchAgent at
~/Library/LaunchAgents/com.firefunc.runner.plist - Linux — a systemd
--userunit at~/.config/systemd/user/firefunc-runner.service, plusloginctl enable-lingerso it starts at boot, not at first login - Windows — a Task Scheduler task (
FireFuncRunner) that starts at sign-in. No WSL, no admin rights, no service wrapper.
It starts at login/boot and restarts itself if it crashes. It does not restart after a deliberate stop, or after FireFunc revokes the runner's token — that is a clean exit, not a fault, and respawning it would just log the same rejection forever.
Per-user, not system-wide, on purpose: the runner uses your claude /
codex / gemini login, your checkouts and your SSH keys. A root daemon
— or a Windows Service, which is the same problem — would have none of those,
and giving it them is exactly the concentration of access FireFunc is designed to
avoid. That is also why Windows gets a Scheduled Task and not a Service: no admin
rights needed, and it runs as you.
On Windows the task overrides four Task Scheduler defaults that would otherwise break it silently: it refuses to start on battery and stops when unplugged (fatal on a laptop), it is killed after 3 days, and it stops when the machine goes idle.
firefunc-runner status # installed? running?
firefunc-runner logs # what has it been doing
firefunc-runner stop # stop it; stays stopped
firefunc-runner uninstall # remove the service entirelyTwo things the installer bakes into the unit, because a service has no shell
profile: your current PATH (or the agent CLIs are not findable and every job
fails with claude: command not found) and HOME/USERPROFILE (or they cannot
find their own logins). If you install a new agent CLI somewhere new, re-run
install.
Tested: the macOS path is verified end to end on a real Mac — installed, killed with
kill -9, and confirmed launchd brought it back. The Linux and Windows paths are unit-tested (unit/XML contents and everysystemctl/schtasksverb) but have not yet been run on a real machine of either kind. Please report anything that misbehaves.
Licence
@firefunc-agent/runner is the client half of FireFunc, published so the machines
that do the work can actually install it. It is free to download and run against
a FireFunc account you are authorised to use — see LICENSE.
The FireFunc service itself (API, workers, dashboard, infrastructure) is proprietary and is not distributed here. This package contains only the daemon that runs on your machine: it invokes coding agents you installed and pay for, works on your checkouts, and reports results back. Your source code does not need to reach FireFunc for any of it to work.
