session-peer 0.6.2__tar.gz → 0.8.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.
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "session-peer",
3
+ "interface": {
4
+ "displayName": "Session Peer"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "session-peer",
9
+ "source": {
10
+ "source": "local",
11
+ "path": "./plugins/session-peer"
12
+ },
13
+ "policy": {
14
+ "installation": "AVAILABLE",
15
+ "authentication": "ON_INSTALL"
16
+ },
17
+ "category": "Productivity"
18
+ }
19
+ ]
20
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: session-peer
3
- Version: 0.6.2
3
+ Version: 0.8.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
@@ -25,6 +25,8 @@ Classifier: Topic :: Software Development
25
25
  Classifier: Topic :: System :: Networking
26
26
  Classifier: Topic :: Utilities
27
27
  Requires-Python: >=3.9
28
+ Provides-Extra: mcp
29
+ Requires-Dist: mcp<2,>=1.12; (python_version >= '3.10') and extra == 'mcp'
28
30
  Description-Content-Type: text/markdown
29
31
 
30
32
  # session-peer
@@ -51,24 +53,51 @@ Install the CLI with `pipx install session-peer` or `uv tool install session-pee
51
53
  For the standalone CLI plus Claude skill, see [Install](#install).
52
54
 
53
55
  ```bash
54
- session-peer list # Claude sessions (default)
55
- session-peer list --agent claude # explicit equivalent
56
+ session-peer list # Claude + Codex sessions (default)
57
+ session-peer list --agent claude # Claude-only filter
56
58
  session-peer list --agent codex # saved Codex threads
57
59
  session-peer list --agent codex --host worker # saved threads on an SSH host
58
60
 
59
- session-peer send --to api-worker "message" # Claude name or PID
60
- session-peer send --to 'codex:<full-thread-uuid>' "message"
61
- session-peer send --host worker --to 'codex:<full-thread-uuid>' --dry-run "message"
61
+ session-peer send --to api-worker --message "message" # Claude name or PID
62
+ session-peer send --to 'codex:<full-thread-uuid>' --message "message" --output-format json
63
+ session-peer send --host worker --to 'codex:<full-thread-uuid>' --dry-run -m "message"
62
64
  ```
63
65
 
64
66
  Replace `<full-thread-uuid>` with a full ID from the destination's Codex listing.
65
- `list` selects one agent at a time; it does not merge both agents. **Use
66
- `--agent codex`, not `--codex`**: `--codex` is not a supported flag and is ambiguous
67
+ `list` includes both agents by default. **Use
68
+ `--agent codex` to filter, not `--codex`**: `--codex` is not a supported flag and is ambiguous
67
69
  with `--codex-home` and `--codex-bin`. `send` selects the agent from its target,
68
70
  not a `--agent` flag.
69
71
 
70
72
  **Posted/queued is not acknowledged.** Saved Codex threads are not necessarily
71
- running, and session-peer does not wake/resume a session or wait for its reply.
73
+ running. Plain send does not activate a session; [explicit `--wake`](docs/wake.md)
74
+ is opt-in and does not confirm consumption or a reply.
75
+
76
+ ### Message input and result output
77
+
78
+ `--message TEXT` (short form `-m`) names the text sent to the destination.
79
+ `--output-format text|json` selects the command result format, not the message
80
+ format. It is available on `list`, `send`, `doctor`, and `update`; the default is
81
+ `text`. The existing `--json` is retained as an alias for `--output-format json`.
82
+
83
+ ```bash
84
+ session-peer send --to worker --message "Report progress" --output-format json
85
+ session-peer send --to worker -m - --output-format json < message.txt
86
+ session-peer list --output-format json
87
+ ```
88
+
89
+ Legacy positional messages and omitted-message stdin input continue to work.
90
+ Use either a positional message or `--message`, not both. `--message -` reads
91
+ stdin; an explicit empty message is still rejected. To send text beginning with
92
+ a dash, use `--message='--literal text'` or stdin. Internal SSH `--b64` input
93
+ cannot be combined with either public message form.
94
+
95
+ `--json --output-format json` is valid; combining `--json` with
96
+ `--output-format text` is an error in either order. Invalid/contradictory output
97
+ options are argparse usage errors (stderr, exit 2); message-source conflicts
98
+ are ordinary command errors (JSON when requested, exit 1). No messages are
99
+ submitted in either case. JSON results still describe submission rather than
100
+ receipt; these flags introduce no structured JSON message-input protocol.
72
101
 
73
102
  ## Install
74
103
 
@@ -146,10 +175,13 @@ plugin or change either agent's permissions or inbound settings.
146
175
  ## Usage
147
176
 
148
177
  ```bash
