@cabane/companion 0.6.185 → 0.6.187
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 +31 -50
- package/dist/cli.js +1166 -3746
- package/dist/launch.js +12 -61
- package/dist/pairing-config.js +52 -63
- package/dist/runtime.js +947 -5617
- package/dist/static/app.js +1 -2
- package/dist/static/styles.css +0 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -14,19 +14,18 @@ Three things, one relation each.
|
|
|
14
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
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
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
|
|
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
18
|
|
|
19
19
|
How a turn runs, top to bottom:
|
|
20
20
|
|
|
21
|
-
| Layer | Holds
|
|
22
|
-
| ------------- |
|
|
23
|
-
| **Cabane** | The agent
|
|
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
|
-
| **
|
|
27
|
-
| **Harness** | Claude Code, Codex or OpenCode with its normal tools. Nothing is removed by name; the sandbox is enforced by the operating system around the process, never by a list of tool names. Nothing asks for permission mid-task. |
|
|
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. |
|
|
28
27
|
|
|
29
|
-
> **An agent
|
|
28
|
+
> **An agent on this device reaches the whole device.** It runs the device's harness with its tools and the files there, and no approval prompts. Put agents on a device where that reach is acceptable. To confine them, set the harness's own sandbox, or isolate the Companion (see Isolation). An agent that reads untrusted input (public web, inbound mail, outside members) runs on a Companion that is isolated, whatever the device.
|
|
30
29
|
|
|
31
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.
|
|
32
31
|
|
|
@@ -71,17 +70,17 @@ If `cabane` isn't found afterwards, open a new terminal, or run the `source` lin
|
|
|
71
70
|
|
|
72
71
|
## Commands
|
|
73
72
|
|
|
74
|
-
| Command | What it does
|
|
75
|
-
| ------------------------------------ |
|
|
76
|
-
| `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.
|
|
77
|
-
| `start [--foreground]` | Run in the background. Never asks. Unpaired, it names `setup`. `--foreground` stays attached, for a supervisor of your own.
|
|
78
|
-
| `stop` | Stop a running Companion cleanly. Ends any turn in progress.
|
|
79
|
-
| `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,
|
|
80
|
-
| `update [--auto on\|off]` | Install the version Cabane names now; with `--auto`, set whether the Companion keeps itself up to date.
|
|
81
|
-
| `service install\|uninstall\|status` | Run as a systemd user service or a LaunchAgent that starts at boot and restarts if it stops; remove it; show its state.
|
|
82
|
-
| `logs [-n N] [-f]` | Recent log lines, or follow.
|
|
83
|
-
| `transcript [file] [--last] [-f]` | Read back a full agent turn, tool calls and results included.
|
|
84
|
-
| `logout [--purge]` | Remove the device token and cached agent credentials. Doesn't remove the device from Cabane.
|
|
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]` | Run in the background. Never asks. Unpaired, it names `setup`. `--foreground` stays attached, for a supervisor of your own. |
|
|
77
|
+
| `stop` | Stop a running Companion cleanly. Ends any turn in progress. |
|
|
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 boot and restarts if it stops; remove it; show its state. |
|
|
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. |
|
|
85
84
|
|
|
86
85
|
Anything else about a device is done in Cabane, on the device's page.
|
|
87
86
|
|
|
@@ -99,7 +98,8 @@ All of it in `~/.cabane/`, mode 600, no database. Cabane is the source of truth
|
|
|
99
98
|
|
|
100
99
|
```
|
|
101
100
|
~/.cabane/
|
|
102
|
-
├── config.json # pairing, local overrides
|
|
101
|
+
├── config.json # pairing, local overrides
|
|
102
|
+
├── work/ # a directory per agent and conversation, for agents with no folder of their own
|
|
103
103
|
├── credentials.json # per-agent workspace-bound credentials, delivered once
|
|
104
104
|
├── secrets.json # { NAME: "value" } for ${NAME} placeholders
|
|
105
105
|
├── transcripts/ # one JSONL per turn, newest ~200 kept, local only
|
|
@@ -116,41 +116,22 @@ An MCP server configured in Cabane names its credential as `${NAME}`; the value
|
|
|
116
116
|
`config.json` can carry, per agent (keyed by id, `@username` or `workspace-slug/username`) or for the whole device:
|
|
117
117
|
|
|
118
118
|
- `cwd`: wins over the agent's **Starts in** folder set in Cabane.
|
|
119
|
-
- `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.
|
|
119
|
+
- `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.
|
|
120
|
+
- `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.
|
|
120
121
|
- `harnesses`: an allowlist such as `["claude-code"]`; absent means all three.
|
|
121
122
|
- `claudeCode.autoMemory`: Claude Code's local memory directory is off by default on every Companion, because notes belong in the workspace where others can read them. `true` hands it back.
|
|
122
123
|
|
|
123
|
-
A malformed block fails `cabane start` with the field named.
|
|
124
|
-
|
|
125
|
-
### Sandbox
|
|
126
|
-
|
|
127
|
-
```jsonc
|
|
128
|
-
{
|
|
129
|
-
"runners": {
|
|
130
|
-
"enabled": true,
|
|
131
|
-
"sandbox": "os", // or "provider": "docker", where the container is the sandbox
|
|
132
|
-
"policy": {
|
|
133
|
-
"hosts": { "allow": ["gitlab.example.com"], "deny": [], "defaults": true },
|
|
134
|
-
"filesystem": { "mode": "blocklist", "denyRead": [], "allowRead": [], "allowWrite": [] },
|
|
135
|
-
"credentials": {
|
|
136
|
-
"env": { "GH_TOKEN": { "secret": "${GITHUB_TOKEN}", "hosts": ["api.github.com"] } },
|
|
137
|
-
"git": [{ "host": "github.com", "secret": "${GITHUB_TOKEN}" }],
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
}
|
|
142
|
-
```
|
|
124
|
+
A malformed block fails `cabane start` with the field named. A `runners` block or a row's `sandbox` from an older Companion is ignored, with one line in the log naming it.
|
|
143
125
|
|
|
144
|
-
|
|
126
|
+
### Isolation
|
|
145
127
|
|
|
146
|
-
|
|
147
|
-
- **Reads**: everything except known credential locations (`~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.config/gh`, `~/.netrc`, `~/.npmrc`, `~/.kube`, cloud CLI configs, every Companion's own `~/.cabane` and the harness logins beside it) plus your `denyRead` globs. `.env` files are readable unless you deny them. `"mode": "strict"` hides the whole home except the working directory, the harness state and your `allowRead` list; name your toolchains there.
|
|
148
|
-
- **Writes**: the working directory, the temp dir, the harness's own state, plus `allowWrite`.
|
|
149
|
-
- **Credentials**: an entry sets the variable to a placeholder inside the sandbox and the proxy swaps the real value in only on requests to the hosts named. The harness never holds the token. A `git` entry does the same for HTTPS remotes (`~/.ssh` is unreadable, so use HTTPS).
|
|
128
|
+
The Companion does no sandboxing, and Cabane has no setting for it. Every agent runs the device's harness with its tools, settings and the files there. Confining agents is set in each harness's own file, and governs your own sessions there as well as every agent on the device:
|
|
150
129
|
|
|
151
|
-
|
|
130
|
+
- **Claude Code**, `~/.claude/settings.json`: `"sandbox": { "enabled": true, "allowUnsandboxedCommands": false, "failIfUnavailable": true }`. Commands can then write only in the agent's folder, the temp folder and the paths you add, and reach only the hosts you allow; reads stay open unless you deny them, and Claude's own file tools obey permission `deny` rules, not the sandbox. Set `allowUnsandboxedCommands: false`: when a sandboxed command fails the model can retry it unsandboxed, and on a Cabane turn there is nobody to ask, so the retry would be approved. `failIfUnavailable` stops commands running unsandboxed when bubblewrap is missing.
|
|
131
|
+
- **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.
|
|
132
|
+
- **OpenCode** is your own `opencode serve`.
|
|
152
133
|
|
|
153
|
-
|
|
134
|
+
For agents stricter than you, run the Companion as a second user account, with its own `~/.claude` and `~/.codex`, or run it somewhere isolated: a container, a VM, or a machine that exists for agents. Only that also covers what neither sandbox touches: MCP servers, hooks, the harness process and reads. Recipes for that follow.
|
|
154
135
|
|
|
155
136
|
## Debugging a turn
|
|
156
137
|
|
|
@@ -167,4 +148,4 @@ cabane logs -f # follow the log
|
|
|
167
148
|
|
|
168
149
|
## Not yet
|
|
169
150
|
|
|
170
|
-
Windows has no service install and no self-update. There is no per-tool permissioning
|
|
151
|
+
Windows has no service install and no self-update. There is no per-tool permissioning in Cabane: an agent on a device reaches the whole device, and the harness's own settings are the harness's.
|