projmux 0.15.3 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-ko.md +3 -4
- package/README.md +3 -3
- package/docs/agent-message-replies.md +82 -2
- package/docs/ai-agent-shortcuts.md +6 -5
- package/docs/architecture.md +134 -57
- package/docs/claude-coordination-endpoints.md +164 -14
- package/docs/cli-guide.md +274 -116
- package/docs/cli.md +645 -563
- package/docs/codex-installed-compatibility.md +6 -11
- package/docs/codex-native-required-migration.md +1 -59
- package/docs/configuration.md +99 -176
- package/docs/globalization.md +11 -1
- package/docs/hooks.md +83 -32
- package/docs/keybindings.md +68 -2
- package/docs/legacy-cli-retirement.md +3 -3
- package/docs/legacy-diagnostics-inventory.md +4 -4
- package/docs/native-picker.md +3 -5
- package/docs/notify-queue.md +1 -1
- package/docs/operational-diagnostics.md +53 -31
- package/docs/pr-guideline.md +66 -22
- package/docs/release.md +97 -0
- package/docs/replacement-contract.md +66 -58
- package/docs/resource-attribution.md +2 -2
- package/docs/session-restore.md +46 -80
- package/docs/settings-ia.md +14 -22
- package/docs/statusbar.md +15 -18
- package/docs/testing.md +15 -0
- package/docs/tmux-surface-inventory.md +8 -10
- package/docs/troubleshooting.md +2 -4
- package/docs/upgrading.md +142 -7
- package/docs/usage-tracking.md +24 -48
- package/package.json +5 -5
- package/docs/agent-workflow.md +0 -2596
- package/docs/codex-generation-pool.md +0 -623
- package/docs/codex-stored-qualification.md +0 -45
package/docs/release.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Release
|
|
2
|
+
|
|
3
|
+
This document describes how a projmux version is released. For the npm
|
|
4
|
+
package layout, publish order, and trusted publishing, see
|
|
5
|
+
[npm-distribution.md](npm-distribution.md). For the PR title rules that feed
|
|
6
|
+
the release notes, see [pr-guideline.md](pr-guideline.md).
|
|
7
|
+
|
|
8
|
+
## Stable releases through release-please
|
|
9
|
+
|
|
10
|
+
`release-please-action` watches `main`, accumulates Conventional Commit
|
|
11
|
+
subjects, and opens or refreshes a "chore(main): release X.Y.Z" PR. That PR
|
|
12
|
+
contains the version bump (`internal/version/version.go` and
|
|
13
|
+
`.release-please-manifest.json`), the `CHANGELOG.md` updates, and the release
|
|
14
|
+
notes.
|
|
15
|
+
|
|
16
|
+
Merging the release PR creates the GitHub Release with auto-generated notes as
|
|
17
|
+
a **draft** (`draft` in `release-please-config.json`).
|
|
18
|
+
|
|
19
|
+
## Tag creation
|
|
20
|
+
|
|
21
|
+
The same package config sets `force-tag-creation`, so release-please creates
|
|
22
|
+
`refs/tags/vX.Y.Z` during its release pass, before it computes the next release
|
|
23
|
+
PR. That tag creation triggers the tag workflow through the release-please PAT.
|
|
24
|
+
|
|
25
|
+
Do not move tag creation into a post-action workflow step. release-please-action
|
|
26
|
+
creates releases before pull requests, and a delayed tag makes the same run
|
|
27
|
+
treat the just-released commits as unreleased.
|
|
28
|
+
|
|
29
|
+
## The tag workflow
|
|
30
|
+
|
|
31
|
+
`.github/workflows/release.yml` triggers on the tag push. It runs the shipped
|
|
32
|
+
E2E shard/suite matrix behind the fail-closed `Release E2E Tests` aggregate,
|
|
33
|
+
then builds the linux/darwin × amd64/arm64 matrix and uploads tarballs to the
|
|
34
|
+
drafted release (`gh release upload --clobber`). `Build Release` depends on the
|
|
35
|
+
aggregate rather than on individual shards.
|
|
36
|
+
|
|
37
|
+
Do not add hardcoded notes back to that workflow. release-please owns the
|
|
38
|
+
notes.
|
|
39
|
+
|
|
40
|
+
## Publish ordering
|
|
41
|
+
|
|
42
|
+
The release becomes visible only in the final `publish-release` job, after
|
|
43
|
+
`publish-npm` succeeds. That ordering is the contract:
|
|
44
|
+
|
|
45
|
+
- Users never see a GitHub release for a version npm cannot install yet.
|
|
46
|
+
- A failed npm publish leaves the release drafted and the workflow red instead
|
|
47
|
+
of shipping a half-published version.
|
|
48
|
+
|
|
49
|
+
See [npm-distribution.md](npm-distribution.md#publish-order) for the npm side
|
|
50
|
+
of that order.
|
|
51
|
+
|
|
52
|
+
## Release candidates
|
|
53
|
+
|
|
54
|
+
Release candidates are cut **outside** release-please, by the
|
|
55
|
+
`workflow_dispatch`-only `.github/workflows/release-rc.yml`. It takes an
|
|
56
|
+
`X.Y.Z-rc.N` version, drafts a GitHub Release marked `--prerelease` against
|
|
57
|
+
`main` HEAD, then pushes `vX.Y.Z-rc.N` with the release-please PAT, so the same
|
|
58
|
+
`release.yml` builds, uploads, and publishes it.
|
|
59
|
+
|
|
60
|
+
Running it is a deliberate manual act: npm publishes cannot be recalled.
|
|
61
|
+
|
|
62
|
+
### Do not configure prerelease in release-please
|
|
63
|
+
|
|
64
|
+
Do **not** add `prerelease` or `prerelease-type` to `release-please-config.json`
|
|
65
|
+
to get release candidates. release-please gates the prerelease flag on
|
|
66
|
+
`config.prerelease && (version.preRelease || version.major === 0)`. This
|
|
67
|
+
repository is `0.x`, so the key would stamp *stable* releases as prereleases,
|
|
68
|
+
`releases/latest` would stop resolving, and default-channel updates would go
|
|
69
|
+
silently dead.
|
|
70
|
+
|
|
71
|
+
### The rc path never touches the manifest
|
|
72
|
+
|
|
73
|
+
The rc path writes exactly one ref: the tag. It never touches
|
|
74
|
+
`.release-please-manifest.json`, so release-please keeps measuring the next
|
|
75
|
+
stable release from the previous *stable* release.
|
|
76
|
+
|
|
77
|
+
release-please picks that boundary by matching the manifest value against a
|
|
78
|
+
tag, with no prerelease filter on that path. An rc holding the manifest slot
|
|
79
|
+
would silently trim the next stable release notes and its `compare/` link.
|
|
80
|
+
|
|
81
|
+
## Channel branching in release.yml
|
|
82
|
+
|
|
83
|
+
`release.yml` branches on the tag only where the channel is decided:
|
|
84
|
+
|
|
85
|
+
- A prerelease tag publishes npm with `--tag rc` and keeps `--prerelease` when
|
|
86
|
+
the release is undrafted.
|
|
87
|
+
- A stable tag runs exactly as before.
|
|
88
|
+
|
|
89
|
+
Job names, order, and the `publish-npm` → `publish-release` gating are
|
|
90
|
+
identical for both. `test/release_workflow_contract_test.py` executes both step
|
|
91
|
+
scripts against a stable and an rc tag to hold that split.
|
|
92
|
+
|
|
93
|
+
## Commit subjects
|
|
94
|
+
|
|
95
|
+
Non-Conventional commit subjects on `main` are silently skipped by
|
|
96
|
+
release-please. Keep PR titles strict. Squash merge ensures the PR title is the
|
|
97
|
+
only subject that lands.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Replacement completion and restorability
|
|
2
2
|
|
|
3
3
|
Three layers of this application hold an execution image, and every consumer of
|
|
4
|
-
`make install`, `npm install`, or a provider
|
|
4
|
+
`make install`, `npm install`, or a provider upgrade believes one
|
|
5
5
|
sentence about all three at once. That sentence is false in a different way on
|
|
6
6
|
each layer. This document fixes what is guaranteed, what is not, and how a
|
|
7
7
|
report can be recovered from the tokens the diagnosis prints.
|
|
@@ -13,7 +13,7 @@ the `projmux doctor` replacement table:
|
|
|
13
13
|
| --- | --- | --- |
|
|
14
14
|
| `L1` | `installed-executable-image` | the file the installed path publishes |
|
|
15
15
|
| `L2` | `long-lived-projmux-processes` | every running child of that file |
|
|
16
|
-
| `L3` | `provider-sessions-and-generations` | provider sessions
|
|
16
|
+
| `L3` | `provider-sessions-and-generations` | provider sessions, whose app-server lifetime the upstream `codex app-server daemon` owns |
|
|
17
17
|
|
|
18
18
|
`projmux doctor` renders the table on an unfiltered run and under
|
|
19
19
|
`projmux doctor --section replacement`. It is read-only in the same sense as
|
|
@@ -44,22 +44,14 @@ image accepts no new work on any of the three layers*.
|
|
|
44
44
|
replace it and is left alone — see *The L2 replacement policy* below. A
|
|
45
45
|
replacement that has not finished within the drain cutoff is reported as
|
|
46
46
|
`replacement-cutoff-reached` and is still not ended.
|
|
47
|
-
- `L3`
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
measures a declared pair in isolation and
|
|
56
|
-
`projmux agent app-server upgrade qualify --receipt <absolute-json>` installs
|
|
57
|
-
the receipt it writes where both doors read it. **What is not guaranteed is
|
|
58
|
-
the measurement's honesty.** The gate checks that the receipt's coverage
|
|
59
|
-
counters can have come from a run — an acceptance claim with no observation
|
|
60
|
-
behind it is refused as forged — but a determined forger who writes a coverage
|
|
61
|
-
count of one is not contradicted by anything else in the receipt. The gate
|
|
62
|
-
makes the receipt state its coverage; it does not attest to it.
|
|
47
|
+
- `L3` is not replaced by an install at all, and this application no longer
|
|
48
|
+
switches an app-server generation: the endpoint lifetime belongs to the
|
|
49
|
+
upstream `codex app-server daemon`, and the private generation pool that once
|
|
50
|
+
owned it — with its upgrade, qualification, and handover commands — is gone.
|
|
51
|
+
What the row still reports is the Registry against provider evidence: a
|
|
52
|
+
`Running` Agent that provider evidence contradicts, and a `Running` Agent that
|
|
53
|
+
nothing can confirm. Absence of both is not evidence of a restore route, so
|
|
54
|
+
restoration stays `unknown`.
|
|
63
55
|
|
|
64
56
|
**Non-Guarantee.** Explicitly outside this contract:
|
|
65
57
|
|
|
@@ -68,13 +60,14 @@ image accepts no new work on any of the three layers*.
|
|
|
68
60
|
`unsupported-platform` with the `unknown` verdict on both axes. This contract
|
|
69
61
|
does not build a substitute observation for that platform; it states the gap.
|
|
70
62
|
- The provider's own upstream seamless-upgrade contract. `L3` reasons about the
|
|
71
|
-
|
|
63
|
+
Registry and the provider evidence it can reach, never about what the provider
|
|
64
|
+
promises.
|
|
72
65
|
- An externally owned (`unmanaged`) app-server. Its state is not this
|
|
73
66
|
application's to observe or restore.
|
|
74
67
|
- Automatic classification of which changes form one invariant. See C-2.
|
|
75
68
|
|
|
76
69
|
**Scope.** In space: one machine's projmux installation, the long-lived
|
|
77
|
-
processes it owns, and the
|
|
70
|
+
processes it owns, and the provider sessions its Registry records. In time: from the return
|
|
78
71
|
of one `install` or `update` to the next. **Expiry: a verdict expires when the
|
|
79
72
|
installed binary's SHA changes.** A table printed before an install describes an
|
|
80
73
|
installation that no longer exists.
|
|
@@ -85,7 +78,7 @@ installation that no longer exists.
|
|
|
85
78
|
| --- | --- | --- |
|
|
86
79
|
| `L1` | this reader's own executable link carries the kernel's `(deleted)` suffix | none for the binary. No copy of the replaced image is retained, and the recovery text the install prints on failure is config convergence, never a rollback. Restorability is `not-restorable` on every supported path. |
|
|
87
80
|
| `L2` | the whole-fleet vintage census, the newest `install-residue.jsonl` record whose own census observed anything, and the last `install-replacement.json` pass | end and relaunch the residual process through the routes this application already ships. The drain cutoff bounds the wait, and reaching it changes the row rather than the fleet, so a failed replacement leaves every process exactly where a successful one would have found it. |
|
|
88
|
-
| `L3` |
|
|
81
|
+
| `L3` | the Running-versus-live-session census | there is no projmux-owned generation switch to undo. A `Running` Agent whose provider session is gone is rebound with `projmux agent resume <ref>`, which moves a retired endpoint reference onto the daemon endpoint; a session nothing can confirm has no route this application can establish. |
|
|
89
82
|
|
|
90
83
|
**Enforcement.** `TestDoctorReplacementLayerVerdictsAreFixedByInputCombination`
|
|
91
84
|
fixes every input combination to its two verdicts and its token.
|
|
@@ -93,15 +86,8 @@ fixes every input combination to its two verdicts and its token.
|
|
|
93
86
|
to name the evidence that was missing.
|
|
94
87
|
`TestDoctorReplacementDarwinReportsUnsupportedPlatformForImageAndProcessLayers`
|
|
95
88
|
holds the platform branch.
|
|
96
|
-
`
|
|
97
|
-
holds the `L3`
|
|
98
|
-
`TestDoctorReplacementL3RestorationMovesWhenTheQualificationLaneOpens` holds the
|
|
99
|
-
transition across it. For the `L3` guarantee above,
|
|
100
|
-
`TestActivateManagedCurrentRefusesEveryUnqualifiedRequestBeforeDraining` and
|
|
101
|
-
`TestResumeRefusesAnUnqualifiedPairBeforeAnyHandoverEffect` hold the two doors,
|
|
102
|
-
`TestResumeStillRetiresAVacantGenerationWithoutAReceipt` holds the vacancy
|
|
103
|
-
exception, and `TestQualificationGateRefusesEvidenceCountersNoObservationBacks`
|
|
104
|
-
holds the forgery refusal. For the `L2` guarantee above,
|
|
89
|
+
`TestDoctorReplacementCensusSeparatesRegistryRunningFromLiveProviderSession`
|
|
90
|
+
holds the `L3` census and its mismatch token. For the `L2` guarantee above,
|
|
105
91
|
`TestBrokerRuntimeDrainsWhenItsOwnImageWasReplaced` holds the vintage entry
|
|
106
92
|
condition and that a runtime on the installed image is not drained by it,
|
|
107
93
|
`TestReplacementRolePoliciesMatchTheContractDocument` and
|
|
@@ -250,19 +236,14 @@ the token constants in the code equal, in both directions.
|
|
|
250
236
|
| `L2` | `install-residue-recorded` | `not-replaced` | `restorable` | no live child was observable, and the newest ledger record whose own census observed anything says that install left residue |
|
|
251
237
|
| `L2` | `install-residue-clean` | `replaced` | `restorable` | no live child was observable, and the newest ledger record whose own census observed anything says that install left none |
|
|
252
238
|
| `L2` | `no-observed-processes` | `unknown` | `unknown` | neither the live census nor any ledger record observed anything. Every reading is silent; none says the fleet is clean |
|
|
253
|
-
| `L3` | `
|
|
254
|
-
| `L3` | `registry-running-provider-session-dead` |
|
|
255
|
-
| `L3` | `
|
|
256
|
-
| `L3` | `
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
`pool-derived` means the replacement axis follows the pool rather than the
|
|
263
|
-
token: `replaced` once a generation is draining, handover-pending, or retired —
|
|
264
|
-
because such a generation accepts no new admission, which is exactly the
|
|
265
|
-
sentence C-1's Assumption makes — and `not-replaced` otherwise.
|
|
239
|
+
| `L3` | `registry-unobserved` | `unknown` | `unknown` | no Registry was read, so nothing about the provider sessions was observed |
|
|
240
|
+
| `L3` | `registry-running-provider-session-dead` | `not-replaced` | `not-restorable` | provider evidence contradicts a Registry `Running` Agent |
|
|
241
|
+
| `L3` | `registry-running-session-unobserved` | `not-replaced` | `unknown` | Running Agents rest on the Registry alone, with no provider handle to check |
|
|
242
|
+
| `L3` | `provider-sessions-uncontradicted` | `not-replaced` | `unknown` | the Registry was read and no Running Agent is contradicted or unconfirmed. Nothing contradicts the sessions; nothing establishes a restore route for them either |
|
|
243
|
+
|
|
244
|
+
The `L3` replacement axis is `not-replaced` on every reading that reached the
|
|
245
|
+
Registry: an install replaces no provider session, and this application owns no
|
|
246
|
+
app-server generation switch that could replace one.
|
|
266
247
|
|
|
267
248
|
## Process role vocabulary
|
|
268
249
|
|
|
@@ -423,15 +404,50 @@ absence is stated by this table's `unsupported-platform` row.
|
|
|
423
404
|
|
|
424
405
|
`projmux internal install-replace` runs as a step of `make install`, immediately
|
|
425
406
|
before the residue census so the census measures the fleet the pass left. It
|
|
426
|
-
takes the census, splits the residual processes by disposition,
|
|
427
|
-
published broker
|
|
407
|
+
takes the census, splits the residual processes by disposition, discovers the
|
|
408
|
+
published generation-scoped broker endpoints in this state domain, and dials
|
|
409
|
+
those whose PID hints select this executable's residual processes. PID is only
|
|
410
|
+
a selection hint; the existing ownership and credential checks still authorize
|
|
411
|
+
the connection. The legacy default endpoint key locates the directory and is
|
|
412
|
+
not assumed to be the published runtime. The pass waits a bounded moment and
|
|
428
413
|
writes `install-replacement.json`.
|
|
429
414
|
|
|
415
|
+
A welcome from a current-image runtime cannot stand in for a residual target.
|
|
416
|
+
A drain/closing refusal confirms reachability; if the exact socket disappears
|
|
417
|
+
during a failed request, its disappearance proves that target is already gone. The runtime writes `drain-required`
|
|
418
|
+
before an idle drain closes its connection. Completion follows the original
|
|
419
|
+
socket identities and ownership-checked runtime IDs captured for accepted
|
|
420
|
+
targets, so an absent unrelated socket or a successor published at the same
|
|
421
|
+
path cannot distort the drained count. Runtime IDs distinguish successors even
|
|
422
|
+
when the filesystem reuses the original socket's inode. An unreadable or
|
|
423
|
+
untrusted successor record alone does not prove completion.
|
|
424
|
+
|
|
430
425
|
It **starts nothing** — a replacement pass that launched what it was sent to
|
|
431
426
|
replace would leave more behind than it found, so it dials and never ensures.
|
|
432
|
-
It **signals nothing**: the only request it makes is a socket handshake.
|
|
433
|
-
|
|
434
|
-
|
|
427
|
+
It **signals nothing**: the only request it makes is a socket handshake.
|
|
428
|
+
An unreachable target makes `internal install-replace` exit 1. `make install`
|
|
429
|
+
still runs the residue census, then fails because replacement did not finish.
|
|
430
|
+
The binary publication and config convergence have already completed; this
|
|
431
|
+
failure does not roll them back. Accepted drains that are still carrying work
|
|
432
|
+
remain successful, as do complete, no-target, and unsupported-platform passes.
|
|
433
|
+
Their output is unchanged.
|
|
434
|
+
|
|
435
|
+
On an unreachable result, stderr retains the count and refusal and adds the
|
|
436
|
+
remaining drain targets' role, pid, and mapped executable revision, followed by
|
|
437
|
+
the impact and next action. Targets are rechecked after the refusal; a vanished
|
|
438
|
+
or unreadable target is not invented, and an unavailable build revision is
|
|
439
|
+
`unknown`. These identities are transient terminal output only:
|
|
440
|
+
`install-replacement.json` and the residue ledger retain counts and tokens.
|
|
441
|
+
The replacement record adds `failureStage` on an unsuccessful request:
|
|
442
|
+
`discovery` means target selection, record, or socket validation failed;
|
|
443
|
+
`dial` means the local socket connection failed; `handshake` means the greeting
|
|
444
|
+
or response failed or did not accept a drain. `refusal` keeps its existing broker
|
|
445
|
+
token, when one is available. A current-image welcome has no refusal token.
|
|
446
|
+
Successful, pending, no-target, and unsupported records omit `failureStage`.
|
|
447
|
+
The diagnostic states that later Codex Agents may lack control while the old
|
|
448
|
+
broker remains. Let existing work finish, check that the named processes exit
|
|
449
|
+
naturally, and retry `make install`. If they remain, the operator reviews the
|
|
450
|
+
targets before deciding on termination; the install does not signal them.
|
|
435
451
|
|
|
436
452
|
Its outcome vocabulary is closed, and it reaches the `L2` row as
|
|
437
453
|
`replacement.outcome`:
|
|
@@ -567,13 +583,6 @@ reconstruction.
|
|
|
567
583
|
| `replacement.drained` | `L2` | counter |
|
|
568
584
|
| `replacement.reported` | `L2` | counter |
|
|
569
585
|
| `registry.observed` | `L3` | `true` / `false` |
|
|
570
|
-
| `pool.status` | `L3` | pool status token, or `unobserved` when no pool diagnosis was read |
|
|
571
|
-
| `pool.reason` | `L3` | pool reason token |
|
|
572
|
-
| `pool.action` | `L3` | pool action token |
|
|
573
|
-
| `pool.generations.live` | `L3` | counter |
|
|
574
|
-
| `pool.generations.draining` | `L3` | counter |
|
|
575
|
-
| `qualification.verdict` | `L3` | qualification verdict token |
|
|
576
|
-
| `qualification.reason` | `L3` | qualification reason token |
|
|
577
586
|
| `sessions.running` | `L3` | counter |
|
|
578
587
|
| `sessions.live` | `L3` | counter |
|
|
579
588
|
| `sessions.dead` | `L3` | counter |
|
|
@@ -591,6 +600,5 @@ The replacement policy above is the one thing on this page that acts, and it
|
|
|
591
600
|
acts through a strictly narrower door. `TestReplacementPathEndsNoProcess` holds
|
|
592
601
|
the same guard over the policy table and the install pass: they carry no
|
|
593
602
|
termination, no signalling, and no restart either. **The whole of the action is
|
|
594
|
-
a socket handshake, and the runtime decides.** `L1` atomicity
|
|
595
|
-
|
|
596
|
-
path may alter their behavior.
|
|
603
|
+
a socket handshake, and the runtime decides.** `L1` atomicity is separate work
|
|
604
|
+
on a separate door, and no change on this path may alter its behavior.
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
Phase 0 provides the read-only attribution contract consumed by the Resource
|
|
4
4
|
Inspector shipped in Phase 1. `projmux resources`, the client-scoped
|
|
5
5
|
`resource-inspector` popup, the statusbar range, and `Resources:Open` all keep
|
|
6
|
-
the snapshot in memory only for the interactive process lifetime; it
|
|
7
|
-
|
|
6
|
+
the snapshot in memory only for the interactive process lifetime; it is never
|
|
7
|
+
persisted.
|
|
8
8
|
|
|
9
9
|
## Identity and inventory
|
|
10
10
|
|
package/docs/session-restore.md
CHANGED
|
@@ -1,80 +1,39 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Project Startup
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
the existing v1 schema and storage behavior. In snapshot save's runtime id
|
|
6
|
-
duplicate check, a Window or Pane recorded as `MissingRuntime`/`RuntimeUnbound`
|
|
7
|
-
does not claim its retained runtime id, so a tmux id reused after a server
|
|
8
|
-
restart does not refuse the save; two live Windows or two live Panes sharing an
|
|
9
|
-
id are still refused.
|
|
3
|
+
A closed Project starts from its Registry desired state. projmux keeps no other
|
|
4
|
+
saved Project state: the Registry (`registry.json`) is the only input.
|
|
10
5
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
projmux create snapshot
|
|
14
|
-
projmux restore snapshot --session <snapshot-session> [--project <ref> | -p <ref>] --dry-run
|
|
15
|
-
projmux restore snapshot --session <snapshot-session> [--project <ref> | -p <ref>] --yes [--client /dev/pts/N]
|
|
16
|
-
projmux delete snapshot --session <snapshot-session>
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Restore requires an exact snapshot and an exact, closed target Project. The
|
|
20
|
-
dry-run validates both inputs and prints replacement, deletion, preserved-UID,
|
|
21
|
-
and lost-conversation-pointer counts with zero Registry, tmux, and snapshot writes.
|
|
22
|
-
Snapshot Project/Window/Pane metadata is checked against the exact target owner
|
|
23
|
-
chain. A UID held by another root, a cross-kind UID reuse, a Project mismatch,
|
|
24
|
-
or conflicting owner metadata refuses before commit. The ordinary Project-open
|
|
25
|
-
trust authorization must also approve the exact target root before the Registry
|
|
26
|
-
transaction begins.
|
|
27
|
-
|
|
28
|
-
After `--yes`, one atomic Registry transaction replaces only the target
|
|
29
|
-
Project's descendant Window/Pane/Agent graph and its descendant name
|
|
30
|
-
reservations. The Project UID, root, trust metadata, unrelated Projects,
|
|
31
|
-
ControlSessions, and source snapshot bytes are preserved. Metadata-bearing
|
|
32
|
-
snapshots reuse their exact target-subtree UIDs and preserve a surviving
|
|
33
|
-
final-v2 Agent or shell anchor plus a surviving direct default shell.
|
|
34
|
-
Metadata-free legacy snapshots reuse target descendants positionally, select
|
|
35
|
-
the first valid Window-local Pane as the role-agnostic anchor, select the first
|
|
36
|
-
direct shell as the optional default, and mint identities only for missing
|
|
37
|
-
items. An Agent-only Window is valid with an empty default. Repeating the same
|
|
38
|
-
projection is a Registry zero-diff.
|
|
39
|
-
|
|
40
|
-
Resource metadata records the Registry schema that produced it. A v3 snapshot
|
|
41
|
-
is projected through the same root-wide same-kind duplicate-group and
|
|
42
|
-
destination-closure rule as Registry migration: affected resources receive
|
|
43
|
-
their exact UID names, unique names outside the closure are preserved, and no
|
|
44
|
-
numeric suffix is minted. A current-v4 snapshot containing a root-wide
|
|
45
|
-
same-kind collision is rejected as damaged before trust authorization,
|
|
46
|
-
Registry/tmux/provider mutation, or any snapshot write.
|
|
47
|
-
|
|
48
|
-
The committed Registry is then converged by the ordinary Project materializer.
|
|
49
|
-
For a restored offline Agent-anchor Window, snapshot materialization visibly plans a
|
|
50
|
-
lazy default shell, creates the Window from that shell, and stages the Agent on
|
|
51
|
-
its retained anchor Pane UID. A successful repeat writes neither Registry nor
|
|
52
|
-
topology. Snapshot Agent recipes use the canonical provider launch/resume path,
|
|
53
|
-
including their existing fresh-conversation fallback. Stored startup
|
|
54
|
-
commands are not directly executed by snapshot restore. A runtime item refusal
|
|
55
|
-
does not roll the Registry back: desired state and the source snapshot remain
|
|
56
|
-
available for another `Continue project`, and the refusal is reported as an
|
|
57
|
-
item notice. If an explicit client is supplied, the final observable step is
|
|
58
|
-
`switch-client -c` to the Project's declared session even when the background
|
|
59
|
-
continuation has no inherited `TMUX` variable.
|
|
60
|
-
|
|
61
|
-
## Project startup
|
|
62
|
-
|
|
63
|
-
A closed Project has exactly two actions:
|
|
6
|
+
A registered closed Project has exactly two actions. A root that is not a
|
|
7
|
+
registered Project is not asked: it opens fresh, which registers it.
|
|
64
8
|
|
|
65
9
|
- `Continue project` opens the current Registry desired state with the ordinary
|
|
66
10
|
materializer. A retained graph keeps its Project, Window, Pane, and Agent
|
|
67
11
|
UIDs. A zero-Window Project keeps its Project UID and atomically receives one
|
|
68
12
|
new canonical Window and shell UID before materialization.
|
|
69
|
-
- `
|
|
13
|
+
- `Clear layout and open` clears the Project's saved Window and Agent layout
|
|
14
|
+
and opens it again; the folder, its files, `.projmux/config.toml`, and trust
|
|
15
|
+
stay. It atomically replaces the same-root graph with a new Project
|
|
70
16
|
UID and one new canonical Window/shell UID chain, after a confirmation naming
|
|
71
17
|
the exact old Project UID and its Window/Pane/Agent counts. Declining returns
|
|
72
18
|
to the startup rows and writes nothing. It does not archive or retain the old
|
|
73
|
-
generation.
|
|
19
|
+
generation. Its new Window's first Pane follows the saved launch default
|
|
20
|
+
(`tmux-ai-split-mode`), exactly as a Window created from the UI does: the
|
|
21
|
+
choice is made before anything is cleared. The first open of an unregistered
|
|
22
|
+
root, which resolves to the same fresh start, behaves the same.
|
|
74
23
|
|
|
75
24
|
Esc/cancel returns to Projects; it is not an action row. Picker failure falls
|
|
76
25
|
back to the non-destructive `Continue project` action.
|
|
77
26
|
|
|
27
|
+
`Continue project` needs a registered Project. On a root that is not a
|
|
28
|
+
registered Project it refuses with zero Registry writes and points to
|
|
29
|
+
`Clear layout and open` (`continue project unavailable: <root> is not a registered
|
|
30
|
+
Project; choose Clear layout and open`). It never falls back to Fresh on its own.
|
|
31
|
+
|
|
32
|
+
projmux does not save Project state on its own at quit or on a timer.
|
|
33
|
+
`projmux quit` offers only `Quit projmux` and `Cancel`. The hidden `internal tmux autosave-session-state`
|
|
34
|
+
route is kept only so status lines rendered by older installs keep working, and
|
|
35
|
+
it does nothing.
|
|
36
|
+
|
|
78
37
|
Continue resumes an Agent's exact recorded conversation after interrupted,
|
|
79
38
|
killed, abnormal, unknown, or unrecorded termination. Intentional and normal
|
|
80
39
|
termination remain excluded. A recorded receipt must agree on the Agent and
|
|
@@ -87,8 +46,8 @@ A missing, blank, malformed, or mismatched conversation ref, a disabled provider
|
|
|
87
46
|
a missing workspace, or a resume preparation failure skips the Agent with a
|
|
88
47
|
reason. Continue never substitutes a new conversation. Shells and other
|
|
89
48
|
recoverable Agents still converge; an unrecoverable Agent that is itself a
|
|
90
|
-
Window's required anchor keeps the existing Window refusal.
|
|
91
|
-
|
|
49
|
+
Window's required anchor keeps the existing Window refusal. `agent resume`
|
|
50
|
+
retains its separate authority.
|
|
92
51
|
|
|
93
52
|
After Continue commits, its startup summary shows the resumed and skipped Agent
|
|
94
53
|
totals and `projmux diagnostics log --component topology`. The same counts are
|
|
@@ -110,21 +69,28 @@ errors. Dry-run writes no execution event; failed or rolled-back execution
|
|
|
110
69
|
records an error with zero committed counts. Journal and display failures are
|
|
111
70
|
best effort and never change the topology result.
|
|
112
71
|
|
|
113
|
-
`
|
|
114
|
-
preserves the root, Git/worktrees, trust decision, and all unrelated Registry
|
|
72
|
+
`Clear layout and open` preserves the root, Git/worktrees, trust decision, and all unrelated Registry
|
|
115
73
|
graphs while changing the Project identity. A rejected commit retains the
|
|
116
|
-
exact old Registry preimage. Repeating `
|
|
74
|
+
exact old Registry preimage. Repeating `Clear layout and open` replaces identity again;
|
|
117
75
|
each successful result has exactly one Project claiming the root.
|
|
118
76
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
the
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
77
|
+
The saved launch default is used only when the open carries the exact client
|
|
78
|
+
that pressed the row. The order is:
|
|
79
|
+
|
|
80
|
+
1. Ask. A picker mode (`selective`, the unset default, or `resume`) opens its
|
|
81
|
+
picker on the Pane the row was pressed in, before the old layout is cleared
|
|
82
|
+
or the new Session exists; a provider mode and `shell` are already the
|
|
83
|
+
answer and open nothing.
|
|
84
|
+
2. Clear the layout and create the new Session with its one shell Pane.
|
|
85
|
+
3. Fill it: an Agent answer is created in that Window first, and the shell is
|
|
86
|
+
then removed through the canonical Pane delete.
|
|
87
|
+
4. Move the pressing client onto the finished Session.
|
|
88
|
+
|
|
89
|
+
The client therefore never sees a shell Pane that is about to be replaced.
|
|
90
|
+
Closing the picker without a choice does not stop the open: the Session opens
|
|
91
|
+
with its shell Pane and nothing is said. An open without the exact client -- a
|
|
92
|
+
detached `start project`, a scripted open -- asks nothing, in every mode, and
|
|
93
|
+
keeps the plain shell Pane. A question that cannot be asked, or an answer that
|
|
94
|
+
cannot be filled in, costs one line on that client after the move and keeps the
|
|
95
|
+
shell Pane; the Project stays open either way. `Continue project` and the
|
|
96
|
+
`start project`/`open project` verbs never use the saved launch default.
|
package/docs/settings-ia.md
CHANGED
|
@@ -58,7 +58,7 @@ step, never a silent no-op.
|
|
|
58
58
|
Project`, which forwards to the canonical `create project --root` route for
|
|
59
59
|
that one exact path, and `Unpin candidate`, which removes the preference and
|
|
60
60
|
leaves the directory alone. Nothing here adopts a path automatically.
|
|
61
|
-
- `Project Sidebar [View]` — holds the
|
|
61
|
+
- `Project Sidebar [View]` — holds the Projects sidebar policy:
|
|
62
62
|
`Runtime diagnostics [Choice]` chooses `When needed` (the read-time default
|
|
63
63
|
with nothing saved) or `Always` for the sidebar's Runtime row. `When needed`
|
|
64
64
|
keeps the row for a refused runtime class or for an observation that could
|
|
@@ -68,22 +68,17 @@ step, never a silent no-op.
|
|
|
68
68
|
Recent Windows links are unchanged, and `projmux runtime diagnostics` and
|
|
69
69
|
`get runtime` never read it. An unrecognized saved value applies the default
|
|
70
70
|
without writing and shows an invalid source.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
`Continue project - off - saved`, skips the picker, and retains the
|
|
76
|
-
registered-Continue/unregistered-Fresh automatic
|
|
77
|
-
adjudication. Reading the row or opening/cancelling the picker never writes
|
|
78
|
-
the default or changes saved preference bytes/mtime.
|
|
71
|
+
The closed-Project startup screen has no setting: a registered closed
|
|
72
|
+
Project always gets it, and a root that is not a registered Project never
|
|
73
|
+
does. Its two rows are `Continue project` and `Clear layout and open`
|
|
74
|
+
(`이어서 열기` / `구성 비우고 새로 열기` in ko-KR).
|
|
79
75
|
`Continue project` materializes the Project's current Registry desired state
|
|
80
|
-
and then moves the client. `
|
|
76
|
+
and then moves the client. `Clear layout and open` confirms the exact old Project
|
|
81
77
|
UID and per-kind counts before writing anything,
|
|
82
78
|
atomically replaces the old Project graph with a new Project UID and a new
|
|
83
79
|
canonical Window/shell UID pair, and leaves exactly one same-root claimant
|
|
84
80
|
before ordinary materialization. Esc returns to Projects. Neither action
|
|
85
|
-
deletes or rewrites
|
|
86
|
-
keeps its `sidebar-startup-picker` spelling.
|
|
81
|
+
deletes or rewrites the folder, its files, Git, worktree data, or trust.
|
|
87
82
|
- **AI** — `AI` is a product category, never an addressable resource.
|
|
88
83
|
- `Default launch target [Choice]` — an Agent Provider, a Shell Pane, or
|
|
89
84
|
choose-at-launch. It is a keybinding/picker preference and does not weaken
|
|
@@ -147,10 +142,10 @@ step, never a silent no-op.
|
|
|
147
142
|
HUD`, `Working directory` and `Git` are component Views because each owns a
|
|
148
143
|
`Visible` Toggle plus an icon `Choice`; cwd/Git icon `off` removes only the
|
|
149
144
|
icon and leaves the text segment visible. `Agent Usage HUD` is a component
|
|
150
|
-
View with `Visible`, then Claude/Codex
|
|
145
|
+
View with `Visible`, then Claude/Codex provider Views in the
|
|
151
146
|
usage-supported catalog order. Each provider owns `Visible` plus only its
|
|
152
|
-
explicit HUD windows
|
|
153
|
-
|
|
147
|
+
explicit HUD windows, `5h` and `Weekly`; Antigravity has no usage source and
|
|
148
|
+
no provider View. Parent off states gate effective visibility without rewriting
|
|
154
149
|
saved child values. Provider/window rows show saved, effective, and source.
|
|
155
150
|
`Project`, `Clock` and `Settings launcher` are direct visibility Toggles. These global
|
|
156
151
|
presentation values default on except Codex `5h`, which defaults off to
|
|
@@ -163,8 +158,6 @@ step, never a silent no-op.
|
|
|
163
158
|
presentation-only and do not disable their underlying producers, cache,
|
|
164
159
|
backoff, explicit table/JSON command, or cached popup.
|
|
165
160
|
- `Language / Locale [Choice]` and `Agent attention badge style [Choice]`.
|
|
166
|
-
- **Snapshots** — the visible noun is the Snapshot resource. `session-state`
|
|
167
|
-
remains the config/route spelling and appears only as source detail.
|
|
168
161
|
- **Keybindings** — `Launch & popups`, `Agent & Pane launch`,
|
|
169
162
|
`Pane & Window navigation`, `Sidebar & picker actions` (nested by surface:
|
|
170
163
|
Project Sidebar, Session Picker, Notification Sidebar, Settings), and
|
|
@@ -221,7 +214,6 @@ step, never a silent no-op.
|
|
|
221
214
|
the approve/revoke actions) and `Project hooks [View]` (`Session lifecycle`
|
|
222
215
|
plus `After notification queued`, with the same per-event Views the global
|
|
223
216
|
scope uses, extended by a trust state row).
|
|
224
|
-
- **Snapshots** — the auto-save override and the saved snapshots.
|
|
225
217
|
|
|
226
218
|
Without an actionable project context the Project surface renders a single
|
|
227
219
|
passive guidance row rather than repeating a disabled reason per row.
|
|
@@ -236,14 +228,14 @@ Confirm and Action rows included, so `Quit Projmux` and `Reset theme` are
|
|
|
236
228
|
focused and never fired. The list is scope-pure: a Global query never returns
|
|
237
229
|
Project nodes and a Project query never returns Global ones, and with no project
|
|
238
230
|
context the Project tab returns nothing. User-data collection items -- an
|
|
239
|
-
individual discovery root, pinned Project
|
|
231
|
+
individual discovery root, pinned Project or candidate -- are data
|
|
240
232
|
rather than settings, so results stop at their parent View and at the
|
|
241
233
|
collection-level controls. Inside a View the query still filters that View's
|
|
242
234
|
rows, and category rows carry their members' search text so search crosses
|
|
243
235
|
categories.
|
|
244
236
|
|
|
245
237
|
The result rows are built from the catalog alone: no Registry, tmux,
|
|
246
|
-
|
|
238
|
+
or filesystem read participates, because a result is a destination
|
|
247
239
|
rather than a rendered value. Where that leaves a row unnameable -- a saved
|
|
248
240
|
user path, a command whose row spelling depends on whether a command is
|
|
249
241
|
already stored, a read-only state row that stands for several rendered lines --
|
|
@@ -254,7 +246,7 @@ more: the View opens, unfocused, and nothing errors.
|
|
|
254
246
|
## Vocabulary and compatibility
|
|
255
247
|
|
|
256
248
|
Visible nouns follow the shared resource vocabulary: `Project`, `Window`,
|
|
257
|
-
`Pane`, `Agent`, `Provider`, `Notification`,
|
|
249
|
+
`Pane`, `Agent`, `Provider`, `Notification`, with `AI` as a category
|
|
258
250
|
and `Session` as the runtime projection. The Agent Usage HUD is a presentation
|
|
259
251
|
of what the canonical `agent usage` command provides; there is no addressable
|
|
260
252
|
`Usage` resource, and Settings never spells usage as a readable resource kind.
|
|
@@ -302,7 +294,7 @@ result replaces it. Typed validation and staged apply failures stay in the popup
|
|
|
302
294
|
instead of being visible only on stdout/stderr.
|
|
303
295
|
|
|
304
296
|
The generic feedback inventory deliberately excludes Welcome, Quit, read-only
|
|
305
|
-
hook/effective/notification diagnostics,
|
|
297
|
+
hook/effective/notification diagnostics, and key
|
|
306
298
|
capture/probe/diagnostic bodies. Those flows own a viewer, confirmation, or
|
|
307
299
|
multi-step output surface; only an actual Settings write at their boundary is
|
|
308
300
|
eligible for transient mutation feedback.
|