session-peer 0.6.2__tar.gz → 0.7.0__tar.gz
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.
- {session_peer-0.6.2 → session_peer-0.7.0}/PKG-INFO +152 -29
- {session_peer-0.6.2 → session_peer-0.7.0}/README.md +151 -28
- {session_peer-0.6.2 → session_peer-0.7.0}/session_peer.py +1075 -57
- {session_peer-0.6.2 → session_peer-0.7.0}/.gitignore +0 -0
- {session_peer-0.6.2 → session_peer-0.7.0}/LICENSE +0 -0
- {session_peer-0.6.2 → session_peer-0.7.0}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: session-peer
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Message coding agent sessions locally and over SSH
|
|
5
5
|
Project-URL: Homepage, https://github.com/abruption/session-peer
|
|
6
6
|
Project-URL: Repository, https://github.com/abruption/session-peer
|
|
@@ -150,6 +150,9 @@ session-peer list # Claude sessions on this mac
|
|
|
150
150
|
session-peer list --host web-01 # Claude sessions over there
|
|
151
151
|
session-peer list --host web-01 --all # Claude stale records / no inbox
|
|
152
152
|
session-peer list --agent codex --all # include archived Codex threads
|
|
153
|
+
session-peer doctor # local inbox/tool/home diagnostics
|
|
154
|
+
session-peer doctor --host web-01 # run the same checks there
|
|
155
|
+
session-peer doctor --host web-01 --check-return-route # also test SSH back here
|
|
153
156
|
|
|
154
157
|
session-peer send --to api-worker "message" # local session
|
|
155
158
|
session-peer send --host web-01 --to api-worker "message"
|
|
@@ -159,6 +162,7 @@ git log --oneline -5 | session-peer send --host web-01 --to api-worker - # std
|
|
|
159
162
|
|
|
160
163
|
session-peer send --host web-01 --to api-worker --dry-run "x" # resolve only
|
|
161
164
|
session-peer list --host web-01 --json # machine-readable
|
|
165
|
+
session-peer list --no-update-notice # disable cached update notices/checks
|
|
162
166
|
|
|
163
167
|
session-peer send --host web-01 --ssh-opt=-p --ssh-opt=2222 --to api-worker "..." # note the '='
|
|
164
168
|
|
|
@@ -177,6 +181,7 @@ From: codex:01a08dd6-d3f6-7783-a62b-52c1fd049181 @ abruptly@mac-mini-m4.example.
|
|
|
177
181
|
message
|
|
178
182
|
|
|
179
183
|
---
|
|
184
|
+
Reply-To: session-peer://v1/reply?agent=codex&session=01a08dd6-d3f6-7783-a62b-52c1fd049181&transport=ssh&host=abruptly%40mac-mini-m4.example.ts.net
|
|
180
185
|
Reply: python3 /path/to/session_peer.py send --host abruptly@mac-mini-m4.example.ts.net --to codex:01a08dd6-d3f6-7783-a62b-52c1fd049181 --no-reply-to
|
|
181
186
|
```
|
|
182
187
|
|
|
@@ -185,12 +190,83 @@ best-effort text derived from the current process environment; it is not an
|
|
|
185
190
|
authentication claim. A plain shell has no agent identity to advertise.
|
|
186
191
|
When the original target is on the same machine and the reply route was detected
|
|
187
192
|
automatically, the generated command omits `--host` and delivers locally. An
|
|
188
|
-
explicit `--reply-to` or configured reply host
|
|
189
|
-
|
|
193
|
+
explicit `--reply-to` or configured reply host is also normalized when it names
|
|
194
|
+
the current OS user on this machine. Other explicit routes and actual remote
|
|
195
|
+
sends continue to advertise an SSH route.
|
|
196
|
+
|
|
197
|
+
`Reply-To` is the canonical, versioned address. Pass the complete URI back as
|
|
198
|
+
`--to`; session-peer validates every field and chooses local or SSH delivery:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
session-peer send --to 'session-peer://v1/reply?agent=claude&session=api-worker&transport=local' 'done'
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The `Reply:` command remains for compatibility. Treat both forms as untrusted
|
|
205
|
+
input: use the URI with session-peer rather than evaluating or sourcing it. A
|
|
206
|
+
URI that points to the current OS user on this machine is normalized to local
|
|
207
|
+
delivery, avoiding an unnecessary self-SSH authentication path. Codex addresses
|
|
208
|
+
may include an encoded `codexHome` when the sender environment identifies it.
|
|
190
209
|
|
|
191
210
|
Repeat `--host` to operate on several SSH destinations. `--json` is available on
|
|
192
|
-
`list`, `send`, and `update
|
|
193
|
-
|
|
211
|
+
`list`, `send`, `doctor`, and `update`.
|
|
212
|
+
|
|
213
|
+
### JSON response contract
|
|
214
|
+
|
|
215
|
+
Every JSON result object starts with the same schema-versioned envelope:
|
|
216
|
+
|
|
217
|
+
```json
|
|
218
|
+
{
|
|
219
|
+
"schemaVersion": 1,
|
|
220
|
+
"ok": true,
|
|
221
|
+
"host": "mac-mini.example.ts.net",
|
|
222
|
+
"command": "list",
|
|
223
|
+
"sessions": [],
|
|
224
|
+
"version": "0.7.0"
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
- `schemaVersion` versions the common envelope. Command-specific nested schemas
|
|
229
|
+
such as `clientUpdate` and `codexHomeResolution` carry their own versions.
|
|
230
|
+
- `ok` is present on every success and failure. A nonzero process exit can still
|
|
231
|
+
contain successful results for other hosts.
|
|
232
|
+
- `host` identifies the destination to which that result applies. Local results
|
|
233
|
+
use the OS hostname. Tailscale-resolved destinations use the verified MagicDNS
|
|
234
|
+
identity; `sshHost` preserves a different caller-supplied SSH alias.
|
|
235
|
+
- `command` is `list`, `send`, `doctor`, or `update`. Remaining fields are that command's
|
|
236
|
+
payload, and failures add `error` plus any structured diagnostic fields.
|
|
237
|
+
|
|
238
|
+
A local or one-host invocation emits one object. Repeating `--host` emits an
|
|
239
|
+
array of these same independently attributable objects in request order. A
|
|
240
|
+
failure that occurs before connecting, such as invalid message input, is still
|
|
241
|
+
emitted once per requested destination. This cardinality is shared by all four
|
|
242
|
+
commands, so consumers can branch only on object versus array and then use the
|
|
243
|
+
same envelope fields.
|
|
244
|
+
|
|
245
|
+
Normal commands read a dedicated 24-hour update cache. A missing, expired, or
|
|
246
|
+
invalid cache starts one detached best-effort GitHub refresh and never delays or
|
|
247
|
+
changes the requested command. When a fresh cache proves that the invoking CLI is
|
|
248
|
+
behind a stable release, JSON results add `clientUpdate`:
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"clientUpdate": {
|
|
253
|
+
"schemaVersion": 1,
|
|
254
|
+
"status": "available",
|
|
255
|
+
"current": "0.7.0",
|
|
256
|
+
"latest": "0.7.1",
|
|
257
|
+
"checkedAt": "2026-09-16T10:00:00Z",
|
|
258
|
+
"source": "github_release_cache",
|
|
259
|
+
"command": "session-peer update"
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Human output gets the same short guidance on stderr. The field is omitted when
|
|
265
|
+
the client is current, the cache is unavailable or stale, the host is offline,
|
|
266
|
+
or notices are disabled, so absence alone does not prove the client is current.
|
|
267
|
+
For multi-host commands the fact remains scoped to the one invoking CLI and is
|
|
268
|
+
copied into each result object; destination `remoteVersion` fields keep
|
|
269
|
+
their separate meaning. Remote subprocesses do not perform their own refresh.
|
|
194
270
|
|
|
195
271
|
When local `tailscale status --json` identifies a `--host` by device hostname,
|
|
196
272
|
short MagicDNS name, full MagicDNS name, or Tailscale IP, session-peer verifies and
|
|
@@ -239,8 +315,10 @@ pipx upgrade session-peer
|
|
|
239
315
|
# or, in its virtual environment: python -m pip install --upgrade session-peer
|
|
240
316
|
```
|
|
241
317
|
|
|
242
|
-
For these installs, local `session-peer update`
|
|
243
|
-
package-
|
|
318
|
+
For these installs, local `session-peer update` prints package-manager guidance
|
|
319
|
+
without replacing package-owned files. `session-peer update --check` checks the
|
|
320
|
+
latest stable GitHub release, refreshes the shared cache, and reports the exact
|
|
321
|
+
upgrade command, but still does not replace those files.
|
|
244
322
|
|
|
245
323
|
For standalone programs:
|
|
246
324
|
|
|
@@ -261,6 +339,8 @@ package-managed remote CLI, upgrade it with its own manager on that host instead
|
|
|
261
339
|
|
|
262
340
|
Neither local nor remote `update` refreshes the Claude skill. Re-run `install.sh`
|
|
263
341
|
from the desired release checkout to refresh both standalone program and skill.
|
|
342
|
+
Local `session-peer update --check` and `session-peer update` also populate the
|
|
343
|
+
same cache used by automatic notices.
|
|
264
344
|
|
|
265
345
|
### Environment variables
|
|
266
346
|
|
|
@@ -272,6 +352,8 @@ from the desired release checkout to refresh both standalone program and skill.
|
|
|
272
352
|
| `ANTHROPIC_CONFIG_DIR` | Fallback if `CLAUDE_CONFIG_DIR` is unset. |
|
|
273
353
|
| `CODEX_HOME` | Codex discovery/queue home (default `~/.codex`); overridden by `--codex-home`. |
|
|
274
354
|
| `SESSION_PEER_CODEX_HOMES` | Additional destination homes to check for duplicate thread UUIDs and stable live writers before an implicit send/dry-run. JSON array of absolute paths (or `~/…`), not a shell command or a path-separated list. It does not merge listings; an unambiguous active writer may change the implicit send home. |
|
|
355
|
+
| `SESSION_PEER_NO_UPDATE_NOTICE` | Set to `1`, `true`, `yes`, or `on` to disable automatic cached update notices and background refreshes. The per-command equivalent is `--no-update-notice`. Explicit `session-peer update --check` still checks. |
|
|
356
|
+
| `XDG_CACHE_HOME` | Base directory for the update cache; otherwise `~/.cache/session-peer/update.json` is used. |
|
|
275
357
|
|
|
276
358
|
With `--host`, discovery uses the destination's environment; local environment
|
|
277
359
|
variables are not automatically forwarded. `--codex-home` and `--codex-bin`
|
|
@@ -356,7 +438,8 @@ environment inspection, and process arguments are not exposed. Activity
|
|
|
356
438
|
inspection runs on the destination machine, including over SSH. Platforms
|
|
357
439
|
without POSIX `flock` or `lsof` cannot automatically resolve competing homes and
|
|
358
440
|
must use `--codex-home`. Unconfigured/custom layouts and copies created after the
|
|
359
|
-
check can still be missed.
|
|
441
|
+
check can still be missed. Use `session-peer doctor` to inspect the selected home,
|
|
442
|
+
bounded candidates, executable, and supported state DB schema without submitting.
|
|
360
443
|
|
|
361
444
|
### Submission and JSON results
|
|
362
445
|
|
|
@@ -373,15 +456,17 @@ session-peer portability policy rather than a measured Codex server limit. NUL
|
|
|
373
456
|
characters cannot be passed as CLI arguments. `--dry-run` verifies the executable
|
|
374
457
|
and saved target without queueing but cannot guarantee a later submission will succeed.
|
|
375
458
|
|
|
376
|
-
Local Codex list JSON
|
|
377
|
-
|
|
459
|
+
Local Codex list JSON uses the common response envelope and includes `sessions`,
|
|
460
|
+
`version`, and the resolved absolute `codexHome`. Each session entry has
|
|
378
461
|
`agent`, `id`, `name` (first line, at most 120 characters), `cwd`, `updatedAt`
|
|
379
|
-
(Unix seconds), and `archived`.
|
|
380
|
-
|
|
381
|
-
|
|
462
|
+
(Unix seconds), and `archived`. Each successful remote result includes
|
|
463
|
+
`sessions`, `version`, `codexHome`, and an optional `remoteVersion` for an
|
|
464
|
+
installed standalone copy. One remote host returns an object; repeated hosts
|
|
465
|
+
return an array.
|
|
382
466
|
|
|
383
|
-
Codex send JSON
|
|
384
|
-
under dry-run), `
|
|
467
|
+
Within the common envelope, Codex send JSON includes `target: {agent, id}`,
|
|
468
|
+
`status: queued` (or `validated` under dry-run), `chars`, `dryRun`, and optional
|
|
469
|
+
`queueId`. It also includes:
|
|
385
470
|
|
|
386
471
|
- `codexHome`: the resolved absolute destination home, not a sender-side guess.
|
|
387
472
|
- `codexHomeResolution`: schema-versioned `status`, `selected`, `reason`, and
|
|
@@ -391,21 +476,40 @@ under dry-run), `ok`, `chars`, `dryRun`, and optional `queueId`. It adds:
|
|
|
391
476
|
- `submitted`: `true` only after successful queue CLI completion, `false` for dry-run.
|
|
392
477
|
- `consumptionConfirmed`: always `false`; neither queued nor validated establishes consumption.
|
|
393
478
|
|
|
394
|
-
Errors
|
|
395
|
-
|
|
479
|
+
Errors set the common envelope's `ok` to `false`, add `error`, and include
|
|
480
|
+
`codexHomeResolution` when home evidence caused the failure.
|
|
396
481
|
A timeout has an unknown submission outcome; missing `submitted` on an error
|
|
397
482
|
must not be interpreted as proof that nothing was queued. Listing results do
|
|
398
|
-
not describe a submission and have no submission/consumption fields.
|
|
399
|
-
are additive, not the cross-command envelope redesign tracked in [#29](https://github.com/abruption/session-peer/issues/29).
|
|
483
|
+
not describe a submission and have no submission/consumption fields.
|
|
400
484
|
|
|
401
|
-
|
|
402
|
-
|
|
485
|
+
For every command, one remote host returns a flat object and multiple hosts
|
|
486
|
+
return an array. When `CODEX_THREAD_ID` (or the compatibility
|
|
403
487
|
fallback `CODEX_SESSION_ID`) is present, the message envelope and reply command
|
|
404
488
|
identify the originating Codex thread.
|
|
405
489
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
490
|
+
### Diagnostics and reply observation
|
|
491
|
+
|
|
492
|
+
`doctor` performs read-only checks on the machine that owns the sessions. It
|
|
493
|
+
reports Claude's configured sessions directory and inbox availability, Codex's
|
|
494
|
+
executable and bounded home/state DB candidates, unsupported DB schemas, and
|
|
495
|
+
permission or unknown failures as distinct codes. It does not connect to an
|
|
496
|
+
inbox, write a queue, scan arbitrary directories, or alter agent/SSH settings.
|
|
497
|
+
|
|
498
|
+
Reverse SSH is checked only with `--check-return-route`. The destination runs a
|
|
499
|
+
fixed `ssh ... true` probe with prompts, password authentication, host-key
|
|
500
|
+
enrollment, and config mutation disabled. Forward SSH success is never reused as
|
|
501
|
+
proof that the reverse path works. Use `--reply-to USER@HOST` when automatic
|
|
502
|
+
Tailscale detection cannot identify the origin. JSON details and status values
|
|
503
|
+
are documented in [docs/diagnostics.md](docs/diagnostics.md).
|
|
504
|
+
|
|
505
|
+
There is deliberately no general `--wait`. Claude Code has a native
|
|
506
|
+
same-machine `notify_when_idle` facility, but it does not cover remote sessions,
|
|
507
|
+
subagents, or Codex, and a successful socket/queue submission is not an
|
|
508
|
+
acknowledgement. session-peer therefore reports
|
|
509
|
+
`capabilities.replyObservation.status: unsupported` instead of tailing mutable
|
|
510
|
+
transcripts and risking a false match. Ask the target to send an explicit reply
|
|
511
|
+
to the supplied `Reply-To` address when completion matters. Optional wake remains
|
|
512
|
+
tracked in [#46](https://github.com/abruption/session-peer/issues/46).
|
|
409
513
|
|
|
410
514
|
## Moving from cc-peer
|
|
411
515
|
|
|
@@ -508,9 +612,10 @@ not as the user typing approval.
|
|
|
508
612
|
Outside that context, it may omit it. This is not an authenticated identity
|
|
509
613
|
protocol; environment variables and session registries are local hints.
|
|
510
614
|
- **Advertised replies need a working return path.** When an agent sender and
|
|
511
|
-
reply host can be determined, a `Reply:` line
|
|
512
|
-
Forward SSH success does not prove reverse SSH
|
|
513
|
-
|
|
615
|
+
reply host can be determined, `Reply-To` and a compatibility `Reply:` line
|
|
616
|
+
describe a return route. Forward SSH success does not prove reverse SSH
|
|
617
|
+
access; use the opt-in doctor check. The address grants no access and
|
|
618
|
+
session-peer does not correlate or wait for a reply.
|
|
514
619
|
- **Tailscale status is a local routing hint.** A known online peer is addressed
|
|
515
620
|
by its current MagicDNS name and a known offline peer is rejected before SSH.
|
|
516
621
|
An unknown destination remains ordinary SSH; session-peer does not claim that
|
|
@@ -525,7 +630,8 @@ not as the user typing approval.
|
|
|
525
630
|
- **Windows support.** Claude's named pipe transport is supported.
|
|
526
631
|
`install.sh` and the standalone remote installer/updater use POSIX shell;
|
|
527
632
|
use a Python package manager on native Windows. Live Codex verification
|
|
528
|
-
|
|
633
|
+
remains macOS-only; the Codex home, Reply-To, doctor, and JSON fixtures run in
|
|
634
|
+
Windows CI.
|
|
529
635
|
|
|
530
636
|
## Tests
|
|
531
637
|
|
|
@@ -533,7 +639,7 @@ not as the user typing approval.
|
|
|
533
639
|
python3 -m unittest discover -s tests -v
|
|
534
640
|
```
|
|
535
641
|
|
|
536
|
-
The suite needs no live agent, SSH server or network. It includes legacy
|
|
642
|
+
The default suite needs no live agent, SSH server or network. It includes legacy
|
|
537
643
|
compatibility tests, shared CLI helpers, fixture-based Codex discovery and queue
|
|
538
644
|
subprocess tests, and isolated standalone installation/coexistence checks.
|
|
539
645
|
Codex coverage includes argv/payload handling, destination home selection,
|
|
@@ -544,6 +650,9 @@ homes, unique/multiple/changing writer evidence, fail-closed inventory errors,
|
|
|
544
650
|
explicit selection, alias deduplication, single-home compatibility and structured
|
|
545
651
|
home/submission metadata. They never infer a live writer from a saved row or
|
|
546
652
|
submit messages to real sessions.
|
|
653
|
+
Update-notice coverage checks freshness and expiry, strict stable versions,
|
|
654
|
+
atomic private writes, single-flight background refresh, opt-out behavior,
|
|
655
|
+
package-manager guidance, multi-host scope, and failure isolation.
|
|
547
656
|
|
|
548
657
|
CI runs tests on Ubuntu/macOS with Python 3.9 and 3.13, and Windows with Python
|
|
549
658
|
3.13 (POSIX installer tests are skipped there). Separate jobs check shell syntax
|
|
@@ -554,6 +663,20 @@ tests remain tracked in [#28](https://github.com/abruption/session-peer/issues/2
|
|
|
554
663
|
|
|
555
664
|
## Verified
|
|
556
665
|
|
|
666
|
+
### session-peer v0.7.0 (2026-09-16)
|
|
667
|
+
|
|
668
|
+
- 240 local tests passed for cached update notices, the shared JSON envelope,
|
|
669
|
+
read-only diagnostics, structured Reply-To parsing/routing, same-machine
|
|
670
|
+
normalization, and opt-in reverse-route classification.
|
|
671
|
+
- CI covers Ubuntu and macOS with Python 3.9/3.13, Windows with Python 3.13,
|
|
672
|
+
package build and isolated installs, standalone install smoke tests, shellcheck,
|
|
673
|
+
and secret scanning.
|
|
674
|
+
- Wheel and sdist contents were inspected and installed independently. Both
|
|
675
|
+
artifacts report v0.7.0 and exclude the frozen legacy `cc_peer.py`.
|
|
676
|
+
- A real SSH doctor run found Claude inboxes and bounded default/Orca Codex homes.
|
|
677
|
+
Its opt-in reverse probe reported authentication failure independently of the
|
|
678
|
+
successful forward connection. No live message was submitted.
|
|
679
|
+
|
|
557
680
|
### session-peer v0.6.2 (2026-09-15)
|
|
558
681
|
|
|
559
682
|
- 198 local tests and the release build checks passed for UUID-specific Codex
|
|
@@ -121,6 +121,9 @@ session-peer list # Claude sessions on this mac
|
|
|
121
121
|
session-peer list --host web-01 # Claude sessions over there
|
|
122
122
|
session-peer list --host web-01 --all # Claude stale records / no inbox
|
|
123
123
|
session-peer list --agent codex --all # include archived Codex threads
|
|
124
|
+
session-peer doctor # local inbox/tool/home diagnostics
|
|
125
|
+
session-peer doctor --host web-01 # run the same checks there
|
|
126
|
+
session-peer doctor --host web-01 --check-return-route # also test SSH back here
|
|
124
127
|
|
|
125
128
|
session-peer send --to api-worker "message" # local session
|
|
126
129
|
session-peer send --host web-01 --to api-worker "message"
|
|
@@ -130,6 +133,7 @@ git log --oneline -5 | session-peer send --host web-01 --to api-worker - # std
|
|
|
130
133
|
|
|
131
134
|
session-peer send --host web-01 --to api-worker --dry-run "x" # resolve only
|
|
132
135
|
session-peer list --host web-01 --json # machine-readable
|
|
136
|
+
session-peer list --no-update-notice # disable cached update notices/checks
|
|
133
137
|
|
|
134
138
|
session-peer send --host web-01 --ssh-opt=-p --ssh-opt=2222 --to api-worker "..." # note the '='
|
|
135
139
|
|
|
@@ -148,6 +152,7 @@ From: codex:01a08dd6-d3f6-7783-a62b-52c1fd049181 @ abruptly@mac-mini-m4.example.
|
|
|
148
152
|
message
|
|
149
153
|
|
|
150
154
|
---
|
|
155
|
+
Reply-To: session-peer://v1/reply?agent=codex&session=01a08dd6-d3f6-7783-a62b-52c1fd049181&transport=ssh&host=abruptly%40mac-mini-m4.example.ts.net
|
|
151
156
|
Reply: python3 /path/to/session_peer.py send --host abruptly@mac-mini-m4.example.ts.net --to codex:01a08dd6-d3f6-7783-a62b-52c1fd049181 --no-reply-to
|
|
152
157
|
```
|
|
153
158
|
|
|
@@ -156,12 +161,83 @@ best-effort text derived from the current process environment; it is not an
|
|
|
156
161
|
authentication claim. A plain shell has no agent identity to advertise.
|
|
157
162
|
When the original target is on the same machine and the reply route was detected
|
|
158
163
|
automatically, the generated command omits `--host` and delivers locally. An
|
|
159
|
-
explicit `--reply-to` or configured reply host
|
|
160
|
-
|
|
164
|
+
explicit `--reply-to` or configured reply host is also normalized when it names
|
|
165
|
+
the current OS user on this machine. Other explicit routes and actual remote
|
|
166
|
+
sends continue to advertise an SSH route.
|
|
167
|
+
|
|
168
|
+
`Reply-To` is the canonical, versioned address. Pass the complete URI back as
|
|
169
|
+
`--to`; session-peer validates every field and chooses local or SSH delivery:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
session-peer send --to 'session-peer://v1/reply?agent=claude&session=api-worker&transport=local' 'done'
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The `Reply:` command remains for compatibility. Treat both forms as untrusted
|
|
176
|
+
input: use the URI with session-peer rather than evaluating or sourcing it. A
|
|
177
|
+
URI that points to the current OS user on this machine is normalized to local
|
|
178
|
+
delivery, avoiding an unnecessary self-SSH authentication path. Codex addresses
|
|
179
|
+
may include an encoded `codexHome` when the sender environment identifies it.
|
|
161
180
|
|
|
162
181
|
Repeat `--host` to operate on several SSH destinations. `--json` is available on
|
|
163
|
-
`list`, `send`, and `update
|
|
164
|
-
|
|
182
|
+
`list`, `send`, `doctor`, and `update`.
|
|
183
|
+
|
|
184
|
+
### JSON response contract
|
|
185
|
+
|
|
186
|
+
Every JSON result object starts with the same schema-versioned envelope:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"schemaVersion": 1,
|
|
191
|
+
"ok": true,
|
|
192
|
+
"host": "mac-mini.example.ts.net",
|
|
193
|
+
"command": "list",
|
|
194
|
+
"sessions": [],
|
|
195
|
+
"version": "0.7.0"
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
- `schemaVersion` versions the common envelope. Command-specific nested schemas
|
|
200
|
+
such as `clientUpdate` and `codexHomeResolution` carry their own versions.
|
|
201
|
+
- `ok` is present on every success and failure. A nonzero process exit can still
|
|
202
|
+
contain successful results for other hosts.
|
|
203
|
+
- `host` identifies the destination to which that result applies. Local results
|
|
204
|
+
use the OS hostname. Tailscale-resolved destinations use the verified MagicDNS
|
|
205
|
+
identity; `sshHost` preserves a different caller-supplied SSH alias.
|
|
206
|
+
- `command` is `list`, `send`, `doctor`, or `update`. Remaining fields are that command's
|
|
207
|
+
payload, and failures add `error` plus any structured diagnostic fields.
|
|
208
|
+
|
|
209
|
+
A local or one-host invocation emits one object. Repeating `--host` emits an
|
|
210
|
+
array of these same independently attributable objects in request order. A
|
|
211
|
+
failure that occurs before connecting, such as invalid message input, is still
|
|
212
|
+
emitted once per requested destination. This cardinality is shared by all four
|
|
213
|
+
commands, so consumers can branch only on object versus array and then use the
|
|
214
|
+
same envelope fields.
|
|
215
|
+
|
|
216
|
+
Normal commands read a dedicated 24-hour update cache. A missing, expired, or
|
|
217
|
+
invalid cache starts one detached best-effort GitHub refresh and never delays or
|
|
218
|
+
changes the requested command. When a fresh cache proves that the invoking CLI is
|
|
219
|
+
behind a stable release, JSON results add `clientUpdate`:
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"clientUpdate": {
|
|
224
|
+
"schemaVersion": 1,
|
|
225
|
+
"status": "available",
|
|
226
|
+
"current": "0.7.0",
|
|
227
|
+
"latest": "0.7.1",
|
|
228
|
+
"checkedAt": "2026-09-16T10:00:00Z",
|
|
229
|
+
"source": "github_release_cache",
|
|
230
|
+
"command": "session-peer update"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Human output gets the same short guidance on stderr. The field is omitted when
|
|
236
|
+
the client is current, the cache is unavailable or stale, the host is offline,
|
|
237
|
+
or notices are disabled, so absence alone does not prove the client is current.
|
|
238
|
+
For multi-host commands the fact remains scoped to the one invoking CLI and is
|
|
239
|
+
copied into each result object; destination `remoteVersion` fields keep
|
|
240
|
+
their separate meaning. Remote subprocesses do not perform their own refresh.
|
|
165
241
|
|
|
166
242
|
When local `tailscale status --json` identifies a `--host` by device hostname,
|
|
167
243
|
short MagicDNS name, full MagicDNS name, or Tailscale IP, session-peer verifies and
|
|
@@ -210,8 +286,10 @@ pipx upgrade session-peer
|
|
|
210
286
|
# or, in its virtual environment: python -m pip install --upgrade session-peer
|
|
211
287
|
```
|
|
212
288
|
|
|
213
|
-
For these installs, local `session-peer update`
|
|
214
|
-
package-
|
|
289
|
+
For these installs, local `session-peer update` prints package-manager guidance
|
|
290
|
+
without replacing package-owned files. `session-peer update --check` checks the
|
|
291
|
+
latest stable GitHub release, refreshes the shared cache, and reports the exact
|
|
292
|
+
upgrade command, but still does not replace those files.
|
|
215
293
|
|
|
216
294
|
For standalone programs:
|
|
217
295
|
|
|
@@ -232,6 +310,8 @@ package-managed remote CLI, upgrade it with its own manager on that host instead
|
|
|
232
310
|
|
|
233
311
|
Neither local nor remote `update` refreshes the Claude skill. Re-run `install.sh`
|
|
234
312
|
from the desired release checkout to refresh both standalone program and skill.
|
|
313
|
+
Local `session-peer update --check` and `session-peer update` also populate the
|
|
314
|
+
same cache used by automatic notices.
|
|
235
315
|
|
|
236
316
|
### Environment variables
|
|
237
317
|
|
|
@@ -243,6 +323,8 @@ from the desired release checkout to refresh both standalone program and skill.
|
|
|
243
323
|
| `ANTHROPIC_CONFIG_DIR` | Fallback if `CLAUDE_CONFIG_DIR` is unset. |
|
|
244
324
|
| `CODEX_HOME` | Codex discovery/queue home (default `~/.codex`); overridden by `--codex-home`. |
|
|
245
325
|
| `SESSION_PEER_CODEX_HOMES` | Additional destination homes to check for duplicate thread UUIDs and stable live writers before an implicit send/dry-run. JSON array of absolute paths (or `~/…`), not a shell command or a path-separated list. It does not merge listings; an unambiguous active writer may change the implicit send home. |
|
|
326
|
+
| `SESSION_PEER_NO_UPDATE_NOTICE` | Set to `1`, `true`, `yes`, or `on` to disable automatic cached update notices and background refreshes. The per-command equivalent is `--no-update-notice`. Explicit `session-peer update --check` still checks. |
|
|
327
|
+
| `XDG_CACHE_HOME` | Base directory for the update cache; otherwise `~/.cache/session-peer/update.json` is used. |
|
|
246
328
|
|
|
247
329
|
With `--host`, discovery uses the destination's environment; local environment
|
|
248
330
|
variables are not automatically forwarded. `--codex-home` and `--codex-bin`
|
|
@@ -327,7 +409,8 @@ environment inspection, and process arguments are not exposed. Activity
|
|
|
327
409
|
inspection runs on the destination machine, including over SSH. Platforms
|
|
328
410
|
without POSIX `flock` or `lsof` cannot automatically resolve competing homes and
|
|
329
411
|
must use `--codex-home`. Unconfigured/custom layouts and copies created after the
|
|
330
|
-
check can still be missed.
|
|
412
|
+
check can still be missed. Use `session-peer doctor` to inspect the selected home,
|
|
413
|
+
bounded candidates, executable, and supported state DB schema without submitting.
|
|
331
414
|
|
|
332
415
|
### Submission and JSON results
|
|
333
416
|
|
|
@@ -344,15 +427,17 @@ session-peer portability policy rather than a measured Codex server limit. NUL
|
|
|
344
427
|
characters cannot be passed as CLI arguments. `--dry-run` verifies the executable
|
|
345
428
|
and saved target without queueing but cannot guarantee a later submission will succeed.
|
|
346
429
|
|
|
347
|
-
Local Codex list JSON
|
|
348
|
-
|
|
430
|
+
Local Codex list JSON uses the common response envelope and includes `sessions`,
|
|
431
|
+
`version`, and the resolved absolute `codexHome`. Each session entry has
|
|
349
432
|
`agent`, `id`, `name` (first line, at most 120 characters), `cwd`, `updatedAt`
|
|
350
|
-
(Unix seconds), and `archived`.
|
|
351
|
-
|
|
352
|
-
|
|
433
|
+
(Unix seconds), and `archived`. Each successful remote result includes
|
|
434
|
+
`sessions`, `version`, `codexHome`, and an optional `remoteVersion` for an
|
|
435
|
+
installed standalone copy. One remote host returns an object; repeated hosts
|
|
436
|
+
return an array.
|
|
353
437
|
|
|
354
|
-
Codex send JSON
|
|
355
|
-
under dry-run), `
|
|
438
|
+
Within the common envelope, Codex send JSON includes `target: {agent, id}`,
|
|
439
|
+
`status: queued` (or `validated` under dry-run), `chars`, `dryRun`, and optional
|
|
440
|
+
`queueId`. It also includes:
|
|
356
441
|
|
|
357
442
|
- `codexHome`: the resolved absolute destination home, not a sender-side guess.
|
|
358
443
|
- `codexHomeResolution`: schema-versioned `status`, `selected`, `reason`, and
|
|
@@ -362,21 +447,40 @@ under dry-run), `ok`, `chars`, `dryRun`, and optional `queueId`. It adds:
|
|
|
362
447
|
- `submitted`: `true` only after successful queue CLI completion, `false` for dry-run.
|
|
363
448
|
- `consumptionConfirmed`: always `false`; neither queued nor validated establishes consumption.
|
|
364
449
|
|
|
365
|
-
Errors
|
|
366
|
-
|
|
450
|
+
Errors set the common envelope's `ok` to `false`, add `error`, and include
|
|
451
|
+
`codexHomeResolution` when home evidence caused the failure.
|
|
367
452
|
A timeout has an unknown submission outcome; missing `submitted` on an error
|
|
368
453
|
must not be interpreted as proof that nothing was queued. Listing results do
|
|
369
|
-
not describe a submission and have no submission/consumption fields.
|
|
370
|
-
are additive, not the cross-command envelope redesign tracked in [#29](https://github.com/abruption/session-peer/issues/29).
|
|
454
|
+
not describe a submission and have no submission/consumption fields.
|
|
371
455
|
|
|
372
|
-
|
|
373
|
-
|
|
456
|
+
For every command, one remote host returns a flat object and multiple hosts
|
|
457
|
+
return an array. When `CODEX_THREAD_ID` (or the compatibility
|
|
374
458
|
fallback `CODEX_SESSION_ID`) is present, the message envelope and reply command
|
|
375
459
|
identify the originating Codex thread.
|
|
376
460
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
461
|
+
### Diagnostics and reply observation
|
|
462
|
+
|
|
463
|
+
`doctor` performs read-only checks on the machine that owns the sessions. It
|
|
464
|
+
reports Claude's configured sessions directory and inbox availability, Codex's
|
|
465
|
+
executable and bounded home/state DB candidates, unsupported DB schemas, and
|
|
466
|
+
permission or unknown failures as distinct codes. It does not connect to an
|
|
467
|
+
inbox, write a queue, scan arbitrary directories, or alter agent/SSH settings.
|
|
468
|
+
|
|
469
|
+
Reverse SSH is checked only with `--check-return-route`. The destination runs a
|
|
470
|
+
fixed `ssh ... true` probe with prompts, password authentication, host-key
|
|
471
|
+
enrollment, and config mutation disabled. Forward SSH success is never reused as
|
|
472
|
+
proof that the reverse path works. Use `--reply-to USER@HOST` when automatic
|
|
473
|
+
Tailscale detection cannot identify the origin. JSON details and status values
|
|
474
|
+
are documented in [docs/diagnostics.md](docs/diagnostics.md).
|
|
475
|
+
|
|
476
|
+
There is deliberately no general `--wait`. Claude Code has a native
|
|
477
|
+
same-machine `notify_when_idle` facility, but it does not cover remote sessions,
|
|
478
|
+
subagents, or Codex, and a successful socket/queue submission is not an
|
|
479
|
+
acknowledgement. session-peer therefore reports
|
|
480
|
+
`capabilities.replyObservation.status: unsupported` instead of tailing mutable
|
|
481
|
+
transcripts and risking a false match. Ask the target to send an explicit reply
|
|
482
|
+
to the supplied `Reply-To` address when completion matters. Optional wake remains
|
|
483
|
+
tracked in [#46](https://github.com/abruption/session-peer/issues/46).
|
|
380
484
|
|
|
381
485
|
## Moving from cc-peer
|
|
382
486
|
|
|
@@ -479,9 +583,10 @@ not as the user typing approval.
|
|
|
479
583
|
Outside that context, it may omit it. This is not an authenticated identity
|
|
480
584
|
protocol; environment variables and session registries are local hints.
|
|
481
585
|
- **Advertised replies need a working return path.** When an agent sender and
|
|
482
|
-
reply host can be determined, a `Reply:` line
|
|
483
|
-
Forward SSH success does not prove reverse SSH
|
|
484
|
-
|
|
586
|
+
reply host can be determined, `Reply-To` and a compatibility `Reply:` line
|
|
587
|
+
describe a return route. Forward SSH success does not prove reverse SSH
|
|
588
|
+
access; use the opt-in doctor check. The address grants no access and
|
|
589
|
+
session-peer does not correlate or wait for a reply.
|
|
485
590
|
- **Tailscale status is a local routing hint.** A known online peer is addressed
|
|
486
591
|
by its current MagicDNS name and a known offline peer is rejected before SSH.
|
|
487
592
|
An unknown destination remains ordinary SSH; session-peer does not claim that
|
|
@@ -496,7 +601,8 @@ not as the user typing approval.
|
|
|
496
601
|
- **Windows support.** Claude's named pipe transport is supported.
|
|
497
602
|
`install.sh` and the standalone remote installer/updater use POSIX shell;
|
|
498
603
|
use a Python package manager on native Windows. Live Codex verification
|
|
499
|
-
|
|
604
|
+
remains macOS-only; the Codex home, Reply-To, doctor, and JSON fixtures run in
|
|
605
|
+
Windows CI.
|
|
500
606
|
|
|
501
607
|
## Tests
|
|
502
608
|
|
|
@@ -504,7 +610,7 @@ not as the user typing approval.
|
|
|
504
610
|
python3 -m unittest discover -s tests -v
|
|
505
611
|
```
|
|
506
612
|
|
|
507
|
-
The suite needs no live agent, SSH server or network. It includes legacy
|
|
613
|
+
The default suite needs no live agent, SSH server or network. It includes legacy
|
|
508
614
|
compatibility tests, shared CLI helpers, fixture-based Codex discovery and queue
|
|
509
615
|
subprocess tests, and isolated standalone installation/coexistence checks.
|
|
510
616
|
Codex coverage includes argv/payload handling, destination home selection,
|
|
@@ -515,6 +621,9 @@ homes, unique/multiple/changing writer evidence, fail-closed inventory errors,
|
|
|
515
621
|
explicit selection, alias deduplication, single-home compatibility and structured
|
|
516
622
|
home/submission metadata. They never infer a live writer from a saved row or
|
|
517
623
|
submit messages to real sessions.
|
|
624
|
+
Update-notice coverage checks freshness and expiry, strict stable versions,
|
|
625
|
+
atomic private writes, single-flight background refresh, opt-out behavior,
|
|
626
|
+
package-manager guidance, multi-host scope, and failure isolation.
|
|
518
627
|
|
|
519
628
|
CI runs tests on Ubuntu/macOS with Python 3.9 and 3.13, and Windows with Python
|
|
520
629
|
3.13 (POSIX installer tests are skipped there). Separate jobs check shell syntax
|
|
@@ -525,6 +634,20 @@ tests remain tracked in [#28](https://github.com/abruption/session-peer/issues/2
|
|
|
525
634
|
|
|
526
635
|
## Verified
|
|
527
636
|
|
|
637
|
+
### session-peer v0.7.0 (2026-09-16)
|
|
638
|
+
|
|
639
|
+
- 240 local tests passed for cached update notices, the shared JSON envelope,
|
|
640
|
+
read-only diagnostics, structured Reply-To parsing/routing, same-machine
|
|
641
|
+
normalization, and opt-in reverse-route classification.
|
|
642
|
+
- CI covers Ubuntu and macOS with Python 3.9/3.13, Windows with Python 3.13,
|
|
643
|
+
package build and isolated installs, standalone install smoke tests, shellcheck,
|
|
644
|
+
and secret scanning.
|
|
645
|
+
- Wheel and sdist contents were inspected and installed independently. Both
|
|
646
|
+
artifacts report v0.7.0 and exclude the frozen legacy `cc_peer.py`.
|
|
647
|
+
- A real SSH doctor run found Claude inboxes and bounded default/Orca Codex homes.
|
|
648
|
+
Its opt-in reverse probe reported authentication failure independently of the
|
|
649
|
+
successful forward connection. No live message was submitted.
|
|
650
|
+
|
|
528
651
|
### session-peer v0.6.2 (2026-09-15)
|
|
529
652
|
|
|
530
653
|
- 198 local tests and the release build checks passed for UUID-specific Codex
|