@flofai/runner
v0.1.14
Published
egos runner — connect a machine to your egos workspace and run agent tasks on it.
Maintainers
Readme
@flofai/runner
The fbuild runner: connect a machine (your laptop, a VM, a CI box) to an fbuild workspace. The runner dials out to the hub over a WebSocket (no inbound ports), registers the machine, and runs the tasks the workspace assigns — using that machine's own Claude Code login. Zero dependencies (Node 22+).
Part of fbuild: console (UI) · hub (Cloudflare Worker) · runner (this).
Quick start
# 1) authorize Claude on this machine once (reused by the runner)
claude setup-token
# 2) connect to your workspace (token from the console → "Add a machine")
cd ~ && npx @flofai/runner@latest connect --hub https://<org>.flof.ai --token <TOKEN>The machine now shows online in the workspace's Soldiers. Leave it running (it auto-reconnects on network drops). Run from any directory except the runner's own source folder (npx would resolve the local unlinked package).
Mapping repos
# map a repo to a local checkout, scoped to a workspace
npx @flofai/runner@latest add-project <owner>/<repo> --dir ~/Developer/<repo> --hub https://<org>.flof.ai
npx @flofai/runner@latest status --hub https://<org>.flof.aiMapped repos appear in Projects with live git status (branch, dirty, ahead/ behind, last commit), and New task dispatches Claude Code runs into them.
Multiple workspaces (like multiple SSH connections)
One machine can join many workspaces at once — each is a separate connect
process with its own --hub and token, and its own config file:
npx @flofai/runner@latest connect --hub https://carna.flof.ai --token <A> # terminal 1
npx @flofai/runner@latest connect --hub https://aceware.flof.ai --token <B> # terminal 2What a run does
Spawns Claude Code headless (claude -p … --output-format stream-json
--include-partial-messages) in the project dir and streams structured events to
the hub: assistant text, tool calls + results, extended thinking, and a
short auto-generated chat title. The Claude session id is captured so a
reply continues the same context (--resume) — even after a runner restart.
Executors
The runner picks how a task runs from --executor (saved to config on connect):
| Executor | What it does |
| --- | --- |
| claude (default) | Claude Code headless in the project dir; rich streamed tool timeline. |
| egos | Runs the task through the egos deterministic spine — see below. |
| shell | Runs task.commands verbatim. For testing. |
| demo | Prints machine output, edits nothing. Proves the loop safely. |
--executor egos
npx @flofai/runner@latest connect --hub https://<org>.flof.ai --token <T> \
--executor egos [--egos-path <egos checkout or bindir>]Routes each assigned task through egos' gated pipeline instead of calling Claude directly. For every order the runner:
- Builds a shape-valid egos Order from the hub task (synthesizes the fields
egos requires: a sanitized id,
successCriteria, acode_patchartifact, and a benign read-only command) and writes it to a temp file — never the repo. - Spawns egos'
f-run.shwith the claude-code backend, which forks a git worktree off the project dir, runs Claude headless inside egos' Tool Police (command allow/deny + budget gate), and writes artifacts/events to a runner-owned workdir under~/.egos/runtime/(kept out of your repo). - Streams
f-run's stdout+stderr verbatim to the task's Terminal tab.
Prerequisites (on the runner machine): egos installed (its install.sh puts
f-run.sh on PATH) or reachable via --egos-path / $EGOS_HOME; plus claude
(the backend rides ambient Claude auth) and jq on PATH. The project must be a
real git checkout (egos forks a worktree from it).
Scope — be aware (MVP): the Terminal tab shows egos' flow/governance
progress (worktree created, command allow/deny, budget gate, manifest, gate
verdict when a PR is attached) — not Claude's per-tool stream. egos runs Claude with
--output-format json and captures its stdout, so the rich per-tool timeline the
claude executor produces is structurally invisible through egos. Parsing
egos' events.log into structured timeline rows is not yet implemented
(tracked as an in-code TODO).
Degrade: if egos, claude, or jq is missing, or the project dir isn't a git
work tree, the run fails cleanly with an actionable reason in the Terminal tab —
the runner never crashes and the task never gets stuck running.
A smoke test for this wiring lives at test/executor-egos.smoke.mjs
(npm test) — it drives the real runner against a fake hub with a stubbed
f-run.sh, no real LLM required.
Keeping it alive
Foreground — run
connectand leave the terminal open. Simplest.Background —
nohup npx @flofai/runner@latest connect --hub … --token … &.Service (recommended on a VM) — keep it up across reboots:
macOS (launchd) —
~/Library/LaunchAgents/ai.flof.runner.plist:<?xml version="1.0" encoding="UTF-8"?> <plist version="1.0"><dict> <key>Label</key><string>ai.flof.runner</string> <key>ProgramArguments</key> <array><string>/usr/local/bin/npx</string><string>@flofai/runner@latest</string><string>connect</string><string>--hub</string><string>https://carna.flof.ai</string></array> <key>RunAtLoad</key><true/><key>KeepAlive</key><true/> </dict></plist>launchctl load ~/Library/LaunchAgents/ai.flof.runner.plistLinux (systemd) —
/etc/systemd/system/fbuild-runner.service:[Unit] Description=fbuild runner After=network-online.target [Service] ExecStart=/usr/bin/npx @flofai/runner@latest connect --hub https://carna.flof.ai Restart=always [Install] WantedBy=multi-user.targetsudo systemctl enable --now fbuild-runner
Config
Per-workspace files under ~/.egos/:
runner.json— the default (carna.flof.ai)runner.<host>.json— one per additional hub (e.g.runner.aceware.flof.ai.json)
Each holds { hub, token, name, machineId, executor, projects }. The token is
saved on first connect, so the service form needs no --token. Executor
defaults to claude (real work); egos routes through the egos spine (see
--executor egos); shell and demo exist for testing.
Commands
| Command | Description |
| --- | --- |
| connect --hub <url> [--token <t>] [--name <n>] [--executor claude\|egos\|shell\|demo] [--egos-path <dir>] | join a workspace, run assigned tasks |
| add-project <owner>/<repo> --dir <path> [--hub <url>] | map a repo to a local checkout |
| status [--hub <url>] | print the resolved config |
© Carna · flof-ai
