
Security News
Cloudflare Introduces a Faster TypeScript Compiler Written in Rust
Cloudflare introduces tsrs, a Rust port of TypeScript’s compiler promising faster checks and lower memory use, with the TypeScript team’s help.
@factiii/runner
Advanced tools
Affected versions:
Factiii Runner, run Board AI agents on a machine you control. Pairs with the Factiii web/mobile clients over WebRTC.
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.
claude and codexsops and age (Secrets), Xcode with a simulator (simulator panel, macOS), Screen Recording and Accessibility for "Factiii Screen" (desktop view, macOS)npm install -g @factiii/runner
Or run without installing:
npx @factiii/runner setup
factiii-runner setup # pair this runner, then check the machine
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 # check what this machine needs, and fix what the runner may fix
factiii-runner service install | status | remove # start at login, restart after a crash
factiii-runner password # enter an old connection password once, to remove it (see Security notes)
setup walks you through the browser pairing flow. After it finishes, factiii-runner start runs the daemon. The host toolchain (git, tmux, redis, the agent CLIs) installs when you first open a space on the board, with progress shown there; factiii-runner setup --tools runs the same install from the terminal.
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.
setup and doctor)setup ends with a checklist of the machine, and doctor prints it again at any time. Each item says which feature needs it and whether it is required, so nobody installs Xcode for a runner that never shows a simulator. An unmet item gets one of three things:
sudo or is your decision to make: packages on Linux (apt, dnf, pacman), sleep and power settings, automatic login, lingering. The runner prints it and never runs it.The tools of this checklist (git, redis-server, tmux, script, node, claude, codex, sops, age) also show in the app, item by item, under Runner Settings > Setup > Environment, with the same install command for each one that is missing.
doctor exits 1 while a required item is unmet and 0 otherwise. Without a terminal, or with --no-fix, it only reports: it asks nothing and changes nothing. --json prints the same report for a script.
sops is not packaged for Debian, Ubuntu or Fedora; there doctor points at the release page instead of offering an install.
service)factiii-runner service install # start at login, restart after a crash
factiii-runner service status # installed? running? what it runs, where it logs
factiii-runner service remove # stop it and delete what install wrote
setup offers this at the end ("Keep this runner running after a restart?"). It uses the operating system's own service manager, for the current user, without sudo:
| What is installed | Where | |
|---|---|---|
| macOS | a LaunchAgent | ~/Library/LaunchAgents/com.factiii.runner.plist |
| Linux | a systemd user service | ~/.config/systemd/user/factiii-runner.service |
| Windows | a scheduled task at logon | task FactiiiRunner, files in ~/.factiii-runner/service/ |
factiii-runner start with the node and the runner that were installed when you ran service install, and the PATH of that terminal. If you move to another Node version or reinstall the runner somewhere else, run service install again: it rewrites its file and restarts the service.~/.factiii-runner/logs/runner.log. When it passes 10 MB the runner copies it to runner.log.1 (replacing the last one) and empties it, at start and once an hour, so the two files are all it ever keeps.service install again.install refuses to overwrite a file of the same name that it did not write, and remove deletes only what install wrote.FACTIII_RUNNER_DIR gets its own service name and log.After a restart with nobody at the machine. The service starts when its user logs in, and the key that opens the runner's config is in that user's keychain, which is locked until then. So an unattended machine needs one more thing, and it is yours to decide. The runner explains it and never does it:
sudo loginctl enable-linger <user> starts user services at boot. The login keyring still has to be unlocked for the runner to read its config.netplwiz), with the same trade as macOS.service install and doctor print the commands (pmset on macOS, including "start up automatically after a power failure"). They never run them.Secrets stay locked after a restart. The board password is never stored. The runner comes back by itself, but each board's secrets stay locked until someone unlocks them from the app.
plutil and its commands are tested against a fake launchd.doctor says WSL2 is missing, and the scheduled task is implemented but untested (beta).The credentials the runner itself stores in ~/.factiii-runner/ — each board's GitHub PAT and OneDrive refresh token (<board>/.creds/), and the pairing JWT (config.json) — are encrypted at rest with AES-256-GCM at permissions 0600, all under the same machine keychain key. Existing plaintext files migrate automatically on the first read; no re-pairing. The Claude/Codex sign-ins are not in this list: see Provider sign-ins below.
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 → Secrets. Fix the keyring, restart, and it picks up where it left off.
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.vault-key.json), so a password-protected runner came up locked after every restart (including auto-update) and could not clone, deploy, or even show which GitHub user was connected until someone typed it. That password can no longer be set or changed. The connections are sealed under the machine key alone, like the pairing config, and the runner reads them the moment it starts. Values that must stay behind a password belong in deploy secrets (below).Upgrading a runner that has a password set: one unlock, then never again. Connection files written before this change are still in the old envelope. With no password set they are converted at the first start. With a password set, the runner needs it one last time: it starts, connects, and reports those files as locked (console, and Runner Settings → Secrets) rather than as "no repository". Enter the password once — in the app, at the terminal prompt start shows, or with factiii-runner password on a host with neither — and every board's files are rewritten under the machine key together. A file is rewritten only after it has been decrypted, through a temp file and a rename, so a failed conversion leaves the old file as it was. An update approved from the app never waits at a terminal for this. The relaunch after a self-update skips the terminal prompt even when the runner was started in a terminal — nobody is sitting at it — so the runner connects with those connections locked, prints the problem and the ways to unlock, and the app asks its owner for the password in the same banner that offered the update, on any page. A runner that is unlocked with factiii-runner password while it is running notices within a few seconds, tells its connected clients, and starts the OneDrive indexes that were waiting.
When the vault file goes. As soon as no file is left in the old envelope — at start, or right after that unlock — vault-key.json is renamed to vault-key.retired.json and the password stops existing: no later restart asks for it. A runner that has a password set but nothing sealed under it loses the password at start without being asked. If a file will not decrypt even with the vault open, it is left in place and named on the console, and the vault stays until that board is reconnected (which replaces the file).
The Claude/Codex OAuth files are written by those CLIs into each board's state dir (<board>/claude, <board>/codex) or the OS keychain, and the CLIs own them. The runner does not encrypt them. An earlier version of this section said they were sealed between sessions; no code does that, and the files are exactly as the CLI left them.
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 to the files without the login keychain: a synced folder, a backup, a disk read on another machine. It does not protect against someone signed in as the runner's OS user, nor a compromised runner host — 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, which is why connection tokens no longer sit behind any password. See .specs/deploy.md.
FAQs
Factiii Runner, run Board AI agents on a machine you control. Pairs with the Factiii web/mobile clients over WebRTC.
The npm package @factiii/runner receives a total of 206 weekly downloads. As such, @factiii/runner popularity was classified as not popular.
We found that @factiii/runner demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.

Security News
Cloudflare introduces tsrs, a Rust port of TypeScript’s compiler promising faster checks and lower memory use, with the TypeScript team’s help.

Security News
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.

Security News
PHP releases emergency patches for two critical RCE vulnerabilities as agencies urge organizations to take unpatched sites offline.