@factiii/runner
v0.11.3
Published
Factiii Runner, run Board AI agents on a machine you control. Pairs with the Factiii web/mobile clients over WebRTC.
Readme
@factiii/runner
A headless daemon that runs Factiii's Board AI agents (Claude-driven coding sessions) on a machine you control. Install it on a workstation, dev box, or VM with a stable network connection. Agents run directly on that machine, so it can drive whatever the machine can: simulators, native builds, platform toolchains. The mobile and web Factiii clients then connect to it over WebRTC and offload AI work.
Requirements
- Node 20+
- git, tmux, and redis-server on PATH (
setupchecks for them) - The agent CLIs you plan to use:
claudeand/orcodex - A Factiii account
- Outbound network access to the Factiii API server
Install
npm install -g @factiii/runnerOr run without installing:
npx @factiii/runner setupUsage
factiii-runner setup # verify the host toolchain, pair this runner
factiii-runner connect # re-pair with a different account
factiii-runner start # run the daemon (keep this process alive)
factiii-runner status # show current config + credential storage state
factiii-runner doctor # show where each host tool resolves, and the PATH
factiii-runner password # set or change the optional connection password
factiii-runner password --clear # remove it (stays keychain-encrypted)setup is the one-shot command that gets you from zero to running. It checks the host toolchain and walks you through the browser pairing flow. After it finishes, factiii-runner start runs the daemon.
doctor is the first thing to run when a board reports "Couldn't initialize the environment". It prints the resolved location of every tool the runner needs and the PATH it searched, which separates a tool that is genuinely absent from one that is installed somewhere the runner cannot see.
Security notes
Everything the runner stores in ~/.factiii-runner/ — the GitHub PAT, the OneDrive refresh token, the Claude/Codex OAuth files, and the pairing JWT — is encrypted at rest with AES-256-GCM at permissions 0600. Existing plaintext files migrate automatically on the first read; no re-pairing.
There is no plaintext fallback. A host with no usable keychain (headless Linux without libsecret, a CI container, a locked login keyring) stores nothing at all: setup refuses, and a running daemon connects but fails every credential read and write. It tells you which tool is missing and how to install it, both on the console and in Runner Settings → Connections. Fix the keyring, restart, and it picks up where it left off.
Two layers
- Machine key (always). A 32-byte key in the OS keychain — macOS Keychain, libsecret on Linux, DPAPI on Windows. Bound to the logged-in OS user, so the daemon works unattended. The runner touches exactly one keychain item (
factiii-runner/config-encryption-key) and never deletes anything; if that item exists but can't be read, it reports the problem rather than minting a replacement over the top of it. - Connection password (optional). A second factor you add in Runner Settings → Connections, or with
factiii-runner password. Both halves are needed to unwrap the data key, so a stolen laptop isn't enough without the password and a leaked password isn't enough without the machine. Cost: the runner comes up locked after every restart (including auto-update) and does no work until you unlock it from the app or type it at the terminal. The key then lives in that daemon process's memory only.
Enabling, changing or clearing the password re-wraps one small key file. No credential is rewritten, so it can't half-migrate.
Provider sign-ins
The Claude/Codex OAuth files are written by those CLIs into each board's state dir, so they can't be encrypted during a session. They're sealed between sessions instead: decrypted when a board's workspace starts, re-encrypted when the board goes idle, on lock, and on shutdown. A crash leaves plaintext behind; the next start sweeps it up (the newer plaintext wins, since the CLIs rotate tokens in place).
Beta on Linux and Windows. Only the macOS Keychain path has been tested end to end. The libsecret (
secret-tool) and Windows DPAPI paths are implemented but unverified — we have no machine to exercise them on yet. They now fail closed rather than degrading, so the expected failure mode is "the runner says it can't store credentials", not silent plaintext. Please report it if you hit that.
What this protects is offline access: a stolen disk, a synced folder, a backup, a stopped runner. It does not protect against a compromised runner host while it is unlocked and running — the daemon can always read what it can use. Only run a runner on a machine you trust, and only pair with accounts you own.
The deploy Secrets panel is a separate store with a different model: sops/age, under a password supplied per operation and never cached. The two passwords are independent on purpose — deploy secrets never need to be read unattended, connection tokens do. See .specs/deploy.md.