149
- session-peer list # Claude sessions on this machine
150
- session-peer list --host web-01 # Claude sessions over there
178
+ session-peer list # Claude + Codex on this machine
179
+ session-peer list --host web-01 # Claude + Codex over there
151
180
  session-peer list --host web-01 --all # Claude stale records / no inbox
152
181
  session-peer list --agent codex --all # include archived Codex threads
182
+ session-peer doctor # local inbox/tool/home diagnostics
183
+ session-peer doctor --host web-01 # run the same checks there
184
+ session-peer doctor --host web-01 --check-return-route # also test SSH back here
153
185
 
154
186
  session-peer send --to api-worker "message" # local session
155
187
  session-peer send --host web-01 --to api-worker "message"
@@ -159,6 +191,7 @@ git log --oneline -5 | session-peer send --host web-01 --to api-worker - # std
159
191
 
160
192
  session-peer send --host web-01 --to api-worker --dry-run "x" # resolve only
161
193
  session-peer list --host web-01 --json # machine-readable
194
+ session-peer list --no-update-notice # disable cached update notices/checks
162
195
 
163
196
  session-peer send --host web-01 --ssh-opt=-p --ssh-opt=2222 --to api-worker "..." # note the '='
164
197
 
@@ -177,6 +210,7 @@ From: codex:01a08dd6-d3f6-7783-a62b-52c1fd049181 @ abruptly@mac-mini-m4.example.
177
210
  message
178
211
 
179
212
  ---
213
+ 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
214
  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
