@bivy/bivy 0.10.1-staging.372 → 0.10.1-staging.374

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,59 +1,108 @@
1
1
  # Bivy
2
2
 
3
- **Give coding agents your real environment, then reach them from anywhere.**
4
-
5
- A provider sandbox starts from an approximation. A Bivy Machine can use the
6
- repository, local services and databases, private networks, existing tools and
7
- caches, and GPUs or local inference already available on your workstation or
8
- server. Bivy turns that local capability into Sessions you can continue remotely
9
- and Runs you can leave working unattended.
10
-
11
- ## What Bivy lets you do
12
-
13
- - **Work where the full environment lives.** Run Claude Code, Codex, Pi, or
14
- another agent beside real repos, dev servers, databases, internal APIs,
15
- toolchains, package caches, and specialized compute.
16
- - **Continue from a phone, browser, or terminal.** Reconnect to the same Session,
17
- steer or stop it, answer questions, and approve supported tool calls. The PWA
18
- supports voice input and read-aloud, phone-to-agent file/image uploads, and
19
- agent-to-phone attachments. Native terminal Sessions can stay remote-visible;
20
- supported runtimes can hand work between terminal and structured chat.
3
+ [![npm](https://img.shields.io/npm/v/@bivy/bivy?color=2b6cb0&label=%40bivy%2Fbivy)](https://www.npmjs.com/package/@bivy/bivy)
4
+ [![license: AGPL-3.0-only](https://img.shields.io/badge/license-AGPL--3.0--only-2b6cb0)](LICENSE)
5
+ [![node](https://img.shields.io/badge/node-%E2%89%A522.19-2b6cb0)](https://nodejs.org)
6
+
7
+ **Run coding agents on the machines you already own — then reach them from your
8
+ phone, browser, or another terminal.**
9
+
10
+ Start Claude Code on your workstation, right where the repo, the running dev
11
+ server, and the staging database already live. Walk away. On the train, open
12
+ your phone: read what the agent did, answer its question, approve the migration
13
+ — over a link only your devices can decrypt. The work never left your machine.
14
+
15
+ ```bash
16
+ curl -fsSL https://bivy.sh/install.sh | bash # install + guided setup
17
+ bivy run claude # start an agent in your repo
18
+ bivy open # pick it up from your phone or browser
19
+ ```
20
+
21
+ **[Quickstart](docs/quickstart.md)** ·
22
+ **[Docs](docs/README.md)** ·
23
+ **[Why Bivy](docs/why-bivy.md)** ·
24
+ **[Security model](docs/security-model.md)** ·
25
+ **[bivy.sh](https://bivy.sh)**
26
+
27
+ > **0.x software.** The core loop is solid and used daily. Interfaces and
28
+ > cross-runtime fidelity still change between releases — check the
29
+ > [runtime support matrix](docs/runtime-support-matrix.md) before you depend on
30
+ > a specific agent capability.
31
+
32
+ ## Why not just a cloud sandbox?
33
+
34
+ A hosted sandbox starts from an *approximation* of your environment. A Bivy
35
+ Machine **is** your environment — the actual working tree, the services already
36
+ running, the caches already warm.
37
+
38
+ | | Cloud sandbox | Bivy Machine |
39
+ |---|---|---|
40
+ | Your repository | a cloned copy | the real working tree, uncommitted changes and all |
41
+ | Dev server & database | mocked, or absent | already running, right beside the agent |
42
+ | Private networks & internal APIs | out of reach | reachable |
43
+ | Toolchains, package caches | cold, reinstalled each time | warm, already installed |
44
+ | GPUs / local inference | rented separately | the ones on your box |
45
+ | Where your code sits | someone else's infrastructure | the machine you already trust |
46
+
47
+ You keep the environment. Bivy adds the part that was missing: **reaching that
48
+ environment from anywhere, and leaving it working while you're gone.**
49
+
50
+ ## What you can do
51
+
52
+ Bivy gives you two ways to put an agent to work.
53
+
54
+ ### Sessions — interactive, and portable
55
+
56
+ Start an agent, watch it work, jump in to steer, stop, or approve. Then leave
57
+ your desk and keep going:
58
+
59
+ ```bash
60
+ bivy run claude # or codex, pi, gemini, and a dozen more
61
+ bivy open # continue the same session in the browser or PWA
62
+ bivy resume # pick it back up in the terminal
63
+ bivy run claude --no-follow # start it in the background instead of attaching
64
+ bivy run claude --chat # start the governed app session and open it in the browser
65
+ ```
66
+
67
+ - **Reconnect from anywhere** — phone, browser, or another terminal — to the
68
+ same live Session. The PWA adds voice input, read-aloud, phone-to-agent
69
+ file/image uploads, and agent-to-phone attachments.
21
70
  - **Move work without starting over.** Import existing Claude Code and Codex
22
- Sessions, or fork/copy/move a Bivy Session to another agent, model, or Machine.
23
- Fidelity is runtime-dependent: a fork may use a native transcript, replayed
24
- history, or a bounded seeded continuation, and cross-Machine moves require the
25
- destination's repo access, agent, and credentials.
26
- - **Operate more than one Machine.** Keep a workstation, private-network server,
27
- and GPU box on one account; select the environment a Session or Run needs.
28
- Optional warm Session replication is Beta, off by default, and manually
29
- promoted rather than automatic failover.
30
- - **Let events start checked work.** Create Runs manually or from failed CI,
31
- GitHub/Linear issues, Slack, schedules, and signed webhooks. Automations can
32
- pin a Machine, agent, model, sandbox, approval mode, and attempt ceiling, then
33
- report bounded check and outcome evidence in a Receipt.
34
- - **Bring your own stack.** Use provider subscriptions through supported native
35
- agent logins, API keys in Bivy's vault, or local/OpenAI-compatible inference.
36
- Add an existing ACP or headless process agent with `bivy agent add`; declarative
37
- agent plugins are Experimental (`v1alpha1`) and run out of process.
38
-
39
- Start with the [five-minute quickstart](docs/quickstart.md), then try the
40
- [capability recipes](docs/capability-recipes.md) or check the exact
41
- [runtime support matrix](docs/runtime-support-matrix.md).
71
+ Sessions, or fork, copy, and move a Bivy Session to another agent, model, or
72
+ Machine.
73
+ - **Run more than one Machine** — a workstation, a private-network server, a GPU
74
+ box — on one account, and pick the environment each Session needs.
42
75
 
43
- Interactive Session traffic is end-to-end encrypted between a Machine and its
44
- paired devices, so the relay cannot decrypt it. The seatbelt has a precise edge:
45
- explicitly enabled hosted provisioning may give the control plane technical
46
- access to encrypted cloud, repository, or key-escrow material, while Slack and
47
- generic webhook instructions reach it in plaintext. See [Why Bivy](docs/why-bivy.md)
48
- and the [security model](docs/security-model.md) for the complete trust model.
76
+ ### Runs — unattended, and accountable
49
77
 
50
- - **Website:** [bivy.sh](https://bivy.sh)
51
- - **Documentation:** [`docs/`](docs/README.md)
52
- - **License:** [AGPL-3.0-only](LICENSE)
78
+ Queue one on demand, or let an event kick it off — either way it returns
79
+ immediately and reports back:
53
80
 
54
- > Bivy is 0.x software. The core loop is solid and used daily, but interfaces,
55
- > cross-runtime fidelity, and behaviour can change between releases. Check the
56
- > support matrix before depending on a particular agent capability.
81
+ ```bash
82
+ bivy runs start "..." # queue a one-off unattended Run, then `bivy runs wait <id>`
83
+ bivy automation init # or define governed jobs in .bivy/automations.yaml
84
+ ```
85
+
86
+ - **Trigger from real events** — a failed CI job, a GitHub or Linear issue,
87
+ Slack, a schedule, or a signed webhook.
88
+ - **Pin the guardrails** — Machine, agent, model, sandbox, approval mode, and a
89
+ hard attempt ceiling — right next to the job.
90
+ - **Get a Receipt** — every Run reports the checks it ran and how it turned out,
91
+ not just a wall of output.
92
+
93
+ Try the [capability recipes](docs/capability-recipes.md) to see each of these
94
+ end to end, or the [runtime support matrix](docs/runtime-support-matrix.md) for
95
+ exactly what each agent supports.
96
+
97
+ ## Bring your own stack
98
+
99
+ Use provider subscriptions through native agent logins, API keys stored in
100
+ Bivy's vault, or local / OpenAI-compatible inference. Add any ACP or headless
101
+ agent with a single command — no per-agent adapter to write:
102
+
103
+ ```bash
104
+ bivy agent add # register an existing ACP or process agent
105
+ ```
57
106
 
58
107
  ## Install
59
108
 
@@ -72,18 +121,26 @@ has Bivy just applies the latest build and restarts the service.
72
121
  Already have Node.js 22.19+? The installer is optional:
73
122
 
74
123
  ```bash
75
- npm install -g @bivy/bivy
76
- bivy setup
124
+ npm install -g @bivy/bivy && bivy setup # install globally
125
+ npx @bivy/bivy setup # or try it once, no install
77
126
  ```
78
127
 
79
- Or try it once without installing anything (`npx` always fetches the latest):
128
+ Releases are published from CI with provenance attestations; verify a build's
129
+ origin with `npm audit signatures`. See [`docs/releasing.md`](docs/releasing.md).
130
+
131
+ ### Your first session
132
+
133
+ Once `bivy setup` finishes, the whole loop is three commands — start local,
134
+ reconnect remote:
80
135
 
81
136
  ```bash
82
- npx @bivy/bivy setup
137
+ bivy run claude # start an agent as a durable session in the current repo
138
+ bivy open # open that same session in the web app (needs relay setup)
139
+ bivy resume # or pick it back up here in the terminal
83
140
  ```
84
141
 
85
- Releases are published from CI with provenance attestations; verify a build's
86
- origin with `npm audit signatures`. See [`docs/releasing.md`](docs/releasing.md).
142
+ From here the [quickstart](docs/quickstart.md) walks through Runs, multiple
143
+ Machines, and automations.
87
144
 
88
145
  ### Install options
89
146
 
@@ -141,7 +198,7 @@ when a newer build is available.
141
198
 
142
199
  ## Architecture
143
200
 
144
- Bivy has three parts. Only the first one holds your data.
201
+ Bivy has three parts. **Only the first one holds your data.**
145
202
 
146
203
  ```text
147
204
  your machine hosted or self-hosted
@@ -166,6 +223,8 @@ Bivy has three parts. Only the first one holds your data.
166
223
 
167
224
  Because the node serves no UI, a browser or phone needs a control plane — hosted
168
225
  at `app.bivy.sh`, or one you deploy yourself. The terminal CLI needs neither.
226
+ Interactive Session traffic is end-to-end encrypted between a Machine and its
227
+ paired devices, so the relay cannot decrypt it.
169
228
 
170
229
  See [`docs/remote-access.md`](docs/remote-access.md) and
171
230
  [`docs/security-model.md`](docs/security-model.md).
@@ -173,14 +232,14 @@ See [`docs/remote-access.md`](docs/remote-access.md) and
173
232
  ## Supported agents
174
233
 
175
234
  **Claude Code and Codex are the recommended, release-certified paths.** The
176
- broader catalog remains available under **More agents** for users who need it;
177
- capabilities and fidelity vary by runtime:
235
+ broader catalog stays available under **More agents**; capabilities and fidelity
236
+ vary by runtime.
178
237
 
179
238
  | Agent | Command | Notes |
180
239
  |---|---|---|
181
- | Pi | `bivy run pi` | Uses the operator-installed `pi` command and Pi auth/config |
182
240
  | Claude Code | `bivy run claude` | Uses the operator-installed `claude` command through an SDK bridge |
183
241
  | Codex | `bivy run codex` | Installs `@openai/codex` |
242
+ | Pi | `bivy run pi` | Uses the operator-installed `pi` command and Pi auth/config |
184
243
  | OpenCode | `bivy run opencode` | Installs `opencode-ai` |
185
244
  | Gemini CLI | `bivy run gemini` | Installs `@google/gemini-cli` |
186
245
  | Qwen Code | `bivy run qwen` | Installs `@qwen-code/qwen-code` |
@@ -202,9 +261,8 @@ Any other command works via `bivy run -- ./your-agent --flags`. ACP-capable
202
261
  agents can be promoted to Bivy's governed protocol path for per-tool approvals
203
262
  and native resume. To add a reusable process or ACP agent to both the CLI and web
204
263
  picker without changing Bivy, run `bivy agent add`, or scaffold and install a
205
- declarative [plugin manifest](docs/plugins.md) with `bivy plugin init`. Both use
206
- the same schema/store; the plugin SDK, diagnostics, and ACP conformance fixtures
207
- support distributable or custom protocol bridges.
264
+ declarative [plugin manifest](docs/plugins.md) with `bivy plugin init`
265
+ (declarative plugins are Experimental, `v1alpha1`, and run out of process).
208
266
 
209
267
  [`docs/runtime-support-matrix.md`](docs/runtime-support-matrix.md) lists exactly
210
268
  what each agent supports — resume, model selection, approvals, sandboxing.
@@ -213,8 +271,8 @@ what each agent supports — resume, model selection, approvals, sandboxing.
213
271
 
214
272
  ```bash
215
273
  bivy # show the command overview
216
- bivy run pi # launch Pi as a durable session
217
- bivy run claude # run a different agent
274
+ bivy run claude # launch Claude Code as a durable session
275
+ bivy run codex # run a different agent
218
276
  bivy sessions # list live and saved sessions
219
277
  bivy resume # resume the most recent session
220
278
  bivy open # open the web app (requires relay setup)
@@ -250,24 +308,24 @@ bivy config init --project # .bivy/policy.yaml
250
308
  ```
251
309
 
252
310
  See [`docs/config-as-code.md`](docs/config-as-code.md). Every environment
253
- variable and precedence rule remains in
311
+ variable and precedence rule lives in
254
312
  [`docs/configuration.md`](docs/configuration.md).
255
313
 
256
314
  ## Approvals and sandboxing
257
315
 
258
316
  The default approval mode is **`autonomous`**: agents act without per-action
259
- prompts. The actual protection depends on the selected runtime. Native-sandbox
317
+ prompts. How much that actually protects you depends on the runtime. Native-sandbox
260
318
  agents enforce the chosen access tier; structured runtimes also pass tool calls
261
319
  through Bivy's policy and approval layer. Process agents that Bivy cannot
262
- intercept run with your OS user permissions. The picker shows this distinction
263
- and requires confirmation before selecting that limited path.
320
+ intercept run with your OS user permissions — the picker flags this and requires
321
+ confirmation before you pick that path.
264
322
 
265
323
  Where Bivy receives structured shell/file calls, a heuristic floor blocks known
266
324
  catastrophic commands and structured writes outside the workspace, and a
267
325
  backstop set (force-push, publish, deploy, sudo) pauses for a human. This catches
268
- accidents; it is not an adversarial isolation boundary.
326
+ accidents; **it is not an adversarial isolation boundary.**
269
327
 
270
- If you want to be asked about more, set the mode explicitly:
328
+ Want to be asked about more? Set the mode explicitly:
271
329
 
272
330
  ```bash
273
331
  BIVY_APPROVAL_MODE=risky # prompt on risky shell commands and file edits
@@ -280,19 +338,14 @@ Approve from the terminal, browser, or phone.
280
338
  Sandbox tiers (`read-only`, `workspace-write`, `danger-full-access`) are enforced
281
339
  natively by agents that support them — Codex, Claude Code, Gemini CLI, Qwen Code.
282
340
  Agents without a native sandbox may expose structured tool or MCP controls, but
283
- those controls do not cover activity the agent performs outside those channels;
284
- some process adapters run entirely with your user permissions. Check the
285
- picker's Protection label. **Bivy does not currently ship its own OS-level jail.**
341
+ those don't cover activity the agent performs outside those channels; some
342
+ process adapters run entirely with your user permissions. Check the picker's
343
+ Protection label. **Bivy does not currently ship its own OS-level jail.**
286
344
 
287
345
  ## Credentials
288
346
 
289
347
  Interactive prompts, transcripts, and workspace files stay encrypted across the
290
- relay. Credentials can remain on a Machine or in a vault you control. If you
291
- explicitly enable hosted unattended provisioning, Bivy Cloud may instead store
292
- encrypted cloud, repository, model, or key-escrow material that the service can
293
- technically access. Treat this as an explicit hosted-custody mode, not as relay
294
- blindness. See the
295
- [security model](docs/security-model.md#what-the-control-plane-sees).
348
+ relay. Credentials can remain on a Machine or in a vault you control:
296
349
 
297
350
  ```bash
298
351
  bivy secrets list
@@ -301,9 +354,15 @@ bivy secrets ref github.repo-token op://Bivy/GitHub/repo-token
301
354
  bivy secrets doctor
302
355
  ```
303
356
 
304
- `secret://`, `env://`, and `op://` (1Password) references are resolved on demand
305
- when the daemon provisions an agent run, so the raw values never sit in your
306
- config. See [`docs/key-management.md`](docs/key-management.md).
357
+ `secret://`, `env://`, and `op://` (1Password) references resolve on demand when
358
+ the daemon provisions an agent run, so raw values never sit in your config.
359
+
360
+ **One deliberate exception to relay blindness:** if you explicitly enable hosted
361
+ unattended provisioning, Bivy Cloud may store encrypted cloud, repository,
362
+ model, or key-escrow material that the service can technically access. Treat this
363
+ as an explicit hosted-custody mode. See the
364
+ [security model](docs/security-model.md#what-the-control-plane-sees) and
365
+ [`docs/key-management.md`](docs/key-management.md).
307
366
 
308
367
  ## Automations as code
309
368
 
@@ -318,7 +377,7 @@ bivy automation apply
318
377
  ```
319
378
 
320
379
  Instructions are encrypted on the applying node before upload. Safety policy
321
- lives beside the job—sandbox, approval mode, and a hard attempt ceiling that
380
+ lives beside the job — sandbox, approval mode, and a hard attempt ceiling that
322
381
  retry/fallback rules cannot exceed. See
323
382
  [`docs/automations-as-code.md`](docs/automations-as-code.md).
324
383
 
@@ -399,8 +458,8 @@ Each URL has a flag and an environment-variable equivalent (the flag wins):
399
458
 
400
459
  Sign-in defaults to GitHub device login (`--github`); pass
401
460
  `--email you@example.com` for an email magic-link, or `--session-token <token>`
402
- to skip interactive sign-in. `relay:setup` checks the control plane is reachable, enrolls
403
- this node, and writes the endpoints to `.bivy/relay.json`, so `bivy open`,
461
+ to skip interactive sign-in. `relay:setup` checks the control plane is reachable,
462
+ enrolls this node, and writes the endpoints to `.bivy/relay.json`, so `bivy open`,
404
463
  `bivy link`, and `bivy update` all keep using your deployment afterwards.
405
464
 
406
465
  **Self-hosting is unsupported** — no SLA, community best-effort via GitHub
@@ -410,16 +469,14 @@ issues. You own TLS, backups, upgrades, and hardening. See
410
469
  ## Security
411
470
 
412
471
  Report vulnerabilities through [GitHub private vulnerability reporting](https://github.com/bivysh/bivy/security/advisories/new).
413
- Please do not open a public issue. See [`SECURITY.md`](SECURITY.md) for scope,
472
+ Please don't open a public issue. See [`SECURITY.md`](SECURITY.md) for scope,
414
473
  response times, and safe harbour, and [`docs/security-model.md`](docs/security-model.md)
415
474
  for the trust model and known limitations.
416
475
 
417
476
  ## License
418
477
 
419
- Bivy Core is free and open-source software licensed under the GNU Affero General
420
- Public License, version 3.0 only (AGPL-3.0-only). You may use, study, modify, and
478
+ Bivy Core is free and open-source software under the GNU Affero General Public
479
+ License, version 3.0 only (AGPL-3.0-only). You may use, study, modify, and
421
480
  self-host it under that license. If you modify Bivy and let users interact with
422
- it over a network, section 13 requires you to offer those users the corresponding
423
- source code.
424
-
425
- See [`LICENSE`](LICENSE).
481
+ it over a network, section 13 requires you to offer them the corresponding
482
+ source code. See [`LICENSE`](LICENSE).
package/bin/bivy.mjs CHANGED
@@ -939,12 +939,14 @@ function extractRunFlags(args) {
939
939
  let name, model, node, workspace;
940
940
  let chat = false;
941
941
  let noOpen = false;
942
+ let noFollow = false;
942
943
  let clone; // undefined = no clone; true = current repo; string = explicit remote
943
944
  for (let i = 0; i < args.length; i++) {
944
945
  const a = args[i];
945
946
  if (a === "--") { rest.push(...args.slice(i)); break; }
946
947
  if (a === "--chat") { chat = true; continue; }
947
948
  if (a === "--no-open") { noOpen = true; continue; }
949
+ if (a === "--no-follow") { noFollow = true; continue; }
948
950
  if (a === "--name" && args[i + 1] !== undefined) { name = args[++i]; continue; }
949
951
  if (a.startsWith("--name=")) { name = a.slice("--name=".length); continue; }
950
952
  if (a === "--model" && args[i + 1] !== undefined) { model = args[++i]; continue; }
@@ -957,7 +959,7 @@ function extractRunFlags(args) {
957
959
  if (a === "--clone") { clone = looksLikeRemote(args[i + 1]) ? args[++i] : true; continue; }
958
960
  rest.push(a);
959
961
  }
960
- return { name: name?.trim() || undefined, model: model?.trim() || undefined, node: node?.trim() || undefined, workspace: workspace?.trim() || undefined, chat, noOpen, clone, rest };
962
+ return { name: name?.trim() || undefined, model: model?.trim() || undefined, node: node?.trim() || undefined, workspace: workspace?.trim() || undefined, chat, noOpen, noFollow, clone, rest };
961
963
  }
962
964
 
963
965
  // A safe-ish workspace dir name from a remote or path (basename minus .git).
@@ -1813,12 +1815,20 @@ function governedChatAgentId(id) {
1813
1815
 
1814
1816
  async function cmdRun(args = []) {
1815
1817
  if (!(await ensureDeps())) process.exit(1);
1816
- const { name, model, node, workspace, chat, noOpen, clone, rest } = extractRunFlags(args);
1818
+ const { name, model, node, workspace, chat, noOpen, noFollow, clone, rest } = extractRunFlags(args);
1817
1819
  // Bare `bivy` (empty rest) resolves to the configured default agent; an
1818
1820
  // explicit `bivy run <agent>` keeps that agent verbatim.
1819
1821
  const [agentIdArg, ...extraArgs] = rest;
1820
1822
  const agentId = agentIdArg || resolveDefaultAgent();
1821
1823
 
1824
+ // --chat already returns immediately, so --no-follow adds nothing there; keep
1825
+ // the two paths distinct rather than silently ignoring the flag.
1826
+ if (chat && noFollow) {
1827
+ console.error(c.red("--no-follow applies to native runs; a --chat session already starts in the background (use --no-open to skip opening the browser)."));
1828
+ process.exit(1);
1829
+ return;
1830
+ }
1831
+
1822
1832
  if (chat) {
1823
1833
  if (node) {
1824
1834
  console.error(c.red("--chat currently starts a governed session on this node; it can't be combined with --node."));
@@ -1923,6 +1933,9 @@ async function cmdRun(args = []) {
1923
1933
  "--relay-config", relayConfigPath,
1924
1934
  "--attach-cmd", JSON.stringify(nodeScriptArgs(attachEntry)),
1925
1935
  "--run", JSON.stringify(spec),
1936
+ // The remote run-terminal is daemon-owned there too, so once it is open
1937
+ // the relay bridge can drop and the session keeps running on the target.
1938
+ ...(noFollow ? ["--no-follow"] : []),
1926
1939
  ], { cwd: repoRoot, env: process.env });
1927
1940
  return;
1928
1941
  }
@@ -1935,7 +1948,7 @@ async function cmdRun(args = []) {
1935
1948
  }
1936
1949
  const spec = { ...resolved.spec, name, model, workspace: undefined }; // workspace is the remote node's, not ours
1937
1950
  console.log(c.dim(`Starting on ${c.cyan(node)} (${target.url})…`));
1938
- await run(nodeBin, [...nodeScriptArgs(attachEntry), "--url", target.url, ...(target.token ? ["--token", target.token] : []), "--run", JSON.stringify(spec)], {
1951
+ await run(nodeBin, [...nodeScriptArgs(attachEntry), "--url", target.url, ...(target.token ? ["--token", target.token] : []), "--run", JSON.stringify(spec), ...(noFollow ? ["--no-follow"] : [])], {
1939
1952
  cwd: repoRoot,
1940
1953
  env: process.env,
1941
1954
  });
@@ -1961,7 +1974,7 @@ async function cmdRun(args = []) {
1961
1974
  try { token = await localDeviceToken(config); }
1962
1975
  catch (error) { console.error(c.red(error?.message || String(error))); process.exit(1); return; }
1963
1976
 
1964
- process.exit(await run(nodeBin, [...nodeScriptArgs(attachEntry), "--url", url(config), "--token", token, "--run", JSON.stringify(spec)], {
1977
+ process.exit(await run(nodeBin, [...nodeScriptArgs(attachEntry), "--url", url(config), "--token", token, "--run", JSON.stringify(spec), ...(noFollow ? ["--no-follow"] : [])], {
1965
1978
  cwd: repoRoot,
1966
1979
  env: startEnv(config),
1967
1980
  }));
@@ -4769,10 +4782,11 @@ async function main() {
4769
4782
  // args (including its own --help) pass straight through to it — e.g.
4770
4783
  // 'bivy run claude --help' must show Claude's help, not bivy's.
4771
4784
  if (args[0] === "-h" || args[0] === "--help") {
4772
- console.log(`Usage: bivy run <agent> [--chat [--no-open]] [--name <label>] [--model <model>] [--node <name>] [--clone [remote]] [--workspace <dir>] | -- <command>
4785
+ console.log(`Usage: bivy run <agent> [--chat [--no-open] | --no-follow] [--name <label>] [--model <model>] [--node <name>] [--clone [remote]] [--workspace <dir>] | -- <command>
4773
4786
 
4774
4787
  Run a native agent (real CLI/TUI) as a relay-visible session.
4775
4788
  Use --chat to start the governed session used by the app instead; --no-open prints its URL without launching a browser.
4789
+ Use --no-follow to start the native session in the background without attaching your terminal; rejoin it with 'bivy resume' or open it in the app.
4776
4790
  Agents: ${[...AGENT_INTEGRATIONS.keys()].join(", ")}, or -- <command> for anything else.
4777
4791
  An agent's own --help passes through, e.g. 'bivy run claude --help'.`);
4778
4792
  break;
@@ -67,10 +67,18 @@ const SDK_PACKAGE = "@anthropic-ai/claude-agent-sdk";
67
67
  // the first prompt. Until then this.models is empty and the picker would show
68
68
  // nothing. These are the models a Claude Pro/Max subscription exposes; once
69
69
  // the query is up, supportedModels() replaces them with the authoritative set.
70
+ // Placeholder catalog shown before a live agent can answer (see getModels() and
71
+ // warmModels()). A not-yet-started session has no subprocess to query, so the
72
+ // picker shows this until warmModels() spawns one and supportedModels() replaces
73
+ // it with the account's real, current lineup. Keep it roughly current so the
74
+ // pre-warm placeholder isn't jarringly stale, but it is only a placeholder — the
75
+ // live list is the source of truth.
70
76
  const FALLBACK_MODELS = [
77
+ { provider: "anthropic", id: "claude-opus-5", name: "Claude Opus 5", reasoning: true },
71
78
  { provider: "anthropic", id: "claude-opus-4-8", name: "Claude Opus 4.8", reasoning: true },
72
79
  { provider: "anthropic", id: "claude-sonnet-5", name: "Claude Sonnet 5", reasoning: true },
73
80
  { provider: "anthropic", id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5", reasoning: true },
81
+ { provider: "anthropic", id: "claude-fable-5", name: "Claude Fable 5", reasoning: true },
74
82
  ];
75
83
  // The SDK's supportedModels() labels each row with a bare family+version
76
84
  // ("Opus 4.8") or a family alias ("Sonnet", "Haiku") — while a not-yet-started
@@ -927,6 +935,29 @@ class ClaudeSession {
927
935
  clearTimeout(timer);
928
936
  }
929
937
  }
938
+ /**
939
+ * Spin up the agent subprocess *without* sending a prompt, purely so
940
+ * supportedModels() can resolve and the picker shows the account's real,
941
+ * current lineup instead of FALLBACK_MODELS. Used to warm a not-yet-started
942
+ * (e.g. draft/new-session) catalog. Gated on credentials — mirroring prompt()'s
943
+ * preflight — so we never spawn a subprocess that would only fail; without a
944
+ * credential the picker simply keeps the placeholder list. Best-effort and
945
+ * idempotent: once the query is up it just re-reads the list.
946
+ */
947
+ async warmModels() {
948
+ if (this.query)
949
+ return this.refreshSupportedModels();
950
+ try {
951
+ const env = { ...process.env, ...depCacheEnv(this.cwd), ...this.runtimeOptions.env, ...(await this.resolveCredentialEnv().catch(() => ({}))) };
952
+ if (anthropicCredentialPreflight(env))
953
+ return; // no credential — keep FALLBACK_MODELS
954
+ await this.ensureStarted();
955
+ await this.refreshSupportedModels();
956
+ }
957
+ catch {
958
+ // Spawn/credential failure — the picker keeps FALLBACK_MODELS.
959
+ }
960
+ }
930
961
  /**
931
962
  * Tear down the running query and re-spawn it resuming the same session, using
932
963
  * a freshly-resolved vault credential (Pi's AuthStorage auto-refreshes an
package/dist/attach.js CHANGED
@@ -15,6 +15,10 @@ import { WebSocket } from "ws";
15
15
  * Modes:
16
16
  * --run <specJson> open a fresh run-terminal for a resolved agent command
17
17
  * --attach <termId> bind to an existing run-terminal (replays scrollback)
18
+ *
19
+ * With `--run --no-follow` the terminal is started but never bound to the local
20
+ * TTY: the daemon keeps the PTY running and this process returns immediately, so
21
+ * `bivy run <agent> --no-follow` launches a background session you rejoin later.
18
22
  */
19
23
  const c = {
20
24
  dim: (s) => `\x1b[2m${s}\x1b[22m`,
@@ -52,6 +56,7 @@ function parseArgs(argv) {
52
56
  let mode = "attach";
53
57
  let run;
54
58
  let termId;
59
+ let noFollow = false;
55
60
  for (let i = 0; i < argv.length; i++) {
56
61
  const arg = argv[i];
57
62
  if (arg === "--url" && argv[i + 1])
@@ -70,8 +75,10 @@ function parseArgs(argv) {
70
75
  mode = "attach";
71
76
  termId = argv[++i];
72
77
  }
78
+ else if (arg === "--no-follow")
79
+ noFollow = true;
73
80
  }
74
- return { url: url.replace(/\/+$/, ""), token, mode, run, termId };
81
+ return { url: url.replace(/\/+$/, ""), token, mode, run, termId, noFollow };
75
82
  }
76
83
  function wsUrl(baseUrl, token) {
77
84
  const u = new URL(baseUrl);
@@ -219,11 +226,62 @@ function bridge(args, open) {
219
226
  });
220
227
  });
221
228
  }
229
+ /**
230
+ * Start a run-terminal on the daemon and return immediately, WITHOUT binding the
231
+ * local TTY. The PTY is daemon-owned, so it keeps running once this client
232
+ * disconnects — the same lifecycle as a Ctrl-\ Ctrl-\ detach, except the
233
+ * terminal was never attached in the first place. Resolves once the daemon
234
+ * confirms the terminal is open (or errors trying).
235
+ */
236
+ function openDetached(args, spec, cols, rows) {
237
+ return new Promise((resolve) => {
238
+ const socket = new WebSocket(wsUrl(args.url, args.token));
239
+ let settled = false;
240
+ const finish = (code) => {
241
+ if (settled)
242
+ return;
243
+ settled = true;
244
+ try {
245
+ socket.close();
246
+ }
247
+ catch { }
248
+ resolve(code);
249
+ };
250
+ socket.on("open", () => socket.send(JSON.stringify({ kind: "terminal.open.run", agent: spec.agent, label: spec.label, name: spec.name, model: spec.model, command: spec.command, args: spec.args ?? [], workspace: spec.workspace, sessionId: spec.sessionId, cols, rows })));
251
+ socket.on("error", (err) => {
252
+ process.stderr.write(c.red(`Connection error: ${err instanceof Error ? err.message : String(err)}\n`));
253
+ finish(1);
254
+ });
255
+ socket.on("close", () => finish(settled ? 0 : 1));
256
+ socket.on("message", (raw) => {
257
+ let msg;
258
+ try {
259
+ msg = JSON.parse(raw.toString());
260
+ }
261
+ catch {
262
+ return;
263
+ }
264
+ if (msg.type === "terminal.opened") {
265
+ const label = spec.name || spec.label || spec.agent || spec.command;
266
+ process.stdout.write(c.green(`Started ${label} in the background.\n`));
267
+ process.stdout.write(c.dim("It keeps running — reopen it in the Bivy app, or with `bivy resume`.\n"));
268
+ finish(0);
269
+ }
270
+ else if (msg.type === "terminal.error") {
271
+ process.stderr.write(c.red(`${String(msg.error || "Terminal error")}\n`));
272
+ finish(1);
273
+ }
274
+ });
275
+ });
276
+ }
222
277
  async function main() {
223
278
  const args = parseArgs(process.argv.slice(2));
224
279
  if (args.mode === "run") {
225
280
  const spec = args.run;
226
281
  const { cols, rows } = termSize();
282
+ if (args.noFollow) {
283
+ process.exit(await openDetached(args, spec, cols, rows));
284
+ }
227
285
  process.stdout.write(c.dim(`Starting ${c.cyan(spec.name || spec.label || spec.agent || spec.command)} — Ctrl-\\ Ctrl-\\ to detach\r\n`));
228
286
  const code = await bridge(args, (ws) => ws.send(JSON.stringify({ kind: "terminal.open.run", agent: spec.agent, label: spec.label, name: spec.name, model: spec.model, command: spec.command, args: spec.args ?? [], workspace: spec.workspace, sessionId: spec.sessionId, cols, rows })));
229
287
  process.exit(code);
@@ -72,6 +72,7 @@ function parseArgs(argv) {
72
72
  attachCmd,
73
73
  run: get("--run"),
74
74
  attachTermId: get("--attach"),
75
+ noFollow: argv.includes("--no-follow"),
75
76
  label: get("--label") || "Bivy CLI (run --node)",
76
77
  };
77
78
  }
@@ -316,6 +317,7 @@ async function main() {
316
317
  localUrl,
317
318
  ...(args.run ? ["--run", args.run] : []),
318
319
  ...(args.attachTermId ? ["--attach", args.attachTermId] : []),
320
+ ...(args.noFollow ? ["--no-follow"] : []),
319
321
  ];
320
322
  note(c.dim(`Paired ✓ starting session on ${c.cyan(args.nodeName)}\n`));
321
323
  const child = spawn(process.execPath, childArgs, { stdio: "inherit", env: process.env });
package/dist/server.js CHANGED
@@ -2411,16 +2411,12 @@ const RELAY_COMMANDS = {
2411
2411
  if (!requestedSessionId && wantedRuntimeId && record?.runtimeId !== wantedRuntimeId)
2412
2412
  record = null;
2413
2413
  record ??= await sessionForModelQuery(wantedRuntimeId);
2414
- const session = record.session;
2415
- const current = session.getCurrentModel();
2416
- const models = await publicModelsList(session, current);
2417
- const thinking = publicThinkingInfo(session);
2418
2414
  // Tag the list with the runtime it was resolved for so the client can
2419
2415
  // tell whether it belongs to the agent it currently has selected. Without
2420
2416
  // this a models.list answered for one agent (e.g. Codex's models) could
2421
2417
  // linger on the composer/picker after the user switched to another agent
2422
2418
  // (e.g. Claude) — the "Claude shows Codex models" bug.
2423
- relay?.sendEvent({ type: "models.list", sessionId: record.id, runtimeId: record.runtimeId, current: current ? publicModel(current, current) : null, models, thinking });
2419
+ relay?.sendEvent(await modelsListEventFor(record));
2424
2420
  },
2425
2421
  "models.prefetch"(msg) {
2426
2422
  // The composer's agent picker opened: warm the scratch session for each
@@ -8105,11 +8101,28 @@ async function sessionForModelQuery(runtimeId) {
8105
8101
  if (inflight)
8106
8102
  return inflight;
8107
8103
  const build = createSession(defaultWorkspace, undefined, { makeActive: false, ephemeral: true, runtimeId: wanted })
8108
- .then((rec) => { modelQueryScratch.set(wanted, rec); return rec; })
8104
+ .then((rec) => { modelQueryScratch.set(wanted, rec); void warmScratchModels(rec); return rec; })
8109
8105
  .finally(() => { modelQueryScratchPending.delete(wanted); });
8110
8106
  modelQueryScratchPending.set(wanted, build);
8111
8107
  return build;
8112
8108
  }
8109
+ // A fresh scratch answers its first models.list from the runtime's placeholder
8110
+ // list (no live agent yet). Warm the real catalog in the background — for Claude
8111
+ // Code this spins up the agent subprocess just far enough for supportedModels()
8112
+ // to resolve — then push an updated models.list so a picker opened on the
8113
+ // placeholder repaints with the account's actual, current lineup. Best-effort:
8114
+ // a runtime without warmModels() (static catalog) or a warm failure is a no-op.
8115
+ async function warmScratchModels(rec) {
8116
+ if (typeof rec.session.warmModels !== "function")
8117
+ return;
8118
+ try {
8119
+ await rec.session.warmModels();
8120
+ relay?.sendEvent(await modelsListEventFor(rec));
8121
+ }
8122
+ catch {
8123
+ // Keep the placeholder list; the on-demand models.list path surfaces real errors.
8124
+ }
8125
+ }
8113
8126
  /**
8114
8127
  * Warm the model-query scratch for one or more runtimes in the background so the
8115
8128
  * first agent switch to any of them answers instantly instead of paying the
@@ -8974,6 +8987,16 @@ async function publicModelsList(session, current) {
8974
8987
  }));
8975
8988
  return [...connected, ...other];
8976
8989
  }
8990
+ // Build the models.list event for a session/scratch record — the single shape
8991
+ // both the on-demand handler and the background warm-push send, so an open
8992
+ // picker updates identically however the list was produced.
8993
+ async function modelsListEventFor(record) {
8994
+ const session = record.session;
8995
+ const current = session.getCurrentModel();
8996
+ const models = await publicModelsList(session, current);
8997
+ const thinking = publicThinkingInfo(session);
8998
+ return { type: "models.list", sessionId: record.id, runtimeId: record.runtimeId, current: current ? publicModel(current, current) : null, models, thinking };
8999
+ }
8977
9000
  function publicThinkingInfo(session) {
8978
9001
  const supports = typeof session.supportsThinking === "function" ? session.supportsThinking() : false;
8979
9002
  const level = typeof session.getThinkingLevel === "function" ? session.getThinkingLevel() : undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bivy/bivy",
3
- "version": "0.10.1-staging.372",
3
+ "version": "0.10.1-staging.374",
4
4
  "type": "module",
5
5
  "license": "AGPL-3.0-only",
6
6
  "description": "Run coding agents on machines you own. Open-source, self-hostable agent workspace.",
@@ -63,6 +63,6 @@
63
63
  "brace-expansion": "5.0.9",
64
64
  "undici": "8.10.0"
65
65
  },
66
- "readme": "# Bivy\n\n**Give coding agents your real environment, then reach them from anywhere.**\n\nA provider sandbox starts from an approximation. A Bivy Machine can use the\nrepository, local services and databases, private networks, existing tools and\ncaches, and GPUs or local inference already available on your workstation or\nserver. Bivy turns that local capability into Sessions you can continue remotely\nand Runs you can leave working unattended.\n\n## What Bivy lets you do\n\n- **Work where the full environment lives.** Run Claude Code, Codex, Pi, or\n another agent beside real repos, dev servers, databases, internal APIs,\n toolchains, package caches, and specialized compute.\n- **Continue from a phone, browser, or terminal.** Reconnect to the same Session,\n steer or stop it, answer questions, and approve supported tool calls. The PWA\n supports voice input and read-aloud, phone-to-agent file/image uploads, and\n agent-to-phone attachments. Native terminal Sessions can stay remote-visible;\n supported runtimes can hand work between terminal and structured chat.\n- **Move work without starting over.** Import existing Claude Code and Codex\n Sessions, or fork/copy/move a Bivy Session to another agent, model, or Machine.\n Fidelity is runtime-dependent: a fork may use a native transcript, replayed\n history, or a bounded seeded continuation, and cross-Machine moves require the\n destination's repo access, agent, and credentials.\n- **Operate more than one Machine.** Keep a workstation, private-network server,\n and GPU box on one account; select the environment a Session or Run needs.\n Optional warm Session replication is Beta, off by default, and manually\n promoted rather than automatic failover.\n- **Let events start checked work.** Create Runs manually or from failed CI,\n GitHub/Linear issues, Slack, schedules, and signed webhooks. Automations can\n pin a Machine, agent, model, sandbox, approval mode, and attempt ceiling, then\n report bounded check and outcome evidence in a Receipt.\n- **Bring your own stack.** Use provider subscriptions through supported native\n agent logins, API keys in Bivy's vault, or local/OpenAI-compatible inference.\n Add an existing ACP or headless process agent with `bivy agent add`; declarative\n agent plugins are Experimental (`v1alpha1`) and run out of process.\n\nStart with the [five-minute quickstart](docs/quickstart.md), then try the\n[capability recipes](docs/capability-recipes.md) or check the exact\n[runtime support matrix](docs/runtime-support-matrix.md).\n\nInteractive Session traffic is end-to-end encrypted between a Machine and its\npaired devices, so the relay cannot decrypt it. The seatbelt has a precise edge:\nexplicitly enabled hosted provisioning may give the control plane technical\naccess to encrypted cloud, repository, or key-escrow material, while Slack and\ngeneric webhook instructions reach it in plaintext. See [Why Bivy](docs/why-bivy.md)\nand the [security model](docs/security-model.md) for the complete trust model.\n\n- **Website:** [bivy.sh](https://bivy.sh)\n- **Documentation:** [`docs/`](docs/README.md)\n- **License:** [AGPL-3.0-only](LICENSE)\n\n> Bivy is 0.x software. The core loop is solid and used daily, but interfaces,\n> cross-runtime fidelity, and behaviour can change between releases. Check the\n> support matrix before depending on a particular agent capability.\n\n## Install\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash\n```\n\nmacOS and Linux. Requires Node.js 22.19 or newer; the installer installs it for\nyou on Debian/Ubuntu and otherwise points you at nodejs.org. It installs the\n[`@bivy/bivy`](https://www.npmjs.com/package/@bivy/bivy) package from npm, puts\nthe `bivy` command on your `PATH`, then runs the guided `bivy setup` wizard —\nagent choice, relay/control-plane sign-in, and an auto-start background service\n(launchd on macOS, systemd on Linux). Re-running it on a machine that already\nhas Bivy just applies the latest build and restarts the service.\n\nAlready have Node.js 22.19+? The installer is optional:\n\n```bash\nnpm install -g @bivy/bivy\nbivy setup\n```\n\nOr try it once without installing anything (`npx` always fetches the latest):\n\n```bash\nnpx @bivy/bivy setup\n```\n\nReleases are published from CI with provenance attestations; verify a build's\norigin with `npm audit signatures`. See [`docs/releasing.md`](docs/releasing.md).\n\n### Install options\n\nEnvironment variables passed to the one-line installer change what it does:\n\n| Goal | Variable |\n|---|---|\n| Track the dev channel (new build on every merge to `main`) | `BIVY_CHANNEL=staging` |\n| Pin an exact version | `BIVY_VERSION=0.1.0` |\n| Install without sudo, into a user-owned prefix | `BIVY_NPM_PREFIX=~/.local` |\n| Preinstall every known upstream agent | `BIVY_INSTALL_ALL_AGENTS=1` |\n\nFor example: `BIVY_CHANNEL=staging curl -fsSL https://bivy.sh/install.sh | bash`.\n\nWorking from a checkout of this repository instead:\n\n```bash\npnpm install\npnpm run setup\n```\n\nSee [`docs/install.md`](docs/install.md) for where data lives, service\nmanagement, and uninstall.\n\n## Updating\n\n```bash\nbivy update\n```\n\n`bivy update` detects how Bivy was installed and does the right thing, then\nwaits for any active session to finish its current turn and restarts the\nbackground service so the node reconnects on the new build:\n\n| Install kind | What `bivy update` does |\n|---|---|\n| npm global (`npm i -g`) | `npm install -g @bivy/bivy@<channel>`, then restart the service |\n| installer / packaged | re-runs `install.sh` (migrating to npm if needed), then restart |\n| git checkout | `git pull --ff-only` + `pnpm install --frozen-lockfile`, then restart |\n| `npx` run | nothing to update — each run already fetches the latest |\n\nUpdates follow the release **channel** recorded at install time — `latest`\n(production) by default, or `staging` if you installed with\n`BIVY_CHANNEL=staging`. Switch channels (the choice is remembered for next\ntime), or skip the wait for a busy session:\n\n```bash\nbivy update --staging # move to the dev channel\nbivy update --stable # move back to production (latest)\nbivy update --force # don't wait for an in-flight turn to finish\n```\n\nThe daemon also checks the registry periodically and posts an in-session notice\nwhen a newer build is available.\n\n## Architecture\n\nBivy has three parts. Only the first one holds your data.\n\n```text\n your machine hosted or self-hosted\n\n ┌──────────────┐ ┌─────────┐ ┌───────────────┐\n │ node daemon │ ──dials──▶ │ relay │ ◀────▶ │ control plane │\n │ agents, keys │ outbound │ opaque │ │ accounts, web │\n │ repo, tools │ │ frames │ │ app, metadata │\n └──────────────┘ └─────────┘ └───────────────┘\n ▲ ▲\n └────────── end-to-end encrypted session ───────────┘\n phone · browser · another terminal\n```\n\n- **Node** — a daemon on your machine. Owns the workspace, credentials, and agent\n processes. Serves an API and WebSocket on `http://localhost:4317` plus a\n `/healthz` probe. **It hosts no web UI.**\n- **Relay** — forwards encrypted frames between your node and your devices. Your\n node dials out, so no inbound port is opened. The relay cannot read the frames.\n- **Control plane** — holds your account, node registry, and session index, and\n serves the web/PWA client. Use the hosted one or run your own.\n\nBecause the node serves no UI, a browser or phone needs a control plane — hosted\nat `app.bivy.sh`, or one you deploy yourself. The terminal CLI needs neither.\n\nSee [`docs/remote-access.md`](docs/remote-access.md) and\n[`docs/security-model.md`](docs/security-model.md).\n\n## Supported agents\n\n**Claude Code and Codex are the recommended, release-certified paths.** The\nbroader catalog remains available under **More agents** for users who need it;\ncapabilities and fidelity vary by runtime:\n\n| Agent | Command | Notes |\n|---|---|---|\n| Pi | `bivy run pi` | Uses the operator-installed `pi` command and Pi auth/config |\n| Claude Code | `bivy run claude` | Uses the operator-installed `claude` command through an SDK bridge |\n| Codex | `bivy run codex` | Installs `@openai/codex` |\n| OpenCode | `bivy run opencode` | Installs `opencode-ai` |\n| Gemini CLI | `bivy run gemini` | Installs `@google/gemini-cli` |\n| Qwen Code | `bivy run qwen` | Installs `@qwen-code/qwen-code` |\n| Goose | `bivy run goose` | Requires `goose` on PATH |\n| Aider | `bivy run aider` | No session resume (upstream gap) |\n| Cline | `bivy run cline` | Installs `cline` |\n| Crush | `bivy run crush` | No session resume (upstream gap) |\n| Cursor | `bivy run cursor` | ACP-capable |\n| GitHub Copilot | `bivy run copilot` | ACP-capable |\n| Grok | `bivy run grok` | Model selection |\n| Amp | `bivy run amp` | Native thread resume |\n| Auggie | `bivy run auggie` | Headless CLI |\n| Droid | `bivy run droid` | Model selection |\n| Continue | `bivy run continue` | Headless CLI |\n| Kilo Code | `bivy run kilocode` | ACP-capable |\n| Rovo Dev | `bivy run rovodev` | Installed out of band |\n\nAny other command works via `bivy run -- ./your-agent --flags`. ACP-capable\nagents can be promoted to Bivy's governed protocol path for per-tool approvals\nand native resume. To add a reusable process or ACP agent to both the CLI and web\npicker without changing Bivy, run `bivy agent add`, or scaffold and install a\ndeclarative [plugin manifest](docs/plugins.md) with `bivy plugin init`. Both use\nthe same schema/store; the plugin SDK, diagnostics, and ACP conformance fixtures\nsupport distributable or custom protocol bridges.\n\n[`docs/runtime-support-matrix.md`](docs/runtime-support-matrix.md) lists exactly\nwhat each agent supports — resume, model selection, approvals, sandboxing.\n\n## Common commands\n\n```bash\nbivy # show the command overview\nbivy run pi # launch Pi as a durable session\nbivy run claude # run a different agent\nbivy sessions # list live and saved sessions\nbivy resume # resume the most recent session\nbivy open # open the web app (requires relay setup)\nbivy automation init # create .bivy/automations.yaml\nbivy agent add # connect an existing ACP or process agent\nbivy plugin list # installed declarative integration packages\nbivy status # config summary and node reachability\nbivy doctor # health check\nbivy logs -f # tail node logs\nbivy update # update Bivy and restart the service\n```\n\nFull command list, flags, and examples: [`docs/cli-reference.md`](docs/cli-reference.md).\n\n## Configuration\n\nThe common knobs:\n\n```bash\nBIVY_WORKSPACE=/path/to/repo # default workspace\nBIVY_SANDBOX=read-only # read-only | workspace-write (default) | danger-full-access\nBIVY_APPROVAL_MODE=risky # never | risky | always | autonomous (default)\n```\n\nCreate and inspect the typed node configuration, or add repository-owned\nsafety/check/retry policy:\n\n```bash\nbivy config init\nbivy config set defaults.agent codex\nbivy config explain defaults.sandbox\nbivy config init --project # .bivy/policy.yaml\n```\n\nSee [`docs/config-as-code.md`](docs/config-as-code.md). Every environment\nvariable and precedence rule remains in\n[`docs/configuration.md`](docs/configuration.md).\n\n## Approvals and sandboxing\n\nThe default approval mode is **`autonomous`**: agents act without per-action\nprompts. The actual protection depends on the selected runtime. Native-sandbox\nagents enforce the chosen access tier; structured runtimes also pass tool calls\nthrough Bivy's policy and approval layer. Process agents that Bivy cannot\nintercept run with your OS user permissions. The picker shows this distinction\nand requires confirmation before selecting that limited path.\n\nWhere Bivy receives structured shell/file calls, a heuristic floor blocks known\ncatastrophic commands and structured writes outside the workspace, and a\nbackstop set (force-push, publish, deploy, sudo) pauses for a human. This catches\naccidents; it is not an adversarial isolation boundary.\n\nIf you want to be asked about more, set the mode explicitly:\n\n```bash\nBIVY_APPROVAL_MODE=risky # prompt on risky shell commands and file edits\nBIVY_APPROVAL_MODE=always # prompt on all shell commands and file edits\nBIVY_APPROVAL_MODE=never # no prompts; structured-tool heuristic blocks still apply where available\n```\n\nApprove from the terminal, browser, or phone.\n\nSandbox tiers (`read-only`, `workspace-write`, `danger-full-access`) are enforced\nnatively by agents that support them — Codex, Claude Code, Gemini CLI, Qwen Code.\nAgents without a native sandbox may expose structured tool or MCP controls, but\nthose controls do not cover activity the agent performs outside those channels;\nsome process adapters run entirely with your user permissions. Check the\npicker's Protection label. **Bivy does not currently ship its own OS-level jail.**\n\n## Credentials\n\nInteractive prompts, transcripts, and workspace files stay encrypted across the\nrelay. Credentials can remain on a Machine or in a vault you control. If you\nexplicitly enable hosted unattended provisioning, Bivy Cloud may instead store\nencrypted cloud, repository, model, or key-escrow material that the service can\ntechnically access. Treat this as an explicit hosted-custody mode, not as relay\nblindness. See the\n[security model](docs/security-model.md#what-the-control-plane-sees).\n\n```bash\nbivy secrets list\nbivy secrets set github.repo-token\nbivy secrets ref github.repo-token op://Bivy/GitHub/repo-token\nbivy secrets doctor\n```\n\n`secret://`, `env://`, and `op://` (1Password) references are resolved on demand\nwhen the daemon provisions an agent run, so the raw values never sit in your\nconfig. See [`docs/key-management.md`](docs/key-management.md).\n\n## Automations as code\n\nDefine governed jobs in `.bivy/automations.yaml`, validate them, and simulate\ntrigger events locally before applying anything:\n\n```bash\nbivy automation init\nbivy automation validate\nbivy automation test --event .bivy/events/failed-ci.yaml\nbivy automation apply\n```\n\nInstructions are encrypted on the applying node before upload. Safety policy\nlives beside the job—sandbox, approval mode, and a hard attempt ceiling that\nretry/fallback rules cannot exceed. See\n[`docs/automations-as-code.md`](docs/automations-as-code.md).\n\n## GitHub Runs\n\nLabel an issue `bivy` (or `bivy/<machine>` to target a Machine), or mention the\nBivy GitHub App in a comment. Bivy creates a Run on the selected Machine, uses an\nisolated worktree, executes configured checks, and reports an explicit outcome.\n\nCore applies no commercial usage limits. Bivy Cloud billing and commercial\npolicy live in the separate Cloud repository.\n\nA private GitHub App only installs on the account that owns it, so connect one\napp per GitHub account — one for your personal repos, one per organization\n(`bivy github:app-create --org <org>`). A node can serve several at once, each\nwith its own key and `@`-mention handle.\n\nSee [`docs/github-work-queue.md`](docs/github-work-queue.md).\n\n## Linear Runs\n\nApply `bivy` or `bivy/<machine>` to a Linear issue to create a Run on the selected\nMachine. The Machine fetches issue content directly from Linear, works in an\nisolated GitHub worktree, and asks the agent to open a pull request. See\n[`docs/linear-work-queue.md`](docs/linear-work-queue.md).\n\n## Development\n\n```bash\npnpm install\npnpm run dev # node daemon on http://localhost:4317\npnpm run dev:web # web client dev server (proxies /api and /ws to the node)\n```\n\nChecks — all of these run in CI:\n\n```bash\npnpm run typecheck\npnpm run typecheck:web\npnpm run lint\npnpm run test:unit\npnpm run test:core\npnpm run check:licenses\npnpm run check:secrets\n```\n\nRepository layout:\n\n- `src/` — node daemon, runtime adapters, approvals, secrets, sessions\n- `bin/` — the `bivy` CLI\n- `packages/core` — shared protocol, pairing, wire format\n- `packages/web` — the React/Vite PWA client (`@bivy/web`)\n- `services/relay` — self-hostable relay\n- `services/control-plane` — self-hostable control plane\n- `deploy/` — self-host deployment examples\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md).\n\n## Self-hosting\n\nNode, relay, and control plane are all in this repository. Point a node at your\nown deployment by passing URLs to `bivy relay:setup` — re-running it switches an\nexisting node over to the new endpoints:\n\n```bash\nbivy relay:setup \\\n --control-plane https://bivy.example.com \\\n --relay wss://relay.example.com\n```\n\nEach URL has a flag and an environment-variable equivalent (the flag wins):\n\n| Flag | Environment variable | Points at | Default |\n|---|---|---|---|\n| `--control-plane <url>` | `BIVY_CONTROL_PLANE_URL` | accounts, node registry, and the web-app API | hosted (`app.bivy.sh`) |\n| `--relay <wss-url>` | `BIVY_RELAY_URL` | the encrypted-frame relay your node dials out to | hosted |\n| `--client <url>` | `BIVY_CLIENT_BASE_URL` | base URL used when building app/PWA links | the `--control-plane` URL |\n\nSign-in defaults to GitHub device login (`--github`); pass\n`--email you@example.com` for an email magic-link, or `--session-token <token>`\nto skip interactive sign-in. `relay:setup` checks the control plane is reachable, enrolls\nthis node, and writes the endpoints to `.bivy/relay.json`, so `bivy open`,\n`bivy link`, and `bivy update` all keep using your deployment afterwards.\n\n**Self-hosting is unsupported** — no SLA, community best-effort via GitHub\nissues. You own TLS, backups, upgrades, and hardening. See\n[`docs/self-host.md`](docs/self-host.md).\n\n## Security\n\nReport vulnerabilities through [GitHub private vulnerability reporting](https://github.com/bivysh/bivy/security/advisories/new).\nPlease do not open a public issue. See [`SECURITY.md`](SECURITY.md) for scope,\nresponse times, and safe harbour, and [`docs/security-model.md`](docs/security-model.md)\nfor the trust model and known limitations.\n\n## License\n\nBivy Core is free and open-source software licensed under the GNU Affero General\nPublic License, version 3.0 only (AGPL-3.0-only). You may use, study, modify, and\nself-host it under that license. If you modify Bivy and let users interact with\nit over a network, section 13 requires you to offer those users the corresponding\nsource code.\n\nSee [`LICENSE`](LICENSE).\n",
66
+ "readme": "# Bivy\n\n[![npm](https://img.shields.io/npm/v/@bivy/bivy?color=2b6cb0&label=%40bivy%2Fbivy)](https://www.npmjs.com/package/@bivy/bivy)\n[![license: AGPL-3.0-only](https://img.shields.io/badge/license-AGPL--3.0--only-2b6cb0)](LICENSE)\n[![node](https://img.shields.io/badge/node-%E2%89%A522.19-2b6cb0)](https://nodejs.org)\n\n**Run coding agents on the machines you already own — then reach them from your\nphone, browser, or another terminal.**\n\nStart Claude Code on your workstation, right where the repo, the running dev\nserver, and the staging database already live. Walk away. On the train, open\nyour phone: read what the agent did, answer its question, approve the migration\n— over a link only your devices can decrypt. The work never left your machine.\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash # install + guided setup\nbivy run claude # start an agent in your repo\nbivy open # pick it up from your phone or browser\n```\n\n**[Quickstart](docs/quickstart.md)** ·\n**[Docs](docs/README.md)** ·\n**[Why Bivy](docs/why-bivy.md)** ·\n**[Security model](docs/security-model.md)** ·\n**[bivy.sh](https://bivy.sh)**\n\n> **0.x software.** The core loop is solid and used daily. Interfaces and\n> cross-runtime fidelity still change between releases — check the\n> [runtime support matrix](docs/runtime-support-matrix.md) before you depend on\n> a specific agent capability.\n\n## Why not just a cloud sandbox?\n\nA hosted sandbox starts from an *approximation* of your environment. A Bivy\nMachine **is** your environment — the actual working tree, the services already\nrunning, the caches already warm.\n\n| | Cloud sandbox | Bivy Machine |\n|---|---|---|\n| Your repository | a cloned copy | the real working tree, uncommitted changes and all |\n| Dev server & database | mocked, or absent | already running, right beside the agent |\n| Private networks & internal APIs | out of reach | reachable |\n| Toolchains, package caches | cold, reinstalled each time | warm, already installed |\n| GPUs / local inference | rented separately | the ones on your box |\n| Where your code sits | someone else's infrastructure | the machine you already trust |\n\nYou keep the environment. Bivy adds the part that was missing: **reaching that\nenvironment from anywhere, and leaving it working while you're gone.**\n\n## What you can do\n\nBivy gives you two ways to put an agent to work.\n\n### Sessions — interactive, and portable\n\nStart an agent, watch it work, jump in to steer, stop, or approve. Then leave\nyour desk and keep going:\n\n```bash\nbivy run claude # or codex, pi, gemini, and a dozen more\nbivy open # continue the same session in the browser or PWA\nbivy resume # pick it back up in the terminal\nbivy run claude --no-follow # start it in the background instead of attaching\nbivy run claude --chat # start the governed app session and open it in the browser\n```\n\n- **Reconnect from anywhere** — phone, browser, or another terminal — to the\n same live Session. The PWA adds voice input, read-aloud, phone-to-agent\n file/image uploads, and agent-to-phone attachments.\n- **Move work without starting over.** Import existing Claude Code and Codex\n Sessions, or fork, copy, and move a Bivy Session to another agent, model, or\n Machine.\n- **Run more than one Machine** — a workstation, a private-network server, a GPU\n box — on one account, and pick the environment each Session needs.\n\n### Runs — unattended, and accountable\n\nQueue one on demand, or let an event kick it off — either way it returns\nimmediately and reports back:\n\n```bash\nbivy runs start \"...\" # queue a one-off unattended Run, then `bivy runs wait <id>`\nbivy automation init # or define governed jobs in .bivy/automations.yaml\n```\n\n- **Trigger from real events** — a failed CI job, a GitHub or Linear issue,\n Slack, a schedule, or a signed webhook.\n- **Pin the guardrails** — Machine, agent, model, sandbox, approval mode, and a\n hard attempt ceiling — right next to the job.\n- **Get a Receipt** — every Run reports the checks it ran and how it turned out,\n not just a wall of output.\n\nTry the [capability recipes](docs/capability-recipes.md) to see each of these\nend to end, or the [runtime support matrix](docs/runtime-support-matrix.md) for\nexactly what each agent supports.\n\n## Bring your own stack\n\nUse provider subscriptions through native agent logins, API keys stored in\nBivy's vault, or local / OpenAI-compatible inference. Add any ACP or headless\nagent with a single command — no per-agent adapter to write:\n\n```bash\nbivy agent add # register an existing ACP or process agent\n```\n\n## Install\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash\n```\n\nmacOS and Linux. Requires Node.js 22.19 or newer; the installer installs it for\nyou on Debian/Ubuntu and otherwise points you at nodejs.org. It installs the\n[`@bivy/bivy`](https://www.npmjs.com/package/@bivy/bivy) package from npm, puts\nthe `bivy` command on your `PATH`, then runs the guided `bivy setup` wizard —\nagent choice, relay/control-plane sign-in, and an auto-start background service\n(launchd on macOS, systemd on Linux). Re-running it on a machine that already\nhas Bivy just applies the latest build and restarts the service.\n\nAlready have Node.js 22.19+? The installer is optional:\n\n```bash\nnpm install -g @bivy/bivy && bivy setup # install globally\nnpx @bivy/bivy setup # or try it once, no install\n```\n\nReleases are published from CI with provenance attestations; verify a build's\norigin with `npm audit signatures`. See [`docs/releasing.md`](docs/releasing.md).\n\n### Your first session\n\nOnce `bivy setup` finishes, the whole loop is three commands — start local,\nreconnect remote:\n\n```bash\nbivy run claude # start an agent as a durable session in the current repo\nbivy open # open that same session in the web app (needs relay setup)\nbivy resume # or pick it back up here in the terminal\n```\n\nFrom here the [quickstart](docs/quickstart.md) walks through Runs, multiple\nMachines, and automations.\n\n### Install options\n\nEnvironment variables passed to the one-line installer change what it does:\n\n| Goal | Variable |\n|---|---|\n| Track the dev channel (new build on every merge to `main`) | `BIVY_CHANNEL=staging` |\n| Pin an exact version | `BIVY_VERSION=0.1.0` |\n| Install without sudo, into a user-owned prefix | `BIVY_NPM_PREFIX=~/.local` |\n| Preinstall every known upstream agent | `BIVY_INSTALL_ALL_AGENTS=1` |\n\nFor example: `BIVY_CHANNEL=staging curl -fsSL https://bivy.sh/install.sh | bash`.\n\nWorking from a checkout of this repository instead:\n\n```bash\npnpm install\npnpm run setup\n```\n\nSee [`docs/install.md`](docs/install.md) for where data lives, service\nmanagement, and uninstall.\n\n## Updating\n\n```bash\nbivy update\n```\n\n`bivy update` detects how Bivy was installed and does the right thing, then\nwaits for any active session to finish its current turn and restarts the\nbackground service so the node reconnects on the new build:\n\n| Install kind | What `bivy update` does |\n|---|---|\n| npm global (`npm i -g`) | `npm install -g @bivy/bivy@<channel>`, then restart the service |\n| installer / packaged | re-runs `install.sh` (migrating to npm if needed), then restart |\n| git checkout | `git pull --ff-only` + `pnpm install --frozen-lockfile`, then restart |\n| `npx` run | nothing to update — each run already fetches the latest |\n\nUpdates follow the release **channel** recorded at install time — `latest`\n(production) by default, or `staging` if you installed with\n`BIVY_CHANNEL=staging`. Switch channels (the choice is remembered for next\ntime), or skip the wait for a busy session:\n\n```bash\nbivy update --staging # move to the dev channel\nbivy update --stable # move back to production (latest)\nbivy update --force # don't wait for an in-flight turn to finish\n```\n\nThe daemon also checks the registry periodically and posts an in-session notice\nwhen a newer build is available.\n\n## Architecture\n\nBivy has three parts. **Only the first one holds your data.**\n\n```text\n your machine hosted or self-hosted\n\n ┌──────────────┐ ┌─────────┐ ┌───────────────┐\n │ node daemon │ ──dials──▶ │ relay │ ◀────▶ │ control plane │\n │ agents, keys │ outbound │ opaque │ │ accounts, web │\n │ repo, tools │ │ frames │ │ app, metadata │\n └──────────────┘ └─────────┘ └───────────────┘\n ▲ ▲\n └────────── end-to-end encrypted session ───────────┘\n phone · browser · another terminal\n```\n\n- **Node** — a daemon on your machine. Owns the workspace, credentials, and agent\n processes. Serves an API and WebSocket on `http://localhost:4317` plus a\n `/healthz` probe. **It hosts no web UI.**\n- **Relay** — forwards encrypted frames between your node and your devices. Your\n node dials out, so no inbound port is opened. The relay cannot read the frames.\n- **Control plane** — holds your account, node registry, and session index, and\n serves the web/PWA client. Use the hosted one or run your own.\n\nBecause the node serves no UI, a browser or phone needs a control plane — hosted\nat `app.bivy.sh`, or one you deploy yourself. The terminal CLI needs neither.\nInteractive Session traffic is end-to-end encrypted between a Machine and its\npaired devices, so the relay cannot decrypt it.\n\nSee [`docs/remote-access.md`](docs/remote-access.md) and\n[`docs/security-model.md`](docs/security-model.md).\n\n## Supported agents\n\n**Claude Code and Codex are the recommended, release-certified paths.** The\nbroader catalog stays available under **More agents**; capabilities and fidelity\nvary by runtime.\n\n| Agent | Command | Notes |\n|---|---|---|\n| Claude Code | `bivy run claude` | Uses the operator-installed `claude` command through an SDK bridge |\n| Codex | `bivy run codex` | Installs `@openai/codex` |\n| Pi | `bivy run pi` | Uses the operator-installed `pi` command and Pi auth/config |\n| OpenCode | `bivy run opencode` | Installs `opencode-ai` |\n| Gemini CLI | `bivy run gemini` | Installs `@google/gemini-cli` |\n| Qwen Code | `bivy run qwen` | Installs `@qwen-code/qwen-code` |\n| Goose | `bivy run goose` | Requires `goose` on PATH |\n| Aider | `bivy run aider` | No session resume (upstream gap) |\n| Cline | `bivy run cline` | Installs `cline` |\n| Crush | `bivy run crush` | No session resume (upstream gap) |\n| Cursor | `bivy run cursor` | ACP-capable |\n| GitHub Copilot | `bivy run copilot` | ACP-capable |\n| Grok | `bivy run grok` | Model selection |\n| Amp | `bivy run amp` | Native thread resume |\n| Auggie | `bivy run auggie` | Headless CLI |\n| Droid | `bivy run droid` | Model selection |\n| Continue | `bivy run continue` | Headless CLI |\n| Kilo Code | `bivy run kilocode` | ACP-capable |\n| Rovo Dev | `bivy run rovodev` | Installed out of band |\n\nAny other command works via `bivy run -- ./your-agent --flags`. ACP-capable\nagents can be promoted to Bivy's governed protocol path for per-tool approvals\nand native resume. To add a reusable process or ACP agent to both the CLI and web\npicker without changing Bivy, run `bivy agent add`, or scaffold and install a\ndeclarative [plugin manifest](docs/plugins.md) with `bivy plugin init`\n(declarative plugins are Experimental, `v1alpha1`, and run out of process).\n\n[`docs/runtime-support-matrix.md`](docs/runtime-support-matrix.md) lists exactly\nwhat each agent supports — resume, model selection, approvals, sandboxing.\n\n## Common commands\n\n```bash\nbivy # show the command overview\nbivy run claude # launch Claude Code as a durable session\nbivy run codex # run a different agent\nbivy sessions # list live and saved sessions\nbivy resume # resume the most recent session\nbivy open # open the web app (requires relay setup)\nbivy automation init # create .bivy/automations.yaml\nbivy agent add # connect an existing ACP or process agent\nbivy plugin list # installed declarative integration packages\nbivy status # config summary and node reachability\nbivy doctor # health check\nbivy logs -f # tail node logs\nbivy update # update Bivy and restart the service\n```\n\nFull command list, flags, and examples: [`docs/cli-reference.md`](docs/cli-reference.md).\n\n## Configuration\n\nThe common knobs:\n\n```bash\nBIVY_WORKSPACE=/path/to/repo # default workspace\nBIVY_SANDBOX=read-only # read-only | workspace-write (default) | danger-full-access\nBIVY_APPROVAL_MODE=risky # never | risky | always | autonomous (default)\n```\n\nCreate and inspect the typed node configuration, or add repository-owned\nsafety/check/retry policy:\n\n```bash\nbivy config init\nbivy config set defaults.agent codex\nbivy config explain defaults.sandbox\nbivy config init --project # .bivy/policy.yaml\n```\n\nSee [`docs/config-as-code.md`](docs/config-as-code.md). Every environment\nvariable and precedence rule lives in\n[`docs/configuration.md`](docs/configuration.md).\n\n## Approvals and sandboxing\n\nThe default approval mode is **`autonomous`**: agents act without per-action\nprompts. How much that actually protects you depends on the runtime. Native-sandbox\nagents enforce the chosen access tier; structured runtimes also pass tool calls\nthrough Bivy's policy and approval layer. Process agents that Bivy cannot\nintercept run with your OS user permissions — the picker flags this and requires\nconfirmation before you pick that path.\n\nWhere Bivy receives structured shell/file calls, a heuristic floor blocks known\ncatastrophic commands and structured writes outside the workspace, and a\nbackstop set (force-push, publish, deploy, sudo) pauses for a human. This catches\naccidents; **it is not an adversarial isolation boundary.**\n\nWant to be asked about more? Set the mode explicitly:\n\n```bash\nBIVY_APPROVAL_MODE=risky # prompt on risky shell commands and file edits\nBIVY_APPROVAL_MODE=always # prompt on all shell commands and file edits\nBIVY_APPROVAL_MODE=never # no prompts; structured-tool heuristic blocks still apply where available\n```\n\nApprove from the terminal, browser, or phone.\n\nSandbox tiers (`read-only`, `workspace-write`, `danger-full-access`) are enforced\nnatively by agents that support them — Codex, Claude Code, Gemini CLI, Qwen Code.\nAgents without a native sandbox may expose structured tool or MCP controls, but\nthose don't cover activity the agent performs outside those channels; some\nprocess adapters run entirely with your user permissions. Check the picker's\nProtection label. **Bivy does not currently ship its own OS-level jail.**\n\n## Credentials\n\nInteractive prompts, transcripts, and workspace files stay encrypted across the\nrelay. Credentials can remain on a Machine or in a vault you control:\n\n```bash\nbivy secrets list\nbivy secrets set github.repo-token\nbivy secrets ref github.repo-token op://Bivy/GitHub/repo-token\nbivy secrets doctor\n```\n\n`secret://`, `env://`, and `op://` (1Password) references resolve on demand when\nthe daemon provisions an agent run, so raw values never sit in your config.\n\n**One deliberate exception to relay blindness:** if you explicitly enable hosted\nunattended provisioning, Bivy Cloud may store encrypted cloud, repository,\nmodel, or key-escrow material that the service can technically access. Treat this\nas an explicit hosted-custody mode. See the\n[security model](docs/security-model.md#what-the-control-plane-sees) and\n[`docs/key-management.md`](docs/key-management.md).\n\n## Automations as code\n\nDefine governed jobs in `.bivy/automations.yaml`, validate them, and simulate\ntrigger events locally before applying anything:\n\n```bash\nbivy automation init\nbivy automation validate\nbivy automation test --event .bivy/events/failed-ci.yaml\nbivy automation apply\n```\n\nInstructions are encrypted on the applying node before upload. Safety policy\nlives beside the job — sandbox, approval mode, and a hard attempt ceiling that\nretry/fallback rules cannot exceed. See\n[`docs/automations-as-code.md`](docs/automations-as-code.md).\n\n## GitHub Runs\n\nLabel an issue `bivy` (or `bivy/<machine>` to target a Machine), or mention the\nBivy GitHub App in a comment. Bivy creates a Run on the selected Machine, uses an\nisolated worktree, executes configured checks, and reports an explicit outcome.\n\nCore applies no commercial usage limits. Bivy Cloud billing and commercial\npolicy live in the separate Cloud repository.\n\nA private GitHub App only installs on the account that owns it, so connect one\napp per GitHub account — one for your personal repos, one per organization\n(`bivy github:app-create --org <org>`). A node can serve several at once, each\nwith its own key and `@`-mention handle.\n\nSee [`docs/github-work-queue.md`](docs/github-work-queue.md).\n\n## Linear Runs\n\nApply `bivy` or `bivy/<machine>` to a Linear issue to create a Run on the selected\nMachine. The Machine fetches issue content directly from Linear, works in an\nisolated GitHub worktree, and asks the agent to open a pull request. See\n[`docs/linear-work-queue.md`](docs/linear-work-queue.md).\n\n## Development\n\n```bash\npnpm install\npnpm run dev # node daemon on http://localhost:4317\npnpm run dev:web # web client dev server (proxies /api and /ws to the node)\n```\n\nChecks — all of these run in CI:\n\n```bash\npnpm run typecheck\npnpm run typecheck:web\npnpm run lint\npnpm run test:unit\npnpm run test:core\npnpm run check:licenses\npnpm run check:secrets\n```\n\nRepository layout:\n\n- `src/` — node daemon, runtime adapters, approvals, secrets, sessions\n- `bin/` — the `bivy` CLI\n- `packages/core` — shared protocol, pairing, wire format\n- `packages/web` — the React/Vite PWA client (`@bivy/web`)\n- `services/relay` — self-hostable relay\n- `services/control-plane` — self-hostable control plane\n- `deploy/` — self-host deployment examples\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md).\n\n## Self-hosting\n\nNode, relay, and control plane are all in this repository. Point a node at your\nown deployment by passing URLs to `bivy relay:setup` — re-running it switches an\nexisting node over to the new endpoints:\n\n```bash\nbivy relay:setup \\\n --control-plane https://bivy.example.com \\\n --relay wss://relay.example.com\n```\n\nEach URL has a flag and an environment-variable equivalent (the flag wins):\n\n| Flag | Environment variable | Points at | Default |\n|---|---|---|---|\n| `--control-plane <url>` | `BIVY_CONTROL_PLANE_URL` | accounts, node registry, and the web-app API | hosted (`app.bivy.sh`) |\n| `--relay <wss-url>` | `BIVY_RELAY_URL` | the encrypted-frame relay your node dials out to | hosted |\n| `--client <url>` | `BIVY_CLIENT_BASE_URL` | base URL used when building app/PWA links | the `--control-plane` URL |\n\nSign-in defaults to GitHub device login (`--github`); pass\n`--email you@example.com` for an email magic-link, or `--session-token <token>`\nto skip interactive sign-in. `relay:setup` checks the control plane is reachable,\nenrolls this node, and writes the endpoints to `.bivy/relay.json`, so `bivy open`,\n`bivy link`, and `bivy update` all keep using your deployment afterwards.\n\n**Self-hosting is unsupported** — no SLA, community best-effort via GitHub\nissues. You own TLS, backups, upgrades, and hardening. See\n[`docs/self-host.md`](docs/self-host.md).\n\n## Security\n\nReport vulnerabilities through [GitHub private vulnerability reporting](https://github.com/bivysh/bivy/security/advisories/new).\nPlease don't open a public issue. See [`SECURITY.md`](SECURITY.md) for scope,\nresponse times, and safe harbour, and [`docs/security-model.md`](docs/security-model.md)\nfor the trust model and known limitations.\n\n## License\n\nBivy Core is free and open-source software under the GNU Affero General Public\nLicense, version 3.0 only (AGPL-3.0-only). You may use, study, modify, and\nself-host it under that license. If you modify Bivy and let users interact with\nit over a network, section 13 requires you to offer them the corresponding\nsource code. See [`LICENSE`](LICENSE).\n",
67
67
  "readmeFilename": "README.md"
68
68
  }