@cabane/companion 0.6.206 → 0.6.208
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 +41 -65
- package/dist/cli.js +59 -2
- package/dist/runtime.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,37 +1,16 @@
|
|
|
1
1
|
# cabane
|
|
2
2
|
|
|
3
|
-
The Cabane Companion runs your Cabane agents on
|
|
3
|
+
The Cabane Companion runs your Cabane agents on a device you choose. It receives their work from Cabane, starts a harness on the device and streams replies back. The harness calls its configured model provider; agents use the local files, tools and credentials available to their environment.
|
|
4
4
|
|
|
5
|
-
It
|
|
5
|
+
It uses **Claude Code**, **Codex** or **OpenCode**. The package includes Claude Code and Codex execution binaries, but setup does not run a vendor CLI installer or sign you in. OpenCode needs its own running server.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Start with [Introduction to the Companion](https://cabane.ai/docs/what-the-companion-does), then [Mac setup](https://cabane.ai/docs/on-a-mac), [Windows setup](https://cabane.ai/docs/on-windows) or [Server and VPS setup](https://cabane.ai/docs/on-a-server). [FAQ and Help](https://cabane.ai/docs/faq) covers sign-in and troubleshooting. This README is the device-side reference: commands, configuration and local state.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Three things, one relation each.
|
|
12
|
-
|
|
13
|
-
- **A device** is a machine running the Companion. It belongs to your account and can be joined to any of your workspaces. Cabane shows it as online, offline or deactivated.
|
|
14
|
-
- **A harness** is a coding tool on the device with a login behind it. The Companion detects each one and reports its state: connected, needs sign-in, limited, problem, off or gone. A device offers exactly the harnesses it has.
|
|
15
|
-
- **An agent** is assigned to one device and runs through one of that device's harnesses, with a model from it. Assign in as many workspaces as you like: one Companion serves them all.
|
|
16
|
-
|
|
17
|
-
**Cabane decides what an agent is; the device decides what it can touch.** Everything about the agent lives on its page in Cabane and is delivered with each turn, so an edit there lands on the next reply with no restart: its charter, its harness and model, its MCP servers and its starting folder. The device holds only what can't travel from a server: the device token, your secrets, and local overrides for this device.
|
|
18
|
-
|
|
19
|
-
How a turn runs, top to bottom:
|
|
20
|
-
|
|
21
|
-
| Layer | Holds |
|
|
22
|
-
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
23
|
-
| **Cabane** | The agent: its charter, harness and model, the folder it starts in and its MCP servers. Who can edit it decides who changes them; an agent never does, and a conversation can't. |
|
|
24
|
-
| **Companion** | The listener on the device. Holds the pairing and the harness logins. |
|
|
25
|
-
| **Runner** | A child process per turn with a one-turn credential. |
|
|
26
|
-
| **Harness** | Claude Code, Codex or OpenCode with its normal tools and your own settings. Nothing asks for permission mid-task. |
|
|
27
|
-
|
|
28
|
-
> **An agent on this device reaches the whole device, with no approval prompts.** It runs the device's harness with its tools and the files there, and nothing waits for a click: nobody is at the screen, and approvals would hold the work to a person's pace. For almost everyone, the recommendation is to run the Companion and its harness together in a container or VM; running directly, with the harness's own sandbox set, is the alternative, and that sandbox restricts particular tools (see Isolation). An agent that reads untrusted input (public web, inbound mail, outside members) runs on a Companion that is isolated, whatever the device.
|
|
29
|
-
|
|
30
|
-
**No account password or full-account token ever touches the device.** The setup code delivers a device token (`cabdev_…`) good only for pulling this device's assignments and reporting liveness. Each assigned agent gets its own workspace-bound credential, delivered once. Renaming, deactivating, removing a device and rotating its token happen in Cabane.
|
|
9
|
+
Pairing supplies a device token, not your Cabane password or a full-account token. The device token is for this device's assignments and liveness; assigned agents receive workspace-bound credentials. The [trust guide](https://cabane.ai/docs/what-the-companion-does) explains the layers, records and access.
|
|
31
10
|
|
|
32
11
|
## Install
|
|
33
12
|
|
|
34
|
-
In a workspace, open **Settings → Devices** and choose **
|
|
13
|
+
In a workspace, open **Settings → Devices** and choose **Set up a new device**. The page mints a setup line with a code in it, good for 15 minutes. Paste it in a terminal on the device. One of:
|
|
35
14
|
|
|
36
15
|
```sh
|
|
37
16
|
curl -fsSL https://cabane.ai/install.sh | bash -s -- CODE
|
|
@@ -43,7 +22,9 @@ The script brings its own Node (checksum-checked, into `~/.cabane`) and needs no
|
|
|
43
22
|
npm i -g @cabane/companion && cabane setup CODE
|
|
44
23
|
```
|
|
45
24
|
|
|
46
|
-
|
|
25
|
+
`cabane setup CODE` pairs the device to your account and joins it to that workspace. From an interactive terminal, setup starts the Companion in the background, waits for its first check-in and reports the device's state. Without an interactive terminal, setup can stay attached to the running Companion. The same line on a device that is already paired joins it to the workspace and mints nothing.
|
|
26
|
+
|
|
27
|
+
If no harness is usable, interactive setup asks which one you want to set up. Follow the complete CLI installation and sign-in steps for [Mac setup](https://cabane.ai/docs/on-a-mac#3-sign-in-inside-the-environment), [Windows setup](https://cabane.ai/docs/on-windows#3-sign-in-inside-the-environment) or [Server and VPS setup](https://cabane.ai/docs/on-a-server#3-sign-in-without-a-browser), then check `cabane status`.
|
|
47
28
|
|
|
48
29
|
```
|
|
49
30
|
✓ Paired as "maya-mbp" with Acme.
|
|
@@ -60,37 +41,45 @@ Either way `cabane setup CODE` pairs the device to your account, joins it to tha
|
|
|
60
41
|
In Cabane: https://app.cabane.ai/acme/settings/devices
|
|
61
42
|
```
|
|
62
43
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
Setup never installs the service. Run `cabane service install` when you want the Companion to start at login and keep itself updated; the closing block names it.
|
|
66
|
-
|
|
67
|
-
A fresh device runs nothing yet. In a workspace, open an agent's page and assign it to the device; the Companion picks the assignment up on its next poll.
|
|
44
|
+
Setup never installs the service. On macOS or Linux, run `cabane service install` when you want the Companion to start at login and keep itself updated; the closing block names it. Native Windows uses the background process and has no service installer.
|
|
68
45
|
|
|
69
46
|
If `cabane` isn't found afterwards, open a new terminal, or run the `source` line setup printed.
|
|
70
47
|
|
|
48
|
+
The [server guide](https://cabane.ai/docs/on-a-server) provides a Dockerfile and Compose example to build locally. Its Dockerfile installs the Companion and all three command-line tools; you sign in inside the container. Follow that guide for pairing and starting the Docker environment.
|
|
49
|
+
|
|
71
50
|
## Commands
|
|
72
51
|
|
|
73
|
-
| Command | What it does
|
|
74
|
-
| ------------------------------------ |
|
|
75
|
-
| `setup [CODE]` | With a code: pair or join, detect harnesses, start. Without: a re-runnable checklist that reports harnesses and starts what isn't running.
|
|
76
|
-
| `start [--foreground]` |
|
|
77
|
-
| `stop` | Stop
|
|
78
|
-
| `status` | Version and install, the paired device by its Cabane name, its state in Cabane's words and when it last checked in, each harness's state, where agents work, declared secret names, and local overrides.
|
|
79
|
-
| `update [--auto on\|off]` | Install the version Cabane names now; with `--auto`, set whether the Companion keeps itself up to date.
|
|
80
|
-
| `service install\|uninstall\|status` | Run as a systemd user service or a LaunchAgent that starts at
|
|
81
|
-
| `logs [-n N] [-f]` | Recent log lines, or follow.
|
|
82
|
-
| `transcript [file] [--last] [-f]` | Read back a full agent turn, tool calls and results included.
|
|
83
|
-
| `logout [--purge]` | Remove the device token and cached agent credentials. Doesn't remove the device from Cabane.
|
|
52
|
+
| Command | What it does |
|
|
53
|
+
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
54
|
+
| `setup [CODE]` | With a code: pair or join, detect harnesses, start. Without: a re-runnable checklist that reports harnesses and starts what isn't running. |
|
|
55
|
+
| `start [--foreground]` | Start the Companion without prompts. From an interactive terminal, run in the background; noninteractive use may stay attached. Unpaired, it names `setup`. `--foreground` stays attached for your supervisor. |
|
|
56
|
+
| `stop` | Stop the Companion cleanly. Ends any turn in progress. |
|
|
57
|
+
| `status` | Version and install, the paired device by its Cabane name, its state in Cabane's words and when it last checked in, each harness's state, where agents work, declared secret names, and local overrides. |
|
|
58
|
+
| `update [--auto on\|off]` | Install the version Cabane names now; with `--auto`, set whether the Companion keeps itself up to date. |
|
|
59
|
+
| `service install\|uninstall\|status` | Run as a systemd user service or a LaunchAgent that starts at login and restarts if it stops; remove it; show its state. |
|
|
60
|
+
| `logs [-n N] [-f]` | Recent log lines, or follow. |
|
|
61
|
+
| `transcript [file] [--last] [-f]` | Read back a full agent turn, tool calls and results included. |
|
|
62
|
+
| `logout [--purge]` | Remove the device token and cached agent credentials. Doesn't remove the device from Cabane. |
|
|
84
63
|
|
|
85
64
|
Anything else about a device is done in Cabane, on the device's page.
|
|
86
65
|
|
|
87
66
|
## Keeping it running
|
|
88
67
|
|
|
89
|
-
|
|
68
|
+
For a direct installation, a reboot or a crash leaves the Companion stopped until the next `cabane start` unless you have installed its service. Under the service it restarts if it stops and starts with its user session (at login on macOS; enable linger on Linux for operation after logout), and follows the version Cabane names: it installs the new version under `~/.cabane/versions`, checks it starts, and swaps between turns. A version that can't start is rolled back by the boot guard. `cabane update --auto off` stops updates; without the service, `cabane update` installs and the next `cabane start` runs it.
|
|
69
|
+
|
|
70
|
+
On native Windows, check the background process with `cabane status` and run `cabane start` after a Windows restart. If you installed OpenCode outside Docker, keep its server running separately; the Companion's service does not supervise it.
|
|
71
|
+
|
|
72
|
+
For the Docker example, keep automatic Companion updates off and rebuild the local image to update the Companion and harness tools. Follow the [server guide's update steps](https://cabane.ai/docs/on-a-server#4-keep-it-running-and-update).
|
|
90
73
|
|
|
91
74
|
Other supervisors: run `cabane start --foreground` with `CABANE_COMPANION_SUPERVISED=1` set, using the absolute paths `~/.cabane/node/bin/node` and `~/.cabane/current/dist/bin.js`, which don't move on an update.
|
|
92
75
|
|
|
93
|
-
|
|
76
|
+
For a direct installation, after **Rotate token** in Cabane, apply the replacement on the device:
|
|
77
|
+
|
|
78
|
+
1. Run `cabane stop`.
|
|
79
|
+
2. In `~/.cabane/config.json`, replace `deviceToken` with the replacement token shown by Cabane.
|
|
80
|
+
3. Run `cabane start`.
|
|
81
|
+
|
|
82
|
+
For Docker, follow [Rotate a Docker device's token](https://cabane.ai/docs/on-a-server#rotate-a-docker-devices-token).
|
|
94
83
|
|
|
95
84
|
## What's on this device
|
|
96
85
|
|
|
@@ -121,9 +110,9 @@ A device with no keychain or browser, such as a server or a container, can sign
|
|
|
121
110
|
- `prepareHook`: a command that resolves the working directory before each turn; wins over both. A device-level hook applies to every agent that doesn't name its own. The hook gets `CABANE_DEFAULT_CWD`, the directory below, for a hook that only adds to it.
|
|
122
111
|
- `root`: where agents work when nothing else says. Every agent gets a directory per conversation under it, `<root>/<workspace>/<agent>/<conversation>/`, made on the first turn and never removed by the Companion. Default `~/.cabane/work`; absolute, or `~/…`. An agent with no folder in Cabane, no `cwd` and no hook stands there; a folder or `cwd` that isn't an existing directory is passed over with a line in the log.
|
|
123
112
|
- `harnesses`: an allowlist such as `["claude-code"]`; absent means all three.
|
|
124
|
-
- `claudeCode.autoMemory`: Claude Code's local memory directory is off by default
|
|
113
|
+
- `claudeCode.autoMemory`: Claude Code's local memory directory is off by default in the Companion, because notes belong in the workspace where others can read them. `true` hands it back.
|
|
125
114
|
|
|
126
|
-
A malformed block fails `cabane start` with the field named. A `runners` block, a row's `sandbox`, or a `prepareHook`'s `validateCached` or `failureReporter` from an older Companion is ignored, with one line in the log naming it.
|
|
115
|
+
A malformed block fails `cabane start` with the field named. A `runners` block, a row's `sandbox`, or a `prepareHook`'s `validateCached` or `failureReporter` from an older version of the Companion is ignored, with one line in the log naming it.
|
|
127
116
|
|
|
128
117
|
Every turn's shell gets `CABANE_CONVERSATION_ID` and `CABANE_AGENT_ID`, so a script an agent runs can tell which conversation and agent it's working for.
|
|
129
118
|
|
|
@@ -145,28 +134,15 @@ What your command can rely on, and can set:
|
|
|
145
134
|
| `CABANE_TRANSCRIPT_DIR` | Set: where the turn writes its transcript. A directory one level under `~/.cabane/transcripts/` lists in `cabane transcript`. |
|
|
146
135
|
| `CABANE_WORK_ROOT_DEDICATED` | Set to `1` when the root is already this one conversation and agent's: the turn stands in it directly, with no per-conversation directory under it. |
|
|
147
136
|
|
|
148
|
-
These names are a contract:
|
|
149
|
-
|
|
150
|
-
### Isolation
|
|
151
|
-
|
|
152
|
-
There are no tool approvals. Every agent runs the device's harness with its tools, settings and the files there, and nothing waits for a click: nobody is at the screen, and with the amount of work a person or a team puts through Cabane, approvals would hold it to a person's pace. The Companion approves Claude Code's tools through a hook, similar to `bypassPermissions` (it doesn't set that permission mode), and runs Codex with `approval_policy = "never"`.
|
|
153
|
-
|
|
154
|
-
Cabane has no sandbox setting of its own. A harness's own sandbox settings restrict particular tools; they don't isolate the Companion and everything it launches. A container or VM contains the Companion and its child processes.
|
|
155
|
-
|
|
156
|
-
So where agents run is your choice, and there are two ways:
|
|
157
|
-
|
|
158
|
-
- **The Companion in a container or VM**, recommended for almost everyone: the Companion and the harness together in Docker, OrbStack or a VM, sharing only the folders and credentials they need. Agents keep a full shell to work and code in, still with no approvals, while the container or VM limits what they reach to what you put in, MCP servers, hooks and the harness process included. If you haven't set one up before, ask Claude to help; [Common device patterns](https://cabane.ai/docs/common-device-patterns) walks through one with Docker.
|
|
159
|
-
- **Directly on your device**, with the harness's own sandbox set to taste. It restricts particular tools, and each harness draws a different line.
|
|
137
|
+
These names are a contract: changing one would break your command, so none changes without a note in the release.
|
|
160
138
|
|
|
161
|
-
|
|
139
|
+
### Harness permissions
|
|
162
140
|
|
|
163
|
-
|
|
164
|
-
- **Codex**, `~/.codex/config.toml` (or `$CODEX_HOME/config.toml`): set `sandbox_mode` and the Companion passes no sandbox flag, so the file governs; set nothing and turns run `danger-full-access`. `workspace-write` confines writes to the agent's folder, `/tmp` and your `writable_roots`, leaves reads open, turns command network off unless `[sandbox_workspace_write] network_access = true`, and runs each command in its own namespace, so a process it leaves running (a dev server, a background build) stops when the command returns. Docker doesn't work inside it.
|
|
165
|
-
- **OpenCode** is your own `opencode serve`.
|
|
141
|
+
The Companion approves Claude Code's tools through a hook and approves OpenCode permission requests; no turn waits for a tool-approval dialog. For Codex it disables approvals and, when your configuration sets a top-level `sandbox_mode`, passes no sandbox flag; without that setting it uses `danger-full-access`. Choose where agents run using [Agent access](https://cabane.ai/docs/how-much-access-agents-get), and configure the tools through [Harness sandboxes](https://cabane.ai/docs/harness-sandboxes).
|
|
166
142
|
|
|
167
143
|
## Debugging a turn
|
|
168
144
|
|
|
169
|
-
Cabane shows the
|
|
145
|
+
Cabane shows the conversation; the device also keeps a detailed local record. Every turn writes its full stream to `~/.cabane/transcripts/`: the tool list, every tool call and its result, the text, the outcome. A failed turn's log line names its transcript.
|
|
170
146
|
|
|
171
147
|
```sh
|
|
172
148
|
cabane transcript --last # render the most recent turn
|
|
@@ -179,4 +155,4 @@ cabane logs -f # follow the log
|
|
|
179
155
|
|
|
180
156
|
## Not yet
|
|
181
157
|
|
|
182
|
-
Windows has no service install and no self-update. There is no per-tool permissioning in Cabane
|
|
158
|
+
Native Windows has no service install and no self-update. There is no per-tool permissioning in Cabane. Control agents' access through their environment and the harness's own settings.
|
package/dist/cli.js
CHANGED
|
@@ -11067,7 +11067,7 @@ init_bundled_binaries();
|
|
|
11067
11067
|
init_cabane_command();
|
|
11068
11068
|
init_config();
|
|
11069
11069
|
import { homedir as homedir6 } from "os";
|
|
11070
|
-
import { join as join7 } from "path";
|
|
11070
|
+
import { join as join7, win32 } from "path";
|
|
11071
11071
|
|
|
11072
11072
|
// src/device-state.ts
|
|
11073
11073
|
var DEVICE_STATES = ["waiting", "online", "offline", "deactivated"];
|
|
@@ -11157,7 +11157,8 @@ function ctx(c = {}) {
|
|
|
11157
11157
|
install: c.install ?? companionInstall(),
|
|
11158
11158
|
profile: "profile" in c ? c.profile ?? null : profileFile({ home }),
|
|
11159
11159
|
reload: "reload" in c ? c.reload ?? null : reloadLine(),
|
|
11160
|
-
hasNpm: c.hasNpm ?? firstOnPath("npm", path) !== null
|
|
11160
|
+
hasNpm: c.hasNpm ?? firstOnPath("npm", path) !== null,
|
|
11161
|
+
windows: (c.platform ?? process.platform) === "win32"
|
|
11161
11162
|
};
|
|
11162
11163
|
}
|
|
11163
11164
|
function loginCommand(runtime) {
|
|
@@ -11224,6 +11225,7 @@ var CHOOSE_AGENT = "Cabane needs one of them. Which will you set up?";
|
|
|
11224
11225
|
var SETUP_AGAIN = `Then ${cabane("status")} shows it signed in; nothing else to run.`;
|
|
11225
11226
|
function agentNote(runtime, c = {}) {
|
|
11226
11227
|
const k = ctx(c);
|
|
11228
|
+
if (k.windows) return windowsAgentNote(runtime, k);
|
|
11227
11229
|
if (runtime === "claude-code") {
|
|
11228
11230
|
const commands = ["curl -fsSL https://claude.ai/install.sh | bash"];
|
|
11229
11231
|
const localBin = join7(k.home, ".local", "bin");
|
|
@@ -11287,6 +11289,61 @@ function agentNote(runtime, c = {}) {
|
|
|
11287
11289
|
]
|
|
11288
11290
|
};
|
|
11289
11291
|
}
|
|
11292
|
+
function windowsAgentNote(runtime, k) {
|
|
11293
|
+
if (runtime === "claude-code") {
|
|
11294
|
+
const commands = ["irm https://claude.ai/install.ps1 | iex"];
|
|
11295
|
+
if (!windowsDirOnPath(win32.join(k.home, ".local", "bin"), k.path)) {
|
|
11296
|
+
commands.push(
|
|
11297
|
+
`$bin = "$env:USERPROFILE\\.local\\bin"`,
|
|
11298
|
+
`$p = [Environment]::GetEnvironmentVariable('PATH', 'User')`,
|
|
11299
|
+
`[Environment]::SetEnvironmentVariable('PATH', "$p;$bin", 'User')`,
|
|
11300
|
+
`$env:PATH += ";$bin"`
|
|
11301
|
+
);
|
|
11302
|
+
}
|
|
11303
|
+
commands.push("claude auth login");
|
|
11304
|
+
return {
|
|
11305
|
+
title: "Set up Claude Code",
|
|
11306
|
+
lines: [
|
|
11307
|
+
"Run these lines in PowerShell. The last one opens your browser",
|
|
11308
|
+
"to sign in with your Claude account.",
|
|
11309
|
+
"",
|
|
11310
|
+
...commands.map(indent),
|
|
11311
|
+
"",
|
|
11312
|
+
SETUP_AGAIN
|
|
11313
|
+
]
|
|
11314
|
+
};
|
|
11315
|
+
}
|
|
11316
|
+
if (runtime === "codex") {
|
|
11317
|
+
return {
|
|
11318
|
+
title: "Set up Codex",
|
|
11319
|
+
lines: [
|
|
11320
|
+
"Run these lines here. The last one opens your browser",
|
|
11321
|
+
"to sign in with your ChatGPT account.",
|
|
11322
|
+
"",
|
|
11323
|
+
indent("npm i -g @openai/codex"),
|
|
11324
|
+
indent("codex login"),
|
|
11325
|
+
"",
|
|
11326
|
+
SETUP_AGAIN
|
|
11327
|
+
]
|
|
11328
|
+
};
|
|
11329
|
+
}
|
|
11330
|
+
return {
|
|
11331
|
+
title: "Set up OpenCode",
|
|
11332
|
+
lines: [
|
|
11333
|
+
"Run the first line here. Then open a second terminal",
|
|
11334
|
+
"window, run the last line there, and leave that window open.",
|
|
11335
|
+
"",
|
|
11336
|
+
indent("npm i -g opencode-ai"),
|
|
11337
|
+
indent("opencode serve --port 4096"),
|
|
11338
|
+
"",
|
|
11339
|
+
`Then ${cabane("status")} shows it signed in; nothing else to run.`
|
|
11340
|
+
]
|
|
11341
|
+
};
|
|
11342
|
+
}
|
|
11343
|
+
function windowsDirOnPath(dir2, path) {
|
|
11344
|
+
const norm = (entry) => entry.replace(/[\\/]+$/, "").toLowerCase();
|
|
11345
|
+
return (path ?? "").split(";").some((entry) => norm(entry) === norm(dir2));
|
|
11346
|
+
}
|
|
11290
11347
|
function indent(line) {
|
|
11291
11348
|
return ` ${line}`;
|
|
11292
11349
|
}
|
package/dist/runtime.js
CHANGED
|
@@ -8875,7 +8875,7 @@ function checkReason(check) {
|
|
|
8875
8875
|
|
|
8876
8876
|
// src/harness-copy.ts
|
|
8877
8877
|
import { homedir as homedir8 } from "os";
|
|
8878
|
-
import { join as join21 } from "path";
|
|
8878
|
+
import { join as join21, win32 } from "path";
|
|
8879
8879
|
var HARNESS_LABELS = {
|
|
8880
8880
|
"claude-code": "Claude Code",
|
|
8881
8881
|
codex: "Codex",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cabane/companion",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.208",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The Cabane Companion (headless): connect an agent on your machine to your Cabane workspace as a responder — drive work against your own codebase, files, and MCP servers without putting any of it in Cabane.",
|
|
6
6
|
"license": "UNLICENSED",
|