215
  ```
182
216
 
@@ -185,12 +219,83 @@ best-effort text derived from the current process environment; it is not an
185
219
  authentication claim. A plain shell has no agent identity to advertise.
186
220
  When the original target is on the same machine and the reply route was detected
187
221
  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.
222
+ explicit `--reply-to` or configured reply host is also normalized when it names
223
+ the current OS user on this machine. Other explicit routes and actual remote
224
+ sends continue to advertise an SSH route.
225
+
226
+ `Reply-To` is the canonical, versioned address. Pass the complete URI back as
227
+ `--to`; session-peer validates every field and chooses local or SSH delivery:
228
+
229
+ ```bash
230
+ session-peer send --to 'session-peer://v1/reply?agent=claude&session=api-worker&transport=local' 'done'
231
+ ```
232
+
233
+ The `Reply:` command remains for compatibility. Treat both forms as untrusted
234
+ input: use the URI with session-peer rather than evaluating or sourcing it. A
235
+ URI that points to the current OS user on this machine is normalized to local
236
+ delivery, avoiding an unnecessary self-SSH authentication path. Codex addresses
237
+ may include an encoded `codexHome` when the sender environment identifies it.
190
238
 
191
239
  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).
240
+ `list`, `send`, `doctor`, and `update`.
241
+
242
+ ### JSON response contract
243
+
244
+ Every JSON result object starts with the same schema-versioned envelope:
245
+
246
+ ```json
247
+ {
248
+ "schemaVersion": 1,
249
+ "ok": true,
250
+ "host": "mac-mini.example.ts.net",
251
+ "command": "list",
252
+ "sessions": [],
253
+ "version": "0.8.0"
254
+ }
255
+ ```
256
+
257
+ - `schemaVersion` versions the common envelope. Command-specific nested schemas
258
+ such as `clientUpdate` and `codexHomeResolution` carry their own versions.
259
+ - `ok` is present on every success and failure. A nonzero process exit can still
260
+ contain successful results for other hosts.
261
+ - `host` identifies the destination to which that result applies. Local results
262
+ use the OS hostname. Tailscale-resolved destinations use the verified MagicDNS
263
+ identity; `sshHost` preserves a different caller-supplied SSH alias.
264
+ - `command` is `list`, `send`, `doctor`, or `update`. Remaining fields are that command's
265
+ payload, and failures add `error` plus any structured diagnostic fields.
266
+
267
+ A local or one-host invocation emits one object. Repeating `--host` emits an
268
+ array of these same independently attributable objects in request order. A
269
+ failure that occurs before connecting, such as invalid message input, is still
270
+ emitted once per requested destination. This cardinality is shared by all four
271
+ commands, so consumers can branch only on object versus array and then use the
272
+ same envelope fields.
273
+
274
+ Normal commands read a dedicated 24-hour update cache. A missing, expired, or
275
+ invalid cache starts one detached best-effort GitHub refresh and never delays or
276
+ changes the requested command. When a fresh cache proves that the invoking CLI is
277
+ behind a stable release, JSON results add `clientUpdate`:
278
+
279
+ ```json
280
+ {
281
+ "clientUpdate": {
282
+ "schemaVersion": 1,
283
+ "status": "available",
284
+ "current": "0.7.0",
285
+ "latest": "0.7.1",
286
+ "checkedAt": "2026-09-16T10:00:00Z",
287
+ "source": "github_release_cache",
288
+ "command": "session-peer update"
289
+ }
290
+ }
291
+ ```
292
+
293
+ Human output gets the same short guidance on stderr. The field is omitted when
294
+ the client is current, the cache is unavailable or stale, the host is offline,
295
+ or notices are disabled, so absence alone does not prove the client is current.
296
+ For multi-host commands the fact remains scoped to the one invoking CLI and is
297
+ copied into each result object; destination `remoteVersion` fields keep
298
+ their separate meaning. Remote subprocesses do not perform their own refresh.
194
299
 
195
300
  When local `tailscale status --json` identifies a `--host` by device hostname,
196
301
  short MagicDNS name, full MagicDNS name, or Tailscale IP, session-peer verifies and
@@ -239,8 +344,10 @@ pipx upgrade session-peer
239
344
  # or, in its virtual environment: python -m pip install --upgrade session-peer
240
345
  ```
241
346
 
242
- For these installs, local `session-peer update` (including `--check`) prints
243
- package-manager guidance without checking GitHub or replacing the package's files.
347
+ For these installs, local `session-peer update` prints package-manager guidance
348
+ without replacing package-owned files. `session-peer update --check` checks the
349
+ latest stable GitHub release, refreshes the shared cache, and reports the exact
350
+ upgrade command, but still does not replace those files.
244
351
 
245
352
  For standalone programs:
246
353
 
@@ -261,6 +368,8 @@ package-managed remote CLI, upgrade it with its own manager on that host instead
261
368
 
262
369
  Neither local nor remote `update` refreshes the Claude skill. Re-run `install.sh`
263
370
  from the desired release checkout to refresh both standalone program and skill.
371
+ Local `session-peer update --check` and `session-peer update` also populate the
372
+ same cache used by automatic notices.
264
373
 
265
374
  ### Environment variables
266
375
 
@@ -272,6 +381,8 @@ from the desired release checkout to refresh both standalone program and skill.
272
381
  | `ANTHROPIC_CONFIG_DIR` | Fallback if `CLAUDE_CONFIG_DIR` is unset. |
273
382
  | `CODEX_HOME` | Codex discovery/queue home (default `~/.codex`); overridden by `--codex-home`. |
274
383
  | `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. |
384
+ | `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. |
385
+ | `XDG_CACHE_HOME` | Base directory for the update cache; otherwise `~/.cache/session-peer/update.json` is used. |
275
386
 
276
387
  With `--host`, discovery uses the destination's environment; local environment
277
388
  variables are not automatically forwarded. `--codex-home` and `--codex-bin`
