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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: session-peer
3
- Version: 0.6.2
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 remains unchanged, and actual
189
- remote sends continue to advertise an SSH route.
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`; v0.6 retains command-specific response shapes rather
193
- than a uniform envelope. See [#29](https://github.com/abruption/session-peer/issues/29).
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` (including `--check`) prints
243
- package-manager guidance without checking GitHub or replacing the package's files.
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. Further diagnostics belong to [#45](https://github.com/abruption/session-peer/issues/45).
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 retains `sessions` and `version`, and adds the resolved
377
- absolute `codexHome` at the top level. Each entry has
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`. Remote list JSON is an array of per-host results,
380
- even for one host; each successful result includes `host`, `sessions`, `version`, `codexHome`
381
- and an optional `remoteVersion` for an installed standalone copy.
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 retains `target: {agent, id}`, `status: queued` (or `validated`
384
- under dry-run), `ok`, `chars`, `dryRun`, and optional `queueId`. It adds:
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 keep the existing `{ok: false, error}` fields (plus host on remote results)
395
- and add `codexHomeResolution` when home evidence caused the failure.
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. The changes
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
- A remote send to one host returns a flat object with `host`; multiple hosts return an array.
402
- Claude output stays compatible. When `CODEX_THREAD_ID` (or the compatibility
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
- `doctor`, reply waiting/`--wait`, structured reply URIs and optional wake are
407
- future work, not v0.6 features: see the [v0.7](https://github.com/abruption/session-peer/issues/45)
408
- and [v0.8](https://github.com/abruption/session-peer/issues/46) roadmaps.
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 supplies an SSH return command.
512
- Forward SSH success does not prove reverse SSH access. v0.6 does not verify
513
- that route, correlate a reply, or wait for one; the address grants no access.
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
- for v0.6 was on macOS, not Windows.
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 remains unchanged, and actual
160
- remote sends continue to advertise an SSH route.
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`; v0.6 retains command-specific response shapes rather
164
- than a uniform envelope. See [#29](https://github.com/abruption/session-peer/issues/29).
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` (including `--check`) prints
214
- package-manager guidance without checking GitHub or replacing the package's files.
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. Further diagnostics belong to [#45](https://github.com/abruption/session-peer/issues/45).
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 retains `sessions` and `version`, and adds the resolved
348
- absolute `codexHome` at the top level. Each entry has
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`. Remote list JSON is an array of per-host results,
351
- even for one host; each successful result includes `host`, `sessions`, `version`, `codexHome`
352
- and an optional `remoteVersion` for an installed standalone copy.
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 retains `target: {agent, id}`, `status: queued` (or `validated`
355
- under dry-run), `ok`, `chars`, `dryRun`, and optional `queueId`. It adds:
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 keep the existing `{ok: false, error}` fields (plus host on remote results)
366
- and add `codexHomeResolution` when home evidence caused the failure.
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. The changes
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
- A remote send to one host returns a flat object with `host`; multiple hosts return an array.
373
- Claude output stays compatible. When `CODEX_THREAD_ID` (or the compatibility
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
- `doctor`, reply waiting/`--wait`, structured reply URIs and optional wake are
378
- future work, not v0.6 features: see the [v0.7](https://github.com/abruption/session-peer/issues/45)
379
- and [v0.8](https://github.com/abruption/session-peer/issues/46) roadmaps.
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 supplies an SSH return command.
483
- Forward SSH success does not prove reverse SSH access. v0.6 does not verify
484
- that route, correlate a reply, or wait for one; the address grants no access.
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
- for v0.6 was on macOS, not Windows.
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