@bivy/bivy 0.16.7-staging.1 → 0.16.7-staging.2
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 +2 -2
- package/bin/bivy.mjs +115 -11
- package/dist/bivy-login.js +1 -1
- package/dist/credentials/store.js +1 -1
- package/dist/credentials-cli.js +2 -2
- package/dist/server.js +24 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -125,8 +125,8 @@ configuration. Re-running the installer updates Bivy and restarts the service.
|
|
|
125
125
|
without an account or server. During setup, choose **local only for now** to skip
|
|
126
126
|
remote access. The browser and phone apps need a control plane: use
|
|
127
127
|
[app.bivy.sh](https://app.bivy.sh) or
|
|
128
|
-
[self-host one](docs/self-host-quickstart.md). You can
|
|
129
|
-
`bivy relay:setup
|
|
128
|
+
[self-host one](docs/self-host-quickstart.md). You can sign in later with
|
|
129
|
+
`bivy login` (or use `bivy relay:setup` for self-hosted endpoint options).
|
|
130
130
|
|
|
131
131
|
Self-hosted Bivy Core is open source and has no usage limits. Bivy Cloud offers
|
|
132
132
|
a managed app, relay, and hosted Machines; see
|
package/bin/bivy.mjs
CHANGED
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
* bivy stop stop the background service
|
|
14
14
|
* bivy restart restart the background service (waits for active sessions to finish; --force to skip)
|
|
15
15
|
* bivy status show config + whether the node is reachable
|
|
16
|
-
* bivy login sign into a
|
|
16
|
+
* bivy login sign this machine into a Bivy account
|
|
17
|
+
* bivy logout sign this machine out of its Bivy account
|
|
18
|
+
* bivy provider login sign into a model provider
|
|
17
19
|
* bivy update update Bivy + install deps + restart service (waits for active sessions to finish; --force to skip)
|
|
18
20
|
* bivy update:log show output of the last (or in-progress) update
|
|
19
21
|
* bivy open open the browser UI
|
|
@@ -1802,7 +1804,7 @@ function cmdCompletions(args = []) {
|
|
|
1802
1804
|
const shell = (args[0] || "").toLowerCase();
|
|
1803
1805
|
const commands = [
|
|
1804
1806
|
"run", "runs", "sessions", "ls", "resume", "promote", "rename", "nodes", "agent", "agents", "agents:install", "shim", "takeover", "token", "exec",
|
|
1805
|
-
"send", "attach", "kill", "setup", "start", "stop", "restart", "status", "doctor", "diagnostics", "capabilities", "logs", "login",
|
|
1807
|
+
"send", "attach", "kill", "setup", "start", "stop", "restart", "status", "doctor", "diagnostics", "capabilities", "logs", "login", "logout", "signout", "provider", "model",
|
|
1806
1808
|
"update", "update:log", "audit", "automation", "config", "plugin", "open", "service", "secrets", "voice", "link", "relay:setup",
|
|
1807
1809
|
"github:connect", "github:app-create", "github:app-connect", "github:app-sync", "prune", "uninstall", "help", "version",
|
|
1808
1810
|
];
|
|
@@ -1820,6 +1822,7 @@ _bivy_completions() {
|
|
|
1820
1822
|
fi
|
|
1821
1823
|
case "$prev" in
|
|
1822
1824
|
run) COMPREPLY=( $(compgen -W "${agents.join(" ")}" -- "$cur") );;
|
|
1825
|
+
provider|model) COMPREPLY=( $(compgen -W "login" -- "$cur") );;
|
|
1823
1826
|
esac
|
|
1824
1827
|
}
|
|
1825
1828
|
complete -F _bivy_completions bivy`);
|
|
@@ -1835,6 +1838,8 @@ _bivy() {
|
|
|
1835
1838
|
compadd -- $cmds
|
|
1836
1839
|
elif [[ \${words[2]} == run ]]; then
|
|
1837
1840
|
compadd -- $agents
|
|
1841
|
+
elif [[ \${words[2]} == provider || \${words[2]} == model ]]; then
|
|
1842
|
+
compadd -- login
|
|
1838
1843
|
fi
|
|
1839
1844
|
}
|
|
1840
1845
|
compdef _bivy bivy`);
|
|
@@ -1844,7 +1849,8 @@ compdef _bivy bivy`);
|
|
|
1844
1849
|
console.log(`# bivy fish completion — save to ~/.config/fish/completions/bivy.fish
|
|
1845
1850
|
complete -c bivy -f
|
|
1846
1851
|
complete -c bivy -n '__fish_use_subcommand' -a '${commands.join(" ")}'
|
|
1847
|
-
complete -c bivy -n '__fish_seen_subcommand_from run' -a '${agents.join(" ")}'
|
|
1852
|
+
complete -c bivy -n '__fish_seen_subcommand_from run' -a '${agents.join(" ")}'
|
|
1853
|
+
complete -c bivy -n '__fish_seen_subcommand_from provider model' -a 'login'`);
|
|
1848
1854
|
return;
|
|
1849
1855
|
}
|
|
1850
1856
|
console.error(c.red("Usage: bivy completions <bash|zsh|fish>"));
|
|
@@ -3785,7 +3791,7 @@ async function cmdSetup(args = []) {
|
|
|
3785
3791
|
const loginCode = await runSetupModelLogin(config);
|
|
3786
3792
|
rl.resume();
|
|
3787
3793
|
if (loginCode !== 0 || !hasModelConfig(loadConfig())) {
|
|
3788
|
-
console.log(c.yellow("Model sign-in did not complete. The node can start, but an agent reply still requires 'bivy login'."));
|
|
3794
|
+
console.log(c.yellow("Model sign-in did not complete. The node can start, but an agent reply still requires 'bivy provider login'."));
|
|
3789
3795
|
}
|
|
3790
3796
|
agentAuthReady = hasModelConfig(loadConfig());
|
|
3791
3797
|
}
|
|
@@ -3848,7 +3854,7 @@ async function cmdSetup(args = []) {
|
|
|
3848
3854
|
console.log(c.bold(c.green("\n ✓ Node running. Check first-task readiness below.\n")));
|
|
3849
3855
|
console.log(` ${c.green("✓")} node reachable at ${url(finalConfig)}`);
|
|
3850
3856
|
console.log(` ${agentReady ? c.green("✓") : c.yellow("!")} runtime ${agentReady ? `${setupAgent?.label || "Pi"} available` : "not installed — run 'bivy agents:install'"}`);
|
|
3851
|
-
console.log(` ${modelReady ? c.green("✓") : c.yellow("!")} model ${modelReady ? (setupAgent?.needsBivyModel ? "credential configured" : "native agent login ready") : (setupAgent?.needsBivyModel ? "not configured — run 'bivy login'" : `${setupAgent?.loginHint || "sign in through the selected agent"}`)}`);
|
|
3857
|
+
console.log(` ${modelReady ? c.green("✓") : c.yellow("!")} model ${modelReady ? (setupAgent?.needsBivyModel ? "credential configured" : "native agent login ready") : (setupAgent?.needsBivyModel ? "not configured — run 'bivy provider login'" : `${setupAgent?.loginHint || "sign in through the selected agent"}`)}`);
|
|
3852
3858
|
console.log(` ${repoReady ? c.green("✓") : c.dim("○")} repository ${repoReady ? "accessible" : "choose one from the directory where you start Bivy or in the app"}`);
|
|
3853
3859
|
const ghReady = githubConnected(finalConfig);
|
|
3854
3860
|
console.log(` ${ghReady ? c.green("✓") : c.dim("○")} GitHub ${ghReady ? "connected — your repos will list in the app" : c.dim("optional — connect later in the app under Settings → GitHub App")}`);
|
|
@@ -3951,7 +3957,7 @@ function printFirstRunSteps(modelReady = false, setupAgent = null) {
|
|
|
3951
3957
|
console.log(" Start your first session:");
|
|
3952
3958
|
if (!modelReady) {
|
|
3953
3959
|
const login = setupAgent?.needsBivyModel
|
|
3954
|
-
? `${c.cyan("bivy login")} ${c.dim("(stored in Bivy's encrypted vault)")}`
|
|
3960
|
+
? `${c.cyan("bivy provider login")} ${c.dim("(stored in Bivy's encrypted vault)")}`
|
|
3955
3961
|
: c.cyan(setupAgent?.command || "the selected agent's native CLI");
|
|
3956
3962
|
console.log(` Model access: ${login}`);
|
|
3957
3963
|
}
|
|
@@ -4225,7 +4231,7 @@ async function cmdDoctor(args = []) {
|
|
|
4225
4231
|
console.log(` ${mark(agentAvailable, true)} agent ${runtimeInfo?.displayName || defaultAgent}${agentAvailable ? "" : c.dim(" not available — install it or run 'bivy setup'")}`);
|
|
4226
4232
|
const credentialReady = readiness?.credential?.ok ?? hasModelConfig(config);
|
|
4227
4233
|
const credentialKnown = readiness?.credential?.probed || readiness?.credential?.configured;
|
|
4228
|
-
console.log(` ${mark(credentialReady, authOwner !== "bivy" || !credentialKnown)} model ${credentialReady ? (readiness?.credential?.probed ? "access verified" : "configured") : authOwner === "bivy" ? c.dim("not ready — run 'bivy login'") : c.dim("agent-native auth — use the agent's CLI login if needed")}`);
|
|
4234
|
+
console.log(` ${mark(credentialReady, authOwner !== "bivy" || !credentialKnown)} model ${credentialReady ? (readiness?.credential?.probed ? "access verified" : "configured") : authOwner === "bivy" ? c.dim("not ready — run 'bivy provider login'") : c.dim("agent-native auth — use the agent's CLI login if needed")}`);
|
|
4229
4235
|
const repositoryReady = Boolean(readiness?.repository?.ok);
|
|
4230
4236
|
console.log(` ${mark(repositoryReady, true)} repository ${repositoryReady ? "accessible" : c.dim("not selected or access could not be verified")}`);
|
|
4231
4237
|
const firstTaskReady = reachable && agentAvailable && credentialReady && repositoryReady;
|
|
@@ -4642,9 +4648,9 @@ function cmdUpdateLog(args) {
|
|
|
4642
4648
|
});
|
|
4643
4649
|
}
|
|
4644
4650
|
|
|
4645
|
-
async function
|
|
4651
|
+
async function cmdProviderLogin(args) {
|
|
4646
4652
|
if (args.includes("-h") || args.includes("--help")) {
|
|
4647
|
-
console.log("Usage: bivy login [provider]\n\nSign into a model provider
|
|
4653
|
+
console.log("Usage: bivy provider login [provider]\n bivy model login [provider]\n\nSign into a model provider. With no provider, prompts interactively for the authentication method and provider.");
|
|
4648
4654
|
return;
|
|
4649
4655
|
}
|
|
4650
4656
|
if (!(await ensureDeps())) process.exit(1);
|
|
@@ -4656,6 +4662,85 @@ async function cmdLogin(args) {
|
|
|
4656
4662
|
process.exit(code);
|
|
4657
4663
|
}
|
|
4658
4664
|
|
|
4665
|
+
async function cmdAccountLogin(args) {
|
|
4666
|
+
if (args.includes("-h") || args.includes("--help")) {
|
|
4667
|
+
console.log("Usage: bivy login [--github|--email <email>]\n\nSign this machine into a Bivy account and enable remote access. With no flags, choose GitHub or an emailed magic link interactively.");
|
|
4668
|
+
return;
|
|
4669
|
+
}
|
|
4670
|
+
if (args[0] && !args[0].startsWith("-")) {
|
|
4671
|
+
console.error(c.red(`'bivy login ${args[0]}' is no longer a model-provider command. Use 'bivy provider login ${args[0]}'.`));
|
|
4672
|
+
process.exitCode = 1;
|
|
4673
|
+
return;
|
|
4674
|
+
}
|
|
4675
|
+
await cmdRelaySetup(args);
|
|
4676
|
+
}
|
|
4677
|
+
|
|
4678
|
+
async function cmdAccountLogout(args = []) {
|
|
4679
|
+
if (args.includes("-h") || args.includes("--help")) {
|
|
4680
|
+
console.log("Usage: bivy logout\n bivy signout\n\nSign this machine out of its Bivy account. Local sessions and model-provider credentials are kept.");
|
|
4681
|
+
return;
|
|
4682
|
+
}
|
|
4683
|
+
if (args.length) {
|
|
4684
|
+
console.error(c.red(`Unknown logout option: ${args[0]}`));
|
|
4685
|
+
process.exitCode = 1;
|
|
4686
|
+
return;
|
|
4687
|
+
}
|
|
4688
|
+
if (!fs.existsSync(relayConfigPath)) {
|
|
4689
|
+
console.log(c.dim("This machine is not signed into a Bivy account."));
|
|
4690
|
+
return;
|
|
4691
|
+
}
|
|
4692
|
+
|
|
4693
|
+
let relayConfig;
|
|
4694
|
+
try {
|
|
4695
|
+
relayConfig = JSON.parse(fs.readFileSync(relayConfigPath, "utf8"));
|
|
4696
|
+
} catch (error) {
|
|
4697
|
+
console.log(c.yellow(`Could not read the existing account configuration: ${error instanceof Error ? error.message : String(error)}`));
|
|
4698
|
+
}
|
|
4699
|
+
|
|
4700
|
+
if (relayConfig?.controlPlaneUrl && relayConfig?.enrollmentToken) {
|
|
4701
|
+
try {
|
|
4702
|
+
const res = await fetch(`${String(relayConfig.controlPlaneUrl).replace(/\/$/, "")}/node`, {
|
|
4703
|
+
method: "DELETE",
|
|
4704
|
+
headers: { authorization: `Bearer ${relayConfig.enrollmentToken}` },
|
|
4705
|
+
});
|
|
4706
|
+
if (!res.ok && res.status !== 401 && res.status !== 404) {
|
|
4707
|
+
console.log(c.yellow(`Could not remove the account's machine registration (${res.status}); signing out locally anyway.`));
|
|
4708
|
+
}
|
|
4709
|
+
} catch (error) {
|
|
4710
|
+
console.log(c.yellow(`Could not reach the account service; signing out locally anyway (${error instanceof Error ? error.message : String(error)}).`));
|
|
4711
|
+
}
|
|
4712
|
+
} else if (relayConfig?.room && relayConfig?.roomToken) {
|
|
4713
|
+
console.log(c.dim("This machine used account-free relay access; removing that local relay configuration."));
|
|
4714
|
+
}
|
|
4715
|
+
|
|
4716
|
+
fs.rmSync(relayConfigPath, { force: true });
|
|
4717
|
+
fs.rmSync(setupSessionPath, { force: true });
|
|
4718
|
+
// This key wraps the account-level model credential vault. It must not cross
|
|
4719
|
+
// an account boundary; the local provider credential store itself is kept.
|
|
4720
|
+
fs.rmSync(path.join(appDir, "model-auth-vault.json"), { force: true });
|
|
4721
|
+
|
|
4722
|
+
const config = loadConfig();
|
|
4723
|
+
if (restartService()) {
|
|
4724
|
+
console.log(c.green("Signed out. Service restarted with remote account access disabled."));
|
|
4725
|
+
return;
|
|
4726
|
+
}
|
|
4727
|
+
if (await isReachable(config)) {
|
|
4728
|
+
try {
|
|
4729
|
+
const token = await localDeviceToken(config);
|
|
4730
|
+
await localApi(config, "/api/relay/reload", {
|
|
4731
|
+
method: "POST",
|
|
4732
|
+
headers: { authorization: `Bearer ${token}` },
|
|
4733
|
+
body: "{}",
|
|
4734
|
+
});
|
|
4735
|
+
console.log(c.green("Signed out. The running node disconnected from the remote account."));
|
|
4736
|
+
return;
|
|
4737
|
+
} catch (error) {
|
|
4738
|
+
console.log(c.yellow(`Signed out locally, but could not disconnect the running node immediately: ${error instanceof Error ? error.message : String(error)}`));
|
|
4739
|
+
}
|
|
4740
|
+
}
|
|
4741
|
+
console.log(c.green("Signed out of Bivy on this machine."));
|
|
4742
|
+
}
|
|
4743
|
+
|
|
4659
4744
|
async function cmdLinkPhone(args = []) {
|
|
4660
4745
|
if (args.includes("-h") || args.includes("--help")) {
|
|
4661
4746
|
console.log("Usage: bivy link\n\nShow a remote web/PWA link (and QR) in the terminal, single-use and short-lived (5 minutes). Requires 'bivy relay:setup' first.");
|
|
@@ -4937,7 +5022,9 @@ ${c.bold("bivy")} — Bivy node CLI
|
|
|
4937
5022
|
${c.cyan("bivy doctor")} Health check: deps, node, model, remote, agents
|
|
4938
5023
|
${c.cyan("bivy capabilities")} [--json] What this Machine unlocks: OS, agents, providers, Docker/GPU, plugins, workspaces
|
|
4939
5024
|
${c.cyan("bivy logs")} [-f] Tail the node logs (systemd journal, launchd, or background log)
|
|
4940
|
-
${c.cyan("bivy login")} Sign into a
|
|
5025
|
+
${c.cyan("bivy login")} Sign this machine into a Bivy account (GitHub or email)
|
|
5026
|
+
${c.cyan("bivy logout")} Sign this machine out (alias: signout)
|
|
5027
|
+
${c.cyan("bivy provider login")} Sign into a model provider (alias: model login)
|
|
4941
5028
|
${c.cyan("bivy update")} Update Bivy + install deps + restart service (waits for active sessions to finish a turn; --force to skip)
|
|
4942
5029
|
${c.cyan("bivy update:log")} Show output of the last (or in-progress) update
|
|
4943
5030
|
${c.cyan("bivy agent add")} Connect an existing user-owned agent
|
|
@@ -5144,8 +5231,25 @@ Unlike 'bivy run', these commands operate on governed background Runs with check
|
|
|
5144
5231
|
await cmdLogs(args);
|
|
5145
5232
|
break;
|
|
5146
5233
|
case "login":
|
|
5147
|
-
await
|
|
5234
|
+
await cmdAccountLogin(args);
|
|
5148
5235
|
break;
|
|
5236
|
+
case "logout":
|
|
5237
|
+
case "signout":
|
|
5238
|
+
await cmdAccountLogout(args);
|
|
5239
|
+
break;
|
|
5240
|
+
case "provider":
|
|
5241
|
+
case "model": {
|
|
5242
|
+
const [action, ...providerArgs] = args;
|
|
5243
|
+
if (action === "login") {
|
|
5244
|
+
await cmdProviderLogin(providerArgs);
|
|
5245
|
+
} else if (!action || ["-h", "--help", "help"].includes(action)) {
|
|
5246
|
+
console.log(`Usage: bivy ${command} login [provider]\n\nSign into a model provider. Both 'bivy provider login' and 'bivy model login' are equivalent.`);
|
|
5247
|
+
} else {
|
|
5248
|
+
console.error(c.red(`Unknown ${command} action: ${action}. Usage: bivy ${command} login [provider]`));
|
|
5249
|
+
process.exitCode = 1;
|
|
5250
|
+
}
|
|
5251
|
+
break;
|
|
5252
|
+
}
|
|
5149
5253
|
case "update":
|
|
5150
5254
|
await cmdUpdate(args);
|
|
5151
5255
|
break;
|
package/dist/bivy-login.js
CHANGED
|
@@ -102,7 +102,7 @@ async function loginApiKey(provider) {
|
|
|
102
102
|
if (provider.id === "anthropic") {
|
|
103
103
|
const probe = await probeAnthropicAccess(apiKey);
|
|
104
104
|
if (probe.probed && !probe.ok) {
|
|
105
|
-
console.log(`⚠ ${probe.reason || "The key was saved but Anthropic rejected it."} Double-check the key; re-run 'bivy login' to replace it.`);
|
|
105
|
+
console.log(`⚠ ${probe.reason || "The key was saved but Anthropic rejected it."} Double-check the key; re-run 'bivy provider login' to replace it.`);
|
|
106
106
|
}
|
|
107
107
|
else if (probe.probed) {
|
|
108
108
|
console.log("✓ Verified: the key can reach the Anthropic API.");
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// At rest the vault is encrypted (AES-256-GCM via the repo's own seal/open — no
|
|
12
12
|
// third crypto implementation) under a 0600 key minted once. Writes are
|
|
13
13
|
// serialized twice over: an in-process per-provider promise chain, and a
|
|
14
|
-
// cross-process mkdir lock (the `bivy login` CLI writes the same file as the
|
|
14
|
+
// cross-process mkdir lock (the `bivy provider login` CLI writes the same file as the
|
|
15
15
|
// running daemon). `modify()` is the only write path, so every mutation is a
|
|
16
16
|
// read-modify-write under the lock — the ordering OAuth refresh depends on
|
|
17
17
|
// (rotated refresh tokens are single-use; a read-then-write loses that race).
|
package/dist/credentials-cli.js
CHANGED
|
@@ -40,7 +40,7 @@ Agent-native logins:
|
|
|
40
40
|
Config file (${path.relative(process.cwd(), configPath) || configPath}):
|
|
41
41
|
bivy credentials config path|show|edit Print path, show, or open in $EDITOR
|
|
42
42
|
|
|
43
|
-
Note: run 'bivy login' to add a provider's default OAuth/API-key login.`);
|
|
43
|
+
Note: run 'bivy provider login' to add a provider's default OAuth/API-key login.`);
|
|
44
44
|
}
|
|
45
45
|
async function askHidden(question) {
|
|
46
46
|
if (!input.isTTY) {
|
|
@@ -89,7 +89,7 @@ function kindLabel(r) {
|
|
|
89
89
|
async function cmdList() {
|
|
90
90
|
const records = [...(await listCredentialRecords(credsDir))].sort((a, b) => `${a.provider}:${a.label}`.localeCompare(`${b.provider}:${b.label}`));
|
|
91
91
|
if (records.length === 0) {
|
|
92
|
-
console.log("No credentials. Add one with 'bivy credentials add', or 'bivy login'.");
|
|
92
|
+
console.log("No credentials. Add one with 'bivy credentials add', or 'bivy provider login'.");
|
|
93
93
|
return;
|
|
94
94
|
}
|
|
95
95
|
const presets = getCredentialPresets(credsDir);
|
package/dist/server.js
CHANGED
|
@@ -2976,14 +2976,27 @@ async function handleRelayMessage(msg) {
|
|
|
2976
2976
|
console.warn("[relay] failed to handle client message:", error);
|
|
2977
2977
|
}
|
|
2978
2978
|
}
|
|
2979
|
+
function stopRelayConnection() {
|
|
2980
|
+
relay?.stop();
|
|
2981
|
+
relay = undefined;
|
|
2982
|
+
// Disconnecting drops any remote clients the old tunnel carried; release the
|
|
2983
|
+
// shared relay size slot so local PTYs it may have shrunk grow back.
|
|
2984
|
+
terminals.dropClient(RELAY_CLIENT_ID);
|
|
2985
|
+
sessionAdvertiseTarget = undefined;
|
|
2986
|
+
if (advertiseResyncTimer)
|
|
2987
|
+
clearInterval(advertiseResyncTimer);
|
|
2988
|
+
advertiseResyncTimer = undefined;
|
|
2989
|
+
if (nodeHeartbeatTimer)
|
|
2990
|
+
clearInterval(nodeHeartbeatTimer);
|
|
2991
|
+
nodeHeartbeatTimer = undefined;
|
|
2992
|
+
controlPlanePoller?.stop();
|
|
2993
|
+
controlPlanePoller = undefined;
|
|
2994
|
+
}
|
|
2979
2995
|
function startRelayIfConfigured() {
|
|
2996
|
+
stopRelayConnection();
|
|
2980
2997
|
const config = loadRelayConfig(appDir);
|
|
2981
2998
|
if (!config)
|
|
2982
2999
|
return false;
|
|
2983
|
-
relay?.stop();
|
|
2984
|
-
// Reconnecting drops any remote clients the old tunnel carried; release the
|
|
2985
|
-
// shared relay size slot so local PTYs it may have shrunk grow back.
|
|
2986
|
-
terminals.dropClient(RELAY_CLIENT_ID);
|
|
2987
3000
|
relay = new RelayConnector(config, (msg) => void handleRelayMessage(msg), {
|
|
2988
3001
|
pairing: pairingStore,
|
|
2989
3002
|
onWorkAvailable: (hint) => {
|
|
@@ -7231,7 +7244,7 @@ function actionableAgentError(runtimeId, error) {
|
|
|
7231
7244
|
if (id.startsWith("codex"))
|
|
7232
7245
|
return "Codex is not signed in. Run `codex login`, then retry; the same login works from Bivy and the PWA.";
|
|
7233
7246
|
if (id === "pi" || id === "aider")
|
|
7234
|
-
return "No model credential is configured. Run `bivy login`, then retry. This is only required once and compatible credentials sync E2E-encrypted to your other Bivy nodes.";
|
|
7247
|
+
return "No model credential is configured. Run `bivy provider login`, then retry. This is only required once and compatible credentials sync E2E-encrypted to your other Bivy nodes.";
|
|
7235
7248
|
return "The selected agent needs model authentication. Sign in through its native CLI, then retry.";
|
|
7236
7249
|
}
|
|
7237
7250
|
return raw;
|
|
@@ -8742,8 +8755,12 @@ app.use("/api", authMiddleware(identity));
|
|
|
8742
8755
|
// Reload relay.json without forcing the user to restart the whole node. This is
|
|
8743
8756
|
// used by `bivy relay:setup` after it enrolls the node.
|
|
8744
8757
|
app.post("/api/relay/reload", (_req, res) => {
|
|
8745
|
-
const
|
|
8746
|
-
|
|
8758
|
+
const enabled = startRelayIfConfigured();
|
|
8759
|
+
if (enabled)
|
|
8760
|
+
startControlPlaneTasksIfConfigured();
|
|
8761
|
+
// A missing relay.json is a valid reload state: `bivy logout` removes it and
|
|
8762
|
+
// calls this endpoint to disconnect a foreground node without restarting it.
|
|
8763
|
+
res.json({ ok: true, enabled });
|
|
8747
8764
|
});
|
|
8748
8765
|
// Link a remote web/PWA device through the relay. Mints a short-lived,
|
|
8749
8766
|
// node-scoped client grant from the control plane and packages it with the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bivy/bivy",
|
|
3
|
-
"version": "0.16.7-staging.
|
|
3
|
+
"version": "0.16.7-staging.2",
|
|
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.",
|
|
@@ -66,6 +66,6 @@
|
|
|
66
66
|
"nanoid": "3.3.18",
|
|
67
67
|
"undici": "8.10.0"
|
|
68
68
|
},
|
|
69
|
-
"readme": "# Bivy\n\n[](https://www.npmjs.com/package/@bivy/bivy)\n[](LICENSE)\n[](https://nodejs.org)\n\n**Run coding agents on your machines and use them from anywhere — from a phone,\nbrowser, terminal, GitHub issue, Slack message, schedule, or webhook.**\n\nStart Claude Code on your workstation, next to the repo, dev server, and\ndatabase you already use. Walk away. From your phone, you can see what it did,\nanswer a question, or approve a migration. CI or a webhook can start the next\njob on the right Machine without waiting for you to return.\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash # install + guided setup\ncd your-repo\nbivy run claude # start an agent in this repo\nbivy open # open it in a browser or on your phone\n```\n\nBivy does not replace Claude Code, Codex, or the other agents you use. It keeps\ntheir Sessions running, routes work to the right Machine, and gives you one place\nto start, join, approve, and review work.\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> **Bivy is 0.x software.** Claude Code, Codex, Pi, and OpenCode are the\n> release-tested paths. Support for other agents varies; check the\n> [runtime support matrix](docs/runtime-support-matrix.md) before relying on a\n> specific feature.\n\n## Why not just a cloud sandbox?\n\nA hosted sandbox clones your repo into a clean environment. Bivy runs in the\nenvironment you already use: the current working tree, running services, and\nwarm caches.\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\nBivy lets you leave that environment running and reach it from anywhere.\n\n## What you can do\n\nEvery task in Bivy becomes a Session on a Machine you choose. Start it from the\nterminal, browser, phone, or an external trigger. Join it while it runs, or let\nit finish in the background.\n\n### Sessions\n\nStart an agent, watch it work, steer it, stop it, or approve a tool call. You can\nleave your desk and keep the Session open:\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 a chat session and open it in the browser\n```\n\n- Reconnect to the same Session from a phone, browser, or terminal.\n- Upload files and images from your phone, or download files the agent creates.\n- Import existing Claude Code and Codex Sessions.\n- Fork or move a Session to another agent, model, or Machine.\n- Connect several Machines, such as a workstation, server, or GPU box.\n\n### Runs\n\nA Run is a Session started as a background job. Start one yourself or trigger it\nfrom another service; Bivy queues it and returns immediately:\n\n```bash\nbivy runs start \"...\" # queue a one-off unattended Run, then `bivy runs wait <id>`\nbivy automation init # define jobs in .bivy/automations.yaml\n```\n\n- Trigger Runs from GitHub, Linear, Slack, a schedule, CI, or a signed webhook.\n- Choose the Machine, agent, model, sandbox, approval mode, and retry limit.\n- Review the changed files, checks, and final result in a Receipt.\n\nSee the [capability recipes](docs/capability-recipes.md) for examples and the\n[runtime support matrix](docs/runtime-support-matrix.md) for per-agent support.\n\n## Bring your own agents and models\n\nUse your existing agent login, an API key in Bivy's vault, or a local\nOpenAI-compatible server. Claude Code, Codex, Pi, and OpenCode have release-tested\nintegrations. Other agents run through ACP or a headless process adapter. Add\nyour own with:\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\nBivy supports macOS and Linux and requires Node.js 20 or newer. The installer\nadds the [`@bivy/bivy`](https://www.npmjs.com/package/@bivy/bivy) package and\n`bivy` command, then runs `bivy setup`. Setup asks which agent to use, installs\nit if needed, configures remote access, and starts a launchd or systemd service.\n\nIf an agent is already installed, Bivy uses its existing command, login, and\nconfiguration. Re-running the installer updates Bivy and restarts the service.\n\n**Local and remote use.** `bivy run`, `bivy resume`, and `bivy sessions` work\nwithout an account or server. During setup, choose **local only for now** to skip\nremote access. The browser and phone apps need a control plane: use\n[app.bivy.sh](https://app.bivy.sh) or\n[self-host one](docs/self-host-quickstart.md). You can switch later with\n`bivy relay:setup`.\n\nSelf-hosted Bivy Core is open source and has no usage limits. Bivy Cloud offers\na managed app, relay, and hosted Machines; see\n[bivy.sh#pricing](https://bivy.sh#pricing) for details.\n\nPrefer to inspect the installer first?\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh -o install.sh\nless install.sh\nbash install.sh\n```\n\n**When the installer uses sudo:**\n\n- Debian/Ubuntu without a suitable Node.js: `sudo apt-get install curl\n ca-certificates`, 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 20+ 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\nAfter setup, start Bivy inside an existing repo:\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| Install optional Bivy bridges/native terminal dependency up front | `BIVY_INSTALL_OPTIONAL_DEPS=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` uses the same install method you used originally. It waits for an\nactive turn to finish, updates Bivy, and restarts the background service:\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 checks for new releases and posts an update notice in the Session.\n\n## Architecture\n\nBivy has three parts. For normal interactive Sessions, code, credentials, and\ntranscripts stay on the node.\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\nThe node has no web UI. The browser and phone apps come from `app.bivy.sh` or\nyour own control plane; the terminal CLI needs neither. Session traffic is\nend-to-end encrypted between the node and paired devices, so the relay cannot\nread it.\n\nQR pairing with `bivy link` lets the node authorize the device directly. Hosted\naccount pairing trusts the control plane to authorize devices and serve the web\napp that holds the keys. Read the\n[known limitations](docs/security-model.md#known-limitations-for-0x) before using\nBivy with sensitive work.\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, Codex, Pi, and OpenCode are the release-tested paths.** The other\nadapters are maintained, but their features vary. Check the\n[runtime support matrix](docs/runtime-support-matrix.md) for resume, models,\napprovals, sandboxing, and test status.\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\nCodebuff, Hermes, and OpenClaw are experimental and hidden from the picker.\nRun them with `BIVY_RUNTIME=<id>`.\n\nRun any command with `bivy run -- ./your-agent --flags`. For a reusable entry in\nthe CLI and web picker, use `bivy agent add`. You can also create an experimental\n`v1alpha1` [plugin manifest](docs/plugins.md) with `bivy plugin init`.\n\nSee the [runtime support matrix](docs/runtime-support-matrix.md) for details.\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\nManage node settings or add repo-specific checks and safety rules:\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`**, so most actions do not prompt.\nProtection depends on the agent. Some agents enforce Bivy's sandbox setting;\nothers expose tool calls that Bivy can approve or deny. A process agent that\nBivy cannot intercept runs with your user permissions. The picker shows which\ncase applies and asks for confirmation on unprotected paths.\n\nFor tool calls it can see, Bivy blocks destructive system commands and writes\noutside the workspace. It asks before force pushes, publishing, deployments,\nand `sudo`. These checks help prevent accidents. **They are not a security\nsandbox.**\n\nTo see more prompts, change the approval mode:\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\nCodex, Claude Code, Gemini CLI, and Qwen Code enforce the `read-only`,\n`workspace-write`, and `danger-full-access` tiers themselves. Other agents may\nrun with your full user permissions even when Bivy can inspect some tool calls.\nCheck the Protection label in the picker. **Bivy does not provide an OS-level\nsandbox.**\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 are resolved only when\nan agent needs them, so the raw values do not appear in config files.\n\nHosted unattended provisioning is different from normal interactive Sessions.\nIf you enable it, Bivy Cloud may hold encrypted cloud, repository, model, or\nkey-escrow data that the service can access. See the\n[security model](docs/security-model.md#what-the-control-plane-sees) and\n[key-management guide](docs/key-management.md).\n\n## Automations as code\n\nDefine jobs in `.bivy/automations.yaml`, validate them, and test trigger events\nlocally:\n\n```bash\nbivy automation init\nbivy automation validate\nbivy automation test --event .bivy/events/failed-ci.yaml\nbivy automation apply\n```\n\nBivy encrypts instructions on the node before upload. Each job records its\nsandbox, approval mode, and maximum number of attempts. 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, runs the configured checks, and posts the result.\n\nCore has no usage limits. Hosted pricing is managed in the separate Cloud\nrepository.\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",
|
|
69
|
+
"readme": "# Bivy\n\n[](https://www.npmjs.com/package/@bivy/bivy)\n[](LICENSE)\n[](https://nodejs.org)\n\n**Run coding agents on your machines and use them from anywhere — from a phone,\nbrowser, terminal, GitHub issue, Slack message, schedule, or webhook.**\n\nStart Claude Code on your workstation, next to the repo, dev server, and\ndatabase you already use. Walk away. From your phone, you can see what it did,\nanswer a question, or approve a migration. CI or a webhook can start the next\njob on the right Machine without waiting for you to return.\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh | bash # install + guided setup\ncd your-repo\nbivy run claude # start an agent in this repo\nbivy open # open it in a browser or on your phone\n```\n\nBivy does not replace Claude Code, Codex, or the other agents you use. It keeps\ntheir Sessions running, routes work to the right Machine, and gives you one place\nto start, join, approve, and review work.\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> **Bivy is 0.x software.** Claude Code, Codex, Pi, and OpenCode are the\n> release-tested paths. Support for other agents varies; check the\n> [runtime support matrix](docs/runtime-support-matrix.md) before relying on a\n> specific feature.\n\n## Why not just a cloud sandbox?\n\nA hosted sandbox clones your repo into a clean environment. Bivy runs in the\nenvironment you already use: the current working tree, running services, and\nwarm caches.\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\nBivy lets you leave that environment running and reach it from anywhere.\n\n## What you can do\n\nEvery task in Bivy becomes a Session on a Machine you choose. Start it from the\nterminal, browser, phone, or an external trigger. Join it while it runs, or let\nit finish in the background.\n\n### Sessions\n\nStart an agent, watch it work, steer it, stop it, or approve a tool call. You can\nleave your desk and keep the Session open:\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 a chat session and open it in the browser\n```\n\n- Reconnect to the same Session from a phone, browser, or terminal.\n- Upload files and images from your phone, or download files the agent creates.\n- Import existing Claude Code and Codex Sessions.\n- Fork or move a Session to another agent, model, or Machine.\n- Connect several Machines, such as a workstation, server, or GPU box.\n\n### Runs\n\nA Run is a Session started as a background job. Start one yourself or trigger it\nfrom another service; Bivy queues it and returns immediately:\n\n```bash\nbivy runs start \"...\" # queue a one-off unattended Run, then `bivy runs wait <id>`\nbivy automation init # define jobs in .bivy/automations.yaml\n```\n\n- Trigger Runs from GitHub, Linear, Slack, a schedule, CI, or a signed webhook.\n- Choose the Machine, agent, model, sandbox, approval mode, and retry limit.\n- Review the changed files, checks, and final result in a Receipt.\n\nSee the [capability recipes](docs/capability-recipes.md) for examples and the\n[runtime support matrix](docs/runtime-support-matrix.md) for per-agent support.\n\n## Bring your own agents and models\n\nUse your existing agent login, an API key in Bivy's vault, or a local\nOpenAI-compatible server. Claude Code, Codex, Pi, and OpenCode have release-tested\nintegrations. Other agents run through ACP or a headless process adapter. Add\nyour own with:\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\nBivy supports macOS and Linux and requires Node.js 20 or newer. The installer\nadds the [`@bivy/bivy`](https://www.npmjs.com/package/@bivy/bivy) package and\n`bivy` command, then runs `bivy setup`. Setup asks which agent to use, installs\nit if needed, configures remote access, and starts a launchd or systemd service.\n\nIf an agent is already installed, Bivy uses its existing command, login, and\nconfiguration. Re-running the installer updates Bivy and restarts the service.\n\n**Local and remote use.** `bivy run`, `bivy resume`, and `bivy sessions` work\nwithout an account or server. During setup, choose **local only for now** to skip\nremote access. The browser and phone apps need a control plane: use\n[app.bivy.sh](https://app.bivy.sh) or\n[self-host one](docs/self-host-quickstart.md). You can sign in later with\n`bivy login` (or use `bivy relay:setup` for self-hosted endpoint options).\n\nSelf-hosted Bivy Core is open source and has no usage limits. Bivy Cloud offers\na managed app, relay, and hosted Machines; see\n[bivy.sh#pricing](https://bivy.sh#pricing) for details.\n\nPrefer to inspect the installer first?\n\n```bash\ncurl -fsSL https://bivy.sh/install.sh -o install.sh\nless install.sh\nbash install.sh\n```\n\n**When the installer uses sudo:**\n\n- Debian/Ubuntu without a suitable Node.js: `sudo apt-get install curl\n ca-certificates`, 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 20+ 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\nAfter setup, start Bivy inside an existing repo:\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| Install optional Bivy bridges/native terminal dependency up front | `BIVY_INSTALL_OPTIONAL_DEPS=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` uses the same install method you used originally. It waits for an\nactive turn to finish, updates Bivy, and restarts the background service:\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 checks for new releases and posts an update notice in the Session.\n\n## Architecture\n\nBivy has three parts. For normal interactive Sessions, code, credentials, and\ntranscripts stay on the node.\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\nThe node has no web UI. The browser and phone apps come from `app.bivy.sh` or\nyour own control plane; the terminal CLI needs neither. Session traffic is\nend-to-end encrypted between the node and paired devices, so the relay cannot\nread it.\n\nQR pairing with `bivy link` lets the node authorize the device directly. Hosted\naccount pairing trusts the control plane to authorize devices and serve the web\napp that holds the keys. Read the\n[known limitations](docs/security-model.md#known-limitations-for-0x) before using\nBivy with sensitive work.\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, Codex, Pi, and OpenCode are the release-tested paths.** The other\nadapters are maintained, but their features vary. Check the\n[runtime support matrix](docs/runtime-support-matrix.md) for resume, models,\napprovals, sandboxing, and test status.\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\nCodebuff, Hermes, and OpenClaw are experimental and hidden from the picker.\nRun them with `BIVY_RUNTIME=<id>`.\n\nRun any command with `bivy run -- ./your-agent --flags`. For a reusable entry in\nthe CLI and web picker, use `bivy agent add`. You can also create an experimental\n`v1alpha1` [plugin manifest](docs/plugins.md) with `bivy plugin init`.\n\nSee the [runtime support matrix](docs/runtime-support-matrix.md) for details.\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\nManage node settings or add repo-specific checks and safety rules:\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`**, so most actions do not prompt.\nProtection depends on the agent. Some agents enforce Bivy's sandbox setting;\nothers expose tool calls that Bivy can approve or deny. A process agent that\nBivy cannot intercept runs with your user permissions. The picker shows which\ncase applies and asks for confirmation on unprotected paths.\n\nFor tool calls it can see, Bivy blocks destructive system commands and writes\noutside the workspace. It asks before force pushes, publishing, deployments,\nand `sudo`. These checks help prevent accidents. **They are not a security\nsandbox.**\n\nTo see more prompts, change the approval mode:\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\nCodex, Claude Code, Gemini CLI, and Qwen Code enforce the `read-only`,\n`workspace-write`, and `danger-full-access` tiers themselves. Other agents may\nrun with your full user permissions even when Bivy can inspect some tool calls.\nCheck the Protection label in the picker. **Bivy does not provide an OS-level\nsandbox.**\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 are resolved only when\nan agent needs them, so the raw values do not appear in config files.\n\nHosted unattended provisioning is different from normal interactive Sessions.\nIf you enable it, Bivy Cloud may hold encrypted cloud, repository, model, or\nkey-escrow data that the service can access. See the\n[security model](docs/security-model.md#what-the-control-plane-sees) and\n[key-management guide](docs/key-management.md).\n\n## Automations as code\n\nDefine jobs in `.bivy/automations.yaml`, validate them, and test trigger events\nlocally:\n\n```bash\nbivy automation init\nbivy automation validate\nbivy automation test --event .bivy/events/failed-ci.yaml\nbivy automation apply\n```\n\nBivy encrypts instructions on the node before upload. Each job records its\nsandbox, approval mode, and maximum number of attempts. 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, runs the configured checks, and posts the result.\n\nCore has no usage limits. Hosted pricing is managed in the separate Cloud\nrepository.\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",
|
|
70
70
|
"readmeFilename": "README.md"
|
|
71
71
|
}
|