@@ -350,13 +461,14 @@ configured databases also prevent implicit submission. Choose `--codex-home`
350
461
  explicitly to bypass unrelated inventory and activity checks. Resolved symlink
351
462
  aliases and repeated paths count as one home.
352
463
 
353
- With no competing saved home, native queue behavior is preserved; `list` still
354
- reads only the selected home. There is no general filesystem scan or process
464
+ With no competing saved home, native queue behavior is preserved. `list`
465
+ aggregates known homes unless `--codex-home` selects exactly one. There is no general filesystem scan or process
355
466
  environment inspection, and process arguments are not exposed. Activity
356
467
  inspection runs on the destination machine, including over SSH. Platforms
357
468
  without POSIX `flock` or `lsof` cannot automatically resolve competing homes and
358
469
  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).
470
+ check can still be missed. Use `session-peer doctor` to inspect the selected home,
471
+ bounded candidates, executable, and supported state DB schema without submitting.
360
472
 
361
473
  ### Submission and JSON results
362
474
 
@@ -373,15 +485,18 @@ session-peer portability policy rather than a measured Codex server limit. NUL
373
485
  characters cannot be passed as CLI arguments. `--dry-run` verifies the executable
374
486
  and saved target without queueing but cannot guarantee a later submission will succeed.
375
487
 
376
- Local Codex list JSON retains `sessions` and `version`, and adds the resolved
377
- absolute `codexHome` at the top level. Each entry has
488
+ Local Codex list JSON uses the common response envelope and includes `sessions`,
489
+ `version`, and per-home diagnostics in `discovery.codex.homes`. Each session entry has
378
490
  `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.
491
+ (Unix seconds), `archived`, canonical `codexHome`, and `stateDb`. Top-level
492
+ `codexHome` is retained only for a single candidate home without inventory errors.
493
+ Each successful remote result includes the same fields and an optional `remoteVersion` for an
494
+ installed standalone copy. One remote host returns an object; repeated hosts
495
+ return an array.
382
496
 
383
- Codex send JSON retains `target: {agent, id}`, `status: queued` (or `validated`
384
- under dry-run), `ok`, `chars`, `dryRun`, and optional `queueId`. It adds:
497
+ Within the common envelope, Codex send JSON includes `target: {agent, id}`,
498
+ `status: queued` (or `validated` under dry-run), `chars`, `dryRun`, and optional
499
+ `queueId`. It also includes:
385
500
 
386
501
  - `codexHome`: the resolved absolute destination home, not a sender-side guess.
387
502
  - `codexHomeResolution`: schema-versioned `status`, `selected`, `reason`, and
@@ -391,21 +506,40 @@ under dry-run), `ok`, `chars`, `dryRun`, and optional `queueId`. It adds:
391
506
  - `submitted`: `true` only after successful queue CLI completion, `false` for dry-run.
392
507
  - `consumptionConfirmed`: always `false`; neither queued nor validated establishes consumption.
393
508
 
394
- Errors keep the existing `{ok: false, error}` fields (plus host on remote results)
395
- and add `codexHomeResolution` when home evidence caused the failure.
509
+ Errors set the common envelope's `ok` to `false`, add `error`, and include
510
+ `codexHomeResolution` when home evidence caused the failure.
396
511
  A timeout has an unknown submission outcome; missing `submitted` on an error
397
512
  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).
513
+ not describe a submission and have no submission/consumption fields.
400
514
 
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
515
+ For every command, one remote host returns a flat object and multiple hosts
516
+ return an array. When `CODEX_THREAD_ID` (or the compatibility
403
517
  fallback `CODEX_SESSION_ID`) is present, the message envelope and reply command
404
518
  identify the originating Codex thread.
405
519
 
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.
520
+ ### Diagnostics and reply observation
521
+
522
+ `doctor` performs read-only checks on the machine that owns the sessions. It
523
+ reports Claude's configured sessions directory and inbox availability, Codex's
524
+ executable and bounded home/state DB candidates, unsupported DB schemas, and
525
+ permission or unknown failures as distinct codes. It does not connect to an
526
+ inbox, write a queue, scan arbitrary directories, or alter agent/SSH settings.
527
+
528
+ Reverse SSH is checked only with `--check-return-route`. The destination runs a
529
+ fixed `ssh ... true` probe with prompts, password authentication, host-key
530
+ enrollment, and config mutation disabled. Forward SSH success is never reused as
531
+ proof that the reverse path works. Use `--reply-to USER@HOST` when automatic
532
+ Tailscale detection cannot identify the origin. JSON details and status values
533
+ are documented in [docs/diagnostics.md](docs/diagnostics.md).
534
+
535
+ There is deliberately no general `--wait`. Claude Code has a native
536
+ same-machine `notify_when_idle` facility, but it does not cover remote sessions,
537
+ subagents, or Codex, and a successful socket/queue submission is not an
538
+ acknowledgement. session-peer therefore reports
539
+ `capabilities.replyObservation.status: unsupported` instead of tailing mutable
540
+ transcripts and risking a false match. Ask the target to send an explicit reply
541
+ to the supplied `Reply-To` address when completion matters. Optional wake remains
542
+ tracked in [#46](https://github.com/abruption/session-peer/issues/46).
409
543
 
410
544
  ## Moving from cc-peer
411
545
 
@@ -508,9 +642,10 @@ not as the user typing approval.
508
642
  Outside that context, it may omit it. This is not an authenticated identity
509
643
  protocol; environment variables and session registries are local hints.
510
644
  - **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.
645
+ reply host can be determined, `Reply-To` and a compatibility `Reply:` line
646
+ describe a return route. Forward SSH success does not prove reverse SSH
647
+ access; use the opt-in doctor check. The address grants no access and
648
+ session-peer does not correlate or wait for a reply.
514
649
  - **Tailscale status is a local routing hint.** A known online peer is addressed
515
650
  by its current MagicDNS name and a known offline peer is rejected before SSH.
516
651
  An unknown destination remains ordinary SSH; session-peer does not claim that
@@ -525,7 +660,8 @@ not as the user typing approval.
525
660
  - **Windows support.** Claude's named pipe transport is supported.
526
661
  `install.sh` and the standalone remote installer/updater use POSIX shell;
527
662
  use a Python package manager on native Windows. Live Codex verification
528
- for v0.6 was on macOS, not Windows.
663
+ remains macOS-only; the Codex home, Reply-To, doctor, and JSON fixtures run in
664
+ Windows CI.
529
665
 
530
666
  ## Tests
531
667
 
@@ -533,7 +669,7 @@ not as the user typing approval.
533
669
  python3 -m unittest discover -s tests -v
534
670
  ```
