@factiii/runner 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,12 @@
1
1
  # @factiii/runner
2
2
 
3
- 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 that has Docker and a stable network connection. The mobile and web Factiii clients then connect to it over WebRTC and offload AI work.
3
+ 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.
4
4
 
5
5
  ## Requirements
6
6
 
7
7
  - Node 20+
8
- - Docker (running and reachable via `docker info`)
8
+ - git, tmux, and redis-server on PATH (`setup` checks for them)
9
+ - The agent CLIs you plan to use: `claude` and/or `codex`
9
10
  - A Factiii account
10
11
  - Outbound network access to the Factiii API server
11
12
 
@@ -24,14 +25,35 @@ npx @factiii/runner setup
24
25
  ## Usage
25
26
 
26
27
  ```bash
27
- factiii-runner setup # verify docker, build the claude image, pair this runner
28
+ factiii-runner setup # verify the host toolchain, pair this runner
28
29
  factiii-runner connect # re-pair with a different account
29
30
  factiii-runner start # run the daemon (keep this process alive)
30
- factiii-runner status # show current config
31
+ factiii-runner status # show current config + credential storage state
32
+ factiii-runner password # set or change the optional connection password
33
+ factiii-runner password --clear # remove it (stays keychain-encrypted)
31
34
  ```
32
35
 
33
- `setup` is the one-shot command that gets you from zero to running. It checks Docker, builds the `factiii-claude` image, and walks you through the browser pairing flow. After it finishes, `factiii-runner start` runs the daemon.
36
+ `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.
34
37
 
35
38
  ## Security notes
36
39
 
37
- Tokens (Claude OAuth, GitHub PAT) are stored **unencrypted** at `~/.factiii-runner/config.json`. Anyone with shell access to this machine as the same user can read them. Only run a runner on a machine you trust, and only pair with accounts you own.
40
+ 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.
41
+
42
+ **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.
43
+
44
+ ### Two layers
45
+
46
+ 1. **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.
47
+ 2. **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.
48
+
49
+ Enabling, changing or clearing the password re-wraps one small key file. No credential is rewritten, so it can't half-migrate.
50
+
51
+ ### Provider sign-ins
52
+
53
+ 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).
54
+
55
+ > **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.
56
+
57
+ 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.
58
+
59
+ 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`.