@bivy/bivy 0.19.4-staging.6 → 0.20.0-staging.1

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
@@ -4,22 +4,27 @@
4
4
  [![license: AGPL-3.0-only](https://img.shields.io/badge/license-AGPL--3.0--only-2b6cb0)](LICENSE)
5
5
  [![node](https://img.shields.io/badge/node-%E2%89%A520-2b6cb0)](https://nodejs.org)
6
6
 
7
- **Build, try, and review apps from your phone. Your coding agent and dev
8
- environment stay on your own machines.**
9
-
10
- Bivy is an open-source remote development environment built around coding
11
- agents. Ask for a change, try the running app, and point to or draw on what
12
- needs fixing. Send that feedback to the agent and try again—all in the same
13
- session, without going back to your computer.
14
-
15
- Live previews bring your app to your phone or browser without deploying it to
16
- Render, building a Docker image, or setting up a separate preview server.
17
- Share a preview link so someone else can try it and leave notes, too.
18
-
19
- Keep Claude Code, Codex, Pi, OpenCode, or another supported agent. Keep your
20
- repos, tools, databases, and development environment. Bivy connects them to
21
- chat, a terminal, app previews, and code review wherever you are. Start work
22
- yourself, or let an issue, CI failure, message, schedule, or webhook start it.
7
+ **Local coding agents that show their work. Anywhere.**
8
+
9
+ Bivy is the open-source workspace for coding agents. It runs Claude Code, Codex,
10
+ Pi, OpenCode and other agents on your own machine. Reach them from a browser or
11
+ your phone, with the live session, its terminal, its approvals, and the app
12
+ they're building right in the chat. Try it, mark what's wrong, and send it back.
13
+
14
+ Bivy is not another coding agent and not a cloud development machine. The agent
15
+ stays local and does the coding with your model provider. Your repos, tools,
16
+ databases, and services stay where they are. Bivy gives you remote access to all
17
+ of it, plus live previews, automations, and review.
18
+
19
+ - **Live previews.** The running app beside the chat. Mark it, send it back,
20
+ share it with someone who has no Bivy account.
21
+ - **Automations.** GitHub issues, failed CI, Linear, Slack, schedules, and
22
+ webhooks start the work. It comes back as a preview link or a pull request.
23
+ - **Any agent.** Hit a usage limit? Fork the session to another agent, or let
24
+ Bivy retry when the limit resets.
25
+ - **Your machine, anywhere.** Start at your desk, pick the session up on your
26
+ phone. The machine dials out, so there are no ports to open, and session
27
+ traffic is end-to-end encrypted.
23
28
 
24
29
  **[Start free on Bivy Cloud](https://app.bivy.sh)** ·
25
30
  **[Quickstart](docs/quickstart.md)** ·
@@ -47,30 +52,34 @@ agents. Connect a Mac, Linux computer, or existing server and bring your own
47
52
  agent subscription, model API key, or local model. You can also self-host the
48
53
  entire remote-access stack.
49
54
 
50
- > **Bivy is 0.x software.** Claude Code, Codex, Pi, and OpenCode are the
55
+ > **Bivy is 0.x software.** Claude Code, Codex, Pi, OpenCode, and Grok are the
51
56
  > release-tested paths. Credential sync, resume, handoffs, approvals, and
52
57
  > sandboxing depend on the runtime. See the
53
58
  > [runtime support matrix](docs/runtime-support-matrix.md).
54
59
 
55
- ## Build → preview → mark up → iterate
60
+ ## Don't just read the diff. Try the app.
56
61
 
57
- Remote chat lets you ask an agent for a change. Bivy also lets you **use what
58
- it built and show it what to fix**, without a separate deployment step.
62
+ Bivy lets you **use what the agent built and show it what to fix**, without a
63
+ separate deployment step.
59
64
 
60
65
  1. **Ask for a change.** The agent works in your repo with your existing tools
61
66
  and local services.
62
- 2. **Try the app.** Open a live preview from the session. Use the running app,
63
- not just a screenshot of what the agent says it finished. Bivy can discover
64
- dev servers running in the session workspace; tap **Preview** to open one.
65
- 3. **Mark up what needs work.** Point at an element or circle and draw on the
66
- preview. Add a note, then send the draft to the agent with the element and
67
- page context. Marked-up screenshots and before/after comparison are available
68
- when agent screenshots are enabled.
69
- 4. **Iterate and review.** Try the next version, inspect the diff, review checks,
70
- and decide when the work is ready—not just when the agent stops.
71
- 5. **Bring someone else into the review.** Copy a public preview link so they
72
- can use the app without a Bivy account and leave notes on specific elements.
73
- Bring their notes into the session when you're ready to act on them.
67
+ 2. **Try the app.** Bivy finds the dev server the agent starts and opens it
68
+ beside the chat: web apps, terminals, and desktop apps. Use the running app,
69
+ not a screenshot of what the agent says it finished.
70
+ 3. **Mark what needs work.** Press and hold anything in the preview to mark it,
71
+ or drag to circle it, then say what you want. **Mark another** keeps
72
+ separate notes separate. The marks go to the agent with the element and page
73
+ context. No screenshots to paste.
74
+ 4. **Follow each note.** Every mark stays in the chat as a pin that resolves
75
+ itself: **Changed** when a later run changes what you marked, **Element
76
+ gone** when it leaves the page, **Done** when you say so.
77
+ 5. **Review the next version.** A new version waits on the preview pill instead
78
+ of reloading under you. Take it when you're ready, compare before and after,
79
+ inspect the diff and checks, and decide when the work is done.
80
+ 6. **Get a second opinion.** Share a preview link for 1 hour, 1 day, or 7 days.
81
+ Teammates and clients try the running app and leave notes without a Bivy
82
+ account. Make it view-only, or **Stop sharing** to end every link at once.
74
83
 
75
84
  On Bivy Cloud, preview delivery is built in: no per-app domains, certificates,
76
85
  public ports, or tunnels to configure. Self-hosters configure preview delivery
@@ -79,27 +88,13 @@ build or dev-server setup, and **the machine serving it must stay awake and
79
88
  online**. These are development previews, not production hosting.
80
89
 
81
90
  **Share deliberately:** anyone with a preview link can use that app, including
82
- its live backend. Links expire after 24 hours and can be revoked sooner.
91
+ its live backend, until the link expires or you stop sharing.
83
92
  Reviewer notes aren't sent to the agent automatically; you send them or explicitly
84
93
  allow agent access. Preview traffic uses HTTPS through the preview relay, not
85
94
  session end-to-end encryption; the relay operator can see it.
86
95
 
87
96
  [App previews, visual feedback, and sharing →](docs/apps.md)
88
97
 
89
- ## Your agents and machines, one workspace
90
-
91
- | Capability | What it means for you |
92
- |---|---|
93
- | **One workspace, multiple agents** | Use different agents and models for different tasks without maintaining a separate workflow for each. |
94
- | **Your machines and environment** | Work beside your existing repos, dev servers, databases, private networks, toolchains, and GPUs. |
95
- | **Automations and triggers** | Let issues, failed CI, messages, schedules, and webhooks start work instead of copying requests into a chat. |
96
- | **Encrypted key and OAuth sync** | Reuse Bivy-managed provider credentials across enrolled machines and compatible runtimes, with less repeated setup. |
97
- | **Live sessions from anywhere** | Build and review from your phone, browser, or terminal; answer questions and approve supported actions in the same session. |
98
- | **Live app previews** | Try the running app without deploying it to a separate hosting service. |
99
- | **Visual feedback and sharing** | Point, draw, and send specific feedback to the agent; share a preview link for outside review. |
100
- | **Reviewable results** | Inspect the app, changes, declared checks, artifacts, and pull requests—not just an agent's claim that it finished. |
101
- | **Hosted convenience or self-hosting** | Use Bivy Cloud for managed remote access, or run the same open-source core yourself. |
102
-
103
98
  ## One workflow, from trigger to review
104
99
 
105
100
  ```text
@@ -131,34 +126,70 @@ creates runs when an event matches.
131
126
  Manual and automated work use the same kind of live session. You can join a run
132
127
  when it needs help rather than wait for a black-box job to finish.
133
128
 
134
- ### Work in the environment you already have
129
+ ### Let events start the work
135
130
 
136
- A clean cloud sandbox isn't always enough. Your agent may need the database
137
- running on localhost, an uncommitted change, an internal API behind your VPN,
138
- or a model running on your GPU. Bivy runs the agent where those things already
139
- exist, subject to that machine's permissions and the runtime's protection.
131
+ Automations turn recurring or incoming work into sessions you can join,
132
+ supervise, and review. An agent picks the task up on your machine and posts
133
+ back a preview link or a pull request, so you try the result where the task
134
+ lives and reply in the same session. Choose the repository, machine, agent,
135
+ model, approval mode, sandbox setting, and maximum attempts.
140
136
 
141
- Connect several machines to the same account: a laptop for interactive work,
142
- a Linux server for background jobs, or a GPU box for local inference. Choose
143
- the machine for each session or pin it in an automation. Repository runs can
144
- use isolated Git worktrees without rebuilding the whole development environment.
137
+ | Trigger | Example workflow |
138
+ |---|---|
139
+ | **GitHub issues and mentions** | Label an issue `bivy` or `bivy/<machine>`, or mention your Bivy GitHub App, to work toward a pull request. |
140
+ | **Failed CI** | Match a failed workflow, ask the agent to reproduce it, make a fix, and run the affected checks. |
141
+ | **Linear** | Label an issue to start work without copying its description into an agent. |
142
+ | **Slack** | Send a request from the conversation where the work came up. |
143
+ | **Schedules** | Run a weekly dependency review, recurring maintenance, or a one-time task. |
144
+ | **Signed webhooks** | Connect alerts, internal tools, or your own event sources. |
145
145
 
146
- **The execution machine must stay awake and online.** To close your laptop and
147
- leave work running, run the agent on a different, always-on machine.
146
+ Configure automations in the app or version them with your repository in
147
+ `.bivy/automations.yaml`:
148
148
 
149
- [Environment and multi-machine recipes →](docs/capability-recipes.md)
149
+ ```bash
150
+ bivy automation init
151
+ # Edit the generated definition for your repository and workflow.
152
+ bivy automation validate
153
+ bivy automation test --event .bivy/events/failed-ci.yaml # supply a local event fixture
154
+ bivy automation apply
155
+ ```
150
156
 
151
- ### Use multiple agents, not multiple disconnected workflows
157
+ Or delegate a one-off job without creating an automation:
152
158
 
153
- Run Claude Code for one task, Codex for another, and Pi or OpenCode where they
154
- fit. Bivy supplies the shared session, remote-access, automation, and review
155
- surfaces; your chosen agent still does the coding and uses your model provider.
159
+ ```bash
160
+ bivy runs start "Review outdated dependencies and propose a small, tested update."
161
+ bivy runs wait <id>
162
+ ```
163
+
164
+ Runs keep routing and lifecycle evidence, check results, and output references
165
+ in a reviewable Receipt. For unattended issue work, Bivy runs declared repository
166
+ checks after the agent's turn; failed required checks fail the run even if the
167
+ agent reports success. A completed process alone is not proof that the task
168
+ succeeded.
156
169
 
170
+ [Automation recipes →](docs/capability-recipes.md#let-events-start-runs) ·
171
+ [Automations as code →](docs/automations-as-code.md) ·
172
+ [Run outcomes and reliability limits →](docs/automation-runs.md)
173
+
174
+ ### Use every agent you pay for. Switch mid-task.
175
+
176
+ Run Claude Code for one task, Codex for another, and Pi or OpenCode where they
177
+ fit, side by side in one session list. Bivy supplies the shared session,
178
+ remote-access, automation, and review surfaces; your chosen agent still does
179
+ the coding and uses your model provider.
180
+
181
+ - **Hit a usage limit? Keep going.** When a turn fails on a limit, fork the
182
+ session, with its code and conversation, to another agent and model, or let
183
+ Bivy retry when the limit resets (the provider has to report a reset time).
184
+ - **Get a second opinion.** `bivy delegate` hands a task to another agent, on
185
+ the same machine or a different one, and brings back its answer, branch, and
186
+ PR. `--to codex,claude@linux` sends one task to several agents to compare.
157
187
  - Choose an agent and, where supported, a model for each session or run.
158
188
  - Import existing Claude Code and Codex sessions.
159
189
  - Fork or move work to another agent or machine when a different setup fits
160
190
  better. Continuation fidelity varies: some paths preserve native history,
161
- while others replay portable turns or seed the destination with context.
191
+ while others replay portable turns or hand over a summary with the earlier
192
+ transcript as a local file.
162
193
  - Use agent-native logins, Bivy-managed credentials, or local inference.
163
194
  Bivy's custom OpenAI-compatible endpoint registry currently feeds Pi;
164
195
  other agents may need their own provider configuration.
@@ -199,48 +230,22 @@ hosted-provisioning custody grants are separate from ordinary encrypted sync.
199
230
  [Credentials guide →](docs/credentials-guide.md) ·
200
231
  [Key storage →](docs/key-management.md)
201
232
 
202
- ### Let events start the work
203
-
204
- Automations turn recurring or incoming work into sessions you can join,
205
- supervise, and review. Choose the repository, machine, agent, model, approval
206
- mode, sandbox setting, and maximum attempts.
207
-
208
- | Trigger | Example workflow |
209
- |---|---|
210
- | **GitHub issues and mentions** | Label an issue `bivy` or `bivy/<machine>`, or mention your Bivy GitHub App, to work toward a pull request. |
211
- | **Failed CI** | Match a failed workflow, ask the agent to reproduce it, make a fix, and run the affected checks. |
212
- | **Linear** | Label an issue to start work without copying its description into an agent. |
213
- | **Slack** | Send a request from the conversation where the work came up. |
214
- | **Schedules** | Run a weekly dependency review, recurring maintenance, or a one-time task. |
215
- | **Signed webhooks** | Connect alerts, internal tools, or your own event sources. |
216
-
217
- Configure automations in the app or version them with your repository in
218
- `.bivy/automations.yaml`:
219
-
220
- ```bash
221
- bivy automation init
222
- # Edit the generated definition for your repository and workflow.
223
- bivy automation validate
224
- bivy automation test --event .bivy/events/failed-ci.yaml # supply a local event fixture
225
- bivy automation apply
226
- ```
233
+ ### Work in the environment you already have
227
234
 
228
- Or delegate a one-off job without creating an automation:
235
+ A clean cloud sandbox isn't always enough. Your agent may need the database
236
+ running on localhost, an uncommitted change, an internal API behind your VPN,
237
+ or a model running on your GPU. Bivy runs the agent where those things already
238
+ exist, subject to that machine's permissions and the runtime's protection.
229
239
 
230
- ```bash
231
- bivy runs start "Review outdated dependencies and propose a small, tested update."
232
- bivy runs wait <id>
233
- ```
240
+ Connect several machines to the same account: a laptop for interactive work,
241
+ a Linux server for background jobs, or a GPU box for local inference. Choose
242
+ the machine for each session or pin it in an automation. Repository runs can
243
+ use isolated Git worktrees without rebuilding the whole development environment.
234
244
 
235
- Runs keep routing and lifecycle evidence, check results, and output references
236
- in a reviewable Receipt. For unattended issue work, Bivy runs declared repository
237
- checks after the agent's turn; failed required checks fail the run even if the
238
- agent reports success. A completed process alone is not proof that the task
239
- succeeded.
245
+ **The execution machine must stay awake and online.** To close your laptop and
246
+ leave work running, run the agent on a different, always-on machine.
240
247
 
241
- [Automation recipes →](docs/capability-recipes.md#let-events-start-runs) ·
242
- [Automations as code →](docs/automations-as-code.md) ·
243
- [Run outcomes and reliability limits →](docs/automation-runs.md)
248
+ [Environment and multi-machine recipes →](docs/capability-recipes.md)
244
249
 
245
250
  ### Start at your desk. Continue anywhere.
246
251
 
@@ -269,6 +274,29 @@ in your browser; adding it to your home screen is optional.
269
274
  [Remote access →](docs/remote-access.md) ·
270
275
  [Voice, files, and terminal recipes →](docs/capability-recipes.md)
271
276
 
277
+ ### Agents can reach you, too
278
+
279
+ Every session gets the `bivy` CLI, so any agent with a shell can talk back
280
+ through the app, not only agents with their own built-in tools:
281
+
282
+ ```bash
283
+ bivy notify "Tests are green, PR is up" # chat card + phone push when you're away
284
+ bivy ask "Ship to staging?" --option Yes --option No # waits for your answer
285
+ bivy attach report.png --caption "Before/after" # show a file in the chat
286
+ bivy suggest "Add a dark theme to settings" # a next task you start in one tap
287
+ bivy context --json # session, workspace, machine, apps
288
+ ```
289
+
290
+ `bivy help --json` lists every command, and with `BIVY_OUTPUT=json` failures
291
+ come back as structured errors with distinct exit codes, so an agent can tell
292
+ what went wrong and what to run next. `bivy guide` prints short playbooks for
293
+ agents, and the same commands are served as MCP tools for agents that prefer
294
+ them. Add your own standing instructions for
295
+ every session in **Settings → Agent instructions**.
296
+
297
+ [Commands for agents inside a session →](docs/cli-reference.md#inside-an-agent-session) ·
298
+ [Agent instructions →](docs/agent-instructions.md)
299
+
272
300
  ## Get started
273
301
 
274
302
  ### Install
@@ -404,9 +432,9 @@ for the task, especially before enabling unattended work.
404
432
 
405
433
  ## Agents and everyday commands
406
434
 
407
- **Claude Code, Codex, Pi, and OpenCode are release-tested.** Additional adapters
408
- include Gemini CLI, Qwen Code, Goose, Aider, Cline, Crush, Cursor, GitHub Copilot,
409
- Grok, Amp, Auggie, Droid, Continue, Kilo Code, and Rovo Dev. Installation,
435
+ **Claude Code, Codex, Pi, OpenCode, and Grok are release-tested.** Additional
436
+ adapters include Gemini CLI, Qwen Code, Goose, Aider, Cline, Crush, Cursor, GitHub
437
+ Copilot, Amp, Auggie, Droid, Continue, Kilo Code, and Rovo Dev. Installation,
410
438
  resume, model selection, and tool protection vary—see the
411
439
  [support matrix](docs/runtime-support-matrix.md) and [agent guides](docs/agents/README.md).
412
440
 
package/bin/bivy.mjs CHANGED
@@ -2826,6 +2826,62 @@ async function cmdInstructions(args = []) {
2826
2826
  fail({ code: "usage", message: usage, exit: EXIT.usage });
2827
2827
  }
2828
2828
 
2829
+ // `bivy automation apply` inside an agent session: the node shows the user what
2830
+ // would change as an approval card and applies it only once they approve, with
2831
+ // this machine's account credential. `proposal <id> [--wait]` follows one.
2832
+ async function cmdAutomationProposal(args = []) {
2833
+ const usage = "Usage (in an agent session): bivy automation apply [path] [--prune] [--timeout 90] [--json]\n bivy automation proposal <id> [--wait] [--timeout 90] [--json]";
2834
+ if (args.includes("-h") || args.includes("--help")) {
2835
+ console.log(`${usage}\n\nInside an agent session, apply goes through this machine's approval mode: usually the user gets an approval card listing what would change and decides; with "never ask" it applies at once. The chat records what was applied. Waits up to --timeout seconds (default 90) for the answer; if it hasn't come, prints the proposal id to check later with 'bivy automation proposal <id> --wait'. The card stays open for 30 minutes. Validate and plan first ('bivy automation validate', 'plan').`);
2836
+ return;
2837
+ }
2838
+ const json = wantsJson(args);
2839
+ const fail = (error) => cliError(error, { json, paint: c.red });
2840
+ const parsed = parseSessionArgs(args, ["--timeout", "--session"]);
2841
+ if (parsed.error) return fail({ code: "usage", message: parsed.error, exit: EXIT.usage });
2842
+ const sessionId = resolveAttachSessionId({ sessionFlag: parsed.one("--session"), env: process.env });
2843
+ if (!sessionId) return fail({ code: "no_session", message: "No session id.", next: "bivy sessions --json", exit: EXIT.usage });
2844
+ const timeout = parsed.one("--timeout") === undefined ? 90 : durationSeconds(parsed.one("--timeout"));
2845
+ if (!Number.isFinite(timeout) || timeout < 0) return fail({ code: "usage", message: "--timeout takes seconds or a duration like 90s or 10m.", exit: EXIT.usage });
2846
+ const base = `/api/session/${encodeURIComponent(sessionId)}/automations/apply`;
2847
+ const [action, target] = parsed.positional;
2848
+ let proposal;
2849
+ if (action === "proposal") {
2850
+ if (!target) return fail({ code: "usage", message: usage, exit: EXIT.usage });
2851
+ const { status, body } = await nodeRequest("GET", `${base}/${encodeURIComponent(target)}`, undefined, { json, sessionId });
2852
+ if (status >= 400) return fail({ code: status === 404 ? "not_found" : "failed", message: body.error || `HTTP ${status}`, exit: status === 404 ? EXIT.notFound : EXIT.failed });
2853
+ proposal = body;
2854
+ if (!parsed.has("--wait")) { if (json) console.log(JSON.stringify(proposal)); else console.log(`Proposal ${proposal.id}: ${proposal.status}`); return; }
2855
+ } else {
2856
+ const file = path.resolve(process.cwd(), target ?? ".bivy/automations.yaml");
2857
+ const { status, body } = await nodeRequest("POST", base, { file, prune: parsed.has("--prune") }, { json, sessionId });
2858
+ if (status === 404 && !body.error?.includes("Session")) return fail({ code: "node_outdated", message: "This node is older than proposing automations from a session.", next: "bivy update", exit: EXIT.unavailable });
2859
+ if (status >= 400) return fail(sessionHttpError("Proposing the automations", status, body));
2860
+ proposal = body;
2861
+ if (!json) {
2862
+ console.error(`Changes to apply (${proposal.file}):`);
2863
+ for (const change of proposal.changes) console.error(` ${change.action === "create" ? "+" : change.action === "remove" ? "-" : "~"} ${change.id}`);
2864
+ }
2865
+ }
2866
+ const deadline = Date.now() + timeout * 1000;
2867
+ let polls = 0;
2868
+ while (proposal.status === "pending" && Date.now() < deadline) {
2869
+ await new Promise((resolve) => setTimeout(resolve, polls === 0 ? 500 : 2000));
2870
+ if (polls++ === 1 && !json) console.error("Waiting for the user to approve them…");
2871
+ const { status, body } = await nodeRequest("GET", `${base}/${encodeURIComponent(proposal.id)}`, undefined, { json, sessionId });
2872
+ if (status < 400) proposal = body;
2873
+ }
2874
+ if (json) console.log(JSON.stringify(proposal));
2875
+ if (proposal.status === "applied") { if (!json) console.log(proposal.output || "Applied."); return; }
2876
+ if (proposal.status === "pending") {
2877
+ if (!json) console.log(`The user hasn't answered yet. Check later with: bivy automation proposal ${proposal.id} --wait`);
2878
+ process.exit(EXIT.timeout);
2879
+ }
2880
+ const message = { rejected: "The user declined these automation changes.", expired: "Nobody answered within 30 minutes; nothing was applied.", failed: `Approved, but applying failed: ${proposal.error || "unknown error"}` }[proposal.status] ?? proposal.status;
2881
+ if (!json) console.error(message);
2882
+ process.exit(proposal.status === "expired" ? EXIT.timeout : EXIT.failed);
2883
+ }
2884
+
2829
2885
  // Cross-agent / cross-machine delegation (docs/agent-delegation.md): hand a
2830
2886
  // self-contained task from this session to another agent, optionally on another
2831
2887
  // account machine, and get its answer back. Agent-agnostic — any agent with a
@@ -6081,6 +6137,11 @@ Unlike 'bivy run', these commands operate on governed background Runs with check
6081
6137
  break;
6082
6138
  }
6083
6139
  case "automation": {
6140
+ // An agent's apply is a proposal the user approves (see cmdAutomationProposal).
6141
+ if ((args[0] === "apply" && !args.includes("--dry-run") && !process.env.BIVY_AUTOMATION_DIRECT && resolveAttachSessionId({ env: process.env })) || args[0] === "proposal") {
6142
+ await cmdAutomationProposal(args);
6143
+ break;
6144
+ }
6084
6145
  if (!(await ensureDeps())) process.exit(1);
6085
6146
  process.exit(await run(nodeBin, [...nodeScriptArgs(automationEntry), ...args], { cwd: process.cwd(), env: process.env }));
6086
6147
  break;
@@ -78,7 +78,11 @@ export const COMMANDS = [
78
78
 
79
79
  // Runs and automations
80
80
  { name: "runs", group: "runs", scope: "account", json: true, usage: 'runs <start|list|status|wait>', summary: "Unattended Runs with checks, evidence and a Receipt", subcommands: ["start", "list", "status", "wait"] },
81
- { name: "automation", aliases: ["automations"], group: "runs", scope: "account", json: true, usage: "automation <list|trigger|init|validate|plan|test|apply>", summary: "Automations as code: validate, plan, apply, trigger", subcommands: ["list", "trigger", "init", "validate", "plan", "test", "test-filter", "apply"] },
81
+ { name: "automation", aliases: ["automations"], group: "runs", scope: "account", json: true, usage: "automation <list|trigger|init|validate|plan|test|apply>", summary: "Automations as code: validate, plan, apply, trigger", subcommands: ["list", "trigger", "init", "validate", "plan", "test", "test-filter", "apply", "proposal"],
82
+ tools: [
83
+ { name: "automation_plan", description: "Check an automations file (.bivy/automations.yaml) and show what each automation would do: trigger, routing, effective safety. Run it before automation_apply.", input: { path: { type: "string", description: "The automations file (default .bivy/automations.yaml)." } }, argv: ["automation", "plan", { arg: "path" }] },
84
+ { name: "automation_apply", description: "Propose applying an automations file to the user's account. They get an approval card listing each change; nothing is applied unless they approve. Returns the proposal: status applied, rejected, expired, failed, or pending (check later with bivy automation proposal <id> --wait).", input: { path: { type: "string", description: "The automations file (default .bivy/automations.yaml)." }, prune: { type: "boolean", description: "Also remove automations this file no longer has." } }, argv: ["automation", "apply", { arg: "path" }, { when: "prune", flag: "--prune" }] },
85
+ ] },
82
86
 
83
87
  // This node
84
88
  { name: "setup", aliases: ["init"], group: "node", scope: "node", usage: "setup", summary: "First-run wizard: agent, model login, remote sign-in, background service" },
@@ -9,11 +9,35 @@ infrastructure code:
9
9
  bivy automation validate # check it
10
10
  bivy automation plan --json # triggers, routing, effective safety
11
11
  bivy automation test --event event.json # which automation an event would start
12
- bivy automation apply # reconcile the account with the file
12
+ bivy automation apply # ask the user, then apply
13
13
  bivy automation list --json
14
14
  bivy automation trigger <id-or-key> # run one now
15
15
 
16
+ A scheduled one (triggers: schedule, github, linear, webhook, manual; the
17
+ format is in docs/automations-as-code.md):
18
+
19
+ version: 1
20
+ automations:
21
+ - id: nightly-tests
22
+ name: Nightly tests
23
+ trigger: schedule
24
+ schedule: { cron: "0 2 * * *", timezone: UTC } # or { at: "2026-10-01T09:00:00Z" }
25
+ repo: owner/name # required for schedules
26
+ instructions: |
27
+ Run the test suite. If it fails, open an issue with the failing tests.
28
+ safety:
29
+ approval: risky
30
+ sandbox: workspace-write
31
+
32
+ From a session, `apply` goes through the machine's approval mode. Usually the
33
+ user gets a card listing every change and decides. With "never ask" it applies
34
+ at once, and the chat records what changed either way. The command waits up to
35
+ 90 seconds for an answer and prints apply's output once it's applied (exit 0). Exit 1 means they declined
36
+ (don't retry the same thing), and exit 5 means they haven't answered yet: carry
37
+ on, and check later with `bivy automation proposal <id> --wait`.
38
+ `apply --dry-run` shows the changes without asking anyone.
39
+
16
40
  To pause one, set `enabled: false` on it and apply. Always `validate` and
17
- `plan` before `apply`, and show the user the plan when it
18
- changes something they didn't ask for. `apply --prune` also removes automations
19
- the file no longer has. `bivy automation --help` has every flag.
41
+ `plan` first, and say in the chat what the automation will do and when.
42
+ `apply --prune` also removes automations the file no longer has.
43
+ `bivy automation --help` has every flag.
@@ -49,6 +49,8 @@ export const BIVY_AGENT_NOTE = [
49
49
  '`bivy delegate "<self-contained task>" --agent <id> [--machine <name>] --wait` runs it there and prints ' +
50
50
  "its answer and any branch/PR; `--to codex,grok@<machine>` asks several to compare, `bivy delegate machines` " +
51
51
  "lists machines and their agents. Use your own sub-agents for everything else.",
52
+ "- Work that should run on its own later (on a schedule, or when CI fails or an issue arrives) is a Bivy automation: " +
53
+ "`bivy guide automate`. Applying one may ask the user first.",
52
54
  "- `bivy context` shows your session, workspace and published apps; `bivy guide` has short playbooks; " +
53
55
  "`bivy help` lists every command (`--json` for all).",
54
56
  ].join("\n");
package/dist/approval.js CHANGED
@@ -30,7 +30,7 @@ export class ApprovalManager {
30
30
  }
31
31
  async request(input) {
32
32
  const request = {
33
- id: randomUUID(),
33
+ id: input.id ?? randomUUID(),
34
34
  sessionId: input.sessionId,
35
35
  toolName: input.toolName,
36
36
  input: input.toolInput,
@@ -727,7 +727,7 @@ input, textarea, select { font-family: inherit; font-size: 16px; }
727
727
  }
728
728
  .approval-fields { display: grid; gap: 6px; margin-bottom: 8px; }
729
729
  .approval-field-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
730
- .approval-field-value { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; overflow-wrap: anywhere; word-break: break-word; }
730
+ .approval-field-value { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; overflow-wrap: anywhere; word-break: break-word; white-space: pre-line; }
731
731
  .approval-raw-toggle { border: 0; background: transparent; color: var(--muted); font-size: 12px; padding: 0; margin-bottom: 8px; text-decoration: underline; }
732
732
  .approval-raw-toggle:hover { color: var(--ink); }
733
733
  .approval-summary { margin: 0 0 10px; background: var(--surface-2); border-radius: var(--radius-sm); padding: 8px 10px; overflow-x: auto; font-size: 12px; }
@@ -32,7 +32,8 @@ Commands:
32
32
  plan [path] [--json] Show triggers, routing, and effective safety
33
33
  test [path] --event <file> Simulate an event and explain the first match
34
34
  test-filter [path] --id <key> --event <json> Execute a trusted filter locally
35
- apply [path] [--prune] Encrypt instructions and reconcile the control plane
35
+ apply [path] [--prune] [--dry-run] Encrypt instructions and reconcile the control plane
36
+ (inside an agent session: proposed to the user first)
36
37
 
37
38
  Run commands (normally invoked as 'bivy runs ...'):
38
39
  start <instructions> Queue definition-free unattended work
@@ -482,6 +483,27 @@ async function main() {
482
483
  const pairing = PairingStore.load(appDir, relay.e2eKey);
483
484
  const current = await request(relay, "/node/automation-config");
484
485
  const wanted = new Set(config.automations.map((a) => a.id));
486
+ // --dry-run: what apply would change, and nothing more. The node shows this
487
+ // on the approval card when an agent proposes automations.
488
+ if (args.includes("--dry-run")) {
489
+ const changes = [
490
+ ...config.automations.map((entry) => {
491
+ const safety = effectiveSafety(entry, file);
492
+ return {
493
+ id: entry.id, action: current.automations.some((a) => a.configKey === entry.id) ? "update" : "create", name: entry.name, enabled: entry.enabled, trigger: entry.trigger,
494
+ schedule: entry.schedule, workspace: entry.repo ?? (entry.repos?.length ? entry.repos.join(", ") : undefined),
495
+ agent: entry.routing.agent ?? "node default", sandbox: safety.sandbox, approval: safety.approval,
496
+ };
497
+ }),
498
+ ...(args.includes("--prune") ? current.automations.filter((a) => a.configKey && !wanted.has(a.configKey)).map((a) => ({ id: a.configKey, action: "remove" })) : []),
499
+ ];
500
+ if (args.includes("--json"))
501
+ console.log(JSON.stringify({ version: 1, changes }, null, 2));
502
+ else
503
+ for (const change of changes)
504
+ console.log(`${change.action === "create" ? "+" : change.action === "remove" ? "-" : "~"} ${change.id}`);
505
+ return;
506
+ }
485
507
  let created = 0, updated = 0, removed = 0;
486
508
  for (const [configOrder, entry] of config.automations.entries()) {
487
509
  const exists = current.automations.some((a) => a.configKey === entry.id);
@@ -19,6 +19,8 @@ export function scoreAgentUx(expect, seen, vars = {}) {
19
19
  }
20
20
  if ("asked" in rule)
21
21
  return { expectation: "asked a question", passed: seen.asked };
22
+ if ("approval" in rule)
23
+ return { expectation: `asked to approve ${rule.approval}`, passed: seen.approvals.includes(rule.approval) };
22
24
  if ("reply" in rule) {
23
25
  const text = fill(rule.reply);
24
26
  return { expectation: `reply mentions "${text}"`, passed: seen.reply.toLowerCase().includes(text.toLowerCase()) };
package/dist/server.js CHANGED
@@ -128,6 +128,7 @@ import { createArtifactCommands } from "./controllers/artifact-commands.js";
128
128
  import { PresenceBook, deviceFrom } from "./session/presence.js";
129
129
  import { buildAgentContext } from "./session/agent-context.js";
130
130
  import { AgentQuestions, askQuestionsFrom } from "./session/agent-questions.js";
131
+ import { AutomationProposals, describeChange } from "./session/automation-proposals.js";
131
132
  import { createSessionTokenCodec, isSessionToken, sessionTokenAllows } from "./session/session-tokens.js";
132
133
  import { setSessionTokenSigner } from "./runtime/session-env.js";
133
134
  import { MAX_NOTICE_TEXT, isAgentNotice, noticePush } from "./session/notices.js";
@@ -412,6 +413,46 @@ setSessionTokenSigner(sessionTokens.sign);
412
413
  // them, and session.question(.resolved) is broadcast from its listeners.
413
414
  const questionManager = new QuestionManager();
414
415
  const agentQuestions = new AgentQuestions(questionManager);
416
+ // `bivy automation apply` from an agent: an approval request like any other, so
417
+ // the node's approval mode decides whether the user is asked ("never" applies
418
+ // at once; autonomous asks, as for deploys). Either way the result lands in the
419
+ // chat, and pushes when nobody was asked.
420
+ const automationProposals = new AutomationProposals({
421
+ runCli: (args, cwd) => new Promise((resolve) => {
422
+ const cli = process.env.BIVY_NODE_CLI ?? path.join(repoRoot, "bin", "bivy.mjs");
423
+ const child = spawn(process.execPath, [cli, ...args], { cwd, env: { ...process.env, BIVY_DATA_DIR: appDir, BIVY_AUTOMATION_DIRECT: "1", NO_COLOR: "1" }, stdio: ["ignore", "pipe", "pipe"] });
424
+ let stdout = "";
425
+ let stderr = "";
426
+ child.stdout.on("data", (chunk) => { stdout += chunk; });
427
+ child.stderr.on("data", (chunk) => { stderr += chunk; });
428
+ child.on("error", (error) => resolve({ code: 1, stdout, stderr: error.message }));
429
+ child.on("close", (code) => resolve({ code: code ?? 1, stdout, stderr }));
430
+ }),
431
+ requestApproval: async ({ id, sessionId, file, changes, prune }) => {
432
+ const approved = await approvals.request({
433
+ id, sessionId, toolName: "apply_automations", timeoutMs: 30 * 60_000,
434
+ toolInput: { file, prune, changes: changes.map(describeChange) },
435
+ reason: "Automations run on their own, on your machines, until you turn them off.",
436
+ });
437
+ if (approved)
438
+ return "approved";
439
+ return approvals.list().find((request) => request.id === id)?.status === "expired" ? "expired" : "rejected";
440
+ },
441
+ applied: (proposal) => {
442
+ const record = openSessions.get(proposal.sessionId);
443
+ if (!record)
444
+ return;
445
+ const lines = proposal.changes.map(describeChange);
446
+ const text = `Applied automations from ${proposal.file}:\n${lines.join("\n")}`.slice(0, MAX_NOTICE_TEXT);
447
+ const notice = { id: `notice-${randomBytes(8).toString("hex")}`, text };
448
+ eventLog.appendNotice(record.id, { afterMessageCount: record.session.getMessages().length, notice });
449
+ broadcast(stampSessionEvent({ type: "session.event", sessionId: record.id, event: { type: "notice", id: notice.id, notice } }));
450
+ // Nobody was asked: make sure the user hears about it.
451
+ if (approvalMode === "never") {
452
+ void sendNotificationHint({ kind: "agent_notice", sessionId: record.id, targetSessionId: record.id, title: sessionNotifyLabel(record), body: `Changed ${lines.length} automation${lines.length === 1 ? "" : "s"} on your account — tap to see what.` });
453
+ }
454
+ },
455
+ });
415
456
  questionManager.onRequest((request) => {
416
457
  scheduleAdvertise();
417
458
  broadcast({ type: "session.question", sessionId: request.sessionId, requestId: request.id, questions: request.questions, createdAt: request.createdAt });
@@ -11607,6 +11648,23 @@ app.post("/api/session/:id/ask/:askId/wait", async (req, res) => {
11607
11648
  return res.status(404).json({ error: "Question not found" });
11608
11649
  res.json(result);
11609
11650
  });
11651
+ // `bivy automation apply` inside a session: propose, and follow the proposal.
11652
+ app.post("/api/session/:id/automations/apply", async (req, res) => {
11653
+ const record = openSessions.get(String(req.params.id));
11654
+ if (!record)
11655
+ return res.status(404).json({ error: "Session not found" });
11656
+ const file = typeof req.body?.file === "string" && req.body.file.trim() ? req.body.file.trim() : ".bivy/automations.yaml";
11657
+ const result = await automationProposals.propose(record.id, harnessDirFor(record), file, req.body?.prune === true);
11658
+ if ("error" in result)
11659
+ return res.status(400).json({ error: result.error });
11660
+ res.status(201).json(result);
11661
+ });
11662
+ app.get("/api/session/:id/automations/apply/:proposalId", (req, res) => {
11663
+ const proposal = automationProposals.get(String(req.params.id), String(req.params.proposalId));
11664
+ if (!proposal)
11665
+ return res.status(404).json({ error: "Proposal not found" });
11666
+ res.json(proposal);
11667
+ });
11610
11668
  // `bivy suggest "<task>"`: the agent proposes a task the user can start in one
11611
11669
  // tap, here or in a parallel session (see packages/web SuggestionCard).
11612
11670
  app.post("/api/session/:id/suggest", (req, res) => {
@@ -0,0 +1,87 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (c) 2026 Petter André Sjulstad
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { randomUUID } from "node:crypto";
6
+ /** One line per change, for the card and the CLI. */
7
+ export function describeChange(change) {
8
+ if (change.action === "remove")
9
+ return `Remove ${change.id}`;
10
+ const when = change.schedule?.kind === "cron" ? `${change.schedule.expression} (${change.schedule.timezone})` : change.schedule?.kind === "once" ? `once at ${change.schedule.at}` : change.trigger ?? "";
11
+ const verb = change.action === "create" ? "Add" : "Update";
12
+ return `${verb} ${change.name ?? change.id}${change.enabled === false ? " (off)" : ""}: ${when}${change.workspace ? ` in ${change.workspace}` : ""}, ${change.agent}, ${change.sandbox}, approvals ${change.approval}`;
13
+ }
14
+ /** `file` resolved inside `workspace`, or an error: an agent can only propose its own workspace's files. */
15
+ export function confinedFile(workspace, file) {
16
+ let root;
17
+ let abs;
18
+ try {
19
+ root = fs.realpathSync(workspace);
20
+ abs = fs.realpathSync(path.resolve(workspace, file));
21
+ }
22
+ catch {
23
+ return { error: `No such file: ${file}` };
24
+ }
25
+ const rel = path.relative(root, abs);
26
+ if (!rel || rel.startsWith("..") || path.isAbsolute(rel))
27
+ return { error: "The automations file must be inside the session workspace." };
28
+ return { abs, rel };
29
+ }
30
+ const KEEP_MS = 24 * 60 * 60 * 1000;
31
+ export class AutomationProposals {
32
+ deps;
33
+ now;
34
+ proposals = new Map();
35
+ constructor(deps, now = Date.now) {
36
+ this.deps = deps;
37
+ this.now = now;
38
+ }
39
+ /** Check the file, work out the changes, and put the card in front of the user. */
40
+ async propose(sessionId, workspace, file, prune) {
41
+ this.prune();
42
+ const target = confinedFile(workspace, file);
43
+ if ("error" in target)
44
+ return target;
45
+ const dry = await this.deps.runCli(["automation", "apply", target.abs, "--dry-run", "--json", ...(prune ? ["--prune"] : [])], workspace);
46
+ if (dry.code !== 0)
47
+ return { error: (dry.stderr || dry.stdout).trim().replace(/^Automation error: /, "") || "The automations file could not be checked." };
48
+ let changes;
49
+ try {
50
+ changes = JSON.parse(dry.stdout).changes;
51
+ }
52
+ catch {
53
+ return { error: "Unexpected output from automation apply --dry-run." };
54
+ }
55
+ if (!changes.length)
56
+ return { error: "The file has no automations to apply." };
57
+ const proposal = { id: randomUUID(), sessionId, status: "pending", file: target.rel, changes };
58
+ this.proposals.set(proposal.id, proposal);
59
+ void this.deps.requestApproval({ id: proposal.id, sessionId, file: target.rel, changes, prune }).then(async (decision) => {
60
+ if (decision === "approved") {
61
+ const run = await this.deps.runCli(["automation", "apply", target.abs, ...(prune ? ["--prune"] : [])], workspace);
62
+ proposal.status = run.code === 0 ? "applied" : "failed";
63
+ proposal.output = run.stdout.trim();
64
+ if (run.code !== 0)
65
+ proposal.error = run.stderr.trim().replace(/^Automation error: /, "");
66
+ else
67
+ this.deps.applied?.(this.view(proposal));
68
+ }
69
+ else
70
+ proposal.status = decision;
71
+ proposal.settledAt = this.now();
72
+ });
73
+ return this.view(proposal);
74
+ }
75
+ get(sessionId, id) {
76
+ const proposal = this.proposals.get(id);
77
+ return proposal && proposal.sessionId === sessionId ? this.view(proposal) : undefined;
78
+ }
79
+ view({ settledAt: _settledAt, ...proposal }) {
80
+ return structuredClone(proposal);
81
+ }
82
+ prune() {
83
+ for (const [id, proposal] of this.proposals)
84
+ if (proposal.settledAt !== undefined && this.now() - proposal.settledAt > KEEP_MS)
85
+ this.proposals.delete(id);
86
+ }
87
+ }
@@ -51,6 +51,8 @@ export const SESSION_TOKEN_ROUTES = [
51
51
  { method: "POST", path: /^\/api\/session\/([^/]+)\/delegated-runs$/, session: "path" },
52
52
  { method: "GET", path: /^\/api\/session\/([^/]+)\/delegated-runs\/[^/]+$/, session: "path" },
53
53
  { method: "POST", path: /^\/api\/session\/([^/]+)\/delegated-runs\/[^/]+\/wait$/, session: "path" },
54
+ { method: "POST", path: /^\/api\/session\/([^/]+)\/automations\/apply$/, session: "path" },
55
+ { method: "GET", path: /^\/api\/session\/([^/]+)\/automations\/apply\/[^/]+$/, session: "path" },
54
56
  { method: "POST", path: /^\/api\/apps\/[a-zA-Z]+$/, session: "body" },
55
57
  { method: "POST", path: /^\/api\/session\/fork$/, session: "body" },
56
58
  { method: "GET", path: /^\/api\/machines$/, session: "none" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bivy/bivy",
3
- "version": "0.19.4-staging.6",
3
+ "version": "0.20.0-staging.1",
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.",
@@ -65,7 +65,7 @@
65
65
  "lodash-es": "4.18.1",
66
66
  "undici": "8.11.2"
67
67
  },
68
- "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%A520-2b6cb0)](https://nodejs.org)\n\n**Build, try, and review apps from your phone. Your coding agent and dev\nenvironment stay on your own machines.**\n\nBivy is an open-source remote development environment built around coding\nagents. Ask for a change, try the running app, and point to or draw on what\nneeds fixing. Send that feedback to the agent and try again—all in the same\nsession, without going back to your computer.\n\nLive previews bring your app to your phone or browser without deploying it to\nRender, building a Docker image, or setting up a separate preview server.\nShare a preview link so someone else can try it and leave notes, too.\n\nKeep Claude Code, Codex, Pi, OpenCode, or another supported agent. Keep your\nrepos, tools, databases, and development environment. Bivy connects them to\nchat, a terminal, app previews, and code review wherever you are. Start work\nyourself, or let an issue, CI failure, message, schedule, or webhook start it.\n\n**[Start free on Bivy Cloud](https://app.bivy.sh)** ·\n**[Quickstart](docs/quickstart.md)** ·\n**[Documentation](docs/README.md)** ·\n**[Self-host](docs/deploy-images.md)** ·\n**[Website](https://bivy.sh)**\n\n**Recommended:** sign in at [app.bivy.sh](https://app.bivy.sh), then copy your\npersonalized **Connect a Machine** command into a terminal on your Mac or Linux\ncomputer. It installs and enrolls the machine without another Bivy login. The\nbrowser connects automatically; choose a repository and send your first task\nright there.\n\nPrefer starting from the terminal?\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash # install + guided setup\ncd your-repo\nbivy run claude # or codex, pi, opencode\nbivy open # continue in the web app (needs remote setup)\n```\n\nBivy Cloud hosts the app, control plane, and relay—not the machines running your\nagents. Connect a Mac, Linux computer, or existing server and bring your own\nagent subscription, model API key, or local model. You can also self-host the\nentire remote-access stack.\n\n> **Bivy is 0.x software.** Claude Code, Codex, Pi, and OpenCode are the\n> release-tested paths. Credential sync, resume, handoffs, approvals, and\n> sandboxing depend on the runtime. See the\n> [runtime support matrix](docs/runtime-support-matrix.md).\n\n## Build → preview → mark up → iterate\n\nRemote chat lets you ask an agent for a change. Bivy also lets you **use what\nit built and show it what to fix**, without a separate deployment step.\n\n1. **Ask for a change.** The agent works in your repo with your existing tools\n and local services.\n2. **Try the app.** Open a live preview from the session. Use the running app,\n not just a screenshot of what the agent says it finished. Bivy can discover\n dev servers running in the session workspace; tap **Preview** to open one.\n3. **Mark up what needs work.** Point at an element or circle and draw on the\n preview. Add a note, then send the draft to the agent with the element and\n page context. Marked-up screenshots and before/after comparison are available\n when agent screenshots are enabled.\n4. **Iterate and review.** Try the next version, inspect the diff, review checks,\n and decide when the work is ready—not just when the agent stops.\n5. **Bring someone else into the review.** Copy a public preview link so they\n can use the app without a Bivy account and leave notes on specific elements.\n Bring their notes into the session when you're ready to act on them.\n\nOn Bivy Cloud, preview delivery is built in: no per-app domains, certificates,\npublic ports, or tunnels to configure. Self-hosters configure preview delivery\nonce for their Bivy deployment, not for every app. The app still needs its normal\nbuild or dev-server setup, and **the machine serving it must stay awake and\nonline**. These are development previews, not production hosting.\n\n**Share deliberately:** anyone with a preview link can use that app, including\nits live backend. Links expire after 24 hours and can be revoked sooner.\nReviewer notes aren't sent to the agent automatically; you send them or explicitly\nallow agent access. Preview traffic uses HTTPS through the preview relay, not\nsession end-to-end encryption; the relay operator can see it.\n\n[App previews, visual feedback, and sharing →](docs/apps.md)\n\n## Your agents and machines, one workspace\n\n| Capability | What it means for you |\n|---|---|\n| **One workspace, multiple agents** | Use different agents and models for different tasks without maintaining a separate workflow for each. |\n| **Your machines and environment** | Work beside your existing repos, dev servers, databases, private networks, toolchains, and GPUs. |\n| **Automations and triggers** | Let issues, failed CI, messages, schedules, and webhooks start work instead of copying requests into a chat. |\n| **Encrypted key and OAuth sync** | Reuse Bivy-managed provider credentials across enrolled machines and compatible runtimes, with less repeated setup. |\n| **Live sessions from anywhere** | Build and review from your phone, browser, or terminal; answer questions and approve supported actions in the same session. |\n| **Live app previews** | Try the running app without deploying it to a separate hosting service. |\n| **Visual feedback and sharing** | Point, draw, and send specific feedback to the agent; share a preview link for outside review. |\n| **Reviewable results** | Inspect the app, changes, declared checks, artifacts, and pull requests—not just an agent's claim that it finished. |\n| **Hosted convenience or self-hosting** | Use Bivy Cloud for managed remote access, or run the same open-source core yourself. |\n\n## One workflow, from trigger to review\n\n```text\nPrompt · GitHub issue · CI failure · Linear · Slack · Schedule · Webhook\n │\n ▼\n Choose machine + agent + model\n + supported credentials\n │\n ▼\n Live agent session\n Join · steer · approve · stop\n │\n ▼\n Try app · inspect changes · checks\n │\n ▼\n Mark up · send feedback · iterate\n │\n ▼\n Share preview · review PR\n```\n\nA **Machine** is a computer or server you connect. A **Session** is live agent\nwork on that machine. A **Run** is delegated background work that creates a\nsession and tracks its outcome. An **Automation** is a reusable definition that\ncreates runs when an event matches.\n\nManual and automated work use the same kind of live session. You can join a run\nwhen it needs help rather than wait for a black-box job to finish.\n\n### Work in the environment you already have\n\nA clean cloud sandbox isn't always enough. Your agent may need the database\nrunning on localhost, an uncommitted change, an internal API behind your VPN,\nor a model running on your GPU. Bivy runs the agent where those things already\nexist, subject to that machine's permissions and the runtime's protection.\n\nConnect several machines to the same account: a laptop for interactive work,\na Linux server for background jobs, or a GPU box for local inference. Choose\nthe machine for each session or pin it in an automation. Repository runs can\nuse isolated Git worktrees without rebuilding the whole development environment.\n\n**The execution machine must stay awake and online.** To close your laptop and\nleave work running, run the agent on a different, always-on machine.\n\n[Environment and multi-machine recipes →](docs/capability-recipes.md)\n\n### Use multiple agents, not multiple disconnected workflows\n\nRun Claude Code for one task, Codex for another, and Pi or OpenCode where they\nfit. Bivy supplies the shared session, remote-access, automation, and review\nsurfaces; your chosen agent still does the coding and uses your model provider.\n\n- Choose an agent and, where supported, a model for each session or run.\n- Import existing Claude Code and Codex sessions.\n- Fork or move work to another agent or machine when a different setup fits\n better. Continuation fidelity varies: some paths preserve native history,\n while others replay portable turns or seed the destination with context.\n- Use agent-native logins, Bivy-managed credentials, or local inference.\n Bivy's custom OpenAI-compatible endpoint registry currently feeds Pi;\n other agents may need their own provider configuration.\n- Register your own ACP or headless process agent with `bivy agent add`.\n\nBivy does not replace your agent, provide model inference, or make every agent's\nfeatures identical. Consult the [support matrix](docs/runtime-support-matrix.md)\nand [handoff recipes](docs/capability-recipes.md#fork-or-move-a-session).\n\n### Less signing in. Less copying secrets.\n\nBivy syncs **Bivy-managed API keys and supported OAuth credentials** across\nenrolled machines for compatible runtimes. Connect supported credentials once\nand reuse them where you run work, rather than manually distributing keys to\neach machine.\n\nFor ordinary account sync, credentials are encrypted on the node before upload.\nThe control plane stores ciphertext and wrapped-key metadata; enrolled nodes\nshare access by wrapping the vault key to one another. Bivy Cloud does not\nreceive plaintext credentials through this sync path.\n\nYou can also keep credentials local, use labeled keys and project presets, or\nreference environment variables and 1Password instead of embedding secrets in\nconfiguration:\n\n```bash\nbivy provider login\nbivy credentials add anthropic work\nbivy secrets ref github.repo-token op://Bivy/GitHub/repo-token\n```\n\n**Not every CLI login syncs.** Native agent logins may still be per-machine;\nGitHub App private-key sync is separately opt-in. If you lose every node and\ndevice able to unwrap a vault, you must sign in to providers again. Explicit\nhosted-provisioning custody grants are separate from ordinary encrypted sync.\n\n[Credential sync and runtime coverage →](docs/credential-sync.md) ·\n[Credentials guide →](docs/credentials-guide.md) ·\n[Key storage →](docs/key-management.md)\n\n### Let events start the work\n\nAutomations turn recurring or incoming work into sessions you can join,\nsupervise, and review. Choose the repository, machine, agent, model, approval\nmode, sandbox setting, and maximum attempts.\n\n| Trigger | Example workflow |\n|---|---|\n| **GitHub issues and mentions** | Label an issue `bivy` or `bivy/<machine>`, or mention your Bivy GitHub App, to work toward a pull request. |\n| **Failed CI** | Match a failed workflow, ask the agent to reproduce it, make a fix, and run the affected checks. |\n| **Linear** | Label an issue to start work without copying its description into an agent. |\n| **Slack** | Send a request from the conversation where the work came up. |\n| **Schedules** | Run a weekly dependency review, recurring maintenance, or a one-time task. |\n| **Signed webhooks** | Connect alerts, internal tools, or your own event sources. |\n\nConfigure automations in the app or version them with your repository in\n`.bivy/automations.yaml`:\n\n```bash\nbivy automation init\n# Edit the generated definition for your repository and workflow.\nbivy automation validate\nbivy automation test --event .bivy/events/failed-ci.yaml # supply a local event fixture\nbivy automation apply\n```\n\nOr delegate a one-off job without creating an automation:\n\n```bash\nbivy runs start \"Review outdated dependencies and propose a small, tested update.\"\nbivy runs wait <id>\n```\n\nRuns keep routing and lifecycle evidence, check results, and output references\nin a reviewable Receipt. For unattended issue work, Bivy runs declared repository\nchecks after the agent's turn; failed required checks fail the run even if the\nagent reports success. A completed process alone is not proof that the task\nsucceeded.\n\n[Automation recipes →](docs/capability-recipes.md#let-events-start-runs) ·\n[Automations as code →](docs/automations-as-code.md) ·\n[Run outcomes and reliability limits →](docs/automation-runs.md)\n\n### Start at your desk. Continue anywhere.\n\nOpen the same session in the browser, phone PWA, or terminal. Watch work live,\nanswer questions, approve supported tool calls, or stop the agent.\n\n- Send screenshots, images, logs, and other files from your phone.\n- Download reports and artifacts the agent creates.\n- Open [session apps](docs/apps.md) from chat or the **Apps** menu: live web\n previews, desktop app views, and CLI/TUI tools. Agents can publish views with\n `bivy app publish bivy.app.json` and create share links with `bivy app share`.\n- Use voice input and read-aloud where supported; provider-backed voice may\n send audio or text to the selected provider.\n- Keep a native terminal workflow or use structured chat, depending on the agent.\n\n```bash\nbivy run claude --no-follow # start without attaching\nbivy open # open the web app\nbivy resume # return to the session in your terminal\nbivy link # pair a device directly via QR\n```\n\nNo phone app installation is required. Open [app.bivy.sh](https://app.bivy.sh)\nin your browser; adding it to your home screen is optional.\n\n[Remote access →](docs/remote-access.md) ·\n[Voice, files, and terminal recipes →](docs/capability-recipes.md)\n\n## Get started\n\n### Install\n\nBivy supports **macOS and Linux with Node.js 20+**. The installer installs the\n`@bivy/bivy` package, runs guided setup, and starts a launchd or systemd service:\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash\n```\n\nSetup helps you choose an agent and configure remote access. Existing agents\nkeep their command, login, and configuration. The installer may use `sudo` to\ninstall a missing Node.js, but never for `npm install`. To inspect it first,\ndownload it with `curl -fsSL https://bivy.sh/install.sh -o install.sh`.\n\nAlready have Node.js and want to avoid sudo?\n\n```bash\nnpm install -g @bivy/bivy\nbivy setup\n```\n\nThen try one small task:\n\n```bash\ncd your-repo\nbivy run claude\n# Ask: \"Explain this repo and make one small, safe improvement. Run the relevant checks.\"\nbivy open\n```\n\nOpen that same session on your phone while it runs. For a web app, ask the agent\nto start its dev server, then open **Apps → Running in this workspace → Preview**.\nTry a page, point to something you'd change, and send the feedback back to the\nagent. No separate preview deployment needed.\n\nOnce that works, share a preview for review, connect another machine, or add\nyour first automation.\n\n**Local-only works too.** `bivy run`, `bivy resume`, and `bivy sessions` need no\naccount or server. Choose **local only for now** during setup; use `bivy login`\nlater. Browser and phone access need a hosted or self-hosted control plane;\nthe node itself does not serve a web UI.\n\n[Full quickstart →](docs/quickstart.md) ·\n[Installer options, service management, and uninstall →](docs/install.md)\n\n### Choose hosted or self-hosted\n\n| Option | What you get |\n|---|---|\n| **Free Cloud — $0** | Every launch feature, including automations; 10 new remote sessions per rolling seven days. No credit card required. |\n| **Cloud — $15/month** | The same features with unlimited remote sessions. |\n| **Self-hosted Core** | Operate the app, control plane, and relay yourself, with no Bivy usage limits. |\n\nManual and automated sessions share the Cloud allowance. Resuming existing\nsessions and viewing history do not consume it. Agent subscriptions and model\nprovider charges are separate. See [current pricing](https://bivy.sh#pricing).\n\n**Self-host anywhere:** deploy the public control-plane (including the web app)\nand relay images with Postgres and [a small set of environment variables](docs/deploy-images.md).\nYour server or container platform handles HTTPS. Set up owner access in the\nbrowser—no SSH, external authentication provider, or Bivy Cloud account required.\nFor a bare VPS, the [Compose installer](docs/self-host-quickstart.md) automates the\nsame stack. These onboarding features require a release containing them.\n\nStart on Cloud and self-host later if you prefer. Deploy the stack, reconnect\nmachines with `bivy relay:setup`, and pair devices to your server. This is not a\none-click migration of your Cloud account; your local repos and agent\nconfiguration stay in place.\n\n```bash\nbivy relay:setup \\\n --control-plane https://bivy.example.com \\\n --relay wss://relay.example.com\n```\n\nSelf-hosting is community-supported: you own TLS, backups, upgrades, and\nhardening. Public multi-architecture images are available as\n`ghcr.io/bivysh/bivy-control-plane` and `ghcr.io/bivysh/bivy-relay`; pin a release\nversion or full commit SHA.\n\n[Deploy the images anywhere →](docs/deploy-images.md) ·\n[Optional VPS installer →](docs/self-host-quickstart.md) ·\n[Operations reference →](docs/self-host.md)\n\n## Architecture\n\nYour environment, with clear security boundaries:\n\n```text\nYour machine Hosted or self-hosted\n┌──────────────────────┐ ┌──────────────────────┐\n│ Node daemon │──outbound──▶│ Relay │\n│ Agents, repos, tools │ │ Encrypted frames │\n│ Local credentials │ └──────────┬───────────┘\n└──────────────────────┘ │\n Browser / phone\n + control plane\n (app, accounts, metadata)\n```\n\n- **Execution stays on your machine.** Bivy Cloud does not run your agents.\n Your model provider still sees whatever the agent sends it.\n- **Interactive session traffic is end-to-end encrypted** between the node and\n paired devices. The relay forwards opaque session frames; your node dials out,\n so no inbound public port is required.\n- **App previews have a separate security boundary.** Preview traffic uses HTTPS\n and an outbound tunnel, not session E2E encryption. The preview ingress/relay\n operator can see it. Public preview links grant anyone holding them access to\n that view and its live backend until expiry or revocation. See\n [preview security and sharing](docs/apps.md#runtime-and-security-boundaries).\n- **Ordinary credential sync uploads ciphertext, not plaintext keys.**\n Supported credentials and recovery limits are documented separately.\n- **Encryption is not universal across integrations.** Slack commands and\n generic webhook instructions reach the control plane in plaintext. Do not\n put secrets in them. Routing and bounded run metadata are also visible there.\n- **Device authorization matters.** QR pairing authorizes a device directly\n through the node. Hosted account pairing trusts the control plane to authorize\n devices and serve the web app that holds client keys.\n- **Bivy is not an OS-level sandbox.** The default approval mode is\n `autonomous`; protection depends on the runtime. Some agents enforce sandbox\n tiers, while process agents may run with your full user permissions.\n Heuristic tool checks help prevent accidents but are not isolation.\n\nReview the runtime's Protection label and configure approval/sandbox settings\nfor the task, especially before enabling unattended work.\n\n[Security model and known limitations →](docs/security-model.md) ·\n[Runtime protection matrix →](docs/runtime-support-matrix.md) ·\n[Configuration →](docs/configuration.md)\n\n## Agents and everyday commands\n\n**Claude Code, Codex, Pi, and OpenCode are release-tested.** Additional adapters\ninclude Gemini CLI, Qwen Code, Goose, Aider, Cline, Crush, Cursor, GitHub Copilot,\nGrok, Amp, Auggie, Droid, Continue, Kilo Code, and Rovo Dev. Installation,\nresume, model selection, and tool protection vary—see the\n[support matrix](docs/runtime-support-matrix.md) and [agent guides](docs/agents/README.md).\n\nRun an arbitrary command with `bivy run -- ./your-agent --flags`, register a\nreusable entry with `bivy agent add`, or package a declarative integration with\nexperimental [plugins](docs/plugins.md).\n\n```bash\nbivy run claude # launch a durable session; also codex, pi, opencode\nbivy sessions # list live and saved sessions\nbivy resume # resume the most recent session\nbivy open # open the web app (requires remote setup)\nbivy nodes # list connected account machines\nbivy runs list # inspect delegated work\nbivy automation init # scaffold repo-owned automations\nbivy provider login # connect supported model credentials\nbivy agent add # register an ACP or process agent\nbivy doctor # check installation and connectivity\nbivy logs -f # follow node logs\nbivy update # update and restart the service\n```\n\n`bivy update` uses your original installation method and waits for an active\nturn to finish before restarting. Use `--force` to skip that wait.\n\n[CLI reference →](docs/cli-reference.md) ·\n[Node and project configuration →](docs/config-as-code.md) ·\n[GitHub setup →](docs/github-setup.md) ·\n[Linear setup →](docs/linear-work-queue.md)\n\n## Development and contributions\n\n```bash\npnpm install\npnpm run dev # node daemon on http://localhost:4317\npnpm run dev:web # web client dev server\n```\n\n| Directory | Contents |\n|---|---|\n| `src/`, `bin/` | Node daemon, CLI, runtime adapters, sessions, approvals, secrets |\n| `packages/core/` | Shared protocol, pairing, and wire format |\n| `packages/web/`, `packages/ui/` | React PWA and shared design system |\n| `services/relay/` | Self-hostable encrypted relay |\n| `services/control-plane/` | Self-hostable control plane |\n| `deploy/` | Deployment examples |\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\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow. Releases\nare published from CI with provenance attestations; see\n[release verification](docs/releasing.md).\n\n**Found a security issue?** Use\n[GitHub private vulnerability reporting](https://github.com/bivysh/bivy/security/advisories/new),\nnot a public issue. See [SECURITY.md](SECURITY.md).\n\n### In development—not available at launch\n\nAutomatically provisioned, short-lived **ephemeral machines** are in development\nfor hosted and bring-your-own-cloud deployments. Neither path is ready or\nsupported for this launch. Use an existing computer or server you operate.\nExperimental provisioning has different credential-custody and encryption\nboundaries; see the [provisioning trust model](docs/hosted-provisioning-trust-model.md).\n\n## License\n\nEverything in this repository—node, CLI, web/PWA, relay, and control plane—is\nfree and open-source **AGPL-3.0-only Core**, with no Bivy usage limits. You may\nuse, modify, and self-host it under that license. If users interact with your\nmodified version over a network, section 13 requires you to offer its\ncorresponding source. See [LICENSE](LICENSE).\n\nBivy Cloud is the hosted operation of that stack plus billing and plans, in a\nseparate private repository. Contributions use the\n[DCO](CONTRIBUTING.md#certificate-of-origin); there is no CLA.\n",
68
+ "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%A520-2b6cb0)](https://nodejs.org)\n\n**Local coding agents that show their work. Anywhere.**\n\nBivy is the open-source workspace for coding agents. It runs Claude Code, Codex,\nPi, OpenCode and other agents on your own machine. Reach them from a browser or\nyour phone, with the live session, its terminal, its approvals, and the app\nthey're building right in the chat. Try it, mark what's wrong, and send it back.\n\nBivy is not another coding agent and not a cloud development machine. The agent\nstays local and does the coding with your model provider. Your repos, tools,\ndatabases, and services stay where they are. Bivy gives you remote access to all\nof it, plus live previews, automations, and review.\n\n- **Live previews.** The running app beside the chat. Mark it, send it back,\n share it with someone who has no Bivy account.\n- **Automations.** GitHub issues, failed CI, Linear, Slack, schedules, and\n webhooks start the work. It comes back as a preview link or a pull request.\n- **Any agent.** Hit a usage limit? Fork the session to another agent, or let\n Bivy retry when the limit resets.\n- **Your machine, anywhere.** Start at your desk, pick the session up on your\n phone. The machine dials out, so there are no ports to open, and session\n traffic is end-to-end encrypted.\n\n**[Start free on Bivy Cloud](https://app.bivy.sh)** ·\n**[Quickstart](docs/quickstart.md)** ·\n**[Documentation](docs/README.md)** ·\n**[Self-host](docs/deploy-images.md)** ·\n**[Website](https://bivy.sh)**\n\n**Recommended:** sign in at [app.bivy.sh](https://app.bivy.sh), then copy your\npersonalized **Connect a Machine** command into a terminal on your Mac or Linux\ncomputer. It installs and enrolls the machine without another Bivy login. The\nbrowser connects automatically; choose a repository and send your first task\nright there.\n\nPrefer starting from the terminal?\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash # install + guided setup\ncd your-repo\nbivy run claude # or codex, pi, opencode\nbivy open # continue in the web app (needs remote setup)\n```\n\nBivy Cloud hosts the app, control plane, and relay—not the machines running your\nagents. Connect a Mac, Linux computer, or existing server and bring your own\nagent subscription, model API key, or local model. You can also self-host the\nentire remote-access stack.\n\n> **Bivy is 0.x software.** Claude Code, Codex, Pi, OpenCode, and Grok are the\n> release-tested paths. Credential sync, resume, handoffs, approvals, and\n> sandboxing depend on the runtime. See the\n> [runtime support matrix](docs/runtime-support-matrix.md).\n\n## Don't just read the diff. Try the app.\n\nBivy lets you **use what the agent built and show it what to fix**, without a\nseparate deployment step.\n\n1. **Ask for a change.** The agent works in your repo with your existing tools\n and local services.\n2. **Try the app.** Bivy finds the dev server the agent starts and opens it\n beside the chat: web apps, terminals, and desktop apps. Use the running app,\n not a screenshot of what the agent says it finished.\n3. **Mark what needs work.** Press and hold anything in the preview to mark it,\n or drag to circle it, then say what you want. **Mark another** keeps\n separate notes separate. The marks go to the agent with the element and page\n context. No screenshots to paste.\n4. **Follow each note.** Every mark stays in the chat as a pin that resolves\n itself: **Changed** when a later run changes what you marked, **Element\n gone** when it leaves the page, **Done** when you say so.\n5. **Review the next version.** A new version waits on the preview pill instead\n of reloading under you. Take it when you're ready, compare before and after,\n inspect the diff and checks, and decide when the work is done.\n6. **Get a second opinion.** Share a preview link for 1 hour, 1 day, or 7 days.\n Teammates and clients try the running app and leave notes without a Bivy\n account. Make it view-only, or **Stop sharing** to end every link at once.\n\nOn Bivy Cloud, preview delivery is built in: no per-app domains, certificates,\npublic ports, or tunnels to configure. Self-hosters configure preview delivery\nonce for their Bivy deployment, not for every app. The app still needs its normal\nbuild or dev-server setup, and **the machine serving it must stay awake and\nonline**. These are development previews, not production hosting.\n\n**Share deliberately:** anyone with a preview link can use that app, including\nits live backend, until the link expires or you stop sharing.\nReviewer notes aren't sent to the agent automatically; you send them or explicitly\nallow agent access. Preview traffic uses HTTPS through the preview relay, not\nsession end-to-end encryption; the relay operator can see it.\n\n[App previews, visual feedback, and sharing →](docs/apps.md)\n\n## One workflow, from trigger to review\n\n```text\nPrompt · GitHub issue · CI failure · Linear · Slack · Schedule · Webhook\n │\n ▼\n Choose machine + agent + model\n + supported credentials\n │\n ▼\n Live agent session\n Join · steer · approve · stop\n │\n ▼\n Try app · inspect changes · checks\n │\n ▼\n Mark up · send feedback · iterate\n │\n ▼\n Share preview · review PR\n```\n\nA **Machine** is a computer or server you connect. A **Session** is live agent\nwork on that machine. A **Run** is delegated background work that creates a\nsession and tracks its outcome. An **Automation** is a reusable definition that\ncreates runs when an event matches.\n\nManual and automated work use the same kind of live session. You can join a run\nwhen it needs help rather than wait for a black-box job to finish.\n\n### Let events start the work\n\nAutomations turn recurring or incoming work into sessions you can join,\nsupervise, and review. An agent picks the task up on your machine and posts\nback a preview link or a pull request, so you try the result where the task\nlives and reply in the same session. Choose the repository, machine, agent,\nmodel, approval mode, sandbox setting, and maximum attempts.\n\n| Trigger | Example workflow |\n|---|---|\n| **GitHub issues and mentions** | Label an issue `bivy` or `bivy/<machine>`, or mention your Bivy GitHub App, to work toward a pull request. |\n| **Failed CI** | Match a failed workflow, ask the agent to reproduce it, make a fix, and run the affected checks. |\n| **Linear** | Label an issue to start work without copying its description into an agent. |\n| **Slack** | Send a request from the conversation where the work came up. |\n| **Schedules** | Run a weekly dependency review, recurring maintenance, or a one-time task. |\n| **Signed webhooks** | Connect alerts, internal tools, or your own event sources. |\n\nConfigure automations in the app or version them with your repository in\n`.bivy/automations.yaml`:\n\n```bash\nbivy automation init\n# Edit the generated definition for your repository and workflow.\nbivy automation validate\nbivy automation test --event .bivy/events/failed-ci.yaml # supply a local event fixture\nbivy automation apply\n```\n\nOr delegate a one-off job without creating an automation:\n\n```bash\nbivy runs start \"Review outdated dependencies and propose a small, tested update.\"\nbivy runs wait <id>\n```\n\nRuns keep routing and lifecycle evidence, check results, and output references\nin a reviewable Receipt. For unattended issue work, Bivy runs declared repository\nchecks after the agent's turn; failed required checks fail the run even if the\nagent reports success. A completed process alone is not proof that the task\nsucceeded.\n\n[Automation recipes →](docs/capability-recipes.md#let-events-start-runs) ·\n[Automations as code →](docs/automations-as-code.md) ·\n[Run outcomes and reliability limits →](docs/automation-runs.md)\n\n### Use every agent you pay for. Switch mid-task.\n\nRun Claude Code for one task, Codex for another, and Pi or OpenCode where they\nfit, side by side in one session list. Bivy supplies the shared session,\nremote-access, automation, and review surfaces; your chosen agent still does\nthe coding and uses your model provider.\n\n- **Hit a usage limit? Keep going.** When a turn fails on a limit, fork the\n session, with its code and conversation, to another agent and model, or let\n Bivy retry when the limit resets (the provider has to report a reset time).\n- **Get a second opinion.** `bivy delegate` hands a task to another agent, on\n the same machine or a different one, and brings back its answer, branch, and\n PR. `--to codex,claude@linux` sends one task to several agents to compare.\n- Choose an agent and, where supported, a model for each session or run.\n- Import existing Claude Code and Codex sessions.\n- Fork or move work to another agent or machine when a different setup fits\n better. Continuation fidelity varies: some paths preserve native history,\n while others replay portable turns or hand over a summary with the earlier\n transcript as a local file.\n- Use agent-native logins, Bivy-managed credentials, or local inference.\n Bivy's custom OpenAI-compatible endpoint registry currently feeds Pi;\n other agents may need their own provider configuration.\n- Register your own ACP or headless process agent with `bivy agent add`.\n\nBivy does not replace your agent, provide model inference, or make every agent's\nfeatures identical. Consult the [support matrix](docs/runtime-support-matrix.md)\nand [handoff recipes](docs/capability-recipes.md#fork-or-move-a-session).\n\n### Less signing in. Less copying secrets.\n\nBivy syncs **Bivy-managed API keys and supported OAuth credentials** across\nenrolled machines for compatible runtimes. Connect supported credentials once\nand reuse them where you run work, rather than manually distributing keys to\neach machine.\n\nFor ordinary account sync, credentials are encrypted on the node before upload.\nThe control plane stores ciphertext and wrapped-key metadata; enrolled nodes\nshare access by wrapping the vault key to one another. Bivy Cloud does not\nreceive plaintext credentials through this sync path.\n\nYou can also keep credentials local, use labeled keys and project presets, or\nreference environment variables and 1Password instead of embedding secrets in\nconfiguration:\n\n```bash\nbivy provider login\nbivy credentials add anthropic work\nbivy secrets ref github.repo-token op://Bivy/GitHub/repo-token\n```\n\n**Not every CLI login syncs.** Native agent logins may still be per-machine;\nGitHub App private-key sync is separately opt-in. If you lose every node and\ndevice able to unwrap a vault, you must sign in to providers again. Explicit\nhosted-provisioning custody grants are separate from ordinary encrypted sync.\n\n[Credential sync and runtime coverage →](docs/credential-sync.md) ·\n[Credentials guide →](docs/credentials-guide.md) ·\n[Key storage →](docs/key-management.md)\n\n### Work in the environment you already have\n\nA clean cloud sandbox isn't always enough. Your agent may need the database\nrunning on localhost, an uncommitted change, an internal API behind your VPN,\nor a model running on your GPU. Bivy runs the agent where those things already\nexist, subject to that machine's permissions and the runtime's protection.\n\nConnect several machines to the same account: a laptop for interactive work,\na Linux server for background jobs, or a GPU box for local inference. Choose\nthe machine for each session or pin it in an automation. Repository runs can\nuse isolated Git worktrees without rebuilding the whole development environment.\n\n**The execution machine must stay awake and online.** To close your laptop and\nleave work running, run the agent on a different, always-on machine.\n\n[Environment and multi-machine recipes →](docs/capability-recipes.md)\n\n### Start at your desk. Continue anywhere.\n\nOpen the same session in the browser, phone PWA, or terminal. Watch work live,\nanswer questions, approve supported tool calls, or stop the agent.\n\n- Send screenshots, images, logs, and other files from your phone.\n- Download reports and artifacts the agent creates.\n- Open [session apps](docs/apps.md) from chat or the **Apps** menu: live web\n previews, desktop app views, and CLI/TUI tools. Agents can publish views with\n `bivy app publish bivy.app.json` and create share links with `bivy app share`.\n- Use voice input and read-aloud where supported; provider-backed voice may\n send audio or text to the selected provider.\n- Keep a native terminal workflow or use structured chat, depending on the agent.\n\n```bash\nbivy run claude --no-follow # start without attaching\nbivy open # open the web app\nbivy resume # return to the session in your terminal\nbivy link # pair a device directly via QR\n```\n\nNo phone app installation is required. Open [app.bivy.sh](https://app.bivy.sh)\nin your browser; adding it to your home screen is optional.\n\n[Remote access →](docs/remote-access.md) ·\n[Voice, files, and terminal recipes →](docs/capability-recipes.md)\n\n### Agents can reach you, too\n\nEvery session gets the `bivy` CLI, so any agent with a shell can talk back\nthrough the app, not only agents with their own built-in tools:\n\n```bash\nbivy notify \"Tests are green, PR is up\" # chat card + phone push when you're away\nbivy ask \"Ship to staging?\" --option Yes --option No # waits for your answer\nbivy attach report.png --caption \"Before/after\" # show a file in the chat\nbivy suggest \"Add a dark theme to settings\" # a next task you start in one tap\nbivy context --json # session, workspace, machine, apps\n```\n\n`bivy help --json` lists every command, and with `BIVY_OUTPUT=json` failures\ncome back as structured errors with distinct exit codes, so an agent can tell\nwhat went wrong and what to run next. `bivy guide` prints short playbooks for\nagents, and the same commands are served as MCP tools for agents that prefer\nthem. Add your own standing instructions for\nevery session in **Settings → Agent instructions**.\n\n[Commands for agents inside a session →](docs/cli-reference.md#inside-an-agent-session) ·\n[Agent instructions →](docs/agent-instructions.md)\n\n## Get started\n\n### Install\n\nBivy supports **macOS and Linux with Node.js 20+**. The installer installs the\n`@bivy/bivy` package, runs guided setup, and starts a launchd or systemd service:\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash\n```\n\nSetup helps you choose an agent and configure remote access. Existing agents\nkeep their command, login, and configuration. The installer may use `sudo` to\ninstall a missing Node.js, but never for `npm install`. To inspect it first,\ndownload it with `curl -fsSL https://bivy.sh/install.sh -o install.sh`.\n\nAlready have Node.js and want to avoid sudo?\n\n```bash\nnpm install -g @bivy/bivy\nbivy setup\n```\n\nThen try one small task:\n\n```bash\ncd your-repo\nbivy run claude\n# Ask: \"Explain this repo and make one small, safe improvement. Run the relevant checks.\"\nbivy open\n```\n\nOpen that same session on your phone while it runs. For a web app, ask the agent\nto start its dev server, then open **Apps → Running in this workspace → Preview**.\nTry a page, point to something you'd change, and send the feedback back to the\nagent. No separate preview deployment needed.\n\nOnce that works, share a preview for review, connect another machine, or add\nyour first automation.\n\n**Local-only works too.** `bivy run`, `bivy resume`, and `bivy sessions` need no\naccount or server. Choose **local only for now** during setup; use `bivy login`\nlater. Browser and phone access need a hosted or self-hosted control plane;\nthe node itself does not serve a web UI.\n\n[Full quickstart →](docs/quickstart.md) ·\n[Installer options, service management, and uninstall →](docs/install.md)\n\n### Choose hosted or self-hosted\n\n| Option | What you get |\n|---|---|\n| **Free Cloud — $0** | Every launch feature, including automations; 10 new remote sessions per rolling seven days. No credit card required. |\n| **Cloud — $15/month** | The same features with unlimited remote sessions. |\n| **Self-hosted Core** | Operate the app, control plane, and relay yourself, with no Bivy usage limits. |\n\nManual and automated sessions share the Cloud allowance. Resuming existing\nsessions and viewing history do not consume it. Agent subscriptions and model\nprovider charges are separate. See [current pricing](https://bivy.sh#pricing).\n\n**Self-host anywhere:** deploy the public control-plane (including the web app)\nand relay images with Postgres and [a small set of environment variables](docs/deploy-images.md).\nYour server or container platform handles HTTPS. Set up owner access in the\nbrowser—no SSH, external authentication provider, or Bivy Cloud account required.\nFor a bare VPS, the [Compose installer](docs/self-host-quickstart.md) automates the\nsame stack. These onboarding features require a release containing them.\n\nStart on Cloud and self-host later if you prefer. Deploy the stack, reconnect\nmachines with `bivy relay:setup`, and pair devices to your server. This is not a\none-click migration of your Cloud account; your local repos and agent\nconfiguration stay in place.\n\n```bash\nbivy relay:setup \\\n --control-plane https://bivy.example.com \\\n --relay wss://relay.example.com\n```\n\nSelf-hosting is community-supported: you own TLS, backups, upgrades, and\nhardening. Public multi-architecture images are available as\n`ghcr.io/bivysh/bivy-control-plane` and `ghcr.io/bivysh/bivy-relay`; pin a release\nversion or full commit SHA.\n\n[Deploy the images anywhere →](docs/deploy-images.md) ·\n[Optional VPS installer →](docs/self-host-quickstart.md) ·\n[Operations reference →](docs/self-host.md)\n\n## Architecture\n\nYour environment, with clear security boundaries:\n\n```text\nYour machine Hosted or self-hosted\n┌──────────────────────┐ ┌──────────────────────┐\n│ Node daemon │──outbound──▶│ Relay │\n│ Agents, repos, tools │ │ Encrypted frames │\n│ Local credentials │ └──────────┬───────────┘\n└──────────────────────┘ │\n Browser / phone\n + control plane\n (app, accounts, metadata)\n```\n\n- **Execution stays on your machine.** Bivy Cloud does not run your agents.\n Your model provider still sees whatever the agent sends it.\n- **Interactive session traffic is end-to-end encrypted** between the node and\n paired devices. The relay forwards opaque session frames; your node dials out,\n so no inbound public port is required.\n- **App previews have a separate security boundary.** Preview traffic uses HTTPS\n and an outbound tunnel, not session E2E encryption. The preview ingress/relay\n operator can see it. Public preview links grant anyone holding them access to\n that view and its live backend until expiry or revocation. See\n [preview security and sharing](docs/apps.md#runtime-and-security-boundaries).\n- **Ordinary credential sync uploads ciphertext, not plaintext keys.**\n Supported credentials and recovery limits are documented separately.\n- **Encryption is not universal across integrations.** Slack commands and\n generic webhook instructions reach the control plane in plaintext. Do not\n put secrets in them. Routing and bounded run metadata are also visible there.\n- **Device authorization matters.** QR pairing authorizes a device directly\n through the node. Hosted account pairing trusts the control plane to authorize\n devices and serve the web app that holds client keys.\n- **Bivy is not an OS-level sandbox.** The default approval mode is\n `autonomous`; protection depends on the runtime. Some agents enforce sandbox\n tiers, while process agents may run with your full user permissions.\n Heuristic tool checks help prevent accidents but are not isolation.\n\nReview the runtime's Protection label and configure approval/sandbox settings\nfor the task, especially before enabling unattended work.\n\n[Security model and known limitations →](docs/security-model.md) ·\n[Runtime protection matrix →](docs/runtime-support-matrix.md) ·\n[Configuration →](docs/configuration.md)\n\n## Agents and everyday commands\n\n**Claude Code, Codex, Pi, OpenCode, and Grok are release-tested.** Additional\nadapters include Gemini CLI, Qwen Code, Goose, Aider, Cline, Crush, Cursor, GitHub\nCopilot, Amp, Auggie, Droid, Continue, Kilo Code, and Rovo Dev. Installation,\nresume, model selection, and tool protection vary—see the\n[support matrix](docs/runtime-support-matrix.md) and [agent guides](docs/agents/README.md).\n\nRun an arbitrary command with `bivy run -- ./your-agent --flags`, register a\nreusable entry with `bivy agent add`, or package a declarative integration with\nexperimental [plugins](docs/plugins.md).\n\n```bash\nbivy run claude # launch a durable session; also codex, pi, opencode\nbivy sessions # list live and saved sessions\nbivy resume # resume the most recent session\nbivy open # open the web app (requires remote setup)\nbivy nodes # list connected account machines\nbivy runs list # inspect delegated work\nbivy automation init # scaffold repo-owned automations\nbivy provider login # connect supported model credentials\nbivy agent add # register an ACP or process agent\nbivy doctor # check installation and connectivity\nbivy logs -f # follow node logs\nbivy update # update and restart the service\n```\n\n`bivy update` uses your original installation method and waits for an active\nturn to finish before restarting. Use `--force` to skip that wait.\n\n[CLI reference →](docs/cli-reference.md) ·\n[Node and project configuration →](docs/config-as-code.md) ·\n[GitHub setup →](docs/github-setup.md) ·\n[Linear setup →](docs/linear-work-queue.md)\n\n## Development and contributions\n\n```bash\npnpm install\npnpm run dev # node daemon on http://localhost:4317\npnpm run dev:web # web client dev server\n```\n\n| Directory | Contents |\n|---|---|\n| `src/`, `bin/` | Node daemon, CLI, runtime adapters, sessions, approvals, secrets |\n| `packages/core/` | Shared protocol, pairing, and wire format |\n| `packages/web/`, `packages/ui/` | React PWA and shared design system |\n| `services/relay/` | Self-hostable encrypted relay |\n| `services/control-plane/` | Self-hostable control plane |\n| `deploy/` | Deployment examples |\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\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow. Releases\nare published from CI with provenance attestations; see\n[release verification](docs/releasing.md).\n\n**Found a security issue?** Use\n[GitHub private vulnerability reporting](https://github.com/bivysh/bivy/security/advisories/new),\nnot a public issue. See [SECURITY.md](SECURITY.md).\n\n### In development—not available at launch\n\nAutomatically provisioned, short-lived **ephemeral machines** are in development\nfor hosted and bring-your-own-cloud deployments. Neither path is ready or\nsupported for this launch. Use an existing computer or server you operate.\nExperimental provisioning has different credential-custody and encryption\nboundaries; see the [provisioning trust model](docs/hosted-provisioning-trust-model.md).\n\n## License\n\nEverything in this repository—node, CLI, web/PWA, relay, and control plane—is\nfree and open-source **AGPL-3.0-only Core**, with no Bivy usage limits. You may\nuse, modify, and self-host it under that license. If users interact with your\nmodified version over a network, section 13 requires you to offer its\ncorresponding source. See [LICENSE](LICENSE).\n\nBivy Cloud is the hosted operation of that stack plus billing and plans, in a\nseparate private repository. Contributions use the\n[DCO](CONTRIBUTING.md#certificate-of-origin); there is no CLA.\n",
69
69
  "readmeFilename": "README.md",
70
70
  "agentBridges": {
71
71
  "@anthropic-ai/claude-agent-sdk": "0.3.285",