535
671
 
536
- The suite needs no live agent, SSH server or network. It includes legacy
672
+ The default suite needs no live agent, SSH server or network. It includes legacy
537
673
  compatibility tests, shared CLI helpers, fixture-based Codex discovery and queue
538
674
  subprocess tests, and isolated standalone installation/coexistence checks.
539
675
  Codex coverage includes argv/payload handling, destination home selection,
@@ -544,6 +680,9 @@ homes, unique/multiple/changing writer evidence, fail-closed inventory errors,
544
680
  explicit selection, alias deduplication, single-home compatibility and structured
545
681
  home/submission metadata. They never infer a live writer from a saved row or
546
682
  submit messages to real sessions.
683
+ Update-notice coverage checks freshness and expiry, strict stable versions,
684
+ atomic private writes, single-flight background refresh, opt-out behavior,
685
+ package-manager guidance, multi-host scope, and failure isolation.
547
686
 
548
687
  CI runs tests on Ubuntu/macOS with Python 3.9 and 3.13, and Windows with Python
549
688
  3.13 (POSIX installer tests are skipped there). Separate jobs check shell syntax
@@ -554,6 +693,31 @@ tests remain tracked in [#28](https://github.com/abruption/session-peer/issues/2
554
693
 
555
694
  ## Verified
556
695
 
696
+ ### session-peer v0.8.0 candidate (2026-09-16)
697
+
698
+ - Integrates unified Claude/Codex listing, optional MCP tools and a Codex plugin,
699
+ explicit bounded Codex wake, multi-home Codex listing, and named message and output
700
+ formatting options from #76, #77, #78, #80, and #82.
701
+ - See [v0.8.0 release notes](docs/releases/v0.8.0.md) for JSON compatibility,
702
+ optional dependencies, the Codex 0.154.0 wake boundary, and validation limits.
703
+ - 301 local tests passed with the MCP SDK; standalone runs skip two optional
704
+ SDK tests. Wheel and sdist installed independently and report v0.8.0.
705
+ - Release preparation does not publish a GitHub release or upload to PyPI.
706
+
707
+ ### session-peer v0.7.0 (2026-09-16)
708
+
709
+ - 240 local tests passed for cached update notices, the shared JSON envelope,
710
+ read-only diagnostics, structured Reply-To parsing/routing, same-machine
711
+ normalization, and opt-in reverse-route classification.
712
+ - CI covers Ubuntu and macOS with Python 3.9/3.13, Windows with Python 3.13,
713
+ package build and isolated installs, standalone install smoke tests, shellcheck,
714
+ and secret scanning.
715
+ - Wheel and sdist contents were inspected and installed independently. Both
716
+ artifacts report v0.7.0 and exclude the frozen legacy `cc_peer.py`.
717
+ - A real SSH doctor run found Claude inboxes and bounded default/Orca Codex homes.
718
+ Its opt-in reverse probe reported authentication failure independently of the
719
+ successful forward connection. No live message was submitted.
720
+
557
721
  ### session-peer v0.6.2 (2026-09-15)
558
722
 
559
723
  - 198 local tests and the release build checks passed for UUID-specific Codex
@@ -621,3 +785,40 @@ agent build.
621
785
  ## License
622
786
 
623
787
  MIT
788
+
789
+ ### Combined session discovery
790
+
791
+ Default `list` and `list --json` query Claude and Codex together. Use
792
+ `--agent claude` to retain the previous Claude-only default, or `--agent codex`
793
+ for Codex only. Every session row includes `agent: "claude" | "codex"`;
794
+ agent-specific fields such as PID and thread UUID remain unchanged. Combined
795
+ human output includes an AGENT column. Claude rows precede Codex rows, preserving
796
+ Claude discovery ordering; Codex rows sort by descending update time, then home and UUID.
797
+
798
+ List responses include `discovery`, keyed by each requested agent, with
799
+ `status: "ok" | "not_installed" | "error"` (the middle state is Codex-only)
800
+ and an `error` explanation for failed sources.
801
+ Any discovery failure returns `ok: false`, a top-level error summary, and exit
802
+ code 1 while retaining successfully discovered sessions. No automatically discovered
803
+ Codex installation is a normal empty result (`not_installed`, exit 0); a missing
804
+ explicitly configured home is an error. A missing Claude sessions directory is an empty result.
805
+ Neither is evidence of a running Codex process. Malformed individual Claude
806
+ records continue to be skipped as before.
807
+
808
+ These semantics apply locally and over SSH. Repeated hosts retain independent
809
+ results in the existing ordered array; any failure makes the overall exit code 1.
810
+ Codex listing includes default, environment-selected, Orca, and configured homes.
811
+ Use `--codex-home PATH` to inspect only that home.
812
+ `--all` retains Claude stale/no-inbox records and includes archived Codex threads.
813
+
814
+ ### Optional MCP / Codex plugin
815
+
816
+ For structured, destination-restricted `list_sessions` and `send_message` tools,
817
+ install `session-peer[mcp]` with Python 3.10+ and follow [MCP setup](docs/mcp.md).
818
+ The default policy permits local listing only. The standalone CLI and shell
819
+ installer retain their existing dependency requirements.
820
+
821
+ For opt-in activation of queued Codex sessions, see [explicit wake](docs/wake.md).
822
+
823
+ See [multi-home Codex listing](docs/multi-home-list.md) for candidate sources,
824
+ per-home errors, duplicate UUIDs, and selecting the exact home for send.