@bivy/bivy 0.12.0 → 0.13.0-staging.409
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 +10 -3
- package/bin/bivy.mjs +26 -20
- package/dist/relay-setup.js +17 -7
- package/dist/server.js +43 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -14,10 +14,14 @@ your phone: read what the agent did, answer its question, approve the migration
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
curl -fsSL https://bivy.sh/install.sh | bash # install + guided setup
|
|
17
|
-
|
|
17
|
+
cd your-repo
|
|
18
|
+
bivy run claude # start an agent where your work lives
|
|
18
19
|
bivy open # pick it up from your phone or browser
|
|
19
20
|
```
|
|
20
21
|
|
|
22
|
+
First thing to try: ask the agent to explain the repository, make one small safe
|
|
23
|
+
change, then open the same Session in the web app or on your phone while it runs.
|
|
24
|
+
|
|
21
25
|
**[Quickstart](docs/quickstart.md)** ·
|
|
22
26
|
**[Docs](docs/README.md)** ·
|
|
23
27
|
**[Why Bivy](docs/why-bivy.md)** ·
|
|
@@ -152,11 +156,14 @@ origin with `npm audit signatures`. See [`docs/releasing.md`](docs/releasing.md)
|
|
|
152
156
|
|
|
153
157
|
### Your first session
|
|
154
158
|
|
|
155
|
-
Once `bivy setup` finishes,
|
|
156
|
-
|
|
159
|
+
Once `bivy setup` finishes, use Bivy from inside an existing repo. The first win
|
|
160
|
+
is simple: start the local agent, give it a real task in that environment, then
|
|
161
|
+
reopen the same Session from another surface.
|
|
157
162
|
|
|
158
163
|
```bash
|
|
164
|
+
cd your-repo
|
|
159
165
|
bivy run claude # start an agent as a durable session in the current repo
|
|
166
|
+
# Try: "Explain this repo and suggest one small, safe improvement."
|
|
160
167
|
bivy open # open that same session in the web app (needs relay setup)
|
|
161
168
|
bivy resume # or pick it back up here in the terminal
|
|
162
169
|
```
|
package/bin/bivy.mjs
CHANGED
|
@@ -3621,8 +3621,9 @@ async function cmdSetup(args = []) {
|
|
|
3621
3621
|
// If self-host endpoints are already provided via the environment, default to
|
|
3622
3622
|
// self-hosted so a scripted or self-hosted install doesn't have to re-pick it
|
|
3623
3623
|
// (BIVY_CONTROL_PLANE_URL / BIVY_RELAY_URL then pre-fill the URL prompts below).
|
|
3624
|
-
const
|
|
3625
|
-
const
|
|
3624
|
+
const nodeClaimCode = process.env.BIVY_NODE_CLAIM_CODE?.trim();
|
|
3625
|
+
const selfHostEnv = !nodeClaimCode && Boolean((process.env.BIVY_CONTROL_PLANE_URL || "").trim() || (process.env.BIVY_RELAY_URL || "").trim());
|
|
3626
|
+
const syncChoice = nodeClaimCode ? "h" : await askChoice(
|
|
3626
3627
|
"Remote access",
|
|
3627
3628
|
[
|
|
3628
3629
|
{ key: "h", label: "hosted (recommended — sign in with GitHub or email; nothing caps your local usage)" },
|
|
@@ -3644,29 +3645,33 @@ async function cmdSetup(args = []) {
|
|
|
3644
3645
|
}
|
|
3645
3646
|
|
|
3646
3647
|
if (syncChoice !== "l") {
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3648
|
+
if (!nodeClaimCode) {
|
|
3649
|
+
const loginChoice = await askChoice(
|
|
3650
|
+
"Remote login",
|
|
3651
|
+
[
|
|
3652
|
+
{ key: "g", label: "GitHub" },
|
|
3653
|
+
{ key: "e", label: "email sign-in link (open or scan on any device)" },
|
|
3654
|
+
],
|
|
3655
|
+
"g",
|
|
3656
|
+
);
|
|
3657
|
+
if (loginChoice === "e") {
|
|
3658
|
+
const email = await ask(" Your account email:", config.env.BIVY_EMAIL || "");
|
|
3659
|
+
if (email.trim()) relayArgs.push("--email", email.trim());
|
|
3660
|
+
else relayArgs.push("--github");
|
|
3661
|
+
} else {
|
|
3662
|
+
relayArgs.push("--github");
|
|
3663
|
+
}
|
|
3661
3664
|
}
|
|
3662
3665
|
|
|
3663
3666
|
const useGithub = relayArgs.includes("--github");
|
|
3664
3667
|
try { fs.rmSync(setupSessionPath, { force: true }); } catch { /* best effort */ }
|
|
3665
3668
|
let relayOk;
|
|
3666
3669
|
for (;;) {
|
|
3667
|
-
console.log(c.dim(
|
|
3668
|
-
? "
|
|
3669
|
-
:
|
|
3670
|
+
console.log(c.dim(nodeClaimCode
|
|
3671
|
+
? " Using the one-time machine claim from your Bivy account; no additional sign-in is required."
|
|
3672
|
+
: useGithub
|
|
3673
|
+
? " We'll open GitHub in your browser (or print the URL on a headless server). Authorize, and setup continues automatically."
|
|
3674
|
+
: " We'll email you a sign-in link. Open it in any browser and setup continues automatically."));
|
|
3670
3675
|
rl.pause();
|
|
3671
3676
|
const code = await run(nodeBin, [...nodeScriptArgs(relaySetupEntry), ...relayArgs, "--emit-session", setupSessionPath], {
|
|
3672
3677
|
cwd: repoRoot,
|
|
@@ -3880,7 +3885,8 @@ function printFirstRunSteps(modelReady = false, setupAgent = null) {
|
|
|
3880
3885
|
}
|
|
3881
3886
|
const agent = setupAgent?.command || setupAgent?.runtimeId || resolveDefaultAgent();
|
|
3882
3887
|
const remoteApp = String(loadRelayConfig()?.clientBaseUrl || "https://app.bivy.sh").replace(/\/+$/, "");
|
|
3883
|
-
console.log(` • In the terminal: ${c.cyan(`bivy run ${agent}`)}`);
|
|
3888
|
+
console.log(` • In the terminal: ${c.cyan(`cd your-repo && bivy run ${agent}`)}`);
|
|
3889
|
+
console.log(` Try: ${c.cyan('"Explain this repository and suggest one small, safe improvement."')}`);
|
|
3884
3890
|
console.log(` Then use the remote app to watch the session or take over in chat.`);
|
|
3885
3891
|
console.log(` • Or start in chat: ${c.cyan(remoteApp)}\n`);
|
|
3886
3892
|
}
|
package/dist/relay-setup.js
CHANGED
|
@@ -197,19 +197,29 @@ async function main() {
|
|
|
197
197
|
const clientBaseUrl = (arg("client", process.env.BIVY_CLIENT_BASE_URL) ?? controlPlaneUrl).replace(/\/$/, "") || controlPlaneUrl;
|
|
198
198
|
const email = arg("email", process.env.BIVY_EMAIL);
|
|
199
199
|
const sessionToken = arg("session-token", process.env.BIVY_SESSION_TOKEN);
|
|
200
|
+
const nodeClaimCode = process.env.BIVY_NODE_CLAIM_CODE?.trim();
|
|
200
201
|
// GitHub is the primary sign-in: used when --github is passed, or by default
|
|
201
|
-
// when neither an email
|
|
202
|
-
|
|
202
|
+
// when neither an email, an existing session token, nor a one-time machine
|
|
203
|
+
// claim is supplied. Claims authorize enrollment only and never mint a user
|
|
204
|
+
// session token.
|
|
205
|
+
const useGithub = process.argv.includes("--github") || process.env.BIVY_AUTH === "github" || (!email && !sessionToken && !nodeClaimCode);
|
|
203
206
|
const identity = NodeIdentity.load(appDir);
|
|
204
207
|
console.log(`Node: ${identity.name} (${identity.nodeId})`);
|
|
205
208
|
console.log(`Control plane: ${controlPlaneUrl}`);
|
|
206
209
|
console.log(`Relay: ${relayUrl}`);
|
|
207
210
|
await checkControlPlane(controlPlaneUrl);
|
|
208
|
-
const token =
|
|
211
|
+
const token = nodeClaimCode ? undefined
|
|
212
|
+
: sessionToken ?? (useGithub ? await githubDeviceLogin(controlPlaneUrl) : await deviceLogin(controlPlaneUrl, email));
|
|
209
213
|
async function enrollNode() {
|
|
210
|
-
|
|
214
|
+
const url = nodeClaimCode
|
|
215
|
+
? `${controlPlaneUrl}/claim/${encodeURIComponent(nodeClaimCode)}/enroll`
|
|
216
|
+
: `${controlPlaneUrl}/nodes/enroll`;
|
|
217
|
+
return fetchJson(url, {
|
|
211
218
|
method: "POST",
|
|
212
|
-
headers: {
|
|
219
|
+
headers: {
|
|
220
|
+
"content-type": "application/json",
|
|
221
|
+
...(token ? { authorization: `Bearer ${token}` } : {}),
|
|
222
|
+
},
|
|
213
223
|
body: JSON.stringify({ nodeId: identity.nodeId, name: identity.name }),
|
|
214
224
|
});
|
|
215
225
|
}
|
|
@@ -247,7 +257,7 @@ async function main() {
|
|
|
247
257
|
// read once and deleted by setup. We skip it when the caller supplied a session
|
|
248
258
|
// token only via --session-token/env with no --emit-session, i.e. non-setup use.
|
|
249
259
|
const emitSession = arg("emit-session");
|
|
250
|
-
if (emitSession) {
|
|
260
|
+
if (emitSession && token) {
|
|
251
261
|
try {
|
|
252
262
|
const handoff = JSON.stringify({ session: token, nodeId: identity.nodeId });
|
|
253
263
|
fs.writeFileSync(emitSession, `${handoff}\n`, { mode: 0o600 });
|
|
@@ -257,7 +267,7 @@ async function main() {
|
|
|
257
267
|
// best effort — setup falls back to opening the plain remote app URL
|
|
258
268
|
}
|
|
259
269
|
}
|
|
260
|
-
console.log(`\n✓ Signed in and enrolled this node. Wrote ${filePath}`);
|
|
270
|
+
console.log(`\n✓ ${nodeClaimCode ? "Claimed and enrolled" : "Signed in and enrolled"} this node. Wrote ${filePath}`);
|
|
261
271
|
console.log('Run "bivy link" to pair a phone, or use "Link remote device" in the app (bivy open).');
|
|
262
272
|
}
|
|
263
273
|
main().catch((error) => {
|
package/dist/server.js
CHANGED
|
@@ -2878,6 +2878,17 @@ const RELAY_COMMANDS = {
|
|
|
2878
2878
|
});
|
|
2879
2879
|
return;
|
|
2880
2880
|
}
|
|
2881
|
+
const remoteSessionRequestId = requestId ?? randomUUID();
|
|
2882
|
+
const sessionAdmission = await admitRelaySessionCreate(remoteSessionRequestId);
|
|
2883
|
+
if (!sessionAdmission.allowed) {
|
|
2884
|
+
relay?.sendEvent({
|
|
2885
|
+
type: "session.error",
|
|
2886
|
+
code: sessionAdmission.code || "remote_session_limit",
|
|
2887
|
+
error: sessionAdmission.error,
|
|
2888
|
+
requestId,
|
|
2889
|
+
});
|
|
2890
|
+
return;
|
|
2891
|
+
}
|
|
2881
2892
|
let record;
|
|
2882
2893
|
try {
|
|
2883
2894
|
// Deduped by requestId so a client's post-reconnect retry adopts the
|
|
@@ -3131,6 +3142,24 @@ async function modelAuthFetch(pathname, init = {}) {
|
|
|
3131
3142
|
headers.set("content-type", "application/json");
|
|
3132
3143
|
return fetch(`${sessionAdvertiseTarget.controlPlaneUrl.replace(/\/$/, "")}${pathname}`, { ...init, headers });
|
|
3133
3144
|
}
|
|
3145
|
+
async function admitRelaySessionCreate(idempotencyKey) {
|
|
3146
|
+
// Self-hosted/direct deployments without an account extension stay unrestricted:
|
|
3147
|
+
// the control plane answers allowed when no deployment extension is configured.
|
|
3148
|
+
const res = await modelAuthFetch("/node/policy/check", {
|
|
3149
|
+
method: "POST",
|
|
3150
|
+
body: JSON.stringify({ operation: "session.create", idempotencyKey }),
|
|
3151
|
+
});
|
|
3152
|
+
if (!res)
|
|
3153
|
+
return { allowed: true };
|
|
3154
|
+
const decision = await res.json().catch(() => ({}));
|
|
3155
|
+
if (res.ok && decision.allowed !== false)
|
|
3156
|
+
return { allowed: true };
|
|
3157
|
+
return {
|
|
3158
|
+
allowed: false,
|
|
3159
|
+
code: decision.code,
|
|
3160
|
+
error: decision.reason || decision.error || "This account has reached its remote session allowance.",
|
|
3161
|
+
};
|
|
3162
|
+
}
|
|
3134
3163
|
// Debounced model-auth sync trigger. A relay wake (`work.available`) fires this
|
|
3135
3164
|
// so peers answer a new node's vault-key request promptly (event-driven) instead
|
|
3136
3165
|
// of on the steady 30s poll. Coalesces a burst of wakes into one sync.
|
|
@@ -4596,18 +4625,23 @@ function invalidateGitHubApps() {
|
|
|
4596
4625
|
// token nor an app key. When BIVY_HOSTED_MINT is set they mint a fresh,
|
|
4597
4626
|
// short-lived token from the control plane per git op — cached until ~5 min
|
|
4598
4627
|
// before expiry so a burst of git ops is a single round trip. This is the final
|
|
4599
|
-
// fallback rung after local apps and BIVY_GITHUB_TOKEN.
|
|
4600
|
-
|
|
4601
|
-
|
|
4628
|
+
// fallback rung after local apps and BIVY_GITHUB_TOKEN. Passing the repo lets
|
|
4629
|
+
// the control plane pick the matching central-app installation and scope the
|
|
4630
|
+
// token down to that repo, so the cache is keyed per repo.
|
|
4631
|
+
const hostedMintCache = new Map();
|
|
4632
|
+
async function hostedMintToken(repo) {
|
|
4602
4633
|
if (!process.env.BIVY_HOSTED_MINT || !sessionAdvertiseTarget)
|
|
4603
4634
|
return undefined;
|
|
4635
|
+
const cacheKey = repo ?? "";
|
|
4604
4636
|
const now = Date.now();
|
|
4605
|
-
|
|
4606
|
-
|
|
4637
|
+
const cached = hostedMintCache.get(cacheKey);
|
|
4638
|
+
if (cached && cached.expiresAt - now > 5 * 60 * 1000)
|
|
4639
|
+
return cached.token;
|
|
4607
4640
|
try {
|
|
4608
4641
|
const res = await fetch(`${sessionAdvertiseTarget.controlPlaneUrl.replace(/\/$/, "")}/node/hosted-git-credential`, {
|
|
4609
4642
|
method: "POST",
|
|
4610
|
-
headers: { authorization: `Bearer ${sessionAdvertiseTarget.enrollmentToken}
|
|
4643
|
+
headers: { authorization: `Bearer ${sessionAdvertiseTarget.enrollmentToken}`, "content-type": "application/json" },
|
|
4644
|
+
body: JSON.stringify(repo ? { repo } : {}),
|
|
4611
4645
|
});
|
|
4612
4646
|
if (!res.ok)
|
|
4613
4647
|
return undefined;
|
|
@@ -4615,7 +4649,7 @@ async function hostedMintToken() {
|
|
|
4615
4649
|
if (!data.token)
|
|
4616
4650
|
return undefined;
|
|
4617
4651
|
const parsed = data.expiresAt ? Date.parse(data.expiresAt) : NaN;
|
|
4618
|
-
hostedMintCache
|
|
4652
|
+
hostedMintCache.set(cacheKey, { token: data.token, expiresAt: Number.isFinite(parsed) ? parsed : now + 55 * 60 * 1000 });
|
|
4619
4653
|
return data.token;
|
|
4620
4654
|
}
|
|
4621
4655
|
catch {
|
|
@@ -4639,7 +4673,7 @@ async function resolveTokenForWorkItem(item) {
|
|
|
4639
4673
|
}
|
|
4640
4674
|
}
|
|
4641
4675
|
}
|
|
4642
|
-
return (await resolveGitHubToken()) ?? (await hostedMintToken());
|
|
4676
|
+
return (await resolveGitHubToken()) ?? (await hostedMintToken(item.repo));
|
|
4643
4677
|
}
|
|
4644
4678
|
/**
|
|
4645
4679
|
* The token for interactive repo operations (clone/fetch/push/PR) on `owner/repo`.
|
|
@@ -4687,7 +4721,7 @@ async function resolveTokenForRepo(owner, repo) {
|
|
|
4687
4721
|
}
|
|
4688
4722
|
}
|
|
4689
4723
|
}
|
|
4690
|
-
return (await resolveGitHubToken()) ?? (await hostedMintToken());
|
|
4724
|
+
return (await resolveGitHubToken()) ?? (await hostedMintToken(`${owner}/${repo}`));
|
|
4691
4725
|
}
|
|
4692
4726
|
/** The session source a Linear-issue pickup advertises, keyed by the issue's
|
|
4693
4727
|
* provider-native id so the control plane can correlate a re-dispatch to it
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bivy/bivy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0-staging.409",
|
|
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.",
|
|
@@ -64,6 +64,6 @@
|
|
|
64
64
|
"nanoid": "3.3.18",
|
|
65
65
|
"undici": "8.10.0"
|
|
66
66
|
},
|
|
67
|
-
"readme": "# Bivy\n\n[](https://www.npmjs.com/package/@bivy/bivy)\n[](LICENSE)\n[](https://nodejs.org)\n\n**Run coding agents on the machines you already own — then reach them from your\nphone, browser, or another terminal.**\n\nStart Claude Code on your workstation, right where the repo, the running dev\nserver, and the staging database already live. Walk away. On the train, open\nyour phone: read what the agent did, answer its question, approve the migration\n— over a link only your devices can decrypt. The work never left your machine.\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash # install + guided setup\nbivy run claude # start an agent in your repo\nbivy open # pick it up from your phone or browser\n```\n\n**[Quickstart](docs/quickstart.md)** ·\n**[Docs](docs/README.md)** ·\n**[Why Bivy](docs/why-bivy.md)** ·\n**[Security model](docs/security-model.md)** ·\n**[bivy.sh](https://bivy.sh)**\n\n> **0.x software.** The core loop is solid and used daily. Interfaces and\n> cross-runtime fidelity still change between releases — check the\n> [runtime support matrix](docs/runtime-support-matrix.md) before you depend on\n> a specific agent capability.\n\n## Why not just a cloud sandbox?\n\nA hosted sandbox starts from an *approximation* of your environment. A Bivy\nMachine **is** your environment — the actual working tree, the services already\nrunning, the caches already warm.\n\n| | Cloud sandbox | Bivy Machine |\n|---|---|---|\n| Your repository | a cloned copy | the real working tree, uncommitted changes and all |\n| Dev server & database | mocked, or absent | already running, right beside the agent |\n| Private networks & internal APIs | out of reach | reachable |\n| Toolchains, package caches | cold, reinstalled each time | warm, already installed |\n| GPUs / local inference | rented separately | the ones on your box |\n| Where your code sits | someone else's infrastructure | the machine you already trust |\n\nYou keep the environment. Bivy adds the part that was missing: **reaching that\nenvironment from anywhere, and leaving it working while you're gone.**\n\n## What you can do\n\nBivy gives you two ways to put an agent to work.\n\n### Sessions — interactive, and portable\n\nStart an agent, watch it work, jump in to steer, stop, or approve. Then leave\nyour desk and keep going:\n\n```bash\nbivy run claude # or codex, pi, gemini, and a dozen more\nbivy open # continue the same session in the browser or PWA\nbivy resume # pick it back up in the terminal\nbivy run claude --no-follow # start it in the background instead of attaching\nbivy run claude --chat # start the governed app session and open it in the browser\n```\n\n- **Reconnect from anywhere** — phone, browser, or another terminal — to the\n same live Session. The PWA adds voice input, read-aloud, phone-to-agent\n file/image uploads, and agent-to-phone attachments.\n- **Move work without starting over.** Import existing Claude Code and Codex\n Sessions, or fork, copy, and move a Bivy Session to another agent, model, or\n Machine.\n- **Run more than one Machine** — a workstation, a private-network server, a GPU\n box — on one account, and pick the environment each Session needs.\n\n### Runs — unattended, and accountable\n\nQueue one on demand, or let an event kick it off — either way it returns\nimmediately and reports back:\n\n```bash\nbivy runs start \"...\" # queue a one-off unattended Run, then `bivy runs wait <id>`\nbivy automation init # or define governed jobs in .bivy/automations.yaml\n```\n\n- **Trigger from real events** — a failed CI job, a GitHub or Linear issue,\n Slack, a schedule, or a signed webhook.\n- **Pin the guardrails** — Machine, agent, model, sandbox, approval mode, and a\n hard attempt ceiling — right next to the job.\n- **Get a Receipt** — every Run reports the checks it ran and how it turned out,\n not just a wall of output.\n\nTry the [capability recipes](docs/capability-recipes.md) to see each of these\nend to end, or the [runtime support matrix](docs/runtime-support-matrix.md) for\nexactly what each agent supports.\n\n## Bring your own stack\n\nUse provider subscriptions through native agent logins, API keys stored in\nBivy's vault, or local / OpenAI-compatible inference. Claude Code, Codex, and Pi\nhave first-class SDK integrations; any other ACP or headless agent needs no\nadapter at all — it's a data row you add with one command:\n\n```bash\nbivy agent add # register an existing ACP or process agent\n```\n\n## Install\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash\n```\n\nmacOS and Linux. Requires Node.js 22.19 or newer. The installer puts the\n[`@bivy/bivy`](https://www.npmjs.com/package/@bivy/bivy) npm package and the\n`bivy` command on your `PATH`, then runs the guided `bivy setup` wizard — agent\nchoice, remote access, and an auto-start background service (launchd on macOS,\nsystemd on Linux). Re-running it on a machine that already has Bivy just applies\nthe latest build and restarts the service.\n\n**What needs an account, and what doesn't.** The CLI alone — `bivy run`,\n`bivy resume`, `bivy sessions` — needs no account and no server; `bivy setup`\nlets you pick **local only for now** and skip remote access. A browser or phone\nUI needs a control plane, because the node hosts none: use the hosted one at\n`app.bivy.sh` (sign in with GitHub or email; free tier plus a paid plan — see\n[bivy.sh#pricing](https://bivy.sh#pricing)) or\n[self-host your own](docs/self-host-quickstart.md). Switch any time with\n`bivy relay:setup`.\n\n**What the installer does with sudo.** It escalates only when it must, and\ntells you when it does:\n\n- Debian/Ubuntu without a suitable Node.js: `sudo apt-get install build-essential\n python3 curl`, then NodeSource's Node 22 setup script via `sudo`.\n- Other Linux, or macOS, without a suitable Node.js: downloads the official\n Node 22 tarball from nodejs.org (sha256-checked) and installs it under\n `/usr/local` with `sudo`.\n- If npm's global prefix isn't writable it falls back to `~/.local` — it never\n runs `npm install` under `sudo`.\n- It appends a marked PATH block to `~/.bashrc` or `~/.zshrc`\n (`BIVY_NO_RC_UPDATE=1` to opt out).\n\nWant no sudo at all? Bring your own Node.js 22.19+ and skip the script:\n\n```bash\nnpm install -g @bivy/bivy && bivy setup # install globally\nnpx @bivy/bivy setup # or try it once, no install\n```\n\nReleases are published from CI with provenance attestations; verify a build's\norigin with `npm audit signatures`. See [`docs/releasing.md`](docs/releasing.md).\n\n### Your first session\n\nOnce `bivy setup` finishes, the whole loop is three commands — start local,\nreconnect remote:\n\n```bash\nbivy run claude # start an agent as a durable session in the current repo\nbivy open # open that same session in the web app (needs relay setup)\nbivy resume # or pick it back up here in the terminal\n```\n\nFrom here the [quickstart](docs/quickstart.md) walks through Runs, multiple\nMachines, and automations.\n\n### Install options\n\nEnvironment variables passed to the one-line installer change what it does:\n\n| Goal | Variable |\n|---|---|\n| Track the dev channel (new build on every merge to `main`) | `BIVY_CHANNEL=staging` |\n| Pin an exact version | `BIVY_VERSION=0.1.0` |\n| Install the npm package into a user-owned prefix | `BIVY_NPM_PREFIX=~/.local` |\n| Preinstall every known upstream agent | `BIVY_INSTALL_ALL_AGENTS=1` |\n| Don't touch `~/.bashrc` / `~/.zshrc`; print the PATH line instead | `BIVY_NO_RC_UPDATE=1` |\n\nFor example: `BIVY_CHANNEL=staging curl -fsSL https://bivy.sh/install.sh | bash`.\n\nWorking from a checkout of this repository instead:\n\n```bash\npnpm install\npnpm run setup\n```\n\nSee [`docs/install.md`](docs/install.md) for where data lives, service\nmanagement, and uninstall.\n\n## Updating\n\n```bash\nbivy update\n```\n\n`bivy update` detects how Bivy was installed and does the right thing, then\nwaits for any active session to finish its current turn and restarts the\nbackground service so the node reconnects on the new build:\n\n| Install kind | What `bivy update` does |\n|---|---|\n| npm global (`npm i -g`) | `npm install -g @bivy/bivy@<channel>`, then restart the service |\n| installer / packaged | re-runs `install.sh` (migrating to npm if needed), then restart |\n| git checkout | `git pull --ff-only` + `pnpm install --frozen-lockfile`, then restart |\n| `npx` run | nothing to update — each run already fetches the latest |\n\nUpdates follow the release **channel** recorded at install time — `latest`\n(production) by default, or `staging` if you installed with\n`BIVY_CHANNEL=staging`. Switch channels (the choice is remembered for next\ntime), or skip the wait for a busy session:\n\n```bash\nbivy update --staging # move to the dev channel\nbivy update --stable # move back to production (latest)\nbivy update --force # don't wait for an in-flight turn to finish\n```\n\nThe daemon also checks the registry periodically and posts an in-session notice\nwhen a newer build is available.\n\n## Architecture\n\nBivy has three parts. **Only the first one holds your data.**\n\n```text\n your machine hosted or self-hosted\n\n ┌──────────────┐ ┌─────────┐ ┌───────────────┐\n │ node daemon │ ──dials──▶ │ relay │ ◀────▶ │ control plane │\n │ agents, keys │ outbound │ opaque │ │ accounts, web │\n │ repo, tools │ │ frames │ │ app, metadata │\n └──────────────┘ └─────────┘ └───────────────┘\n ▲ ▲\n └────────── end-to-end encrypted session ───────────┘\n phone · browser · another terminal\n```\n\n- **Node** — a daemon on your machine. Owns the workspace, credentials, and agent\n processes. Serves an API and WebSocket on `http://localhost:4317` plus a\n `/healthz` probe. **It hosts no web UI.**\n- **Relay** — forwards encrypted frames between your node and your devices. Your\n node dials out, so no inbound port is opened. The relay cannot read the frames.\n- **Control plane** — holds your account, node registry, and session index, and\n serves the web/PWA client. Use the hosted one or run your own.\n\nBecause the node serves no UI, a browser or phone needs a control plane — hosted\nat `app.bivy.sh`, or one you deploy yourself. The terminal CLI needs neither.\nInteractive Session traffic is end-to-end encrypted between a Machine and its\npaired devices: the relay never sees plaintext and cannot decrypt it. Who can\n*authorize* a device depends on how you pair — with a QR / `bivy link` pairing,\nor on a self-hosted deployment, the control plane can't read your Sessions\neither; with hosted account sign-in you trust the control plane to authorize\ndevices and to serve the web app that holds the keys. See\n[known limitations](docs/security-model.md#known-limitations-for-0x).\n\nSee [`docs/remote-access.md`](docs/remote-access.md) and\n[`docs/security-model.md`](docs/security-model.md).\n\n## Supported agents\n\n**Claude Code and Codex are the recommended, release-certified paths.** The\nbroader catalog stays available under **More agents**; capabilities and fidelity\nvary by runtime.\n\n| Agent | Command | Notes |\n|---|---|---|\n| Claude Code | `bivy run claude` | Uses the operator-installed `claude` command through an SDK bridge |\n| Codex | `bivy run codex` | Installs `@openai/codex` |\n| Pi | `bivy run pi` | Uses the operator-installed `pi` command and Pi auth/config |\n| OpenCode | `bivy run opencode` | Installs `opencode-ai` |\n| Gemini CLI | `bivy run gemini` | Installs `@google/gemini-cli` |\n| Qwen Code | `bivy run qwen` | Installs `@qwen-code/qwen-code` |\n| Goose | `bivy run goose` | Requires `goose` on PATH |\n| Aider | `bivy run aider` | No session resume (upstream gap) |\n| Cline | `bivy run cline` | Installs `cline` |\n| Crush | `bivy run crush` | No session resume (upstream gap) |\n| Cursor | `bivy run cursor` | ACP-capable |\n| GitHub Copilot | `bivy run copilot` | ACP-capable |\n| Grok | `bivy run grok` | Model selection |\n| Amp | `bivy run amp` | Native thread resume |\n| Auggie | `bivy run auggie` | Headless CLI |\n| Droid | `bivy run droid` | Model selection |\n| Continue | `bivy run continue` | Headless CLI |\n| Kilo Code | `bivy run kilocode` | ACP-capable |\n| Rovo Dev | `bivy run rovodev` | Installed out of band |\n\nAlso defined but hidden from the picker as *Experimental* — runnable via\n`BIVY_RUNTIME=<id>`: Codebuff (`codebuff`, no verified headless mode upstream\nyet), Hermes (`hermes`, generic process adapter), and OpenClaw (`openclaw`,\nCLI adapter only, no resume yet).\n\nAny other command works via `bivy run -- ./your-agent --flags`. ACP-capable\nagents can be promoted to Bivy's governed protocol path for per-tool approvals\nand native resume. To add a reusable process or ACP agent to both the CLI and web\npicker without changing Bivy, run `bivy agent add`, or scaffold and install a\ndeclarative [plugin manifest](docs/plugins.md) with `bivy plugin init`\n(declarative plugins are Experimental, `v1alpha1`, and run out of process).\n\n[`docs/runtime-support-matrix.md`](docs/runtime-support-matrix.md) lists exactly\nwhat each agent supports — resume, model selection, approvals, sandboxing.\n\n## Common commands\n\n```bash\nbivy # show the command overview\nbivy run claude # launch Claude Code as a durable session\nbivy run codex # run a different agent\nbivy sessions # list live and saved sessions\nbivy resume # resume the most recent session\nbivy open # open the web app (requires relay setup)\nbivy automation init # create .bivy/automations.yaml\nbivy agent add # connect an existing ACP or process agent\nbivy plugin list # installed declarative integration packages\nbivy status # config summary and node reachability\nbivy doctor # health check\nbivy logs -f # tail node logs\nbivy update # update Bivy and restart the service\n```\n\nFull command list, flags, and examples: [`docs/cli-reference.md`](docs/cli-reference.md).\n\n## Configuration\n\nThe common knobs:\n\n```bash\nBIVY_WORKSPACE=/path/to/repo # default workspace\nBIVY_SANDBOX=read-only # read-only | workspace-write (default) | danger-full-access\nBIVY_APPROVAL_MODE=risky # never | risky | always | autonomous (default)\n```\n\nCreate and inspect the typed node configuration, or add repository-owned\nsafety/check/retry policy:\n\n```bash\nbivy config init\nbivy config set defaults.agent codex\nbivy config explain defaults.sandbox\nbivy config init --project # .bivy/policy.yaml\n```\n\nSee [`docs/config-as-code.md`](docs/config-as-code.md). Every environment\nvariable and precedence rule lives in\n[`docs/configuration.md`](docs/configuration.md).\n\n## Approvals and sandboxing\n\nThe default approval mode is **`autonomous`**: agents act without per-action\nprompts. How much that actually protects you depends on the runtime. Native-sandbox\nagents enforce the chosen access tier; structured runtimes also pass tool calls\nthrough Bivy's policy and approval layer. Process agents that Bivy cannot\nintercept run with your OS user permissions — the picker flags this and requires\nconfirmation before you pick that path.\n\nWhere Bivy receives structured shell/file calls, a heuristic floor blocks known\ncatastrophic commands and structured writes outside the workspace, and a\nbackstop set (force-push, publish, deploy, sudo) pauses for a human. This catches\naccidents; **it is not an adversarial isolation boundary.**\n\nWant to be asked about more? Set the mode explicitly:\n\n```bash\nBIVY_APPROVAL_MODE=risky # prompt on risky shell commands and file edits\nBIVY_APPROVAL_MODE=always # prompt on all shell commands and file edits\nBIVY_APPROVAL_MODE=never # no prompts; structured-tool heuristic blocks still apply where available\n```\n\nApprove from the terminal, browser, or phone.\n\nSandbox tiers (`read-only`, `workspace-write`, `danger-full-access`) are enforced\nnatively by agents that support them — Codex, Claude Code, Gemini CLI, Qwen Code.\nAgents without a native sandbox may expose structured tool or MCP controls, but\nthose don't cover activity the agent performs outside those channels; some\nprocess adapters run entirely with your user permissions. Check the picker's\nProtection label. **Bivy does not currently ship its own OS-level jail.**\n\n## Credentials\n\nInteractive prompts, transcripts, and workspace files stay encrypted across the\nrelay. Credentials can remain on a Machine or in a vault you control:\n\n```bash\nbivy secrets list\nbivy secrets set github.repo-token\nbivy secrets ref github.repo-token op://Bivy/GitHub/repo-token\nbivy secrets doctor\n```\n\n`secret://`, `env://`, and `op://` (1Password) references resolve on demand when\nthe daemon provisions an agent run, so raw values never sit in your config.\n\n**One deliberate exception to relay blindness:** if you explicitly enable hosted\nunattended provisioning, Bivy Cloud may store encrypted cloud, repository,\nmodel, or key-escrow material that the service can technically access. Treat this\nas an explicit hosted-custody mode. See the\n[security model](docs/security-model.md#what-the-control-plane-sees) and\n[`docs/key-management.md`](docs/key-management.md).\n\n## Automations as code\n\nDefine governed jobs in `.bivy/automations.yaml`, validate them, and simulate\ntrigger events locally before applying anything:\n\n```bash\nbivy automation init\nbivy automation validate\nbivy automation test --event .bivy/events/failed-ci.yaml\nbivy automation apply\n```\n\nInstructions are encrypted on the applying node before upload. Safety policy\nlives beside the job — sandbox, approval mode, and a hard attempt ceiling that\nretry/fallback rules cannot exceed. See\n[`docs/automations-as-code.md`](docs/automations-as-code.md).\n\n## GitHub Runs\n\nLabel an issue `bivy` (or `bivy/<machine>` to target a Machine), or mention the\nBivy GitHub App in a comment. Bivy creates a Run on the selected Machine, uses an\nisolated worktree, executes configured checks, and reports an explicit outcome.\n\nCore applies no commercial usage limits. Bivy Cloud billing and commercial\npolicy live in the separate Cloud repository.\n\nA private GitHub App only installs on the account that owns it, so connect one\napp per GitHub account — one for your personal repos, one per organization\n(`bivy github:app-create --org <org>`). A node can serve several at once, each\nwith its own key and `@`-mention handle.\n\nSee [`docs/github-work-queue.md`](docs/github-work-queue.md).\n\n## Linear Runs\n\nApply `bivy` or `bivy/<machine>` to a Linear issue to create a Run on the selected\nMachine. The Machine fetches issue content directly from Linear, works in an\nisolated GitHub worktree, and asks the agent to open a pull request. See\n[`docs/linear-work-queue.md`](docs/linear-work-queue.md).\n\n## Development\n\n```bash\npnpm install\npnpm run dev # node daemon on http://localhost:4317\npnpm run dev:web # web client dev server (proxies /api and /ws to the node)\n```\n\nChecks — all of these run in CI:\n\n```bash\npnpm run typecheck\npnpm run typecheck:web\npnpm run lint\npnpm run test:unit\npnpm run test:core\npnpm run check:licenses\npnpm run check:secrets\n```\n\nRepository layout:\n\n- `src/` — node daemon, runtime adapters, approvals, secrets, sessions\n- `bin/` — the `bivy` CLI\n- `packages/core` — shared protocol, pairing, wire format\n- `packages/web` — the React/Vite PWA client (`@bivy/web`)\n- `services/relay` — self-hostable relay\n- `services/control-plane` — self-hostable control plane\n- `deploy/` — self-host deployment examples\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md).\n\n## Self-hosting\n\nNode, relay, and control plane are all in this repository. Point a node at your\nown deployment by passing URLs to `bivy relay:setup` — re-running it switches an\nexisting node over to the new endpoints:\n\n```bash\nbivy relay:setup \\\n --control-plane https://bivy.example.com \\\n --relay wss://relay.example.com\n```\n\nEach URL has a flag and an environment-variable equivalent (the flag wins):\n\n| Flag | Environment variable | Points at | Default |\n|---|---|---|---|\n| `--control-plane <url>` | `BIVY_CONTROL_PLANE_URL` | accounts, node registry, and the web-app API | hosted (`app.bivy.sh`) |\n| `--relay <wss-url>` | `BIVY_RELAY_URL` | the encrypted-frame relay your node dials out to | hosted |\n| `--client <url>` | `BIVY_CLIENT_BASE_URL` | base URL used when building app/PWA links | the `--control-plane` URL |\n\nSign-in defaults to GitHub device login (`--github`); pass\n`--email you@example.com` for an email magic-link, or `--session-token <token>`\nto skip interactive sign-in. `relay:setup` checks the control plane is reachable,\nenrolls this node, and writes the endpoints to `.bivy/relay.json`, so `bivy open`,\n`bivy link`, and `bivy update` all keep using your deployment afterwards.\n\n**Self-hosting is community-supported** — no SLA, best-effort help via GitHub\nissues. You own TLS, backups, upgrades, and hardening. Start with the\none-command VPS path in\n[`docs/self-host-quickstart.md`](docs/self-host-quickstart.md); the ops\nreference (backups, rotation, security boundary) is\n[`docs/self-host.md`](docs/self-host.md).\n\n## Security\n\nReport vulnerabilities through [GitHub private vulnerability reporting](https://github.com/bivysh/bivy/security/advisories/new).\nPlease don't open a public issue. See [`SECURITY.md`](SECURITY.md) for scope,\nresponse times, and safe harbour, and [`docs/security-model.md`](docs/security-model.md)\nfor the trust model and known limitations.\n\n## License\n\nBivy Core is free and open-source software under the GNU Affero General Public\nLicense, version 3.0 only (AGPL-3.0-only). You may use, study, modify, and\nself-host it under that license. If you modify Bivy and let users interact with\nit over a network, section 13 requires you to offer them the corresponding\nsource code. See [`LICENSE`](LICENSE).\n\n**Where the open-core line is.** Everything in this repository — node, CLI,\nrelay, control plane, and the web/PWA client — is AGPL Core, with no usage\nlimits. **Bivy Cloud** is the hosted operation of that stack plus billing and\nplans, and lives in a separate private repository. Contributions are accepted\nunder the [DCO](CONTRIBUTING.md#certificate-of-origin); there is no CLA.\n",
|
|
67
|
+
"readme": "# Bivy\n\n[](https://www.npmjs.com/package/@bivy/bivy)\n[](LICENSE)\n[](https://nodejs.org)\n\n**Run coding agents on the machines you already own — then reach them from your\nphone, browser, or another terminal.**\n\nStart Claude Code on your workstation, right where the repo, the running dev\nserver, and the staging database already live. Walk away. On the train, open\nyour phone: read what the agent did, answer its question, approve the migration\n— over a link only your devices can decrypt. The work never left your machine.\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash # install + guided setup\ncd your-repo\nbivy run claude # start an agent where your work lives\nbivy open # pick it up from your phone or browser\n```\n\nFirst thing to try: ask the agent to explain the repository, make one small safe\nchange, then open the same Session in the web app or on your phone while it runs.\n\n**[Quickstart](docs/quickstart.md)** ·\n**[Docs](docs/README.md)** ·\n**[Why Bivy](docs/why-bivy.md)** ·\n**[Security model](docs/security-model.md)** ·\n**[bivy.sh](https://bivy.sh)**\n\n> **0.x software.** The core loop is solid and used daily. Interfaces and\n> cross-runtime fidelity still change between releases — check the\n> [runtime support matrix](docs/runtime-support-matrix.md) before you depend on\n> a specific agent capability.\n\n## Why not just a cloud sandbox?\n\nA hosted sandbox starts from an *approximation* of your environment. A Bivy\nMachine **is** your environment — the actual working tree, the services already\nrunning, the caches already warm.\n\n| | Cloud sandbox | Bivy Machine |\n|---|---|---|\n| Your repository | a cloned copy | the real working tree, uncommitted changes and all |\n| Dev server & database | mocked, or absent | already running, right beside the agent |\n| Private networks & internal APIs | out of reach | reachable |\n| Toolchains, package caches | cold, reinstalled each time | warm, already installed |\n| GPUs / local inference | rented separately | the ones on your box |\n| Where your code sits | someone else's infrastructure | the machine you already trust |\n\nYou keep the environment. Bivy adds the part that was missing: **reaching that\nenvironment from anywhere, and leaving it working while you're gone.**\n\n## What you can do\n\nBivy gives you two ways to put an agent to work.\n\n### Sessions — interactive, and portable\n\nStart an agent, watch it work, jump in to steer, stop, or approve. Then leave\nyour desk and keep going:\n\n```bash\nbivy run claude # or codex, pi, gemini, and a dozen more\nbivy open # continue the same session in the browser or PWA\nbivy resume # pick it back up in the terminal\nbivy run claude --no-follow # start it in the background instead of attaching\nbivy run claude --chat # start the governed app session and open it in the browser\n```\n\n- **Reconnect from anywhere** — phone, browser, or another terminal — to the\n same live Session. The PWA adds voice input, read-aloud, phone-to-agent\n file/image uploads, and agent-to-phone attachments.\n- **Move work without starting over.** Import existing Claude Code and Codex\n Sessions, or fork, copy, and move a Bivy Session to another agent, model, or\n Machine.\n- **Run more than one Machine** — a workstation, a private-network server, a GPU\n box — on one account, and pick the environment each Session needs.\n\n### Runs — unattended, and accountable\n\nQueue one on demand, or let an event kick it off — either way it returns\nimmediately and reports back:\n\n```bash\nbivy runs start \"...\" # queue a one-off unattended Run, then `bivy runs wait <id>`\nbivy automation init # or define governed jobs in .bivy/automations.yaml\n```\n\n- **Trigger from real events** — a failed CI job, a GitHub or Linear issue,\n Slack, a schedule, or a signed webhook.\n- **Pin the guardrails** — Machine, agent, model, sandbox, approval mode, and a\n hard attempt ceiling — right next to the job.\n- **Get a Receipt** — every Run reports the checks it ran and how it turned out,\n not just a wall of output.\n\nTry the [capability recipes](docs/capability-recipes.md) to see each of these\nend to end, or the [runtime support matrix](docs/runtime-support-matrix.md) for\nexactly what each agent supports.\n\n## Bring your own stack\n\nUse provider subscriptions through native agent logins, API keys stored in\nBivy's vault, or local / OpenAI-compatible inference. Claude Code, Codex, and Pi\nhave first-class SDK integrations; any other ACP or headless agent needs no\nadapter at all — it's a data row you add with one command:\n\n```bash\nbivy agent add # register an existing ACP or process agent\n```\n\n## Install\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash\n```\n\nmacOS and Linux. Requires Node.js 22.19 or newer. The installer puts the\n[`@bivy/bivy`](https://www.npmjs.com/package/@bivy/bivy) npm package and the\n`bivy` command on your `PATH`, then runs the guided `bivy setup` wizard — agent\nchoice, remote access, and an auto-start background service (launchd on macOS,\nsystemd on Linux). Re-running it on a machine that already has Bivy just applies\nthe latest build and restarts the service.\n\n**What needs an account, and what doesn't.** The CLI alone — `bivy run`,\n`bivy resume`, `bivy sessions` — needs no account and no server; `bivy setup`\nlets you pick **local only for now** and skip remote access. A browser or phone\nUI needs a control plane, because the node hosts none: use the hosted one at\n`app.bivy.sh` (sign in with GitHub or email; free tier plus a paid plan — see\n[bivy.sh#pricing](https://bivy.sh#pricing)) or\n[self-host your own](docs/self-host-quickstart.md). Switch any time with\n`bivy relay:setup`.\n\n**What the installer does with sudo.** It escalates only when it must, and\ntells you when it does:\n\n- Debian/Ubuntu without a suitable Node.js: `sudo apt-get install build-essential\n python3 curl`, then NodeSource's Node 22 setup script via `sudo`.\n- Other Linux, or macOS, without a suitable Node.js: downloads the official\n Node 22 tarball from nodejs.org (sha256-checked) and installs it under\n `/usr/local` with `sudo`.\n- If npm's global prefix isn't writable it falls back to `~/.local` — it never\n runs `npm install` under `sudo`.\n- It appends a marked PATH block to `~/.bashrc` or `~/.zshrc`\n (`BIVY_NO_RC_UPDATE=1` to opt out).\n\nWant no sudo at all? Bring your own Node.js 22.19+ and skip the script:\n\n```bash\nnpm install -g @bivy/bivy && bivy setup # install globally\nnpx @bivy/bivy setup # or try it once, no install\n```\n\nReleases are published from CI with provenance attestations; verify a build's\norigin with `npm audit signatures`. See [`docs/releasing.md`](docs/releasing.md).\n\n### Your first session\n\nOnce `bivy setup` finishes, use Bivy from inside an existing repo. The first win\nis simple: start the local agent, give it a real task in that environment, then\nreopen the same Session from another surface.\n\n```bash\ncd your-repo\nbivy run claude # start an agent as a durable session in the current repo\n# Try: \"Explain this repo and suggest one small, safe improvement.\"\nbivy open # open that same session in the web app (needs relay setup)\nbivy resume # or pick it back up here in the terminal\n```\n\nFrom here the [quickstart](docs/quickstart.md) walks through Runs, multiple\nMachines, and automations.\n\n### Install options\n\nEnvironment variables passed to the one-line installer change what it does:\n\n| Goal | Variable |\n|---|---|\n| Track the dev channel (new build on every merge to `main`) | `BIVY_CHANNEL=staging` |\n| Pin an exact version | `BIVY_VERSION=0.1.0` |\n| Install the npm package into a user-owned prefix | `BIVY_NPM_PREFIX=~/.local` |\n| Preinstall every known upstream agent | `BIVY_INSTALL_ALL_AGENTS=1` |\n| Don't touch `~/.bashrc` / `~/.zshrc`; print the PATH line instead | `BIVY_NO_RC_UPDATE=1` |\n\nFor example: `BIVY_CHANNEL=staging curl -fsSL https://bivy.sh/install.sh | bash`.\n\nWorking from a checkout of this repository instead:\n\n```bash\npnpm install\npnpm run setup\n```\n\nSee [`docs/install.md`](docs/install.md) for where data lives, service\nmanagement, and uninstall.\n\n## Updating\n\n```bash\nbivy update\n```\n\n`bivy update` detects how Bivy was installed and does the right thing, then\nwaits for any active session to finish its current turn and restarts the\nbackground service so the node reconnects on the new build:\n\n| Install kind | What `bivy update` does |\n|---|---|\n| npm global (`npm i -g`) | `npm install -g @bivy/bivy@<channel>`, then restart the service |\n| installer / packaged | re-runs `install.sh` (migrating to npm if needed), then restart |\n| git checkout | `git pull --ff-only` + `pnpm install --frozen-lockfile`, then restart |\n| `npx` run | nothing to update — each run already fetches the latest |\n\nUpdates follow the release **channel** recorded at install time — `latest`\n(production) by default, or `staging` if you installed with\n`BIVY_CHANNEL=staging`. Switch channels (the choice is remembered for next\ntime), or skip the wait for a busy session:\n\n```bash\nbivy update --staging # move to the dev channel\nbivy update --stable # move back to production (latest)\nbivy update --force # don't wait for an in-flight turn to finish\n```\n\nThe daemon also checks the registry periodically and posts an in-session notice\nwhen a newer build is available.\n\n## Architecture\n\nBivy has three parts. **Only the first one holds your data.**\n\n```text\n your machine hosted or self-hosted\n\n ┌──────────────┐ ┌─────────┐ ┌───────────────┐\n │ node daemon │ ──dials──▶ │ relay │ ◀────▶ │ control plane │\n │ agents, keys │ outbound │ opaque │ │ accounts, web │\n │ repo, tools │ │ frames │ │ app, metadata │\n └──────────────┘ └─────────┘ └───────────────┘\n ▲ ▲\n └────────── end-to-end encrypted session ───────────┘\n phone · browser · another terminal\n```\n\n- **Node** — a daemon on your machine. Owns the workspace, credentials, and agent\n processes. Serves an API and WebSocket on `http://localhost:4317` plus a\n `/healthz` probe. **It hosts no web UI.**\n- **Relay** — forwards encrypted frames between your node and your devices. Your\n node dials out, so no inbound port is opened. The relay cannot read the frames.\n- **Control plane** — holds your account, node registry, and session index, and\n serves the web/PWA client. Use the hosted one or run your own.\n\nBecause the node serves no UI, a browser or phone needs a control plane — hosted\nat `app.bivy.sh`, or one you deploy yourself. The terminal CLI needs neither.\nInteractive Session traffic is end-to-end encrypted between a Machine and its\npaired devices: the relay never sees plaintext and cannot decrypt it. Who can\n*authorize* a device depends on how you pair — with a QR / `bivy link` pairing,\nor on a self-hosted deployment, the control plane can't read your Sessions\neither; with hosted account sign-in you trust the control plane to authorize\ndevices and to serve the web app that holds the keys. See\n[known limitations](docs/security-model.md#known-limitations-for-0x).\n\nSee [`docs/remote-access.md`](docs/remote-access.md) and\n[`docs/security-model.md`](docs/security-model.md).\n\n## Supported agents\n\n**Claude Code and Codex are the recommended, release-certified paths.** The\nbroader catalog stays available under **More agents**; capabilities and fidelity\nvary by runtime.\n\n| Agent | Command | Notes |\n|---|---|---|\n| Claude Code | `bivy run claude` | Uses the operator-installed `claude` command through an SDK bridge |\n| Codex | `bivy run codex` | Installs `@openai/codex` |\n| Pi | `bivy run pi` | Uses the operator-installed `pi` command and Pi auth/config |\n| OpenCode | `bivy run opencode` | Installs `opencode-ai` |\n| Gemini CLI | `bivy run gemini` | Installs `@google/gemini-cli` |\n| Qwen Code | `bivy run qwen` | Installs `@qwen-code/qwen-code` |\n| Goose | `bivy run goose` | Requires `goose` on PATH |\n| Aider | `bivy run aider` | No session resume (upstream gap) |\n| Cline | `bivy run cline` | Installs `cline` |\n| Crush | `bivy run crush` | No session resume (upstream gap) |\n| Cursor | `bivy run cursor` | ACP-capable |\n| GitHub Copilot | `bivy run copilot` | ACP-capable |\n| Grok | `bivy run grok` | Model selection |\n| Amp | `bivy run amp` | Native thread resume |\n| Auggie | `bivy run auggie` | Headless CLI |\n| Droid | `bivy run droid` | Model selection |\n| Continue | `bivy run continue` | Headless CLI |\n| Kilo Code | `bivy run kilocode` | ACP-capable |\n| Rovo Dev | `bivy run rovodev` | Installed out of band |\n\nAlso defined but hidden from the picker as *Experimental* — runnable via\n`BIVY_RUNTIME=<id>`: Codebuff (`codebuff`, no verified headless mode upstream\nyet), Hermes (`hermes`, generic process adapter), and OpenClaw (`openclaw`,\nCLI adapter only, no resume yet).\n\nAny other command works via `bivy run -- ./your-agent --flags`. ACP-capable\nagents can be promoted to Bivy's governed protocol path for per-tool approvals\nand native resume. To add a reusable process or ACP agent to both the CLI and web\npicker without changing Bivy, run `bivy agent add`, or scaffold and install a\ndeclarative [plugin manifest](docs/plugins.md) with `bivy plugin init`\n(declarative plugins are Experimental, `v1alpha1`, and run out of process).\n\n[`docs/runtime-support-matrix.md`](docs/runtime-support-matrix.md) lists exactly\nwhat each agent supports — resume, model selection, approvals, sandboxing.\n\n## Common commands\n\n```bash\nbivy # show the command overview\nbivy run claude # launch Claude Code as a durable session\nbivy run codex # run a different agent\nbivy sessions # list live and saved sessions\nbivy resume # resume the most recent session\nbivy open # open the web app (requires relay setup)\nbivy automation init # create .bivy/automations.yaml\nbivy agent add # connect an existing ACP or process agent\nbivy plugin list # installed declarative integration packages\nbivy status # config summary and node reachability\nbivy doctor # health check\nbivy logs -f # tail node logs\nbivy update # update Bivy and restart the service\n```\n\nFull command list, flags, and examples: [`docs/cli-reference.md`](docs/cli-reference.md).\n\n## Configuration\n\nThe common knobs:\n\n```bash\nBIVY_WORKSPACE=/path/to/repo # default workspace\nBIVY_SANDBOX=read-only # read-only | workspace-write (default) | danger-full-access\nBIVY_APPROVAL_MODE=risky # never | risky | always | autonomous (default)\n```\n\nCreate and inspect the typed node configuration, or add repository-owned\nsafety/check/retry policy:\n\n```bash\nbivy config init\nbivy config set defaults.agent codex\nbivy config explain defaults.sandbox\nbivy config init --project # .bivy/policy.yaml\n```\n\nSee [`docs/config-as-code.md`](docs/config-as-code.md). Every environment\nvariable and precedence rule lives in\n[`docs/configuration.md`](docs/configuration.md).\n\n## Approvals and sandboxing\n\nThe default approval mode is **`autonomous`**: agents act without per-action\nprompts. How much that actually protects you depends on the runtime. Native-sandbox\nagents enforce the chosen access tier; structured runtimes also pass tool calls\nthrough Bivy's policy and approval layer. Process agents that Bivy cannot\nintercept run with your OS user permissions — the picker flags this and requires\nconfirmation before you pick that path.\n\nWhere Bivy receives structured shell/file calls, a heuristic floor blocks known\ncatastrophic commands and structured writes outside the workspace, and a\nbackstop set (force-push, publish, deploy, sudo) pauses for a human. This catches\naccidents; **it is not an adversarial isolation boundary.**\n\nWant to be asked about more? Set the mode explicitly:\n\n```bash\nBIVY_APPROVAL_MODE=risky # prompt on risky shell commands and file edits\nBIVY_APPROVAL_MODE=always # prompt on all shell commands and file edits\nBIVY_APPROVAL_MODE=never # no prompts; structured-tool heuristic blocks still apply where available\n```\n\nApprove from the terminal, browser, or phone.\n\nSandbox tiers (`read-only`, `workspace-write`, `danger-full-access`) are enforced\nnatively by agents that support them — Codex, Claude Code, Gemini CLI, Qwen Code.\nAgents without a native sandbox may expose structured tool or MCP controls, but\nthose don't cover activity the agent performs outside those channels; some\nprocess adapters run entirely with your user permissions. Check the picker's\nProtection label. **Bivy does not currently ship its own OS-level jail.**\n\n## Credentials\n\nInteractive prompts, transcripts, and workspace files stay encrypted across the\nrelay. Credentials can remain on a Machine or in a vault you control:\n\n```bash\nbivy secrets list\nbivy secrets set github.repo-token\nbivy secrets ref github.repo-token op://Bivy/GitHub/repo-token\nbivy secrets doctor\n```\n\n`secret://`, `env://`, and `op://` (1Password) references resolve on demand when\nthe daemon provisions an agent run, so raw values never sit in your config.\n\n**One deliberate exception to relay blindness:** if you explicitly enable hosted\nunattended provisioning, Bivy Cloud may store encrypted cloud, repository,\nmodel, or key-escrow material that the service can technically access. Treat this\nas an explicit hosted-custody mode. See the\n[security model](docs/security-model.md#what-the-control-plane-sees) and\n[`docs/key-management.md`](docs/key-management.md).\n\n## Automations as code\n\nDefine governed jobs in `.bivy/automations.yaml`, validate them, and simulate\ntrigger events locally before applying anything:\n\n```bash\nbivy automation init\nbivy automation validate\nbivy automation test --event .bivy/events/failed-ci.yaml\nbivy automation apply\n```\n\nInstructions are encrypted on the applying node before upload. Safety policy\nlives beside the job — sandbox, approval mode, and a hard attempt ceiling that\nretry/fallback rules cannot exceed. See\n[`docs/automations-as-code.md`](docs/automations-as-code.md).\n\n## GitHub Runs\n\nLabel an issue `bivy` (or `bivy/<machine>` to target a Machine), or mention the\nBivy GitHub App in a comment. Bivy creates a Run on the selected Machine, uses an\nisolated worktree, executes configured checks, and reports an explicit outcome.\n\nCore applies no commercial usage limits. Bivy Cloud billing and commercial\npolicy live in the separate Cloud repository.\n\nA private GitHub App only installs on the account that owns it, so connect one\napp per GitHub account — one for your personal repos, one per organization\n(`bivy github:app-create --org <org>`). A node can serve several at once, each\nwith its own key and `@`-mention handle.\n\nSee [`docs/github-work-queue.md`](docs/github-work-queue.md).\n\n## Linear Runs\n\nApply `bivy` or `bivy/<machine>` to a Linear issue to create a Run on the selected\nMachine. The Machine fetches issue content directly from Linear, works in an\nisolated GitHub worktree, and asks the agent to open a pull request. See\n[`docs/linear-work-queue.md`](docs/linear-work-queue.md).\n\n## Development\n\n```bash\npnpm install\npnpm run dev # node daemon on http://localhost:4317\npnpm run dev:web # web client dev server (proxies /api and /ws to the node)\n```\n\nChecks — all of these run in CI:\n\n```bash\npnpm run typecheck\npnpm run typecheck:web\npnpm run lint\npnpm run test:unit\npnpm run test:core\npnpm run check:licenses\npnpm run check:secrets\n```\n\nRepository layout:\n\n- `src/` — node daemon, runtime adapters, approvals, secrets, sessions\n- `bin/` — the `bivy` CLI\n- `packages/core` — shared protocol, pairing, wire format\n- `packages/web` — the React/Vite PWA client (`@bivy/web`)\n- `services/relay` — self-hostable relay\n- `services/control-plane` — self-hostable control plane\n- `deploy/` — self-host deployment examples\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md).\n\n## Self-hosting\n\nNode, relay, and control plane are all in this repository. Point a node at your\nown deployment by passing URLs to `bivy relay:setup` — re-running it switches an\nexisting node over to the new endpoints:\n\n```bash\nbivy relay:setup \\\n --control-plane https://bivy.example.com \\\n --relay wss://relay.example.com\n```\n\nEach URL has a flag and an environment-variable equivalent (the flag wins):\n\n| Flag | Environment variable | Points at | Default |\n|---|---|---|---|\n| `--control-plane <url>` | `BIVY_CONTROL_PLANE_URL` | accounts, node registry, and the web-app API | hosted (`app.bivy.sh`) |\n| `--relay <wss-url>` | `BIVY_RELAY_URL` | the encrypted-frame relay your node dials out to | hosted |\n| `--client <url>` | `BIVY_CLIENT_BASE_URL` | base URL used when building app/PWA links | the `--control-plane` URL |\n\nSign-in defaults to GitHub device login (`--github`); pass\n`--email you@example.com` for an email magic-link, or `--session-token <token>`\nto skip interactive sign-in. `relay:setup` checks the control plane is reachable,\nenrolls this node, and writes the endpoints to `.bivy/relay.json`, so `bivy open`,\n`bivy link`, and `bivy update` all keep using your deployment afterwards.\n\n**Self-hosting is community-supported** — no SLA, best-effort help via GitHub\nissues. You own TLS, backups, upgrades, and hardening. Start with the\none-command VPS path in\n[`docs/self-host-quickstart.md`](docs/self-host-quickstart.md); the ops\nreference (backups, rotation, security boundary) is\n[`docs/self-host.md`](docs/self-host.md).\n\n## Security\n\nReport vulnerabilities through [GitHub private vulnerability reporting](https://github.com/bivysh/bivy/security/advisories/new).\nPlease don't open a public issue. See [`SECURITY.md`](SECURITY.md) for scope,\nresponse times, and safe harbour, and [`docs/security-model.md`](docs/security-model.md)\nfor the trust model and known limitations.\n\n## License\n\nBivy Core is free and open-source software under the GNU Affero General Public\nLicense, version 3.0 only (AGPL-3.0-only). You may use, study, modify, and\nself-host it under that license. If you modify Bivy and let users interact with\nit over a network, section 13 requires you to offer them the corresponding\nsource code. See [`LICENSE`](LICENSE).\n\n**Where the open-core line is.** Everything in this repository — node, CLI,\nrelay, control plane, and the web/PWA client — is AGPL Core, with no usage\nlimits. **Bivy Cloud** is the hosted operation of that stack plus billing and\nplans, and lives in a separate private repository. Contributions are accepted\nunder the [DCO](CONTRIBUTING.md#certificate-of-origin); there is no CLA.\n",
|
|
68
68
|
"readmeFilename": "README.md"
|
|
69
69
|
}
|