projmux 0.15.0 → 0.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/agent-message-replies.md +49 -0
- package/docs/agent-workflow.md +166 -9
- package/docs/architecture.md +10 -0
- package/docs/claude-coordination-endpoints.md +15 -0
- package/docs/cli-guide.md +49 -6
- package/docs/cli.md +15 -15
- package/docs/codex-generation-pool.md +5 -0
- package/docs/codex-stored-qualification.md +45 -0
- package/docs/column-profiles.md +14 -9
- package/docs/heterogeneous-dialogue-canary.md +23 -0
- package/docs/keybindings.md +85 -0
- package/docs/operational-diagnostics.md +14 -0
- package/docs/replacement-contract.md +53 -12
- package/docs/session-restore.md +43 -3
- package/docs/troubleshooting.md +64 -3
- package/package.json +5 -5
|
@@ -208,6 +208,21 @@ real-provider observation is opt-in through
|
|
|
208
208
|
`scripts/agent-dialogue-live-canary.sh`; each version-stress row must qualify
|
|
209
209
|
independently.
|
|
210
210
|
|
|
211
|
+
`TestClaudeDialogueStreamReplaysObservedFrameCorpus` pins the reply-only
|
|
212
|
+
validator's verdict on preserved real frame shapes. Neither it nor L20 proves
|
|
213
|
+
installed-provider compatibility, value drift (the corpus keeps top-level key
|
|
214
|
+
shape with placeholder values), or acceptance of unknown frames and fields (the
|
|
215
|
+
closed vocabulary rejects them by design). The L20 fixture emits none of the
|
|
216
|
+
corpus's dropped side frames. Two recorded real shapes are rejected today:
|
|
217
|
+
`result-success-25-keys` (the result allowlist lacks `origin`) and
|
|
218
|
+
`system-init-allowlist-diff` (the init allowlist lacks `memory_paths` and
|
|
219
|
+
`terminal_slash_commands`). Shapes without preserved evidence are gaps, not
|
|
220
|
+
items: `command_lifecycle` keys and values, a non-null assistant
|
|
221
|
+
`context_management`, `system` `thinking_tokens`, hook and user `tool_result`
|
|
222
|
+
frames, the exact real init key set, every nested value, `rate_limit_event`
|
|
223
|
+
envelope keys beyond `type` and `rate_limit_info`, and the lost earlier shape
|
|
224
|
+
inventories.
|
|
225
|
+
|
|
211
226
|
Provider sources: [SessionStart and Stop hooks](https://code.claude.com/docs/en/hooks)
|
|
212
227
|
and [cross-session messaging](https://code.claude.com/docs/en/cross-session-messaging).
|
|
213
228
|
|
package/docs/cli-guide.md
CHANGED
|
@@ -376,10 +376,16 @@ The generated `MouseDown3Pane` menu treats its Horizontal Split, Vertical
|
|
|
376
376
|
Split, and Kill entries as Projmux resource actions. Both splits pass the exact
|
|
377
377
|
clicked pane through the popup-origin anchor above and reach the same canonical
|
|
378
378
|
`create pane` materializer as the CLI, so the new pane receives a Registry uid.
|
|
379
|
-
Kill resolves that anchor's mirrored uid and
|
|
380
|
-
including its printed delete result
|
|
381
|
-
|
|
382
|
-
|
|
379
|
+
Kill on a pane with `@projmux_pane_uid` resolves that anchor's mirrored uid and
|
|
380
|
+
reaches canonical `delete pane`, including its printed delete result; a pane
|
|
381
|
+
without the mirror runs tmux's own `kill-pane` instead of being refused. The
|
|
382
|
+
menu never falls back to a raw tmux mutation when either route refuses. The
|
|
383
|
+
reason is displayed on the exact client that opened the menu instead of being
|
|
384
|
+
lost as a `run-shell` exit code. The app config's `prefix >` and
|
|
385
|
+
`M-MouseDown3Pane` Pane menus follow the same rules, and its `prefix <`,
|
|
386
|
+
`MouseDown3Status`, and `M-MouseDown3Status` Window menus route Kill on a
|
|
387
|
+
mirrored Window to canonical `delete window`; see
|
|
388
|
+
[Managed menus](keybindings.md#managed-menus).
|
|
383
389
|
|
|
384
390
|
tmux Respawn has no equivalent in the current resource model: it preserves the
|
|
385
391
|
same pane handle, layout, Registry uid, and original command, while canonical
|
|
@@ -389,6 +395,23 @@ menu therefore omits Respawn entirely and does not expose a refusal handler or
|
|
|
389
395
|
invent a replace operation. User-authored tmux bindings remain outside this
|
|
390
396
|
managed-menu contract.
|
|
391
397
|
|
|
398
|
+
#### Managed close keys
|
|
399
|
+
|
|
400
|
+
The generated app config routes tmux's `prefix x` and `prefix &` through the
|
|
401
|
+
same resource routes whenever the target carries a Registry identity mirror.
|
|
402
|
+
`prefix x` on a Pane with `@projmux_pane_uid` confirms on the exact client, then
|
|
403
|
+
runs the Pane menu Kill route above: canonical `delete pane` with an
|
|
404
|
+
`intentional` termination receipt. The Agent that owned the Pane stays in the
|
|
405
|
+
Registry as Offline with a `deleted` exit, which Continue never replays.
|
|
406
|
+
`prefix &` on a Window with
|
|
407
|
+
`@projmux_window_uid` confirms, then runs `internal tmux window-delete`, which is
|
|
408
|
+
canonical `delete window` on that exact Window; a Project's last Window leaves a
|
|
409
|
+
zero-Window Project. A refusal is shown on that client and never falls back to
|
|
410
|
+
a raw kill. A target without the mirror keeps tmux's stock `confirm-before`
|
|
411
|
+
prompt and kill, with no Registry write. See
|
|
412
|
+
[Managed close keys](keybindings.md#managed-close-keys) for changing or
|
|
413
|
+
disabling the keys.
|
|
414
|
+
|
|
392
415
|
### Rename and rebind live convergence
|
|
393
416
|
|
|
394
417
|
`rename project|window|pane` commits the selected Registry `metadata.name` and
|
|
@@ -537,7 +560,9 @@ generated `pane-exited` hook. The supervisor must have durably journaled a
|
|
|
537
560
|
same-generation `normal` receipt, the hook must name the exact `%N` Pane and
|
|
538
561
|
the owner Window must carry its exact last-positive `$N/@N` binding on the same
|
|
539
562
|
socket, and fresh preflight plus locked observations must still resolve the
|
|
540
|
-
same Registry owner chain.
|
|
563
|
+
same Registry owner chain. This includes Windows re-materialized by Project
|
|
564
|
+
start/Continue topology replay: the replay records each Window it materializes
|
|
565
|
+
with its live `$N/@N` in the same commit. A non-last Pane is removed while its directly owning
|
|
541
566
|
Agent is retained Offline with its conversation identity. For a last Pane, that evidence is retained until a
|
|
542
567
|
matching `window-unlinked` hook removes the Window; a final Project Window also
|
|
543
568
|
removes its Window descendants while retaining the exact Project uid, root,
|
|
@@ -549,6 +574,14 @@ content, prompt, history, and transcript are never parsed. `abnormal`,
|
|
|
549
574
|
`killed`, `unknown`, stale/resumed bindings, empty or unavailable inventory,
|
|
550
575
|
permission failure, and foreign-host/window observations keep their diagnostic
|
|
551
576
|
rows and produce no automatic delete plan.
|
|
577
|
+
Every teardown decision on this hook path appends one
|
|
578
|
+
`topology.teardown.decision` journal record (`projmux diagnostics log
|
|
579
|
+
--component topology`) with its `delete-window`/`delete-pane-agent`/`retain`/
|
|
580
|
+
`refuse` decision, `topology.teardown.<reason>` code, Window/Pane UID, and
|
|
581
|
+
termination classification. An unpaired `window-unlinked` records `retain`
|
|
582
|
+
with `topology.teardown.awaiting-pane-exit` when it first waits and again when
|
|
583
|
+
its bounded pair wait is exhausted; `kill-window` closes surface this way,
|
|
584
|
+
because tmux fires no `pane-exited` for them.
|
|
552
585
|
|
|
553
586
|
For `pane-exited`, tmux supplies `%N` as `#{hook_pane}`. Its current-context
|
|
554
587
|
session/window formats may already name a surviving client Window, so the owner
|
|
@@ -760,6 +793,14 @@ Registry-only result reports that no tmux Pane was killed, preserves the owning
|
|
|
760
793
|
Window/root/socket and all siblings, and repeating the exact apply returns the
|
|
761
794
|
ordinary no-match result.
|
|
762
795
|
|
|
796
|
+
A name, scope, or active-target delete of a target that carries that evidence
|
|
797
|
+
still refuses with the live-mirror refusal, but the refusal then names the
|
|
798
|
+
typed resource's exact form to run instead —
|
|
799
|
+
`projmux delete pane|agent uid:<uid> --socket-path <server> --dry-run`, then the
|
|
800
|
+
same command with `--yes` — and says which evidence qualifies it. A target the
|
|
801
|
+
`uid:` form would refuse too, such as a Pane without `MissingRuntime` or a
|
|
802
|
+
`Running` or `Failed` Agent, gets no such pointer.
|
|
803
|
+
|
|
763
804
|
`delete window|pane|agent` names the server its live half addresses the same
|
|
764
805
|
way `reconcile resources` does: `--socket <name>`, `--socket-path <absolute>`,
|
|
765
806
|
or the inherited absolute `$TMUX`. Outside tmux with neither flag it refuses
|
|
@@ -1144,7 +1185,9 @@ autosave-session-state`, `window record`, and
|
|
|
1144
1185
|
successful `diagnostics log` views do not produce an event. Errors from those
|
|
1145
1186
|
automatic hook/poll paths still produce one safe `error` outcome. Successful
|
|
1146
1187
|
direct command help and explicit `--dry-run` preview modes also remain
|
|
1147
|
-
read-only and do not produce an event.
|
|
1188
|
+
read-only and do not produce an event. The automatic `internal tmux converge`
|
|
1189
|
+
route still appends one typed `topology.teardown.decision` record per Window or
|
|
1190
|
+
Pane teardown decision it consumes. Journal failures are a best-effort side
|
|
1148
1191
|
channel and never change command output or exit status. See
|
|
1149
1192
|
[operational-diagnostics.md](operational-diagnostics.md) for the file,
|
|
1150
1193
|
retention, concurrency, and privacy contracts.
|
package/docs/cli.md
CHANGED
|
@@ -130,7 +130,7 @@ projmux agent app-server upgrade resume|abort --operation <ref>
|
|
|
130
130
|
projmux agent app-server handover plan|apply --request <absolute-json>
|
|
131
131
|
projmux agent app-server handover resume|abort --operation <ref>
|
|
132
132
|
projmux agent capabilities [<agent-ref> | --provider <codex|claude|antigravity>] [-o json]
|
|
133
|
-
projmux agent message send <agent-ref> [--message-ref <ref>] [--reply-to <ref>] [--ttl <duration>] -- <text>
|
|
133
|
+
projmux agent message send <agent-ref> [--source <agent-ref>] [--message-ref <ref>] [--reply-to <ref>] [--ttl <duration>] -- <text>
|
|
134
134
|
projmux agent message status <message-ref> [-o json]
|
|
135
135
|
projmux agent message qualify <claude-agent-ref> --evidence <absolute-private-json> --confirm-isolated-provider-push -o json
|
|
136
136
|
projmux agent wait <agent-ref> [--until idle] [--timeout <duration>] [-o json]
|
|
@@ -150,7 +150,7 @@ Subcommands:
|
|
|
150
150
|
| [`projmux agent usage`](#projmux-agent-usage) | Read provider account usage quota snapshots |
|
|
151
151
|
| [`projmux agent app-server`](#projmux-agent-app-server) | Manage explicitly requested private Codex app-server generation operations |
|
|
152
152
|
| [`projmux agent capabilities`](#projmux-agent-capabilities) | Read static provider support or one exact Agent's Registry-backed runtime eligibility |
|
|
153
|
-
| [`projmux agent message`](#projmux-agent-message) | Exchange bounded untrusted coordination messages
|
|
153
|
+
| [`projmux agent message`](#projmux-agent-message) | Exchange bounded untrusted coordination messages; --source selects a source Agent anchor, not caller authentication (default: active Pane) |
|
|
154
154
|
| [`projmux agent wait`](#projmux-agent-wait) | Wait read-only for one exact Agent's Registry-backed idle observation |
|
|
155
155
|
|
|
156
156
|
Canonical spelling: `projmux agent status`, `projmux agent topic`, `projmux agent resume`, `projmux agent turn start`, `projmux agent turn steer`, `projmux agent turn interrupt`, `projmux agent approval review`, `projmux agent review`, `projmux agent integrate`, `projmux agent usage`, `projmux agent app-server upgrade qualify`, `projmux agent app-server upgrade plan`, `projmux agent app-server upgrade apply`, `projmux agent app-server upgrade resume`, `projmux agent app-server upgrade abort`, `projmux agent app-server handover plan`, `projmux agent app-server handover apply`, `projmux agent app-server handover resume`, `projmux agent app-server handover abort`, `projmux agent capabilities`, `projmux agent message send`, `projmux agent message status`, `projmux agent message qualify`, `projmux agent wait`
|
|
@@ -736,7 +736,7 @@ Output modes (`-o`): `json`
|
|
|
736
736
|
|
|
737
737
|
### `projmux agent message`
|
|
738
738
|
|
|
739
|
-
Exchange bounded untrusted coordination messages
|
|
739
|
+
Exchange bounded untrusted coordination messages; --source selects a source Agent anchor, not caller authentication (default: active Pane)
|
|
740
740
|
|
|
741
741
|
Selectorless authority: `refusal` — there is no safe selectorless action; refuse before output or mutation.
|
|
742
742
|
|
|
@@ -752,7 +752,7 @@ Allowed effects:
|
|
|
752
752
|
- `domain-effect=agent-delivery`
|
|
753
753
|
|
|
754
754
|
```
|
|
755
|
-
projmux agent message send <agent-ref> [--message-ref <ref>] [--reply-to <ref>] [--ttl <duration>] -- <text>
|
|
755
|
+
projmux agent message send <agent-ref> [--source <agent-ref>] [--message-ref <ref>] [--reply-to <ref>] [--ttl <duration>] -- <text>
|
|
756
756
|
projmux agent message status <message-ref> [-o json]
|
|
757
757
|
projmux agent message qualify <claude-agent-ref> --evidence <absolute-private-json> --confirm-isolated-provider-push -o json
|
|
758
758
|
```
|
|
@@ -761,7 +761,7 @@ Subcommands:
|
|
|
761
761
|
|
|
762
762
|
| Route | Summary |
|
|
763
763
|
| --- | --- |
|
|
764
|
-
| [`projmux agent message send`](#projmux-agent-message-send) | Submit
|
|
764
|
+
| [`projmux agent message send`](#projmux-agent-message-send) | Submit bounded peer coordination; --source selects a source Agent anchor, not caller authentication (default: active Pane) |
|
|
765
765
|
| [`projmux agent message status`](#projmux-agent-message-status) | Read a payload-free broker delivery receipt |
|
|
766
766
|
| [`projmux agent message qualify`](#projmux-agent-message-qualify) | Explicitly qualify one exact Claude target using owned current-version isolation evidence and one marker push |
|
|
767
767
|
|
|
@@ -769,7 +769,7 @@ Canonical spelling: `projmux agent message send`, `projmux agent message status`
|
|
|
769
769
|
|
|
770
770
|
#### `projmux agent message send`
|
|
771
771
|
|
|
772
|
-
Submit
|
|
772
|
+
Submit bounded peer coordination; --source selects a source Agent anchor, not caller authentication (default: active Pane)
|
|
773
773
|
|
|
774
774
|
Selectorless authority: `explicit-target` — the route or caller must name the exact target.
|
|
775
775
|
|
|
@@ -785,7 +785,7 @@ Allowed effects:
|
|
|
785
785
|
- `domain-effect=agent-delivery`
|
|
786
786
|
|
|
787
787
|
```
|
|
788
|
-
projmux agent message send <agent-ref> [--message-ref <ref>] [--reply-to <ref>] [--ttl <duration>] -- <text>
|
|
788
|
+
projmux agent message send <agent-ref> [--source <agent-ref>] [--message-ref <ref>] [--reply-to <ref>] [--ttl <duration>] -- <text>
|
|
789
789
|
```
|
|
790
790
|
|
|
791
791
|
#### `projmux agent message status`
|
|
@@ -2003,10 +2003,10 @@ Subcommands:
|
|
|
2003
2003
|
|
|
2004
2004
|
| Route | Summary |
|
|
2005
2005
|
| --- | --- |
|
|
2006
|
-
| [`projmux get projects`](#projmux-get-projects) | List Project resources as NAME STATUS ACTIONS; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context |
|
|
2007
|
-
| [`projmux get windows`](#projmux-get-windows) | List Window resources as NAME STATUS ACTIONS; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry |
|
|
2008
|
-
| [`projmux get panes`](#projmux-get-panes) | List Pane resources as NAME STATUS ACTIONS; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry |
|
|
2009
|
-
| [`projmux get agents`](#projmux-get-agents) | List Agent resources as NAME STATUS ACTIONS; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry |
|
|
2006
|
+
| [`projmux get projects`](#projmux-get-projects) | List Project resources as NAME STATUS ACTIONS AGE; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context |
|
|
2007
|
+
| [`projmux get windows`](#projmux-get-windows) | List Window resources as NAME STATUS ACTIONS AGE; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry |
|
|
2008
|
+
| [`projmux get panes`](#projmux-get-panes) | List Pane resources as NAME STATUS ACTIONS AGE; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry |
|
|
2009
|
+
| [`projmux get agents`](#projmux-get-agents) | List Agent resources as NAME STATUS ACTIONS AGE; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry |
|
|
2010
2010
|
| [`projmux get runtime`](#projmux-get-runtime) | List every tmux Session, Window, and Pane on one exact server with its attribution |
|
|
2011
2011
|
| [`projmux get notifications`](#projmux-get-notifications) | List pending notification rows |
|
|
2012
2012
|
| [`projmux get snapshots`](#projmux-get-snapshots) | List saved session snapshots |
|
|
@@ -2016,7 +2016,7 @@ Canonical spelling: `projmux get projects`, `projmux get windows`, `projmux get
|
|
|
2016
2016
|
|
|
2017
2017
|
### `projmux get projects`
|
|
2018
2018
|
|
|
2019
|
-
List Project resources as NAME STATUS ACTIONS; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context
|
|
2019
|
+
List Project resources as NAME STATUS ACTIONS AGE; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context
|
|
2020
2020
|
|
|
2021
2021
|
Selectorless authority: `explicit-fan-out` — the route spelling is an intentional global or whole-set opt-in.
|
|
2022
2022
|
|
|
@@ -2041,7 +2041,7 @@ Output modes (`-o`): `uid`, `name`, `ref`, `metadata`, `json`, `none`, `wide`
|
|
|
2041
2041
|
|
|
2042
2042
|
### `projmux get windows`
|
|
2043
2043
|
|
|
2044
|
-
List Window resources as NAME STATUS ACTIONS; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry
|
|
2044
|
+
List Window resources as NAME STATUS ACTIONS AGE; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry
|
|
2045
2045
|
|
|
2046
2046
|
Selectorless authority: `natural-omitted` — omission resolves one predictable current resource or documented contextual read/scope; any selector replaces it.
|
|
2047
2047
|
|
|
@@ -2066,7 +2066,7 @@ Output modes (`-o`): `uid`, `name`, `ref`, `metadata`, `json`, `none`, `wide`
|
|
|
2066
2066
|
|
|
2067
2067
|
### `projmux get panes`
|
|
2068
2068
|
|
|
2069
|
-
List Pane resources as NAME STATUS ACTIONS; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry
|
|
2069
|
+
List Pane resources as NAME STATUS ACTIONS AGE; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry
|
|
2070
2070
|
|
|
2071
2071
|
Selectorless authority: `natural-omitted` — omission resolves one predictable current resource or documented contextual read/scope; any selector replaces it.
|
|
2072
2072
|
|
|
@@ -2089,7 +2089,7 @@ Output modes (`-o`): `uid`, `name`, `ref`, `metadata`, `json`, `none`, `wide`
|
|
|
2089
2089
|
|
|
2090
2090
|
### `projmux get agents`
|
|
2091
2091
|
|
|
2092
|
-
List Agent resources as NAME STATUS ACTIONS; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry
|
|
2092
|
+
List Agent resources as NAME STATUS ACTIONS AGE; route-implied KIND is omitted, shifting stdout positions; -o wide retains KIND and diagnostics, and -o json retains kind and invocation context; inside tmux defaults to the active managed root, and --all-projects lists the whole Registry
|
|
2093
2093
|
|
|
2094
2094
|
Selectorless authority: `natural-omitted` — omission resolves one predictable current resource or documented contextual read/scope; any selector replaces it.
|
|
2095
2095
|
|
|
@@ -217,6 +217,11 @@ handover resume refuses before it drives any effect. A receipt qualifies the one
|
|
|
217
217
|
pair it names and no other, and the refusal for a pair with no stored receipt
|
|
218
218
|
names the two commands that produce and install one.
|
|
219
219
|
|
|
220
|
+
`projmux doctor --section integrations` reports the saved version pairs and
|
|
221
|
+
their verdicts even without a generation journal. Text, JSON, and support
|
|
222
|
+
`doctor.json` distinguish an empty store from damaged or misfiled receipts;
|
|
223
|
+
see [Stored Codex version-pair qualification](codex-stored-qualification.md).
|
|
224
|
+
|
|
220
225
|
The same `receipt.json` also goes verbatim into the `qualification` field of an
|
|
221
226
|
`agent app-server upgrade plan|apply --request <absolute>.json` document. The
|
|
222
227
|
upgrade request requires that receipt's version pair to match the exact current
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Stored Codex version-pair qualification
|
|
2
|
+
|
|
3
|
+
`projmux agent app-server upgrade qualify --receipt <absolute-json>` installs
|
|
4
|
+
one measured receipt for its exact old/new Codex version pair. Inspect the
|
|
5
|
+
saved receipts with:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
projmux doctor --section integrations
|
|
9
|
+
projmux doctor --section integrations --json
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The default Doctor report includes the same inventory. Its
|
|
13
|
+
`codex_stored_qualification` JSON field also appears in support `doctor.json`,
|
|
14
|
+
with version pairs, statuses, verdicts, reasons, and readiness preserved.
|
|
15
|
+
The read does not depend on a generation-pool journal or a readable Registry.
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
Codex stored version-pair qualification
|
|
19
|
+
Store: stored
|
|
20
|
+
0.153.2 -> 0.153.4: stored; verdict: yes; reason: qualified; qualification ready: true
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
| Store status | Meaning |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `stored` | All enumerated receipts decoded and matched their filenames. |
|
|
26
|
+
| `absent` | No saved receipt exists; the directory may be absent or empty. |
|
|
27
|
+
| `damaged` | At least one receipt could not be read as its filename's pair. Other receipts remain visible. |
|
|
28
|
+
| `unavailable` | The store path could not be resolved or the directory could not be read. |
|
|
29
|
+
|
|
30
|
+
Each `version_pairs` row reports `stored`, `damaged`, or
|
|
31
|
+
`version-pair-mismatch`. A mismatch means a valid receipt names a different pair
|
|
32
|
+
from its filename; its verdict is not reported for the filename's pair. A
|
|
33
|
+
malformed `.json` filename produces a damaged row without exposing that name.
|
|
34
|
+
Non-regular receipt files are damaged; temporary save files are ignored.
|
|
35
|
+
|
|
36
|
+
For a stored row, `verdict` and `reason` come from the existing strict receipt
|
|
37
|
+
decoder. `qualification_ready` comes from the existing qualification gate:
|
|
38
|
+
a saved `no` or a self-consistent `yes` with unbacked evidence counters remains
|
|
39
|
+
not ready. This field describes only the pair's qualification, and does not
|
|
40
|
+
assert that the generation pool or an upgrade operation is ready.
|
|
41
|
+
|
|
42
|
+
Schema v2 has no timestamps or expiry policy. A receipt stays reportable until
|
|
43
|
+
it is replaced or removed. Doctor reads it without running qualification,
|
|
44
|
+
writing receipts or journals, restoring upgrade state, or executing lifecycle
|
|
45
|
+
commands.
|
package/docs/column-profiles.md
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
# Column profiles
|
|
2
2
|
|
|
3
3
|
Plural Registry reads (`get projects|windows|panes|agents`) now default to
|
|
4
|
-
`NAME STATUS ACTIONS`. The route already selects the resource kind. Runtime
|
|
4
|
+
`NAME STATUS ACTIONS AGE`. The route already selects the resource kind. Runtime
|
|
5
5
|
reads default to their identity, containment, and classification columns. Use `-o wide` (or `--output wide`) to print the full
|
|
6
6
|
column profile. Terminal width and data length never select a profile.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
Adding AGE changes these four default tables from three columns to four, keeping
|
|
9
|
+
NAME, STATUS and ACTIONS in their existing positions. AGE uses the same stored
|
|
10
|
+
creation timestamp and formatter as wide; unavailable ages remain empty cells.
|
|
11
|
+
The AGE header and a two-cell gap add five display cells when ages fit within
|
|
12
|
+
three cells; longer ages widen the table further. Resource CLI output is not
|
|
13
|
+
clipped at COLUMNS 40/80/112, so narrow terminals can wrap earlier.
|
|
14
|
+
Positional parsers must account for the added field; each resource's `kind`
|
|
15
|
+
remains available in `-o wide` and `-o json`.
|
|
11
16
|
Mixed Registry/Runtime pickers keep KIND in both profiles.
|
|
12
17
|
|
|
13
18
|
Scripts that need diagnostic columns must request `-o wide` or a structured projection explicitly. Registry JSON items
|
|
@@ -18,15 +23,15 @@ projections retain their contracts, as do singular reads and selector cardinalit
|
|
|
18
23
|
|
|
19
24
|
| Surface / kind | Default | Wide |
|
|
20
25
|
| --- | --- | --- |
|
|
21
|
-
| Registry Project | NAME STATUS ACTIONS | KIND NAME STATUS ACTIONS CONTEXT SOURCE OBSERVED AGE |
|
|
22
|
-
| Registry Window | NAME STATUS ACTIONS | KIND NAME STATUS ACTIONS CONTEXT SOURCE OBSERVED PROJECT AGE |
|
|
23
|
-
| Registry Pane | NAME STATUS ACTIONS | KIND NAME STATUS ACTIONS CONTEXT SOURCE OBSERVED PROJECT WINDOW AGENT TERMINATION AGE |
|
|
24
|
-
| Registry Agent | NAME STATUS ACTIONS | KIND NAME STATUS ACTIONS CONTEXT SOURCE OBSERVED INTERACTION PROJECT WINDOW SESSION TERMINATION AGE |
|
|
26
|
+
| Registry Project | NAME STATUS ACTIONS AGE | KIND NAME STATUS ACTIONS CONTEXT SOURCE OBSERVED AGE |
|
|
27
|
+
| Registry Window | NAME STATUS ACTIONS AGE | KIND NAME STATUS ACTIONS CONTEXT SOURCE OBSERVED PROJECT AGE |
|
|
28
|
+
| Registry Pane | NAME STATUS ACTIONS AGE | KIND NAME STATUS ACTIONS CONTEXT SOURCE OBSERVED PROJECT WINDOW AGENT TERMINATION AGE |
|
|
29
|
+
| Registry Agent | NAME STATUS ACTIONS AGE | KIND NAME STATUS ACTIONS CONTEXT SOURCE OBSERVED INTERACTION PROJECT WINDOW SESSION TERMINATION AGE |
|
|
25
30
|
| Runtime Session | SESSION NAME CLASS | SESSION NAME CLASS UID RESOURCE REASON |
|
|
26
31
|
| Runtime Window | WINDOW SESSION NAME CLASS | WINDOW SESSION NAME CLASS UID RESOURCE REASON |
|
|
27
32
|
| Runtime Pane | PANE WINDOW TITLE CLASS | PANE WINDOW TITLE CLASS UID RESOURCE REASON |
|
|
28
33
|
|
|
29
|
-
Registry defaults omit KIND, CONTEXT, SOURCE, OBSERVED
|
|
34
|
+
Registry defaults omit KIND, CONTEXT, SOURCE, OBSERVED and each kind's owner-chain,
|
|
30
35
|
INTERACTION, SESSION and TERMINATION diagnostics shown in the wide column above.
|
|
31
36
|
Runtime defaults omit UID, RESOURCE and REASON. Wide retains their full values;
|
|
32
37
|
stdout is unbounded and copyable, including long names, context, provider session
|
|
@@ -337,3 +337,26 @@ The selectorless E2E remains the single deterministic L20 scenario. Actual
|
|
|
337
337
|
active-tool/human overlap, multiple ordinary requests, same-UID recovery and
|
|
338
338
|
installed smoke remain separate unverified evidence. They are not run by this
|
|
339
339
|
qualification-plus-one-idle transaction and are not inferred from its result.
|
|
340
|
+
|
|
341
|
+
`TestClaudeDialogueStreamReplaysObservedFrameCorpus` replays the preserved
|
|
342
|
+
Claude Code 2.1.263 frame shapes through the reply-only validator and fails when
|
|
343
|
+
a recorded verdict moves. Neither it nor L20 proves:
|
|
344
|
+
|
|
345
|
+
- compatibility with the installed provider, which only this canary observes;
|
|
346
|
+
- value drift, because the corpus keeps top-level key shape and fills values
|
|
347
|
+
with placeholders;
|
|
348
|
+
- acceptance of unknown frames or fields, which the closed vocabulary rejects
|
|
349
|
+
by design.
|
|
350
|
+
|
|
351
|
+
The L20 fixture emits none of the corpus's dropped side frames. Recorded real
|
|
352
|
+
shapes the validator rejects today:
|
|
353
|
+
|
|
354
|
+
- `result-success-25-keys`: the result allowlist lacks `origin`;
|
|
355
|
+
- `system-init-allowlist-diff`: the init allowlist lacks `memory_paths` and
|
|
356
|
+
`terminal_slash_commands`.
|
|
357
|
+
|
|
358
|
+
Shapes without preserved evidence are gaps, not corpus items: `command_lifecycle`
|
|
359
|
+
keys and values; a non-null assistant `context_management` value; `system`
|
|
360
|
+
`thinking_tokens` frames; hook and user `tool_result` frames; the exact real init
|
|
361
|
+
key set; nested values of every frame; `rate_limit_event` envelope keys beyond
|
|
362
|
+
`type` and `rate_limit_info`; and earlier shape inventories, which were lost.
|
package/docs/keybindings.md
CHANGED
|
@@ -217,6 +217,91 @@ without storing or replacing the transport default. Rename actions no longer
|
|
|
217
217
|
have a built-in terminal fallback; use tmux's prefix rename flow or configure
|
|
218
218
|
an explicit safe key where the action is editable.
|
|
219
219
|
|
|
220
|
+
## Managed close keys
|
|
221
|
+
|
|
222
|
+
The generated app config replaces tmux's stock `prefix x` (kill Pane) and
|
|
223
|
+
`prefix &` (kill Window) with two catalog actions, `pane.delete` (v0 id
|
|
224
|
+
`delete-pane`) and `window.delete` (v0 id `delete-window`). Each binding
|
|
225
|
+
branches on the target's Registry identity mirror:
|
|
226
|
+
|
|
227
|
+
| Key | Target carries the mirror | Target has no mirror |
|
|
228
|
+
| --- | --- | --- |
|
|
229
|
+
| `prefix x` | `@projmux_pane_uid`: confirm, then the Pane menu Kill route (canonical `delete pane`) | tmux stock `confirm-before -p "kill-pane #P? (y/n)" kill-pane` |
|
|
230
|
+
| `prefix &` | `@projmux_window_uid`: confirm, then canonical `delete window` | tmux stock `confirm-before -p "kill-window #W? (y/n)" kill-window` |
|
|
231
|
+
|
|
232
|
+
A managed target is always confirmed first. The prompt is localized (en-US and
|
|
233
|
+
ko-KR) when the key is pressed. It says the resource is deleted from the
|
|
234
|
+
Registry and what happens to Agents: deleting a Pane leaves its owning Agent in
|
|
235
|
+
the Registry as Offline with a `deleted` exit, and deleting a Window deletes the
|
|
236
|
+
Agents in it. Neither comes back on Continue. Answering `y` deletes the target
|
|
237
|
+
with an `intentional` termination receipt, so a later Project start does not
|
|
238
|
+
re-materialize it. Deleting a Project's last Window follows `delete window` and
|
|
239
|
+
leaves a zero-Window Project. When the canonical route refuses, the reason is
|
|
240
|
+
shown on the client that pressed the key and nothing falls back to a raw tmux
|
|
241
|
+
kill.
|
|
242
|
+
|
|
243
|
+
A target without the mirror gets tmux's own stock prompt and kill, unchanged,
|
|
244
|
+
and projmux writes nothing to the Registry. The projmux process never issues
|
|
245
|
+
`kill-pane` or `kill-window` for either key: the stock body is tmux's binding,
|
|
246
|
+
run by tmux. The standalone `~/.tmux.conf` snippet does not carry these
|
|
247
|
+
actions, so a plain tmux server keeps both keys stock.
|
|
248
|
+
|
|
249
|
+
Both actions follow the ordinary keymap rules. In `keymap.toml`,
|
|
250
|
+
`prefix = "<key>"` moves the managed binding, `prefix = ""` disables it, and
|
|
251
|
+
`keys` adds root-table keys that run the same branching binding:
|
|
252
|
+
|
|
253
|
+
```toml
|
|
254
|
+
[bindings."pane.delete"]
|
|
255
|
+
prefix = "X"
|
|
256
|
+
|
|
257
|
+
[bindings."window.delete"]
|
|
258
|
+
prefix = ""
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
When an action no longer owns its stock key, because it was disabled or moved,
|
|
262
|
+
the generated config unbinds that key and binds tmux's stock body back onto it.
|
|
263
|
+
`prefix x` and `prefix &` therefore return to tmux's own behavior on the next
|
|
264
|
+
apply, including on a server that is already running, instead of being left
|
|
265
|
+
with no binding at all. Two managed actions on one prefix key are rejected.
|
|
266
|
+
Settings > Keybindings adds and removes root-table keys for these actions; their
|
|
267
|
+
prefix key is changed in `keymap.toml`.
|
|
268
|
+
|
|
269
|
+
## Managed menus
|
|
270
|
+
|
|
271
|
+
The generated app config also replaces tmux's stock Window and Pane menus. Each
|
|
272
|
+
generated menu keeps tmux's title, position, item names, key shortcuts, and dim
|
|
273
|
+
conditions, and changes only the items that alter topology or identity:
|
|
274
|
+
|
|
275
|
+
| Menu | Bindings | Kill on a target with the mirror | Kill on a target without it | Typed items | Removed |
|
|
276
|
+
| --- | --- | --- | --- | --- | --- |
|
|
277
|
+
| Window | `prefix <`, `MouseDown3Status`, `M-MouseDown3Status` | `@projmux_window_uid`: `internal tmux window-delete`, canonical `delete window` | tmux stock `kill-window` | Rename: `internal tmux window-rename`; New At End: `internal tmux window-create` | Respawn, New After |
|
|
278
|
+
| Pane | `prefix >`, `M-MouseDown3Pane` | `@projmux_pane_uid`: the Pane menu Kill route, canonical `delete pane` | tmux stock `kill-pane` | Horizontal Split / Vertical Split: `internal tmux pane-menu split-right` / `split-down` | Respawn |
|
|
279
|
+
| Pane context | `MouseDown3Pane` | same as the Pane menus | tmux stock `kill-pane` | Horizontal Split / Vertical Split, as above | Respawn |
|
|
280
|
+
|
|
281
|
+
Swap Left, Swap Right, Swap Marked, Swap Up, Swap Down, Mark, Zoom, and the
|
|
282
|
+
copy-mode items (Go To Top, Go To Bottom, Search For, Type, Copy, Copy Line)
|
|
283
|
+
are presentation and run tmux's own commands. `MouseDown3Pane` also keeps its
|
|
284
|
+
AI Resume Picker entry.
|
|
285
|
+
|
|
286
|
+
Selecting Kill is the confirmation, as it is in tmux's own menus, so a managed
|
|
287
|
+
Kill asks nothing more. It deletes the target with an `intentional` termination
|
|
288
|
+
receipt: a Pane's owning Agent stays in the Registry as Offline with a `deleted`
|
|
289
|
+
exit, the Agents of a deleted Window are deleted with it, and deleting a
|
|
290
|
+
Project's last Window leaves a zero-Window Project. When the canonical route
|
|
291
|
+
refuses, for example because the mirror names no Registry resource, the reason
|
|
292
|
+
is shown on the client that opened the menu and nothing falls back to a raw
|
|
293
|
+
tmux kill. A target without the mirror gets tmux's own kill with no Registry
|
|
294
|
+
write; the projmux process never issues `kill-pane` or `kill-window`.
|
|
295
|
+
|
|
296
|
+
A mouse menu acts on what was clicked, not on what is focused: Kill, Rename, and
|
|
297
|
+
New At End in the status-line Window menu act on the clicked Window, and the
|
|
298
|
+
Rename prompt starts with that Window's name.
|
|
299
|
+
|
|
300
|
+
The standalone `~/.tmux.conf` snippet keeps tmux's stock `prefix <`, `prefix >`,
|
|
301
|
+
`MouseDown3Status`, `M-MouseDown3Status`, and `M-MouseDown3Pane` menus; it
|
|
302
|
+
carries only the `MouseDown3Pane` menu. A `keymap.toml` that assigns a managed
|
|
303
|
+
action to `prefix <` or `prefix >` keeps that key.
|
|
304
|
+
|
|
220
305
|
## Product Requirements
|
|
221
306
|
|
|
222
307
|
Settings > Keybindings stays a discovery surface. It must continue to expose
|
|
@@ -44,6 +44,20 @@ UIDs and stage labels are bounded control data; root paths, pane content,
|
|
|
44
44
|
history, prompts, transcripts, and snapshot contents are never identity or
|
|
45
45
|
intent authority.
|
|
46
46
|
|
|
47
|
+
Automatic Window teardown decisions use `component=topology` and
|
|
48
|
+
`event=topology.teardown.decision`: one `info`/`success` record per decision
|
|
49
|
+
the `internal tmux converge` hook path consumes. An unpaired `window-unlinked`
|
|
50
|
+
records `retain` when its own hook first waits and again when its bounded pair
|
|
51
|
+
wait is exhausted, never for the carried retries between; its Window/Pane UID
|
|
52
|
+
is resolved read-only from the exact `$N/@N` handles and omitted when
|
|
53
|
+
ambiguous. The record adds only
|
|
54
|
+
a closed `decision` (`retain`, `delete-pane-agent`, `delete-window`, `refuse`),
|
|
55
|
+
a `code` from the closed `topology.teardown.<reason>` set that mirrors every
|
|
56
|
+
core teardown reason, an optional closed termination `classification`, and
|
|
57
|
+
optional opaque `window_uid` (`win-…`) and `pane_uid` (`pane-…`) Registry UIDs.
|
|
58
|
+
tmux `%N`/`@N`/`$N` handles, socket paths, session names, cwd, argv, and free
|
|
59
|
+
text are never recorded, and every other event family rejects these fields.
|
|
60
|
+
|
|
47
61
|
Session State mutations use one outcome-only `session-state.outcome` record
|
|
48
62
|
per selected attempt. The closed operations are `session-state.save`,
|
|
49
63
|
`session-state.autosave`, `session-state.restore`, and `session-state.delete`;
|
|
@@ -105,7 +105,9 @@ holds the forgery refusal. For the `L2` guarantee above,
|
|
|
105
105
|
`TestBrokerRuntimeDrainsWhenItsOwnImageWasReplaced` holds the vintage entry
|
|
106
106
|
condition and that a runtime on the installed image is not drained by it,
|
|
107
107
|
`TestReplacementRolePoliciesMatchTheContractDocument` and
|
|
108
|
-
`TestReplacementSessionClientIsNeverADrainTarget` hold the policy table,
|
|
108
|
+
`TestReplacementSessionClientIsNeverADrainTarget` hold the policy table,
|
|
109
|
+
`TestReplacementRoutesNameARunnableAction` holds that every role's action is a
|
|
110
|
+
runnable `projmux` command or a closed lifecycle event, and
|
|
109
111
|
`TestInstallReplacementPassOutcomesAreFixedByFleetAndRequest` fixes every
|
|
110
112
|
outcome of the install pass.
|
|
111
113
|
|
|
@@ -321,18 +323,46 @@ measurement, and they are fixed here rather than at a call site.
|
|
|
321
323
|
when it actually goes. `report-only` means no install touches it; the route that
|
|
322
324
|
does replace it is named instead, so a reader of the row knows what would.
|
|
323
325
|
|
|
324
|
-
`TestReplacementRolePoliciesMatchTheContractDocument` holds this table
|
|
325
|
-
|
|
326
|
+
`TestReplacementRolePoliciesMatchTheContractDocument` holds this table — its
|
|
327
|
+
operator actions included — and the lifecycle event table below equal to the
|
|
328
|
+
code's policy map and event set, in both directions.
|
|
326
329
|
|
|
327
|
-
| Role | Disposition | Replacement route |
|
|
328
|
-
| --- | --- | --- |
|
|
329
|
-
| `broker-runtime` | `drain` | `broker-drain` |
|
|
330
|
-
| `lifecycle-observer` | `report-only` | `pane-relaunch` |
|
|
331
|
-
| `supervisor` | `report-only` | `pane-relaunch` |
|
|
332
|
-
| `session-client` | `report-only` | `operator-reattach` |
|
|
333
|
-
| `agent-endpoint` | `report-only` | `pane-relaunch` |
|
|
334
|
-
| `usage-watcher` | `report-only` | `lease-expiry` |
|
|
335
|
-
| `other` | `report-only` | `process-exit` |
|
|
330
|
+
| Role | Disposition | Replacement route | Operator action |
|
|
331
|
+
| --- | --- | --- | --- |
|
|
332
|
+
| `broker-runtime` | `drain` | `broker-drain` | event `install-replacement-pass` |
|
|
333
|
+
| `lifecycle-observer` | `report-only` | `pane-relaunch` | `projmux stop project <project-ref>`, then `projmux start project <project-ref>` |
|
|
334
|
+
| `supervisor` | `report-only` | `pane-relaunch` | `projmux stop project <project-ref>`, then `projmux start project <project-ref>` |
|
|
335
|
+
| `session-client` | `report-only` | `operator-reattach` | event `shell-wrapper-exit`, then `projmux shell` |
|
|
336
|
+
| `agent-endpoint` | `report-only` | `pane-relaunch` | `projmux stop project <project-ref>`, then `projmux start project <project-ref>` |
|
|
337
|
+
| `usage-watcher` | `report-only` | `lease-expiry` | event `usage-demand-lapse` |
|
|
338
|
+
| `other` | `report-only` | `process-exit` | event `invocation-exit` |
|
|
339
|
+
|
|
340
|
+
**The operator action is the route spelled as something that can happen.** A
|
|
341
|
+
route name says which kind of replacement applies; the action says what carries
|
|
342
|
+
it out, step by step. A step is either a `projmux` command the shipped CLI
|
|
343
|
+
catalog resolves to a runnable verb, or one of the lifecycle events below, which
|
|
344
|
+
replace a role with no command at all.
|
|
345
|
+
`TestReplacementRoutesNameARunnableAction` fails when a command names a route
|
|
346
|
+
the catalog does not have, stops at a verb that refuses without its child, or
|
|
347
|
+
reaches into `internal`, and when an event is outside this list.
|
|
348
|
+
|
|
349
|
+
| Event | What happens |
|
|
350
|
+
| --- | --- |
|
|
351
|
+
| `install-replacement-pass` | `make install` runs `projmux internal install-replace`, which dials the superseded broker runtime. The runtime drains, closes when its last binding goes, and the next binding starts one on the installed image |
|
|
352
|
+
| `shell-wrapper-exit` | the terminal command that ran `projmux shell` returns. The wrapper waits on its `tmux attach-session` child, so it ends only when that client does |
|
|
353
|
+
| `usage-demand-lapse` | no usage render has refreshed the watcher's demand marker within its 15-second TTL, so the watcher cancels itself and releases its lease; the next render starts one on the installed image. A status line still rendering the usage segment keeps that demand fresh |
|
|
354
|
+
| `invocation-exit` | a short-lived invocation returns on its own, and the next one runs the installed image |
|
|
355
|
+
|
|
356
|
+
**`pane-relaunch` is a Project runtime cycle.** Each role it covers lives as
|
|
357
|
+
long as one managed Pane: the supervisor is that Pane's own process, the
|
|
358
|
+
lifecycle observer ends once its Pane binding is gone, and the endpoint helper
|
|
359
|
+
ends once its provider process does. `projmux stop project` ends the Project's
|
|
360
|
+
exact tmux session and preserves its Registry graph; `projmux start project`
|
|
361
|
+
materializes that graph again from the installed image, and its Continue
|
|
362
|
+
launches or resumes the Project's declared Agents under the same eligibility
|
|
363
|
+
every Continue uses. It ends every Pane of that Project, which is exactly why
|
|
364
|
+
no install runs it on the operator's behalf. A Pane under the Home control
|
|
365
|
+
session belongs to no Project, and no Project verb reaches it.
|
|
336
366
|
|
|
337
367
|
**Exactly one role drains, and that is a fact about what exists rather than a
|
|
338
368
|
first instalment.** A drain is a protocol: the runtime has to be able to hear
|
|
@@ -350,6 +380,17 @@ typed into. It is report-only and no cutoff reaches it.
|
|
|
350
380
|
`TestReplacementSessionClientIsNeverADrainTarget` holds that as a property of
|
|
351
381
|
the table rather than of any call site.
|
|
352
382
|
|
|
383
|
+
**Detaching and reattaching does not by itself finish that replacement.** The
|
|
384
|
+
census counts the `projmux shell` wrapper, not the tmux client. The wrapper
|
|
385
|
+
starts `tmux attach-session` as a child process and waits on it, so the
|
|
386
|
+
wrapper — the process still on the pre-install image — keeps running until that
|
|
387
|
+
client exits and the terminal command that ran `projmux shell` returns. A
|
|
388
|
+
reattach that leaves that command running, such as switching sessions or
|
|
389
|
+
attaching a second client, leaves the wrapper exactly where it was. The required
|
|
390
|
+
action is to end the wrapper by exiting the terminal session running
|
|
391
|
+
`projmux shell`, then start `projmux shell` again, which runs the installed
|
|
392
|
+
image.
|
|
393
|
+
|
|
353
394
|
**No disposition severs work.** The one hard kill this repository has measured —
|
|
354
395
|
2026-09-05, four panes — brought three of the four back automatically and left
|
|
355
396
|
the fourth wedged on `backlog-overflow`. A recovery asymmetry that large is what
|