@primusclaw/connector 0.1.4 → 0.1.6
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 +155 -38
- package/dist/cli.js +2668 -457
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,8 +41,12 @@ If npm answers `EACCES`, point its global prefix at a directory you own (`npm co
|
|
|
41
41
|
```sh
|
|
42
42
|
claw-connector init # writes agents.toml and prints where: ~/.config/claw-connector/agents.toml unless XDG_CONFIG_HOME or CLAW_CONNECTOR_HOME is set
|
|
43
43
|
claw-connector status # after you edit it: prints a "problem:" line if the file is wrong
|
|
44
|
+
claw-connector doctor # checks the machine (step 5), then starts each agent's adapter, opens a session (no prompt) and checks the modes it offers
|
|
44
45
|
```
|
|
45
46
|
|
|
47
|
+
`init` runs the adapter check of `doctor` at the end. `doctor` says `ok` for an agent whose phone sessions will open, and otherwise a
|
|
48
|
+
`problem:` line with the fix, for example an agent whose sessions would be refused with `mode_unavailable`.
|
|
49
|
+
|
|
46
50
|
By default every agent asks before it writes a file or runs a command, and your phone answers each question. To let phone sessions run
|
|
47
51
|
like your terminal instead, run `claw-connector init --approval never` (or set `approval = "never"` on an agent later); see
|
|
48
52
|
[Running without per-step approval](#running-without-per-step-approval).
|
|
@@ -80,15 +84,36 @@ claw-connector service status
|
|
|
80
84
|
|
|
81
85
|
This starts the connector now and keeps it up: at login and after a reboot, and again 5 seconds after it dies for any reason, except
|
|
82
86
|
one that only you can fix (the connector was revoked, or Claw refused the sign-in), which leaves it stopped until you run `login` again.
|
|
87
|
+
Only `claw-connector stop` (or stopping the service) stops it for good: a `kill` of the connector's process from anywhere else ends it
|
|
88
|
+
with exit 75, and it is started again.
|
|
83
89
|
It uses `systemd --user` on Linux and launchd on macOS. On Linux, run `loginctl enable-linger $USER` once (`service install` says so
|
|
84
90
|
when it is needed) so it also runs while you are logged out. In a container without systemd, `service install` starts a small
|
|
85
|
-
supervisor
|
|
86
|
-
when the supervisor is up)
|
|
91
|
+
supervisor, writes `keepalive.sh` and adds it to your crontab when a cron daemon runs; when none does it says so, and the container's
|
|
92
|
+
startup command must run that script (it does nothing when the supervisor is up) for a restarted container to come back. Keys the
|
|
93
|
+
agents read from your shell (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`...) are kept for the service in a 0600 file, never in the unit.
|
|
94
|
+
See [Keeping it running](#keeping-it-running).
|
|
87
95
|
|
|
88
96
|
To try it in the foreground instead, `claw-connector run` prints `connecting claude to https://claw.example.com/claw-api as
|
|
89
97
|
"<machine name>"` and stays up until Ctrl-C, which stops it and every agent it started.
|
|
90
98
|
|
|
91
|
-
**5.
|
|
99
|
+
**5. Check the machine**
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
claw-connector doctor
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`doctor` checks what makes a first phone session fail far from the machine that caused it, and prints one fix per problem:
|
|
106
|
+
Node.js 22 or newer; each agent's program on `PATH` (and on the `PATH` the installed service starts it with, which is not your
|
|
107
|
+
shell's); whether Claude Code and Codex are signed in (`claude auth status`, `codex login status`, or the model provider's key
|
|
108
|
+
variable in `~/.codex/config.toml`); the `roots` writable; `HTTPS_PROXY` and `https_proxy` not set to different values; a service
|
|
109
|
+
installed (and, for `keepalive.sh`, something calling it); and Claw answering, including whether Node.js trusts its certificate
|
|
110
|
+
(Node does not read the system's CA store by default: behind a company CA set `NODE_USE_SYSTEM_CA=1` or `NODE_EXTRA_CA_CERTS`). Then it
|
|
111
|
+
runs the adapter check of step 2. It exits 1 when something will stop sessions (`--json`: `ok` is the adapters' verdict,
|
|
112
|
+
`machine_ok` and `environment` the machine's). The
|
|
113
|
+
running connector repeats the machine checks with its own environment (in a child process, so a stalled disk cannot stall
|
|
114
|
+
it) every 15 minutes, and at once when `doctor` runs (it signals the connector), and Clawy's `/agents` card shows what it found under the machine ("Codex is not signed in: run `codex login` on that machine").
|
|
115
|
+
|
|
116
|
+
**6. See it in Clawy**
|
|
92
117
|
|
|
93
118
|
In Clawy (or any chat client built on Claw), send `/agents`. The agents of this machine are listed, online while `run` is up.
|
|
94
119
|
A session started there runs on this machine, inside one of your `roots`, and each permission request comes back as a card in the chat.
|
|
@@ -116,7 +141,9 @@ id = "codex"
|
|
|
116
141
|
preset = "codex"
|
|
117
142
|
roots = ["~/work/repo-a", "~/work/repo-b"]
|
|
118
143
|
[agents.env] # passed to the adapter; the model settings live here, never in Claw
|
|
119
|
-
OPENAI_API_KEY = "..." # or leave your own environment / CODEX_HOME to supply it
|
|
144
|
+
OPENAI_API_KEY = "..." # or leave your own environment / CODEX_HOME to supply it; with only a key, the
|
|
145
|
+
# connector signs Codex in with it (Codex keeps it in its auth.json, like
|
|
146
|
+
# "codex login --with-api-key")
|
|
120
147
|
|
|
121
148
|
[[agents]]
|
|
122
149
|
id = "mine"
|
|
@@ -136,10 +163,23 @@ Presets and the adapter versions they pin (override `command` and `args` to move
|
|
|
136
163
|
| `codex` | `npx @agentclientprotocol/codex-acp@2.3.0` | `read-only` | `read-only` | `agent-full-access` |
|
|
137
164
|
| `cursor` | `agent acp` (the Cursor CLI) | `ask` | `ask`, `plan` | `agent`, started as `agent --force acp` |
|
|
138
165
|
|
|
166
|
+
The pinned adapters (the `npx -y <package>@<version>` presets above) are installed once into the connector's state
|
|
167
|
+
directory (`adapters/<package>@<version>`), by `init`, by `service install` and in the background when `run` starts, and are
|
|
168
|
+
then started from there with the connector's own Node.js: a session does not wait for npx to look the package up in a
|
|
169
|
+
registry (about 70 seconds when the registry cannot be reached) or download it (Claude's adapter takes about 350 MB on
|
|
170
|
+
disk with its dependencies), and a repository's own `.npmrc` cannot pick the registry. The install uses `npm install` with your npm
|
|
171
|
+
settings (`~/.npmrc`, `npm_config_*`, an `npm_config_registry` in the agent's `env`). A session that opens while its
|
|
172
|
+
adapter is still being installed waits for it; if the install failed, the agent's npx command runs as before, in the
|
|
173
|
+
connector's state directory, and the install is tried again in the background ten minutes later. An agent with its own
|
|
174
|
+
`command` or `args` is started exactly as written.
|
|
175
|
+
|
|
139
176
|
`claude-attach` does not start new conversations: it takes over Claude Code conversations that already exist on this
|
|
140
177
|
machine (see [Taking over an existing conversation](#taking-over-an-existing-conversation)).
|
|
141
178
|
|
|
142
|
-
An agent with no `roots` is never offered. A configuration problem is reported at start-up, not skipped.
|
|
179
|
+
An agent with no `roots` is never offered. A configuration problem is reported at start-up, not skipped. A root that does
|
|
180
|
+
not exist, or whose disk does not answer (a network mount that is down or not mounted yet), is not a configuration problem:
|
|
181
|
+
`run` warns about it and keeps going, and that root's sessions are refused (`cwd_not_found`, `root_unavailable`) until it is
|
|
182
|
+
back. Reading `agents.toml` never touches a root.
|
|
143
183
|
|
|
144
184
|
## Running without per-step approval
|
|
145
185
|
|
|
@@ -165,23 +205,20 @@ unattended while Cursor keeps asking. For that agent the connector then:
|
|
|
165
205
|
`mode_update` carry `unattended`, so a client can always show whether a session asks. `status` and the line `run` prints
|
|
166
206
|
at start-up name the agents without per-step approval.
|
|
167
207
|
|
|
168
|
-
**
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
`
|
|
173
|
-
|
|
174
|
-
```
|
|
175
|
-
warning: claude: sessions will be refused (mode_not_enforced): Claude defaults to bypassPermissions here (permissions.defaultMode in /home/me/.claude/settings.json); set approval = "never" on this agent or change defaultMode
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
Choose one: `approval = "never"` on that agent (knowing the risk below), or another `defaultMode` in that file. The check
|
|
179
|
-
reads the two files from which the Claude adapter takes `bypassPermissions` (it ignores that value in a repository's
|
|
180
|
-
`.claude/settings.json` and `.claude/settings.local.json`), and only the exact spelling counts, as for the adapter; root
|
|
181
|
-
without `IS_SANDBOX` cannot use bypass, and `permissions.disableBypassPermissionsMode = "disable"` turns it off. It applies
|
|
182
|
-
to every agent that runs `claude-agent-acp` except `claude-attach`. Codex and Cursor have no equivalent: their own
|
|
208
|
+
**Your own Claude settings may default to `bypassPermissions`** (`permissions.defaultMode` in your user `settings.json`,
|
|
209
|
+
`$CLAUDE_CONFIG_DIR` or `~/.claude`, or in Claude's managed settings). For a `claude` agent that asks (no
|
|
210
|
+
`approval = "never"`), the connector tells the adapter to leave that mode out (`allowDangerouslySkipPermissions: false`),
|
|
211
|
+
so its sessions start in `default` and ask; before 0.1.5 each of them was closed with `mode_not_enforced`. An agent with
|
|
212
|
+
`approval = "never"` runs in `bypassPermissions` either way. A `claude-attach` agent takes over a conversation in the mode
|
|
213
|
+
its terminal chose and accepts the adapter's warning while it starts. Codex and Cursor have no equivalent: their own
|
|
183
214
|
settings are replaced by the mode the connector sets and reads back.
|
|
184
215
|
|
|
216
|
+
**Root.** Claude Code offers `bypassPermissions` to root only when `IS_SANDBOX` is set. For an agent that runs
|
|
217
|
+
`claude-agent-acp` with `approval = "never"` (or `allow_unsafe_modes = true`), the connector sets `IS_SANDBOX=1` in that
|
|
218
|
+
agent's adapter environment when it runs as root, and `run` prints a `note:` line saying so; nothing else gets it. Without
|
|
219
|
+
that, every phone session of such an agent was refused with `mode_unavailable`. To keep it off, set `IS_SANDBOX` yourself
|
|
220
|
+
in the agent's `[agents.env]` (an empty value is kept as it is; `status` then warns that sessions will be refused).
|
|
221
|
+
|
|
185
222
|
**The risk, in one sentence:** an agent without per-step approval acts on whatever it is told, including text it read in
|
|
186
223
|
a file or a web page, with everything your account can do inside its roots (and `--force` or full access reach outside the
|
|
187
224
|
sandbox the adapter would otherwise keep), and nobody is asked first.
|
|
@@ -209,7 +246,24 @@ All of these run on your machine and fail closed.
|
|
|
209
246
|
|
|
210
247
|
- **Directories.** A session's working directory is resolved (symlinks included) and must be inside one of the agent's
|
|
211
248
|
`roots`; otherwise no process is started and the session is closed with `cwd_outside_roots`. The agent runs in the
|
|
212
|
-
resolved path.
|
|
249
|
+
resolved path. A folder can be given the way people type it: `~` and `~/x` are the agent's home directory (its
|
|
250
|
+
`[agents.env]` `HOME`, else the connector's), and a relative name (`repo`, `repo/sub`) is looked up under each root and
|
|
251
|
+
taken when exactly one has it (`cwd_ambiguous` when several do); a root's own last segment names that root. A relative
|
|
252
|
+
name never climbs out (`..`). Every look at the disk on the way to opening a session is asynchronous with a 10-second
|
|
253
|
+
limit, so a root on a stalled network mount refuses its own sessions (`root_unavailable`), never those under a healthy
|
|
254
|
+
root, and never freezes the connector or its heartbeat. A restored session whose root does not answer is kept: its
|
|
255
|
+
commands are rejected `root_unavailable` until it does, and `close` still closes it.
|
|
256
|
+
- **Signed in before ready.** A new session of an agent that reports its sign-in (Claude Code does) and reports none is
|
|
257
|
+
refused at once with `agent_auth_required`, instead of opening and failing at its first message; a session that
|
|
258
|
+
already exists is kept and its prompts say why. A prompt refused for the same reason later
|
|
259
|
+
(an expired login) ends its turn with `error: "agent_auth_required"` and the fix, and the next prompt starts the agent
|
|
260
|
+
afresh, so a sign-in done on the machine meanwhile is picked up. An adapter that needs a sign-in and offers an
|
|
261
|
+
`api-key` method (Codex) is told to `authenticate` with it when its environment has `OPENAI_API_KEY` or `CODEX_API_KEY`;
|
|
262
|
+
the key itself is never sent, the adapter reads its own environment.
|
|
263
|
+
- **Why, in one sentence.** Every refusal (`session_closed`, `command_rejected`, and a `turn_end` that failed for a known
|
|
264
|
+
reason) carries its stable `reason` code and a `hint`: one English sentence of what to do about it (sign in with which
|
|
265
|
+
command, which folder to pick, `claw-connector doctor`), with no path and nothing secret, for a client to show beside
|
|
266
|
+
its own translation of the code.
|
|
213
267
|
- **Ask mode, read back.** After the adapter creates a session, the connector sets the agent's ask mode and reads the
|
|
214
268
|
mode back from the adapter. Your own agent settings may start an adapter in a mode that never asks (bypass, full
|
|
215
269
|
access); an adapter that does not confirm the ask mode, or that warns it will not invoke its permission callback, is
|
|
@@ -229,6 +283,9 @@ All of these run on your machine and fail closed.
|
|
|
229
283
|
which cannot write. `approval = "never"` selects `agent` and starts `agent --force acp` (`--force` is a root flag of the
|
|
230
284
|
Cursor CLI, "force allow commands unless explicitly denied"; it is accepted before or after `acp`). Cursor
|
|
231
285
|
has no `session/resume`; the connector uses `session/load` and marks the replayed history `replay: true`.
|
|
286
|
+
A Cursor agent that asks therefore answers and plans but changes no file: its capabilities say `edits: false` with an
|
|
287
|
+
`edits_hint`, `read_only_modes` lists `ask` and `plan` (each such mode in `session_started` carries `read_only: true`),
|
|
288
|
+
`run` prints a note, and the sample `agents.toml` says so above the Cursor block.
|
|
232
289
|
- **Permissions.** Each permission request becomes a card with the options **the adapter offered**, passed through with
|
|
233
290
|
their own ids and kinds (`allow_once`, `allow_always`, `reject_once`). An answer must be one of those ids; any other is refused
|
|
234
291
|
and the request stays open. An unanswered request is answered `cancelled` after 10 minutes, and a cancel,
|
|
@@ -258,6 +315,17 @@ reference, title, directory, last activity, and whether anything holds it open),
|
|
|
258
315
|
chat client can offer a choice; `session.new` then names the chosen one (`resume_ref`). Claw and the chat client know no
|
|
259
316
|
product: the agent's `kind` is the label `attach`.
|
|
260
317
|
|
|
318
|
+
**You do not have to add this agent.** Every agent made from the `claude` preset brings one with the same roots, adapter,
|
|
319
|
+
approval and environment, named `<id>-sessions`, so the conversations already on the machine show up on the phone by
|
|
320
|
+
themselves. `existing_sessions = false` on the `claude` agent turns that off; an explicit `claude-attach` agent reading the same
|
|
321
|
+
Claude config directory replaces it.
|
|
322
|
+
|
|
323
|
+
Each entry also says, for a conversation a terminal holds open, what Claude Code says that terminal is doing (`activity`:
|
|
324
|
+
`working`, `waiting` for the person at it, or `idle`; with `waiting`, `waiting_for` in its words, such as "input needed"). The
|
|
325
|
+
connector looks at Claude Code's session registry and projects directory every 10 seconds (file names and times only; nothing
|
|
326
|
+
is started) and reports a change at once instead of at the next heartbeat, so a conversation a terminal has just opened, or one
|
|
327
|
+
that starts waiting, reaches the phone within seconds.
|
|
328
|
+
|
|
261
329
|
```toml
|
|
262
330
|
[[agents]]
|
|
263
331
|
id = "claude-attach"
|
|
@@ -319,6 +387,18 @@ A transcript written within the last 10 seconds is refused too (a terminal that
|
|
|
319
387
|
`session_live`, `recently_written` and `twin_check_failed`; the agent that this connector itself started for the conversation
|
|
320
388
|
is not mistaken for a twin.
|
|
321
389
|
|
|
390
|
+
A conversation that a terminal has open when the phone asks for it is not refused but watched, read-only. Nothing is
|
|
391
|
+
started: the connector reads the transcript the terminal writes, from its end (opened read-only; nothing is ever written to it),
|
|
392
|
+
and sends each new line as the update an adapter would have sent (the user's words, the agent's words, the steps it starts
|
|
393
|
+
and how they end; thinking and sub-agents are left out), scrubbed for credentials like every event and marked `read_only`.
|
|
394
|
+
The last twenty updates already there are sent first, marked `replay`. `session_started` says `read_only: true` and
|
|
395
|
+
`read_only_reason: "session_live"`. A prompt, a mode change or a decision sent to it is refused with
|
|
396
|
+
`read_only_live_session` and reaches nothing that could write to the transcript; the server refuses them too
|
|
397
|
+
(`session_read_only`). The heartbeat still reports the conversation as `live`, and an attach agent's capabilities say `watch_live: true`, so a
|
|
398
|
+
client offers the watch only where the connector can do it. When the terminal no longer has it open the
|
|
399
|
+
watch ends (`session_closed`, reason `terminal_closed`), and taking it over is then a new session, through every check
|
|
400
|
+
above. A watched session stays read-only across a restart of the connector.
|
|
401
|
+
|
|
322
402
|
The ask mode still applies: a conversation keeps the mode it was left in, often one that never asks (`bypassPermissions`),
|
|
323
403
|
and the adapter says so while it sets the session up. That warning describes the mode that is about to be replaced, so it is
|
|
324
404
|
set aside until the ask mode (`default`) is locked and read back from the adapter; a warning that comes after that, or a mode
|
|
@@ -335,6 +415,7 @@ session stops the agent process; it never deletes the conversation.
|
|
|
335
415
|
| `run [--supervised]` | Connect and serve. Exit code 78 means starting it again will not help: the connector was revoked, Claw or the identity service refused the sign-in (at start, or for two minutes in a row while running), or there is no usable `agents.toml` or sign-in; the reason is kept in `needs-login.json`, and until `login` removes it `run` exits 78 at once without contacting Claw. `--supervised` marks a run the service started. Any other non-zero exit is worth a restart. A unit written by hand for 0.1.2 and older (`RestartPreventExitStatus=3`): replace it with `claw-connector service install`, which writes the same file. |
|
|
336
416
|
| `service install\|uninstall\|status [--supervisor systemd\|launchd\|script] [--env NAME ...]` | Keep `run` up (see [Keeping it running](#keeping-it-running)). `install` stops a `run` started by hand so the service takes over; `status` also lists the last five disconnects and why. |
|
|
337
417
|
| `status [--json]` | Running or not, paused, signed in, agents, adapter processes, the last disconnect and its reason (`last down:`), a `problem:` line when a new sign-in is needed, and a `warning:` line for each agent whose sessions will be refused because Claude's own settings default to `bypassPermissions` (see [Running without per-step approval](#running-without-per-step-approval)). |
|
|
418
|
+
| `doctor [--agent ID] [--json]` | Check this machine and print one fix per problem (see step 5 of the quick start), then each agent's adapter (step 2); exit 1 when something stops sessions. The report is kept in `doctor.json`; a running connector is signalled to check again and sends what it finds to Claw (each agent's `capabilities.health`). |
|
|
338
419
|
| `pause` / `resume` | Stop every agent within a second and stay offline, or undo that. |
|
|
339
420
|
| `stop` | Stop the running connector and every agent it started. |
|
|
340
421
|
| `logout` | Stop, revoke this machine's connector at Claw (with a key, `DELETE /v1/remote-agents/connectors/:cid`; with a device sign-in, the connector-side `POST .../connectors/:cid/revoke`), ask the identity service to revoke the sign-in, and delete it from this machine. The next sign-in registers a new connector. When Claw cannot be reached or refuses (a Claw from before the connector-side route refuses a device sign-in), the sign-in is still deleted, but `logout` says the connector was not revoked, prints the `curl` that revokes it with a Claw API key of yours, keeps its id (so a later sign-in reuses it), and exits 1. |
|
|
@@ -347,12 +428,12 @@ the connector sees it within a heartbeat, stops every agent and exits without re
|
|
|
347
428
|
|
|
348
429
|
## Files
|
|
349
430
|
|
|
350
|
-
`~/.config/claw-connector/` (or `$XDG_CONFIG_HOME/claw-connector
|
|
351
|
-
refused). `~/.local/state/claw-connector/` (or `$XDG_STATE_HOME/claw-connector/`): `connector.json` (the connector's identity and the
|
|
431
|
+
`~/.config/claw-connector/` (or `$XDG_CONFIG_HOME/claw-connector/`, or `$CLAW_CONNECTOR_CONFIG_DIR`): `agents.toml`, `credentials.json`
|
|
432
|
+
(0600; a file other users can read is refused), and `service-env.json` (0600, the agents' sign-in variables `service install` kept). `~/.local/state/claw-connector/` (or `$XDG_STATE_HOME/claw-connector/`): `connector.json` (the connector's identity and the
|
|
352
433
|
commands handled), `sessions.json`, `outbox/` (events not yet acknowledged by Claw), `audit.jsonl` (spawn, directory
|
|
353
434
|
decisions, every command received, every permission request and answer, every automatic approval, mode changes),
|
|
354
|
-
`logs/`, `children.json`, `connector.pid`, `disconnects.jsonl`, `needs-login.json` (only after a run that needs a new sign-in),
|
|
355
|
-
the script supervisor `supervisor.pid`, `keepalive.sh` and `run.log`. `CLAW_CONNECTOR_HOME=/some/dir` keeps all of it under one directory.
|
|
435
|
+
`logs/`, `children.json`, `connector.pid`, `disconnects.jsonl`, `needs-login.json` (only after a run that needs a new sign-in), `doctor.json`
|
|
436
|
+
(the last `doctor` report), and with the script supervisor `supervisor.pid`, `keepalive.sh`, `keepalive-last` (when it last ran) and `run.log`. `CLAW_CONNECTOR_HOME=/some/dir` keeps all of it under one directory.
|
|
356
437
|
|
|
357
438
|
## Keeping it running
|
|
358
439
|
|
|
@@ -365,32 +446,68 @@ the script supervisor `supervisor.pid`, `keepalive.sh` and `run.log`. `CLAW_CONN
|
|
|
365
446
|
Log: `run.log` in the state directory.
|
|
366
447
|
- **script** (a container without systemd; an `systemctl` that answers "Running in chroot" counts as none): `claw-connector supervise`
|
|
367
448
|
runs in the background and restarts the connector 5 seconds after it dies; `keepalive.sh` in the state directory starts that
|
|
368
|
-
supervisor unless it is alive (recorded pid and start time) or a sign-in is needed.
|
|
369
|
-
|
|
449
|
+
supervisor unless it is alive (recorded pid and start time) or a sign-in is needed. Where a cron daemon runs, `install` adds an
|
|
450
|
+
`@reboot` and a 5-minute line that call `keepalive.sh` to your crontab (once; `uninstall` removes them). Where none runs (most
|
|
451
|
+
containers), `install` says so: nothing brings the connector back after a restart until the container's startup command (or
|
|
452
|
+
`~/.bashrc`) runs `sh keepalive.sh`. Log: `run.log`.
|
|
453
|
+
|
|
454
|
+
**A container whose home directory does not outlive it** (a dev pod): when `agents.toml` and the sign-in sit on the container's own
|
|
455
|
+
file system (overlay, tmpfs), `init` and `service install` say so. Keep them on storage that survives the container with
|
|
456
|
+
`CLAW_CONNECTOR_CONFIG_DIR=/mnt/<your persistent volume>/claw-connector` (only the configuration and sign-in move; pid files, the outbox
|
|
457
|
+
and logs stay on the local disk), set in your shell profile and in the container's startup command, which then runs
|
|
458
|
+
`claw-connector service ensure` (after installing the package again, if it lived on the container's file system too).
|
|
370
459
|
|
|
371
460
|
A successful `login` starts an installed service again, so after a revocation or a refused key signing in is the whole fix.
|
|
372
461
|
`keepalive.sh` and the script supervisor start nothing while only a person can help (no `agents.toml`, not signed in,
|
|
373
462
|
`needs-login.json`); under launchd every exit 78 is turned into a clean exit, which launchd does not restart. The service
|
|
374
463
|
installed for a state directory is recorded in its `service.json`.
|
|
375
464
|
|
|
376
|
-
The unit carries `PATH` (so the agents are found), `CLAW_CONNECTOR_HOME`, `
|
|
377
|
-
`CODEX_HOME`, the CA and proxy variables
|
|
378
|
-
|
|
379
|
-
|
|
465
|
+
The unit carries `PATH` (so the agents are found), `CLAW_CONNECTOR_HOME`, `CLAW_CONNECTOR_CONFIG_DIR`, `XDG_CONFIG_HOME`, `XDG_STATE_HOME`,
|
|
466
|
+
`CLAUDE_CONFIG_DIR`, `CODEX_HOME`, the CA and proxy variables (with `NODE_USE_SYSTEM_CA` and `NODE_USE_ENV_PROXY`), `LANG`, `IS_SANDBOX`, the npm registry and proxy settings, and every
|
|
467
|
+
plain setting of the agents (`ANTHROPIC_*`, `CLAUDE_CODE_*`, `OPENAI_*`, `CODEX_*`, `CURSOR_*` that is not named like a credential:
|
|
468
|
+
`ANTHROPIC_BASE_URL`, `ANTHROPIC_MODEL`, `CLAUDE_CODE_USE_BEDROCK`...) from the shell that ran `install` (a proxy URL with a password in
|
|
469
|
+
it only when named with `--env`, e.g. `--env HTTPS_PROXY`); `--env NAME` adds another.
|
|
470
|
+
|
|
471
|
+
The agents' own sign-in variables are never written into a unit. When the shell that runs `install` has `ANTHROPIC_API_KEY`,
|
|
472
|
+
`ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_OAUTH_TOKEN`, `ANTHROPIC_CUSTOM_HEADERS`, `OPENAI_API_KEY`, `CODEX_API_KEY`, `CURSOR_API_KEY`, the
|
|
473
|
+
AWS keys, a variable Codex's `config.toml` names as a provider's `env_key`, or an `--env` name that looks like a credential (`KEY`,
|
|
474
|
+
`TOKEN`, `SECRET`, `PASSWORD`, `CREDENTIAL`), they are kept in `service-env.json` beside `credentials.json` (mode 0600) and every `run`
|
|
475
|
+
gives them to the agents that do not set them in `[agents.env]` (a configuration directory its group or others may write is first made 0700; one owned by another account is refused). `install` prints their names, never their values; `service status`
|
|
476
|
+
lists them; `uninstall` deletes the file. Without this a connector that works in a terminal loses its agents' sign-in as a service,
|
|
477
|
+
and each session fails at its first message. `CLAW_CONNECTOR_KEY` is never copied. Run `install` again after changing any of them, or
|
|
478
|
+
after moving Node. With a service installed, `claw-connector stop` stops the connector until the next login,
|
|
380
479
|
boot or keep-alive check; to stay offline use `pause`, or `service uninstall`.
|
|
381
480
|
|
|
382
481
|
**Why it went down.** Every disconnect is appended to `disconnects.jsonl` in the state directory: `server_closed` (a Claw release or
|
|
383
482
|
restart, `superseded` by another run, `token_expired`; reconnected at once), `stream_lost` (the network, with the error), `stopped`,
|
|
384
|
-
`revoked`, `auth_failed`, `failed`,
|
|
385
|
-
dated by its last heartbeat)
|
|
483
|
+
`revoked`, `auth_failed`, `failed`, `process_died` (the previous run never shut down: killed, crashed or the machine restarted;
|
|
484
|
+
dated by its last heartbeat), and `connector_limit_reached` (Claw already holds the most connectors one person may have: remove a
|
|
485
|
+
machine you no longer use, in the chat with `/agents` or with `claw-connector logout` on it; the run stays up and tries again every 10
|
|
486
|
+
minutes instead of being restarted every 5 seconds). `status` shows the latest, `service status` the last five.
|
|
386
487
|
|
|
387
488
|
## Restarts and crashes
|
|
388
489
|
|
|
389
|
-
A prompt counts as handled only when it reaches the agent (or is dropped by a cancel
|
|
390
|
-
dies with a prompt still queued is sent that prompt again by Claw instead of
|
|
391
|
-
for an answer lives in the adapter, which dies with the connector: the next run
|
|
392
|
-
`connector_restart`), so a phone is not left with a button that does nothing. Session
|
|
393
|
-
their sequence numbers are on disk; a session resumes in a fresh adapter on its next prompt
|
|
490
|
+
A prompt counts as handled only when it reaches the agent (or is dropped by a cancel or a close), so a connector that
|
|
491
|
+
dies, or is stopped or restarted by its supervisor, with a prompt still queued is sent that prompt again by Claw instead of
|
|
492
|
+
losing it. A permission request waiting for an answer lives in the adapter, which dies with the connector: the next run
|
|
493
|
+
closes such a card (`cancelled`, by `connector_restart`), so a phone is not left with a button that does nothing. Session
|
|
494
|
+
state, unacknowledged events and their sequence numbers are on disk; a session resumes in a fresh adapter on its next prompt
|
|
495
|
+
(Claude Code's `session/resume`, the conversation intact).
|
|
496
|
+
|
|
497
|
+
The turn an agent is running is on disk too, from the moment its prompt reaches the agent until its `turn_end`. The next run
|
|
498
|
+
(after a crash, a kill, a pod restart, `stop`, or an upgrade) finds it and:
|
|
499
|
+
|
|
500
|
+
- carries it on when the agent was waiting for a person's permission for a tool call (not a plan or a question card), the agent
|
|
501
|
+
always asks (no `approval = "never"`, no `allow_unsafe_modes`) and its session was in a mode that asks, the connector is not
|
|
502
|
+
paused, and it was away no longer than a card lives (10 minutes): the agent is told the connector restarted and to go on, so
|
|
503
|
+
it asks again and a new card comes; the prompt's own `turn_end` still ends it. It only asks, so nothing runs that nobody
|
|
504
|
+
approved. Nothing is carried on before the run has signed in (a revoked connector carries on nothing);
|
|
505
|
+
- otherwise ends it with `turn_end` `{"stopReason": "error", "error": "connector_restarted"}`, naming its prompt (`cmd_id`,
|
|
506
|
+
`cmd_seq`), so a phone stops waiting for it. The agent is not re-run by itself; the next message resumes the conversation.
|
|
507
|
+
|
|
508
|
+
Every session used in the last 4 hours, and every one with a turn found this way, then gets one `session_recovered` event
|
|
509
|
+
(`interrupted`: a turn was cut off; `continuing`: it is being carried on; `cmd_id` and `cmd_seq` of that turn), which a chat
|
|
510
|
+
shows as "recovered". A stop by the kill switch (`pause`, a revocation) still ends every turn and drops the queue.
|
|
394
511
|
|
|
395
512
|
Known limit: the working-directory check resolves the path and starts the adapter in the resolved path, but another process of
|
|
396
513
|
the same user that can rewrite a directory in that path could swap a symlink between the check and the start. The
|