projmux 0.15.3 → 0.16.1

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.
Files changed (38) hide show
  1. package/README-ko.md +3 -4
  2. package/README.md +3 -3
  3. package/docs/agent-message-replies.md +149 -6
  4. package/docs/ai-agent-shortcuts.md +6 -5
  5. package/docs/architecture.md +467 -66
  6. package/docs/claude-coordination-endpoints.md +192 -20
  7. package/docs/cli-guide.md +872 -148
  8. package/docs/cli.md +1459 -485
  9. package/docs/codex-installed-compatibility.md +6 -11
  10. package/docs/codex-native-required-migration.md +1 -59
  11. package/docs/configuration.md +694 -222
  12. package/docs/globalization.md +18 -5
  13. package/docs/hooks.md +529 -62
  14. package/docs/keybindings.md +74 -4
  15. package/docs/legacy-cli-retirement.md +3 -3
  16. package/docs/legacy-diagnostics-inventory.md +4 -4
  17. package/docs/native-picker.md +3 -5
  18. package/docs/notify-queue.md +1 -1
  19. package/docs/npm-distribution.md +4 -0
  20. package/docs/operational-diagnostics.md +319 -34
  21. package/docs/pr-guideline.md +66 -22
  22. package/docs/release.md +101 -0
  23. package/docs/replacement-contract.md +72 -58
  24. package/docs/repo-layout.md +3 -0
  25. package/docs/resource-attribution.md +6 -2
  26. package/docs/session-restore.md +50 -80
  27. package/docs/settings-ia.md +14 -22
  28. package/docs/statusbar.md +38 -37
  29. package/docs/testing.md +83 -18
  30. package/docs/theme-palette.md +6 -6
  31. package/docs/tmux-surface-inventory.md +21 -10
  32. package/docs/troubleshooting.md +2 -4
  33. package/docs/upgrading.md +161 -24
  34. package/docs/usage-tracking.md +40 -49
  35. package/package.json +5 -5
  36. package/docs/agent-workflow.md +0 -2596
  37. package/docs/codex-generation-pool.md +0 -623
  38. package/docs/codex-stored-qualification.md +0 -45
package/docs/cli-guide.md CHANGED
@@ -20,8 +20,18 @@ Exit codes:
20
20
 
21
21
  - `0` — success.
22
22
  - `1` — runtime failure.
23
- - `2` — usage error (unknown flag, bad enum, missing required flag) or a
24
- deterministic semantic exit (e.g. `focus` cannot resolve the target).
23
+ - `2` — usage error (unknown flag, bad enum, missing required flag, a
24
+ positional argument the route does not accept, or an unknown or missing
25
+ subcommand) or a deterministic semantic exit (e.g. `focus` cannot resolve
26
+ the target).
27
+ - A flag parse failure on a public route (an unknown flag, a missing flag
28
+ value, or a malformed boolean) prints the reason line first and then the
29
+ route's `Usage:` block, byte-identical to the one `projmux <route> --help`
30
+ prints, on stderr; stdout stays empty and the exit code is `2`. The Go flag
31
+ package's own `Usage of <route>:` flag listing is never printed.
32
+ - The hidden `projmux internal …` plumbing is outside this table: it follows
33
+ its caller's contract (generated tmux config, provider hooks, supervisors),
34
+ so a flag error there keeps its existing exit code and output.
25
35
 
26
36
  ## Help boundary
27
37
 
@@ -48,8 +58,12 @@ with it keeps one notion of help; the boundary never interprets a flag value:
48
58
  unchanged.
49
59
  - An unknown command keeps its `unknown command: <token>` error and exit `1`
50
60
  even with `--help`, and `projmux help` / bare `projmux` keep printing the
51
- top-level list. A bare `help` word nested under a command
52
- (`projmux pin help`) still reaches that command's own handler.
61
+ top-level list.
62
+ - On a command that has sub-commands, a bare `help` word right after it (before
63
+ any `--`) prints that command's help, whatever follows it: `projmux agent help`
64
+ and `projmux agent help instructions` both print `projmux agent --help`. A
65
+ command without sub-commands receives `help` as an ordinary argument, and a
66
+ `help` after `--` is payload.
53
67
  - Because a help invocation runs no handler, it is never recorded as a state
54
68
  change in the operations journal, at any depth — `projmux agent topic set --help`
55
69
  logs neither an error nor a state-changing success.
@@ -97,8 +111,24 @@ invocation context. Mixed Registry/Runtime pickers keep KIND in both profiles.
97
111
  Wide stdout preserves full values at every terminal width. See [Column profiles](column-profiles.md)
98
112
  for the exact per-kind matrix and migration from the previous default output.
99
113
 
100
- The resource routes (`get`, `describe`, `create`, `rename`, `rebind`, `delete`,
101
- `agent resume`) address stored resources through one shared selector grammar.
114
+ STATUS in `get` and `describe` is observed on the tmux server the caller is
115
+ attached to (`$TMUX`). Outside tmux -- another terminal, an IDE, a script --
116
+ they observe the app server `-L projmux`, so a live Window reads `live` there
117
+ too; with no app server running, rows read `offline`.
118
+
119
+ STATUS is one of `live`, `offline`, `unknown`, or `missing-root`. `offline`
120
+ means the server was read and no runtime object mirrors the resource.
121
+ `unknown` means the server could not be read, so the resource was neither seen
122
+ running nor seen absent. An `unknown` row offers only `delete` in ACTIONS -- no
123
+ `start`, `resume`, or `open` -- because starting something that may already be
124
+ running is not safe. A Project's STATUS and ACTIONS both come from the same
125
+ observation of its session, not from the stored session projection. `-o json`
126
+ is unchanged: it carries no STATUS, and `context.observed` still reports
127
+ whether the context was observed.
128
+
129
+ The resource routes (`get`, `describe`, `create`, `rename`, `label`, `rebind`,
130
+ `delete`, `agent resume`) address stored resources through one shared selector
131
+ grammar.
102
132
 
103
133
  The grammar in one paragraph: a value is either `uid:<uid>` or a bare
104
134
  `metadata.name`. There is no bare-uid form, values are never split on commas,
@@ -148,9 +178,12 @@ The contract:
148
178
  partially specified selector. The active *Project* is a separate rule and does
149
179
  apply to a reference -- see [Reference scope](#reference-scope-the-active-project-namespace)
150
180
  below.
151
- - **Only the singular routes and `create`.** The plural reads (`get
152
- projects|windows|panes|agents`) stay 0..N inventories over their whole scope,
153
- and `delete` is unchanged. `create` has its own spelling of the same rule --
181
+ - **Only the singular routes, `delete`, and `create`.** The plural reads (`get
182
+ projects|windows|panes|agents`) stay 0..N inventories over their whole scope.
183
+ `delete window|pane|agent` with neither a selector nor `--all` targets the
184
+ active Window, Pane, or Agent and asks before removing it -- see
185
+ [Delete confirmation](#delete-confirmation); `--all` still means every one in
186
+ the registry. `create` has its own spelling of the same rule --
154
187
  see [Create scope](#create-scope) -- because a create resolves a scope to put
155
188
  something *into* rather than a target to act *on*.
156
189
  - **Inside tmux is decided by `$TMUX_PANE` plus `$TMUX`**, not by whether a tmux
@@ -171,6 +204,28 @@ and `@projmux_window_uid` on its window — and derives every ancestor from
171
204
  registry `ownerRef`. The session-scoped `@projmux_project_uid` is deliberately
172
205
  not consulted.
173
206
 
207
+ ### Delete confirmation
208
+
209
+ `delete window|pane|agent` and `unregister project` ask before they remove
210
+ anything, with one exception: a `delete pane` whose selector resolves to
211
+ exactly one Pane deletes it without asking. The selector is anything the
212
+ operator typed -- a positional `<ref>`, a `--project`/`-p`,
213
+ `--window`/`-w`, or `--pane` scope, or a `--selector` label. The argv already
214
+ names the one resource that goes away, and a Pane is a leaf: it cascades to
215
+ nothing, an Agent that owned it stays as an Offline resource, and deleting a
216
+ Window's last Pane starts a replacement shell first, so the Window and its
217
+ session stay.
218
+
219
+ Everything else asks: `delete pane` with no selector (the active Pane inside
220
+ tmux), `--all`, a selector that matches several Panes, and every `delete
221
+ window`, `delete agent`, and `unregister project`. Asking means `--yes`
222
+ proceeds; without it, a terminal prompts and a declined answer exits `2`, and
223
+ a caller with no terminal is refused with exit `2` and a `needs confirmation`
224
+ message. Either way the answer is settled before anything is deleted.
225
+ `--dry-run` prints the full target and cascade plan and deletes nothing, with
226
+ or without `--yes`. To preview a single named Pane, pass `--dry-run`: without
227
+ it the Pane is already gone.
228
+
174
229
  ### Plural read scope: the active managed root
175
230
 
176
231
  Inside tmux, selector-omitted `get windows|panes|agents` derives one exact
@@ -201,7 +256,7 @@ the item: only an exact UID-bound live Window name or Pane title sets
201
256
  `observed: true`; Project and Agent context, Registry fallbacks, and unmatched
202
257
  runtime objects remain unobserved. This is a read projection, not stored
203
258
  resource state or selector authority. It does not change `-o metadata`, the
204
- Registry or snapshot schema, singular `describe ... -o json`, or `get pane -o
259
+ Registry schema, singular `describe ... -o json`, or `get pane -o
205
260
  json`; an empty plural result remains one List document with `"items": []`.
206
261
 
207
262
  ### Reference scope: the active Project namespace
@@ -361,12 +416,19 @@ Every create is **detached**: no create moves the client. Use `focus pane` or
361
416
  `-o pane-id` when you want to end up in the new pane. One exception: the human
362
417
  intent route `internal tmux window-create` (the `window.create` key and the
363
418
  Window menu New At End) moves the pressing client to the new Window after its
364
- create commits; public `create` stays detached. A natural create validates
419
+ create commits and then opens that Window's first Pane with the saved launch
420
+ default; public `create` stays detached and never reads that saved default. A natural create validates
365
421
  the inherited exact route and Pane containment. An explicit resource scope
366
422
  binds the selected app resource route without letting unrelated inherited
367
423
  `TMUX`/`TMUX_PANE` choose or change the resource target; exact Project plus
368
424
  `--create-window` therefore uses the validated app logical `-L` route on its
369
- first attempt, with no `env -u` workaround. Runtime safety remains independent
425
+ first attempt, with no `env -u` workaround. `agent resume` binds the same way,
426
+ and for the same reason: the Agent it rebinds is one exact reference and the
427
+ Pane it splits is that Agent's Window's stored `spec.anchorPaneRef`, so no
428
+ anchor Pane has to be typed or inherited to name a target that is already
429
+ named. Unsetting `TMUX` is not a substitute for either — it selects the
430
+ detached branch, which asks for an explicit `--anchor %N` instead of asking for
431
+ less. Runtime safety remains independent
370
432
  and may refuse before mutation. An inherited app-owned `TMUX` socket/PID stays
371
433
  route evidence: projmux validates its exact `-S` path, ownership/logical
372
434
  markers, logical `-L` alias, and PID while ignoring unrelated `TMUX_PANE`
@@ -472,6 +534,54 @@ already committed, and names the same public reconcile route as the retry. A
472
534
  valid unique Project UID wins over the old path after rebind; unknown and
473
535
  duplicate UID claims remain fail-closed.
474
536
 
537
+ ### Labels after creation
538
+
539
+ `projmux label project|window|pane|agent` writes `metadata.labels` on exactly
540
+ one resolved resource. It is the post-creation half of `create --label`, which
541
+ keeps its exact behavior: the same field, written by two routes at two moments.
542
+ A label change has no live projection at all -- no tmux option, no tab, no pane
543
+ title -- so the Registry commit is the whole operation and there is nothing to
544
+ converge afterwards.
545
+
546
+ The operand grammar is Kubernetes': `key=value` sets a label, `key=` sets it to
547
+ the empty string, and `key-` removes it. Set and remove operands may be mixed in
548
+ one invocation, and a key named twice is refused rather than resolved by argv
549
+ order.
550
+
551
+ Two properties follow from that grammar and are worth stating outright:
552
+
553
+ - **Shape decides what a positional token is, never the Registry.** A token
554
+ carrying `=` is always a label operand, and it can never be a resource name
555
+ anyway, because `=` is not a legal name rune. A token ending in `-` is always
556
+ a removal. A resource whose `metadata.name` happens to end in `-` is therefore
557
+ addressed by `uid:<uid>` or by its scope flag rather than positionally.
558
+ - **There is no `--overwrite` guard and no value policy.** Setting a key that
559
+ already holds a value overwrites it, and removing a key that is absent
560
+ succeeds and changes nothing; both report the resulting label set. A label
561
+ value has no length or character-set rule here, unlike in Kubernetes. The
562
+ syntax is borrowed; the value constraints deliberately are not, because
563
+ `create --label` has never had them and one field must not have two contracts
564
+ depending on which route wrote it.
565
+
566
+ Because nothing constrains the characters of a key or value, the human-readable
567
+ lines that print a metadata map quote the ones that would break them. The
568
+ `label` result line and the `Labels:` and `Annotations:` rows of `describe`
569
+ spell each pair as `key=value` on one line, and a key or value renders in Go
570
+ `strconv.Quote` form when it holds a character `strconv.IsPrint` rejects (a
571
+ newline, tab, CR, ESC, or other control or format character; the ASCII space
572
+ is printable), is not valid UTF-8, or starts with `"`. So a value written as
573
+ `$'line1\nline2'` prints as `k="line1\nline2"`, and a key written as
574
+ `$'bad\nkey'` prints as `"bad\nkey"=v`. Every other key and value, including
575
+ printable non-ASCII text, prints exactly as stored. Quoting is display only:
576
+ the stored value, `--selector`, and `-o json` keep the original bytes.
577
+
578
+ What belongs in a label is decided by one question: is this a value you will
579
+ ever filter on? `--selector key=value` reads labels and only labels, so
580
+ classification that selects (`role=epic-owner`, `phase=task-0`) belongs there.
581
+ A value that is unique per resource -- a link, an artifact path -- fills the
582
+ selector space with keys nothing will ever match and belongs in an annotation
583
+ instead.
584
+
475
585
  ### Agent topic, interaction, activation, and workspace
476
586
 
477
587
  `projmux agent capabilities --provider <codex|claude|antigravity>` prints the
@@ -486,6 +596,15 @@ current Registry-backed `available`, and
486
596
  `completionPrecision` are separate fields. Use `-o json` for the stable machine
487
597
  projection.
488
598
 
599
+ `projmux agent models [--provider claude] [-o json]` lists, in order, the
600
+ Claude model names projmux suggests for `create --model` and a Profile `model`:
601
+ one name per line, or `{"provider","models","acceptsUnlisted":true}` with
602
+ `-o json`. It reads a fixed list without opening the Registry, tmux, a provider
603
+ process, or the network. The list is a suggestion, not an allowlist: any other
604
+ well-formed model name is still accepted. `--provider codex` (or any other
605
+ provider projmux does not apply a model to) is a usage error rather than an
606
+ empty list.
607
+
489
608
  The closed static modes are `generic-registry`, `provider-resume`,
490
609
  `native-exact-control`, `provider-hook`, `read-only-adapter`, and
491
610
  `unsupported`. `message.send`, `message.status`, and `wait.idle` are provider-neutral commands whose availability is decided from
@@ -513,6 +632,20 @@ correlated model reply is a separate envelope with the original
513
632
  self-claims that envelope. Message lifecycle updates neither Agent interaction
514
633
  state nor tmux badges.
515
634
 
635
+ `--source` names the source Agent; it does not prove the caller is that Agent.
636
+ When the source is a Claude Agent with a registered Claude process and the
637
+ sending process does not descend from that process, the send still proceeds
638
+ exactly as before (same receipt, delivery, and exit status), but it prints one
639
+ `agent message send: warning:` line on stderr naming the source Agent UID, its
640
+ registered Claude session, the caller pid, and `CLAUDE_CODE_SESSION_ID` when
641
+ set, and records one `agent.message.foreign-source` event readable with
642
+ `projmux diagnostics log --component agent`. It usually means another Claude
643
+ session, such as a `claude --resume` in another terminal or a background
644
+ session left by `/exit` "Move to background", is sending as that Agent: end
645
+ that session, or send from the registered one. Nothing is judged when the
646
+ process lineage cannot be read, and a Claude `--reply-to` is already refused
647
+ for such a caller.
648
+
516
649
  Claude messaging is opt-in through `projmux agent integrate claude`. The
517
650
  integration installs no receiver waiter or `asyncRewake`; ingress is immediate
518
651
  through the exact registered provider socket. Capability JSON keeps Claude
@@ -532,8 +665,12 @@ and connection epoch still match exactly. `start` sends only the exact thread
532
665
  id and one text input. Immediately before that write it reads one bounded,
533
666
  content-free lifecycle snapshot: fresh active/in-progress returns
534
667
  `turn-in-progress`, fresh idle/terminal repairs stale cached state and starts
535
- once, and an unavailable or inconsistent snapshot returns
536
- `turn-state-unavailable` with no turn mutation. `steer` also reads that
668
+ once, and so does a fresh system-error thread (left by a provider error) whose
669
+ latest turn is not in progress. An unavailable or inconsistent snapshot returns
670
+ `turn-state-unavailable` with no turn mutation; its line says the read failed,
671
+ returned a different thread, or names the observed thread and turn state
672
+ (for example `thread=system-error turn=in-progress`). Broker read admission refusals
673
+ remain visible as `lifecycle-retry` or `lifecycle-busy`. `steer` also reads that
537
674
  content-free snapshot before any write and submits exactly once only when it
538
675
  still proves the same exact active turn. Fresh idle, terminal, or different-turn
539
676
  state returns `no-active-turn`; an unavailable or inconsistent read, including
@@ -546,6 +683,12 @@ supplies the cached exact turn id without adopting the steer preflight in this
546
683
  phase. These commands never install sticky model, effort, cwd, sandbox,
547
684
  permission, or collaboration overrides.
548
685
 
686
+ Codex coordination delivery chooses start or steer inside one native control
687
+ operation from one lifecycle snapshot. If that read returns `lifecycle-retry`,
688
+ it waits through the fixed retry window and reads once more before any write;
689
+ no provider write is ever retried.
690
+ An older observer that refuses this operation with `invalid-operation` gets one legacy start attempt, followed by steer only for `turn-in-progress`.
691
+
549
692
  Approval review shows only the safe one-shot intersection supplied by the
550
693
  exact pending request. Command, file, and network requests are limited to
551
694
  `accept`, `decline`, and `cancel`; permission grants echo the received supported
@@ -558,6 +701,39 @@ identity mismatch produces no provider write. Approval queue rows advertise
558
701
  advertise the exact-Agent `Open Codex` focus fallback; resolution removes the
559
702
  row. Neither route stores prompt, command, path, permission, or request content.
560
703
 
704
+ `agent approval list` and `agent approval answer` read and settle the same
705
+ pending Codex approvals without a picker, over the same exact binding:
706
+
707
+ ```sh
708
+ projmux agent approval list <agent-ref> [-o json]
709
+ projmux agent approval answer <agent-ref> <request-id> --allow|--deny [--via popup|cli|<client>]
710
+ ```
711
+
712
+ `list` works whatever `agent-approval-answering` says and prints it. Each
713
+ request shows its normalized id, `waiting`, the approval kind as `toolName`
714
+ (`command`, `file-change`, `permissions`), its full details as `toolInput`,
715
+ which of `allow` and `deny` `answer` can send (`answers`), and what `--deny`
716
+ would send (`denyDecision`; in text `deny(decline: the turn continues)` or
717
+ `deny(cancel: the turn stops)`). A request whose id is ambiguous across raw
718
+ JSON-RPC ids, or that offers neither, is marked for `agent approval review`.
719
+ `answer` needs `projmux config agent-approvals --answering projmux` (otherwise
720
+ `permission-answering-off`, with no broker call). It sends exactly one
721
+ decision: `accept` for `--allow`, never a widened grant or exec-policy
722
+ amendment; for `--deny`, `decline` when the request offers it, so the turn
723
+ continues, and otherwise `cancel`, which also interrupts the turn. Real Codex
724
+ command approvals may offer `accept` and `cancel` without `decline`, so a deny
725
+ there stops the turn. Nothing runs either way. A request offering no fitting
726
+ decision (a permission grant for both flags, or `--allow` on a file change with
727
+ a root grant) is refused as `permission-decision-unavailable`, and an unknown
728
+ or ambiguous id as `permission-not-pending`. The result line names the
729
+ decision sent, for example `7 denied for agent/codex (decision cancel; the turn
730
+ stops)`. `review` keeps the picker, the grant decision, and `Open Codex`. The Codex TUI, `review`, and `answer`
731
+ all stay usable, and the first answer wins: a later one is refused by the
732
+ provider or finds the request gone. Before sending, `answer` appends an
733
+ `allowed` or `denied` line to the agent approval audit log (see
734
+ [hooks.md](hooks.md#answering-claude-permission-requests-in-projmux)); if that
735
+ line cannot be written nothing is sent.
736
+
561
737
  `agent topic get|set|clear` and `agent status get|set` resolve exactly one
562
738
  Agent, either from an explicit Agent reference or from the Agent-owned active
563
739
  managed Pane. Topic is a non-identifying Registry annotation. Interaction is a
@@ -596,7 +772,7 @@ with its live `$N/@N` in the same commit. A non-last Pane is removed while its d
596
772
  Agent is retained Offline with its conversation identity. For a last Pane, that evidence is retained until a
597
773
  matching `window-unlinked` hook removes the Window; a final Project Window also
598
774
  removes its Window descendants while retaining the exact Project uid, root,
599
- reservation, pins, snapshots, and external assets as a valid zero-Window
775
+ reservation, pins, and external assets as a valid zero-Window
600
776
  Project. Managed runtime Stop is different: it stops only the exact runtime and
601
777
  keeps the complete desired Project/Window/Pane graph closed for a same-UID
602
778
  Continue. Shell and Claude/Codex clean exit have the same result; `/exit`, pane
@@ -646,19 +822,31 @@ owner Project root from `get`/`describe`, and a successful resume persists that
646
822
  normalized effective workspace without changing Window Project ownership.
647
823
 
648
824
  When `create agent -- <initial-prompt>` is used, normal resource creation and
649
- provider activation are distinct. Projmux first waits up to five seconds for an
650
- exact provider `SessionStart`; that readiness evidence leaves activation
651
- `pending` and opens an independent five-second initial-task acknowledgement
825
+ provider activation are distinct. Projmux first waits up to thirty-five seconds
826
+ for an exact provider `SessionStart`; that readiness evidence leaves activation
827
+ `pending` and opens an independent twelve-second initial-task acknowledgement
652
828
  window. A `UserPromptSubmit` acknowledgement may also arrive directly before
653
829
  the readiness observer sees `SessionStart`. The two stages are independently
654
- bounded, so provider startup plus an acknowledgement later than two seconds may
655
- take more than five but never more than ten seconds. Neither stage captures pane
656
- content or stores the prompt. Acknowledgement returns success and the requested
657
- exact `%N` output. If
658
- activation cannot be confirmed, the command exits nonzero while naming the
659
- exact Agent UID and Pane plus safe provider retry and `delete agent ... --yes`
660
- cleanup options. The live resources remain explicit and retryable rather than
661
- being reported as an ordinary success.
830
+ bounded, so provider startup plus a late acknowledgement may take more than
831
+ either bound alone but never more than forty-seven seconds. Both bounds are
832
+ sized from measured provider startup on a loaded machine, with headroom past
833
+ the measured peak, because a provider that is merely slow is not a failed one;
834
+ they are not sized for a dead provider, which is why exceeding them still
835
+ reports failure. Neither stage captures pane content or stores the prompt.
836
+ Acknowledgement returns success and the requested exact `%N` output.
837
+
838
+ If activation still cannot be confirmed, the command exits nonzero. A nonzero
839
+ exit here does not mean the Agent is gone or unusable: the Agent and its
840
+ managed Pane were created and are still live, and nothing is rolled back. The
841
+ diagnostic therefore names the exact Agent UID and Pane first and orders the
842
+ remediation cheapest-first — re-read the committed activation with `projmux get
843
+ agent uid:<uid>`, since a provider hook that arrives after the bound still
844
+ refines the activation to `acknowledged`; then look at the Pane or the provider
845
+ transcript for the initial task and retry it through the provider if it never
846
+ arrived; and only when neither read shows activation evidence, clean up with
847
+ `projmux delete agent uid:<uid> --yes`. Deletion is the last option rather than
848
+ the first, because a caller that acts on the exit code alone would otherwise
849
+ remove an Agent that is already working.
662
850
 
663
851
  Activation metadata is bounded to provider-hook provenance and fixed
664
852
  acknowledged/timed-out/failed diagnostics. Provider error strings and initial
@@ -764,17 +952,16 @@ client only after it converges; a refusal, a failed preflight, or a rolled-back
764
952
  partial leaves the client where it was and reports the exact stage. The
765
953
  activation is pinned to the session the open targets, so a Project whose
766
954
  Registry projects a different session name is refused instead of populating a
767
- session the open never reaches. With no saved `sidebar-startup-picker`
768
- preference, the closed-Project startup screen has exactly two neutral actions;
769
- the missing-file default is read-only and does not create a config file. Saved
770
- `on` retains that explicit choice, while saved `off` skips the screen and keeps
771
- the registered-Continue/unregistered-Fresh automatic decision. `Continue
955
+ session the open never reaches. A registered closed Project always gets the
956
+ startup screen, which has exactly two neutral actions; a root that is not a
957
+ registered Project never gets it and opens fresh. There is no setting that
958
+ skips the screen. `Continue
772
959
  project` materializes current Registry desired state with the same Project UID.
773
960
  A retained graph keeps descendant UIDs; a
774
961
  zero-Window Project atomically receives a new canonical Window/shell UID chain.
775
- A deleted Project may use only the exact usable snapshot compatibility path;
776
- an unavailable Continue is an explicit zero-write refusal with no Fresh
777
- fallback. `Recreate Project` is the one startup row that replaces identity, and it asks
962
+ A root that is not a registered Project cannot be continued: Continue is an
963
+ explicit zero-write refusal that points to `Clear layout and open`, with no Fresh
964
+ fallback. `Clear layout and open` is the one startup row that replaces identity, and it asks
778
965
  before it does. Choosing it opens a confirmation naming the exact old Project
779
966
  UID and its Window/Pane/Agent counts; declining returns to the startup rows
780
967
  with zero Registry writes, and an unreadable confirmation declines rather than
@@ -782,7 +969,7 @@ proceeds. An unregistered root has no identity to replace and is not asked.
782
969
  Confirmed, it atomically replaces the same-root graph with a new Project UID
783
970
  and new canonical Window/shell UIDs, then hands off only after ordinary
784
971
  materialization. A repeat replaces identity again. The root, git/worktrees,
785
- trust decision, unrelated roots, and snapshot bytes remain unchanged.
972
+ trust decision, and unrelated roots remain unchanged.
786
973
 
787
974
  Materialization launches or resumes declared Agents through the canonical
788
975
  provider/trust path and creates their managed Agent-owned Panes. An individual
@@ -810,9 +997,12 @@ report a final-window cascade with its actual root kind.
810
997
  Pane and Agent Registry-only deletion is deliberately narrower. It accepts
811
998
  only an explicit exact `uid:` selector: a Pane must carry durable
812
999
  `MissingRuntime=True/RuntimeUnbound` evidence, and an Agent must be `Offline`
813
- with no `paneRef` (with every retained descendant Pane also marked
814
- `MissingRuntime`). The exact routed server must answer with a non-empty socket
815
- identity and a non-empty Pane inventory that proves the target has zero mirrors.
1000
+ or `Failed` with no `paneRef` (with every retained descendant Pane also marked
1001
+ `MissingRuntime`). Both phases are accepted under the same authority; the
1002
+ reported evidence names the phase, such as `Failed` or
1003
+ `Offline+MissingRuntime`. The exact routed server must answer with a non-empty
1004
+ socket identity and a non-empty Pane inventory that proves the target has zero
1005
+ mirrors.
816
1006
  A missing server, empty or failed inventory, unavailable or permission-denied
817
1007
  transport, implicit/name/scope/`--all` selection, and duplicate or foreign
818
1008
  mirrors are not absence authority and make zero writes. Dry-run and apply sign
@@ -829,7 +1019,7 @@ typed resource's exact form to run instead —
829
1019
  `projmux delete pane|agent uid:<uid> --socket-path <server> --dry-run`, then the
830
1020
  same command with `--yes` — and says which evidence qualifies it. A target the
831
1021
  `uid:` form would refuse too, such as a Pane without `MissingRuntime` or a
832
- `Running` or `Failed` Agent, gets no such pointer.
1022
+ `Running` Agent, gets no such pointer.
833
1023
 
834
1024
  `delete window|pane|agent` names the server its live half addresses the same
835
1025
  way `reconcile resources` does: `--socket <name>`, `--socket-path <absolute>`,
@@ -896,7 +1086,7 @@ the server, and no write verb is ever sent.
896
1086
  ## runtime diagnostics
897
1087
 
898
1088
  ```text
899
- projmux runtime diagnostics [--socket <name> | --socket-path <absolute>] [--ui=popup|sidebar]
1089
+ projmux runtime diagnostics [--socket <name> | --socket-path <absolute>] [--ui popup|sidebar]
900
1090
  ```
901
1091
 
902
1092
  The interactive half of the same read. It lists every tmux object on the exact
@@ -1012,7 +1202,7 @@ hook payload, or a `make install` log.
1012
1202
 
1013
1203
  | Route | Purpose |
1014
1204
  | --- | --- |
1015
- | `internal tmux` | Generated config render/install/apply, popup entry helpers, pane rebalance/rename, snapshot autosave. |
1205
+ | `internal tmux` | Generated config render/install/apply, popup entry helpers, pane rebalance/rename, and the retained no-op `autosave-session-state`. |
1016
1206
  | `internal status` | Status bar segment renderers (`git`, `project`, `usage`, `notify`, `resources`). |
1017
1207
  | `internal statusbar` | Status bar click and shortcut dispatch (`click`, `usage-refresh`). |
1018
1208
  | `internal preview` | Persisted preview cursor (`cycle-pane`, `cycle-window`, `select`). |
@@ -1050,10 +1240,17 @@ operator's question, so they stay reachable only as `projmux internal tmux ...`.
1050
1240
  ## switch
1051
1241
 
1052
1242
  ```
1053
- projmux switch [--ui=popup|sidebar]
1243
+ projmux switch [--ui popup|sidebar] [--anchor <pane>]
1054
1244
  projmux switch open <path>
1055
- projmux switch toggle-tag | toggle-pin | kill | settings | preview
1056
- projmux switch cycle-pane | cycle-window | sidebar-focus
1245
+ projmux switch toggle-tag [path]
1246
+ projmux switch toggle-pin [path]
1247
+ projmux switch kill [path]
1248
+ projmux switch preview [--ui popup|sidebar] [path]
1249
+ projmux switch settings
1250
+ projmux switch cycle-pane <path> <next|prev>
1251
+ projmux switch cycle-window <path> <next|prev>
1252
+ projmux switch sidebar-focus <path>
1253
+ projmux switch sidebar-open --path <path> --anchor <pane> [--session <name>] [--mode <mode>] [--query <text>] [--client <client>]
1057
1254
  ```
1058
1255
 
1059
1256
  Project picker. With no positional argument, opens the configured picker popup
@@ -1108,31 +1305,21 @@ shows every key arriving, skip terminal remediation.
1108
1305
  ## doctor
1109
1306
 
1110
1307
  ```
1111
- projmux doctor [--json] [--section deps|runtime|integrations|session-state|logs] [--verbose]
1308
+ projmux doctor [--json] [--section deps|runtime|integrations|logs] [--verbose]
1112
1309
  ```
1113
1310
 
1114
1311
  Runs read-only diagnostics, including a dependency check for `tmux ≥ 3.4`,
1115
1312
  `git`, and `stty` (POSIX only), then reports read-only AI notify integration diagnostics
1116
- for Codex hooks, Claude Code hooks, Antigravity hooks/statusline, and the tmux bell
1313
+ for Codex hooks, Claude Code hooks, Antigravity hooks, and the tmux bell
1117
1314
  fallback. AI notify integration statuses are `installed`, `missing`, or
1118
1315
  `conflict`; missing or conflicting integrations are informational and do not
1119
- make doctor fail. It also reports read-only Session State resume metadata
1120
- diagnostics for saved agent panes, including `available`, `stale`, or
1121
- `unavailable` status plus confidence, source, updated-at, and the affected
1122
- snapshot/window/pane.
1123
-
1124
- Session State preview and doctor report the resume source captured on the pane.
1125
- Live `hook`/`session-id` metadata is high confidence; DB-validated Antigravity
1126
- `antigravity-last-conversation` and `antigravity-conversation-metadata` picker
1127
- sources are medium confidence; legacy `antigravity-history` is low confidence.
1128
- Disk discovery never lowers or overwrites an already captured live source.
1316
+ make doctor fail.
1129
1317
 
1130
1318
  The default text report shows per-section summaries plus failing or warning
1131
1319
  items. `--verbose` adds successful checks and complete typed detail, including
1132
1320
  versions, paths, confidence/source metadata, and displayed remediation.
1133
1321
  `--section` projects the same inventory used by text and JSON: `deps` selects
1134
- dependencies, `integrations` selects AI notify integrations, and
1135
- `session-state` selects resume metadata plus retention guidance. `runtime`
1322
+ dependencies, and `integrations` selects AI notify integrations. `runtime`
1136
1323
  selects the fixed `tmux` backend, an actual one-second read-only probe of the
1137
1324
  app socket, generated-versus-live config digest state, and a
1138
1325
  `projmux_process_vintage` census of this executable's live children by role and
@@ -1156,8 +1343,7 @@ bits are authoritative on both, so a readable path always resolves to a
1156
1343
  private or insecure classification. Doctor never changes permissions.
1157
1344
 
1158
1345
  JSON reports have integer `schema_version: 2`. An unfiltered report retains the
1159
- existing typed `dependencies`, `ai_notify_integrations`,
1160
- `session_state_resume`, and `session_state_prune` detail and adds ordered
1346
+ existing typed `dependencies` and `ai_notify_integrations` detail and adds ordered
1161
1347
  `runtime` and `logs` finding arrays. Every finding has closed `severity`,
1162
1348
  stable `code`, and closed `remediation`; bounded aggregates may add `count`
1163
1349
  and `safe_codes`. A filtered report contains only the selected typed field(s).
@@ -1180,8 +1366,9 @@ diagnose terminal key delivery; use `projmux setup` for that.
1180
1366
 
1181
1367
  JSON migration: consumers must switch on `schema_version` before decoding.
1182
1368
  Version 2 changes the previously empty/reserved `runtime` and `logs` arrays to
1183
- the typed finding shape above; field meanings inside the version 1 dependency,
1184
- integration, and Session State inventories are unchanged. Consumers that only
1369
+ the typed finding shape above; field meanings inside the version 1 dependency
1370
+ and integration inventories are unchanged. The former `session_state_resume`
1371
+ and `session_state_prune` fields are no longer emitted. Consumers that only
1185
1372
  understand version 1 must reject version 2 rather than decoding the new arrays
1186
1373
  as the old empty placeholder shape.
1187
1374
 
@@ -1197,7 +1384,7 @@ than a standalone Settings row.
1197
1384
 
1198
1385
  ```
1199
1386
  projmux diagnostics log [--tail N] [--json]
1200
- [--level info|error] [--component NAME] [--path]
1387
+ [--level info|warn|error] [--component NAME] [--path]
1201
1388
  projmux diagnostics report [--output <path>]
1202
1389
  ```
1203
1390
 
@@ -1290,22 +1477,22 @@ which of them a command had touched.
1290
1477
  | `create project` | creates or reuses the Project, its canonical Window, and its shell | not started | not moved |
1291
1478
  | `start project` | unchanged | materialized when offline | not moved |
1292
1479
  | `open project` | unchanged | materialized when offline | moved to the Project |
1293
- | `attach project` | unchanged | materialized when offline | the outside caller attaches |
1480
+ | `attach project` | unchanged; an absolute root no Project claims is registered as a new Project | materialized when offline | the outside caller attaches |
1294
1481
  | `focus project` | unchanged | never materialized | moved to the Project |
1295
1482
  | `stop project` | unchanged | the exact session ends | existing safe fallback |
1296
1483
  | `unregister project` | the Project subtree is removed | **preserved** | not moved |
1297
1484
 
1298
1485
  `open project` and `attach project` are the same operation seen from the two
1299
1486
  sides of a tmux client. Inside tmux, `open` moves the client you are in and
1300
- `attach` refuses with a pointer at `open`; outside tmux, `attach` attaches the
1301
- caller and `open` refuses with a pointer at `attach`. Both refusals happen
1302
- before anything is materialized.
1487
+ `attach` refuses with a pointer at `focus project`; outside tmux, `attach`
1488
+ attaches the caller and `open` refuses with a pointer at `attach`. Both
1489
+ refusals happen before anything is materialized.
1303
1490
 
1304
1491
  `stop project` refuses an offline target rather than succeeding silently: it
1305
1492
  declares exactly one runtime outcome, and reporting `runtime=stopped` for a
1306
1493
  session that was never running would be false. `unregister project` is the
1307
1494
  inverse -- it removes the Registry graph and deliberately leaves the running
1308
- session, the root, Git/worktrees, and snapshots exactly as they were.
1495
+ session, the root, and Git/worktrees exactly as they were.
1309
1496
 
1310
1497
  `delete project` is a deprecated alias of `unregister project`. It keeps its
1311
1498
  exact behavior and its exact stdout; it adds one deprecation line on stderr and
@@ -1313,7 +1500,22 @@ one `compatibilityWarnings` entry in the receipt. It is not scheduled for
1313
1500
  removal in this release.
1314
1501
 
1315
1502
  The reference for a Project can be `uid:<uid>`, a bare `metadata.name`, or the
1316
- absolute root path the Project claims.
1503
+ absolute root path the Project claims. `start`, `open`, `attach`, and `stop
1504
+ project` resolve these forms with one resolver, and a `uid:` or name that
1505
+ matches no Project is refused with exit 2 before anything is written or
1506
+ started. `attach project` also accepts an
1507
+ absolute path no Project claims yet: it registers that root as a new Project
1508
+ and then attaches, where `open project` refuses the same path and points at
1509
+ `projmux create project --root`.
1510
+
1511
+ A Project registered without `--name` -- by `create project`, by opening an
1512
+ unregistered directory, or by `Clear layout and open` -- is named after its root
1513
+ directory, sanitized into a valid name (`~/src/my repo` becomes `my-repo`). If
1514
+ that basename sanitizes to nothing or another Project already holds it, the new
1515
+ Project is named by its exact uid instead; a numbered variant is never invented.
1516
+ `Clear layout and open` keeps an operator-chosen name, but not a name shaped
1517
+ like a Project uid. Windows, Panes, and Agents keep their exact-uid automatic
1518
+ names.
1317
1519
 
1318
1520
  ### Operation receipts
1319
1521
 
@@ -1407,8 +1609,8 @@ projmux notification reconcile [--json]
1407
1609
  `get notifications` and is considered only by reconcile together with a gone
1408
1610
  target. Reconcile also retains only the newest 256 rows. `--text` is hard-capped to 80 runes (longer text is
1409
1611
  truncated server-side). After a successful queue write, projmux sends a
1410
- best-effort refresh event to open native notify sidebars and fires
1411
- declarative `[hooks.send-noti]` asynchronously if configured. Event delivery
1612
+ best-effort refresh event to open native notify sidebars and, if configured,
1613
+ runs declarative `[hooks.send-noti]` and waits until it exits or its timeout. Event delivery
1412
1614
  failure does not fail the queue write; reopening the sidebar still shows the
1413
1615
  latest queue. The hook gets a JSON payload on stdin plus
1414
1616
  `PROJMUX_NOTIFY_*` env vars, and it does not replace the normal desktop
@@ -1450,7 +1652,7 @@ Authoritative AI account usage. See [usage-tracking.md](usage-tracking.md)
1450
1652
  for adapter detail.
1451
1653
 
1452
1654
  ```
1453
- projmux agent usage [--model codex|claude|antigravity|all] [--window 5h|weekly|context|quota|all]
1655
+ projmux agent usage [--model codex|claude|all] [--window 5h|weekly|context|quota|all]
1454
1656
  [--json] [--force|-f]
1455
1657
  ```
1456
1658
 
@@ -1508,7 +1710,7 @@ Defensive ambiguous attribution stays in its stable internal bucket, is
1508
1710
  included in Attributed totals, and appears only as a bounded CPU/RSS/pane
1509
1711
  diagnostic rather than a project row. Warming, partial, unavailable, unknown,
1510
1712
  and overage states also remain explicit. No process
1511
- command list, mutation, history, graph, daemon, persistence, or Session State
1713
+ command list, mutation, history, graph, daemon, or persistence
1512
1714
  telemetry is created. Linux/tmux provides attribution; unsupported platforms
1513
1715
  show an unavailable reason rather than zero metrics.
1514
1716
 
@@ -1541,9 +1743,8 @@ projmux internal status resources
1541
1743
  local changes, `+N` staged entries, and `↑N`/`↓N` ahead/behind counts, with
1542
1744
  compact per-token colors in tmux output.
1543
1745
  - `usage` — HUD-style provider blocks containing only official `5h` and
1544
- `weekly` windows. Antigravity's exact `quota/gemini-weekly` snapshot is
1545
- projected as `weekly` without changing its cached identity; other named
1546
- quotas and context never consume status width. Claude typed `limits[]`
1746
+ `weekly` windows from Claude and Codex; named quotas and context never
1747
+ consume status width. Claude typed `limits[]`
1547
1748
  named/model rows are likewise excluded, so only its aggregate `5h` and
1548
1749
  `weekly` rows reach the status line. Narrow tiers keep one primary window per
1549
1750
  provider (`5h`, otherwise `weekly`) before hard truncation.
@@ -1566,19 +1767,21 @@ projmux internal status resources
1566
1767
  ## internal statusbar
1567
1768
 
1568
1769
  ```
1569
- projmux internal statusbar click <range-id> [--socket <s>] [--mouse-window <id>]
1570
- [--client <tty>] [--mouse-x N] [--mouse-y N]
1770
+ projmux internal statusbar click <range-id> [--socket <s>] [--client <tty>]
1771
+ [--mouse-x N] [--mouse-y N]
1571
1772
  projmux internal statusbar usage-refresh
1572
1773
  ```
1573
1774
 
1574
1775
  Click/keyboard dispatcher for the two-line status bar. Implemented range ids:
1575
- `session pwd git resources usage notify settings`. The bare `window` /
1576
- `window|<idx>` token (tmux's built-in window-list range) and the empty
1577
- range fall through to `select-window -t @<mouse_window>` so the native
1578
- click-to-switch tab affordance is preserved on row 1. Unknown range ids are
1579
- non-specialized placeholders and no-op. `session` opens the existing-session
1580
- popup; `pwd` shows the current pane path in a native-framed display-only
1581
- popup; `git` opens the project switcher popup;
1776
+ `session pwd git resources usage notify settings`. Window-list clicks on
1777
+ row 1 are handled natively by the binding (`if-shell -F` on the bare `window`
1778
+ range runs `select-window -t =`); if a `window|<idx>` token reaches the
1779
+ dispatcher it selects `:<idx>`, and a bare `window` token is a no-op. The
1780
+ empty range and unknown range ids are no-ops. The binding passes only
1781
+ `#{mouse_status_range}` and `#{client_tty}`; `--mouse-window <v>` is accepted
1782
+ for compatibility with bindings from older releases and ignored. `session`
1783
+ opens the existing-session popup; `pwd` shows the current pane path in a
1784
+ native-framed display-only popup; `git` opens the project switcher popup;
1582
1785
  `settings` toggles the settings popup for the tmux client; `usage` opens the
1583
1786
  detailed cached account-usage popup. Legacy context rows are suppressed and
1584
1787
  named quotas retain exact identity/reset/freshness values. Claude model-scoped
@@ -1601,7 +1804,7 @@ projmux attention toggle [pane]
1601
1804
  projmux attention clear [pane]
1602
1805
  projmux attention arm [pane]
1603
1806
  projmux attention list [--json] [--all]
1604
- projmux attention window [window]
1807
+ projmux attention window [window] [style]
1605
1808
  ```
1606
1809
 
1607
1810
  Toggles the `✳` pane title prefix and the `@projmux_attention_state` pane
@@ -1632,10 +1835,11 @@ projmux agent status [get [<agent-ref>] | set <unknown|idle|in_progress|approval
1632
1835
  projmux agent topic get|clear [<agent-ref>] [--agent <ref>]
1633
1836
  projmux agent topic set <text> [<agent-ref>] [--agent <ref>]
1634
1837
  projmux agent capabilities [<agent-ref> | --provider <codex|claude|antigravity>] [-o json]
1838
+ projmux agent models [--provider claude] [-o json]
1635
1839
  projmux internal agent-hook watch-title [pane]
1636
1840
  projmux internal agent-hook ingest codex-hook [--pane <pane_uid|pane_id>] < payload.json
1637
1841
  projmux internal agent-hook ingest claude-hook [--pane <pane_uid|pane_id>] < payload.json
1638
- projmux internal agent-hook ingest antigravity-hook [--event <PreInvocation|PostInvocation|PostToolUse|Stop|Statusline>] [--pane <pane_uid|pane_id>] < payload.json
1842
+ projmux internal agent-hook ingest antigravity-hook [--event <PreInvocation|PostInvocation|PostToolUse|Stop>] [--pane <pane_uid|pane_id>] < payload.json
1639
1843
  projmux internal agent-hook ingest bell --pane <pane_id>
1640
1844
  projmux diagnostics agent-hook [--tail N] [--json] [--path]
1641
1845
  projmux agent integrate codex [--dry-run] [--remove]
@@ -1698,6 +1902,511 @@ plain Agent on purpose; it is Codex-only and equivalent on `create agent
1698
1902
  multi-operand payloads, `agent resume`, Claude, and Antigravity are unaffected.
1699
1903
  See [Codex Native-Required Create Migration](codex-native-required-migration.md).
1700
1904
 
1905
+ An Agent can be given named instructions: `create agent --provider claude
1906
+ --instructions <name>` (and `create claude --instructions <name>`) appends the
1907
+ stored content to the new session's system prompt through Claude's
1908
+ `--append-system-prompt-file`; it never replaces the system prompt, so Claude
1909
+ Code's own tool instructions stay. Manage the files with `projmux instructions
1910
+ list|show|edit|set|delete` (`edit` opens `$EDITOR`, then `$VISUAL`; `set
1911
+ <name> --file <path>` or `-` writes without an editor). The files are
1912
+ `<config dir>/personas/<name>.md` (by default
1913
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/personas/`), with a 64 KiB limit.
1914
+ The directory keeps its older name; no `instructions/` directory is created.
1915
+ The older command and flag names are listed under
1916
+ [Deprecated instruction spellings](#deprecated-instruction-spellings).
1917
+ `delete` refuses, with exit 2
1918
+ and `profile-instructions-in-use`, instructions that a stored
1919
+ [profile](configuration.md#agent-profiles) names -- valid or not -- lists
1920
+ each such profile, and deletes nothing; change or delete those profiles
1921
+ first. Instructions no profile names delete as before.
1922
+
1923
+ The content is copied when an Agent starts: create copies it to the existing
1924
+ content-addressed snapshot `<state dir>/personas/sha256-<hex>.md`, passes only
1925
+ that path on the Claude command line, and records the existing
1926
+ `projmux.io/persona` and `projmux.io/persona-digest` keys on the Agent; the
1927
+ keys, too, keep their older name. `agent resume`,
1928
+ `agent relaunch`, Continue/topology replay, and a resume-picker create compare
1929
+ the current content of the instructions the Agent's
1930
+ [settings layers](#settings-layers) name with the recorded digest: when the
1931
+ file was edited, or the layers name other instructions, they pass a snapshot
1932
+ of the current content, record its digest and
1933
+ `projmux.io/system-prompt-snapshot=off`, and the Claude launch passes
1934
+ `--system-prompt-snapshot off`; when nothing changed they pass the recorded
1935
+ snapshot again. Instructions that cannot be read now keep the recorded
1936
+ snapshot, with one `persona-unavailable` line (on stderr for `agent resume`,
1937
+ among the replay notices for Continue; a resume-picker create, which already
1938
+ discloses what of the inherited snapshot it cannot re-pass, adds no line).
1939
+ An Agent with the old keys and snapshot resumes
1940
+ without migration. If the snapshot is gone, resume proceeds without the
1941
+ instructions and discloses one `persona-unavailable` line (on stderr for
1942
+ `agent resume`, among the replay notices for Continue). Missing, oversized,
1943
+ or badly named files refuse with the stable `persona-not-found`,
1944
+ `persona-too-large`, or `persona-name-invalid` reason and write no Registry,
1945
+ tmux, or snapshot state.
1946
+
1947
+ A Codex Agent can be given named instructions directly or through a Profile
1948
+ when created with a prompt
1949
+ (`create agent --provider codex --instructions <name> -- <prompt>`, or
1950
+ `create codex --instructions <name> -- <prompt>`). This lane opens a thread of
1951
+ its own. Codex accepts the instructions when that thread starts: create sends
1952
+ the snapshot content as the thread's `developerInstructions`, and the shared app server records it once as the
1953
+ thread's `developer` message. The content goes over that connection and
1954
+ nowhere else -- never onto a command line, where `ps` would publish it -- and
1955
+ the create records the same `projmux.io/persona` and `projmux.io/persona-digest`
1956
+ annotations Claude records. From then on the thread carries the instructions: `agent resume`,
1957
+ Continue/topology replay, and a resume picked from the Codex catalog re-send
1958
+ nothing and disclose nothing, because nothing was lost.
1959
+ A conversation opened from the resume picker inherits the two stored
1960
+ instruction keys from Agents that already record it, so the new Agent reports
1961
+ the instructions its thread is running; it inherits no other launch value. A
1962
+ Codex Agent's instructions cannot be changed afterwards: the instructions are fixed when the
1963
+ thread starts. `agent relaunch` refuses a change of them with
1964
+ `codex-instructions-immutable` before writing a snapshot or Registry state or
1965
+ stopping a Pane. Codex resume replays the original developer message, even
1966
+ when a new instruction is supplied to its CLI or app server. Start a new Agent
1967
+ with a prompt to use different instructions.
1968
+
1969
+ Every other `--instructions` create refuses with
1970
+ `persona-provider-unsupported` and zero Registry, tmux, and snapshot writes:
1971
+ a Codex create with no prompt or with `--interactive-only` (its plain lane
1972
+ cannot carry private developer instructions without exposing their body in
1973
+ the process arguments), `--dialogue-reply-only`, and any other provider. The
1974
+ refusal tells the operator to create a new Agent with `-- <prompt>` and omit
1975
+ `--interactive-only`.
1976
+
1977
+ An existing Claude Agent's named instructions are changed with
1978
+ `projmux agent relaunch <agent-ref> --instructions <name>` and removed with
1979
+ `--instructions none`, both described below. A change of instructions after the
1980
+ conversation started records `projmux.io/system-prompt-snapshot=off`. The key
1981
+ is sticky and makes every later resume of that Agent pass
1982
+ `--system-prompt-snapshot off`: Claude records the system prompt of a
1983
+ conversation's first request and replays that record on resume, so without it
1984
+ instructions given after the conversation started would be ignored on the next
1985
+ resume. In steady state that costs little: each resume re-creates a
1986
+ byte-identical system prompt, so the prompt cache still hits and the extra cost
1987
+ is a few dozen cache-creation tokens per resume (measured +4 to +45); after the
1988
+ environment context in the system prompt changes (date, git state, CLAUDE.md),
1989
+ the first resume can re-cache the prompt prefix once.
1990
+
1991
+ A Claude Agent created with `--effort <level>` records it as `projmux.io/effort`
1992
+ on the Agent, because Claude does not restore a conversation's effort on
1993
+ resume. Every resume passes it again as `--effort <level>`: `agent resume`,
1994
+ Continue/topology replay, and the restart of `agent relaunch`. A recorded
1995
+ value that is not one of `low`, `medium`, `high`, `xhigh`, or `max` is
1996
+ skipped, the resume still proceeds, and one `effort-invalid` line is disclosed
1997
+ where a `persona-unavailable` line would be. The model given with `--model`
1998
+ (or filled in by a profile) is recorded as `projmux.io/model`, exactly as it
1999
+ was passed, but never passed again: Claude restores the conversation's model
2000
+ itself on resume, and passing the create-time model would override a `/model`
2001
+ switch made in the session. The record is the requested model, not
2002
+ necessarily the one the provider runs now. A create without `--model` records
2003
+ no model.
2004
+
2005
+ `projmux agent resume <ref> [--model <model>] [--effort <level>]` resumes an
2006
+ Offline or Failed Claude or Codex Agent on the same UID and conversation with
2007
+ another model or effort. `--model` is passed on that launch only and recorded
2008
+ as `projmux.io/model`; the provider's conversation keeps the model on later
2009
+ resumes, which do not pass it again. `--effort` is recorded as
2010
+ `projmux.io/effort`, so later plain resumes pass it again. Both are recorded in
2011
+ the resume's own transaction, so a resume that fails rolls back and records
2012
+ neither. A resume without `--model` leaves a recorded model as it was. Both flags take create's values and refusals: any
2013
+ other provider, an invalid model or effort, and `--dialogue-reply-only` are
2014
+ refused before anything changes (`nothing was changed`).
2015
+
2016
+ `--dialogue-reply-only` on `create agent` or `agent resume` launches a Claude
2017
+ Agent into the reply-only activation and records that on the Agent as
2018
+ `projmux.io/dialogue-reply-only=on`, in the transaction of that launch. From
2019
+ then on every resume of the Agent is the reply-only activation again:
2020
+ `agent resume` without the flag, `agent relaunch`, and the restart of
2021
+ `agent instructions attach|detach`, whether the Agent is Running or Offline
2022
+ with no managed Pane left. Nothing removes the record; an Agent that should
2023
+ run without it is a new Agent. Because that launch is fixed, a request it
2024
+ cannot carry is refused before anything changes (`nothing was changed`):
2025
+ `--profile`, `none` included (`profile-lane-unsupported`); `--instructions`,
2026
+ a `--reset` of the instructions, and `agent instructions attach|detach`
2027
+ (`persona-provider-unsupported`); and `--model`, `--effort`, or any other
2028
+ `--reset` (`reply-only-launch-fixed`), on `agent resume` too. A plain
2029
+ `agent relaunch` of a Running reply-only Agent compares only what that launch
2030
+ carries -- not the agent guidance or the Project's label link rules -- so it
2031
+ reports `unchanged`. An Agent made reply-only before the record existed
2032
+ carries none and is resumed as an ordinary Agent unless the flag is given
2033
+ again.
2034
+
2035
+ `projmux agent relaunch <agent-ref> [--profile <name>|none] [--instructions
2036
+ <name>|none] [--model <model>] [--effort <level>] [--reset <item>[,...]|all]
2037
+ [--project <ref>] [--window <ref>] [--yes] [--dry-run] [--socket <name> |
2038
+ --socket-path <absolute>] [-o json]` restarts one existing Claude or Codex
2039
+ Agent on the same UID and the same provider conversation with other settings,
2040
+ all in one restart. It is the one way to change an Agent's
2041
+ [settings layers](#settings-layers):
2042
+
2043
+ - `--profile <name>` switches the Agent to that profile (`none`: to no
2044
+ profile). A switch clears every override: the instructions, model, and
2045
+ effort take the new profile's values (none where it sets none), its
2046
+ permissions apply, and only the overrides given with it (`--instructions`,
2047
+ `--model`, `--effort`) are overrides again. The profile is recorded with
2048
+ `projmux.io/profile-source=relaunch`. Naming the profile the Agent already
2049
+ has is no switch: its overrides stay. This is how an Agent created before
2050
+ profiles, or created without one, gets a profile; a `role` label is read
2051
+ only when an Agent is created, never by a relaunch.
2052
+ - `--instructions <name>` overrides the instructions (`none`: explicitly no
2053
+ instructions), `--model` and `--effort` override the model and the effort.
2054
+ - `--reset <item>[,...]` removes the override of `instructions`, `model`, or
2055
+ `effort` (`all`: of every item), so the item takes the profile's current
2056
+ value again, or none where the profile sets none or there is no profile. A
2057
+ model left without a value is not passed and its recorded value is removed.
2058
+ Giving an item a value and resetting it in the same command is a usage
2059
+ error.
2060
+
2061
+ Without any of them it restarts the Agent with the settings its layers resolve
2062
+ to now -- after a profile edit, for example -- and reports `unchanged` when
2063
+ they are what the Agent runs already. A Running Agent's managed
2064
+ Pane is closed through `delete pane`, and the Agent is brought back through the
2065
+ `agent resume` rebind with the overrides (outcome `restarted`, with the new
2066
+ Pane in `newPaneUID`); an Offline or Failed Agent is only resumed (outcome
2067
+ `resumed`). The new Pane carries the closed Pane's name unless that name was
2068
+ its own uid; when the name cannot be carried (another Pane took it), the new
2069
+ Pane keeps its automatic name and stderr says why in one `projmux: agent/<name>
2070
+ new Pane keeps an automatic name: <reason>` line. An Offline or Failed Agent,
2071
+ here and on `agent resume`, carries the name of its old Pane row instead; when
2072
+ no such row is left -- `delete pane` removed it -- the new Pane is named
2073
+ `<agent-name>-pane`, as `create agent` names it. That name falls back to the
2074
+ automatic one the same way: with the same stderr line when another resource
2075
+ holds it, and silently when it is too long to be a name. A name given with
2076
+ `rename pane` is not remembered once its row is gone. The settings are recorded by the rebind transaction -- the profile,
2077
+ `projmux.io/model`, `projmux.io/effort`, the instructions, and their sources --
2078
+ so a failed launch records none of them; later plain resumes pass the effort
2079
+ again but not the model. Nothing is written before the stop. On a Codex Agent the model and effort ride the
2080
+ native resume as `-m <model>` and `-c model_reasoning_effort=<level>`.
2081
+
2082
+ The refusals all happen before any Registry, tmux, or Pane change, ending with
2083
+ `nothing was changed`: a provider other than Claude or Codex
2084
+ (`relaunch-provider-unsupported`); an invalid model or effort (create's
2085
+ refusal); an Agent with no stored conversation, one that is not Running,
2086
+ Offline, or Failed, or one whose final resume would be refused (a Codex thread
2087
+ with no durable endpoint included) (`relaunch-no-conversation`); the Agent
2088
+ whose managed Pane the command runs in (`relaunch-self-target`) -- an
2089
+ environment inherited from that Pane is not enough on its own, the command must
2090
+ be one of that Pane's processes, and when that cannot be determined the refusal
2091
+ says so; and a Running Agent whose interaction is not `idle` or
2092
+ `response_complete` -- `unknown` included -- without `--yes`
2093
+ (`relaunch-agent-busy`). An Agent that records the reply-only activation
2094
+ refuses every `--profile`, `--instructions`, `--model`, `--effort`, and
2095
+ `--reset` with the reasons given for it above. A change to the layers
2096
+ adds its own: a profile that does not exist or that `profile list` marks
2097
+ invalid (the store's reason, such as `profile-not-found`) or that names another
2098
+ provider (`profile-provider-mismatch`); instructions that cannot be read
2099
+ (`persona-not-found`), named or brought by a profile or a reset; on a Codex
2100
+ Agent, any change of its instructions -- `--instructions`, a profile with other
2101
+ instructions, or a reset of them (`codex-instructions-immutable`: its thread
2102
+ keeps the developer message it started with) -- and a profile switch that
2103
+ would leave the thread on the old profile's sandbox or approval, because the
2104
+ new profile sets none where the old one set one or cannot be read
2105
+ (`relaunch-codex-permissions-kept`: a Codex resume can set a sandbox or an
2106
+ approval but not remove one). A Codex switch to a profile with the same
2107
+ instructions and both permissions, and any model or effort, is allowed.
2108
+ Outside tmux the stop needs `--socket <name>` or `--socket-path <absolute>`,
2109
+ exactly as `delete pane` does. A Running Agent without `--model` whose
2110
+ settings, `--effort` included, resolve to exactly what it was launched with,
2111
+ whose agent guidance and Project label link rules are the ones it recorded,
2112
+ and whose `--profile`, `--instructions`, or `--reset` changes no recorded value,
2113
+ source, or profile, reports `unchanged` and restarts nothing; `--model` always restarts, because the
2114
+ recorded model is the last one requested, not necessarily the one the provider
2115
+ runs now (a `/model` switch in the session is not observed). `--dry-run` changes nothing and
2116
+ reports `would-restart` or `would-resume`.
2117
+
2118
+ `-o json` prints exactly one object with `action` (`relaunch`), `dryRun`,
2119
+ `outcome` (`unchanged`, `restarted`, `resumed`, `would-restart`, or
2120
+ `would-resume`), `agentUID`, `agentName`, `provider`, `phase`, `interaction`,
2121
+ `paneUID`, `newPaneUID`, `currentEffort` (the recorded effort),
2122
+ `currentModel` (the recorded model, the last one requested), `newEffort`
2123
+ (the requested effort; empty when only `--model` is given, and the recorded
2124
+ effort carries on), `newModel`, `restart`, `confirmationRequired`,
2125
+ `unchanged`, `currentSettings` and `newSettings` (the settings as the Agent
2126
+ recorded them and as the relaunch runs them: `profile` with `name`, `digest`,
2127
+ and `source`, and `instructions`, `model`, and `effort` each with `value`,
2128
+ `source` -- empty when not known -- `profileValue`, and `override`), and
2129
+ `relaunchReasons` (why the relaunch would launch something other than what the
2130
+ Agent recorded, in this order: `profile-changed`, `instructions-changed`,
2131
+ `instructions-content-changed`, `model-changed`, `effort-changed`,
2132
+ `guidance-changed` (the current agent guidance digest differs from the
2133
+ recorded `projmux.io/agent-guidance-digest`: guidance added, edited, or turned
2134
+ off), `link-rules-changed` (the Project's current label link rules digest
2135
+ differs from the recorded `projmux.io/project-link-rules-digest`); empty when
2136
+ it would not. The last two are Claude only, like the guidance and the rules
2137
+ themselves, and change no setting); the empty string fields before
2138
+ `currentSettings` are omitted. A switched profile, overridden or reset items,
2139
+ and their sources show on the `newSettings` side. Without `-o json` the output
2140
+ of the stop and the resume is followed by one result line, which also names
2141
+ the profile and the instructions when their names change (`profile=role
2142
+ instructions=lead`, `none` for none).
2143
+
2144
+ If closing the managed Pane reports an error, the command checks whether that
2145
+ Pane is still alive: if it is, the old session keeps running and the command
2146
+ fails with the Registry unchanged; if it is already closed, the resume proceeds
2147
+ with a warning on stderr; if it cannot tell, stderr prints the same
2148
+ `projmux agent relaunch` command to re-run. If the resume fails after the stop,
2149
+ the Agent stays Offline with its previous settings and stderr prints the
2150
+ `projmux agent resume uid:<agent> --project uid:<project> --window
2151
+ uid:<window> --model <model> --effort <level>` command, with the flags that
2152
+ were given, that finishes the job; after `--profile`, `--instructions`, or
2153
+ `--reset`, which `agent resume` cannot carry, it prints the same
2154
+ `projmux agent relaunch` command instead, which only resumes the Offline Agent.
2155
+
2156
+ A Claude conversation opened from the resume picker creates a new Agent, and
2157
+ when Agents in the Registry already record that conversation (in any Project or
2158
+ Window, live or not) the new Agent inherits their launch values: the named
2159
+ instructions and their snapshot (`projmux.io/persona`, `projmux.io/persona-digest`), the
2160
+ system prompt snapshot mode (`projmux.io/system-prompt-snapshot`), and the
2161
+ effort (`projmux.io/effort`). It launches with them and records them, so its own
2162
+ later resumes behave like theirs; a snapshot that is gone or an effort Claude
2163
+ would not take is disclosed with `persona-unavailable` or `effort-invalid`, as
2164
+ on `agent resume`. Inheritance happens only when every such Agent records the
2165
+ same values; if they disagree, nothing is inherited and one
2166
+ `launch-values-ambiguous` notice names them. The creator, topic, and
2167
+ labels of those Agents are never inherited, and they keep their conversation
2168
+ and annotations. A Codex picker selection inherits the two stored
2169
+ instruction keys under the same agreement rule and nothing else -- the snapshot mode and the effort
2170
+ are Claude launch options -- and it changes no argv, because the thread
2171
+ already carries the instructions. Antigravity picker selections inherit nothing.
2172
+
2173
+ ### Deprecated instruction spellings
2174
+
2175
+ These spellings are no longer in `projmux help`, in any route's help listing or
2176
+ synopsis, or in the [CLI reference](cli.md). Each still runs with the stdout,
2177
+ `-o json`, exit code, and reason tokens it had and still answers `--help`; it
2178
+ adds one line on stderr that names its replacement:
2179
+
2180
+ ```text
2181
+ projmux: persona list is deprecated; use `projmux instructions list` instead.
2182
+ ```
2183
+
2184
+ None is scheduled for removal in this release.
2185
+
2186
+ | Deprecated | Use |
2187
+ | --- | --- |
2188
+ | `projmux persona list\|show\|edit\|set\|delete` | `projmux instructions list\|show\|edit\|set\|delete` |
2189
+ | `--persona <name>` on `create agent`, `create claude`, and `create codex` | `--instructions <name>` |
2190
+ | `projmux agent instructions attach <agent-ref> <name>`, `projmux agent persona attach <agent-ref> <persona>` | `projmux agent relaunch <agent-ref> --instructions <name>` |
2191
+ | `projmux agent instructions detach <agent-ref>`, `projmux agent persona detach <agent-ref>` | `projmux agent relaunch <agent-ref> --instructions none` |
2192
+
2193
+ `projmux persona` and `--persona` read and write the same files and record
2194
+ the same keys as `projmux instructions` and `--instructions`; their output says
2195
+ `persona` where the replacement says `instructions`. A create given both
2196
+ `--instructions` and `--persona` is refused.
2197
+
2198
+ An attach (`projmux agent instructions attach <agent-ref> <name>`) or a detach
2199
+ (`projmux agent instructions detach <agent-ref>`, both with `[--project <ref>]
2200
+ [--window <ref>] [--yes] [--dry-run] [-o json]`) is the relaunch in the table
2201
+ above, recorded with the source `attach` and printed in the attach's own output: the same
2202
+ restart, the same [settings layers](#settings-layers), and the same launch.
2203
+ `agent persona attach|detach` is the same command and says `persona` where
2204
+ `agent instructions attach|detach` says `instructions`. Both names operate on
2205
+ the same Agent keys, snapshot, and digest. The Agent keeps its uid and provider
2206
+ conversation. A Running Agent's managed Pane is closed through
2207
+ `delete pane`, which leaves it Offline, and the Agent is resumed through the
2208
+ same rebind `agent resume` uses, on a new managed Pane; an Offline or Failed
2209
+ Agent is only resumed. Before that the command writes the snapshot and records
2210
+ `projmux.io/persona`, `projmux.io/persona-digest`, and
2211
+ `projmux.io/system-prompt-snapshot=off` in one Registry change (detach removes
2212
+ the first two). A Running Agent whose interaction is not `idle` or
2213
+ `response_complete` -- `unknown` included -- is refused with
2214
+ `persona-agent-busy` unless `--yes` confirms cutting its turn, and `--dry-run`
2215
+ (`-o json` for scripts) reports the target, its interaction, the current and
2216
+ new instructions, and whether that confirmation is required without changing
2217
+ anything. The Agent whose managed Pane the command runs in is refused with
2218
+ `persona-self-target`: an environment inherited from that Pane is not enough on
2219
+ its own, the command must be one of that Pane's processes, and when that cannot
2220
+ be determined the refusal says so. An Agent with no stored conversation is
2221
+ refused with `persona-no-conversation`. Attaching the instructions an Agent already runs with,
2222
+ same name and same content digest, with the snapshot mode off, reports
2223
+ `unchanged` and restarts nothing, unless the Agent's other settings resolve to
2224
+ something else (a profile edit, for example); after the instructions file is
2225
+ edited the digest differs and the attach restarts with the new snapshot. Unlike
2226
+ `agent relaunch`, which writes nothing before the stop, an attach records the
2227
+ instructions before it, so a plain `agent resume` finishes an attach whose
2228
+ resume failed. Outside tmux the stop needs `--socket <name>` or
2229
+ `--socket-path <absolute>`, exactly as `delete pane` does. Refusals leave no
2230
+ snapshot, Registry, or Pane change. If the resume fails after the stop, the
2231
+ Agent stays Offline with its new annotations and stderr prints the
2232
+ `projmux agent resume uid:<agent> --project uid:<project> --window uid:<window>`
2233
+ command that finishes the job with the instructions. If closing the managed Pane
2234
+ reports an error, the command checks whether that Pane is still alive: if it
2235
+ is, the previous annotations are restored; if it is already closed, the new
2236
+ annotations are kept and the resume proceeds with a warning on stderr (a failed
2237
+ resume prints the recovery command above); if it cannot tell, the previous
2238
+ annotations are restored and stderr prints the command to re-run.
2239
+
2240
+ ### Agent profiles at create
2241
+
2242
+ `create agent --profile <name>` (and the provider shortcuts) starts the Agent
2243
+ from a [profile](configuration.md#agent-profiles). Without `--profile`, a
2244
+ `--label role=<role>` selects the one profile whose `roles` lists that role; a
2245
+ role no profile lists selects none. A role that several profiles list
2246
+ (`profile-role-claimed`) refuses the create: remove the role from all but one
2247
+ of the listed profiles, or pass `--profile none`. A role whose one listing
2248
+ profile is invalid (`profile-role-profile-invalid`, naming the profile and its
2249
+ own reason) refuses too, rather than create the Agent without that profile's
2250
+ permissions: fix the profile, or pass `--profile none`. `--profile none`
2251
+ applies no profile and does no role mapping. The label is read only at
2252
+ creation. A profile that is missing, or that `profile list` marks invalid --
2253
+ including `profile-role-claimed` -- refuses the create with exit 2 and its
2254
+ reason token, whether it is named with `--profile` or selected by a role.
2255
+
2256
+ A profile that names a `provider` applies only to Agents of that provider. Any
2257
+ other provider refuses the create with exit 2 (`profile-provider-mismatch`,
2258
+ naming both providers) before anything is written or launched, on every lane:
2259
+ `create agent --provider <p>`, the `create <provider>` shortcuts, a role label,
2260
+ and a create from the UI. A profile without `provider` applies to every
2261
+ provider.
2262
+
2263
+ `create agent` may omit `--provider` when the profile it selects -- by
2264
+ `--profile` or by a role label -- names one; the Agent is then created with
2265
+ that provider, exactly as if `--provider` had spelled it. With a profile
2266
+ `reviewer` that sets `provider = "codex"`:
2267
+
2268
+ ```sh
2269
+ projmux create agent --profile reviewer --project alpha --window main -- "review the diff"
2270
+ ```
2271
+
2272
+ An explicit `--provider` still wins and is still refused when it differs from
2273
+ the profile's. A profile that cannot be resolved refuses with its own reason.
2274
+ Without a profile, with `--profile none`, or with a profile that names no
2275
+ provider, `create agent` still requires `--provider`.
2276
+
2277
+ An explicit flag wins over the profile item it overlaps: `--instructions` over
2278
+ `instructions`, `--model` over `model`, `--effort` over `effort`. The profile's instructions go through the same path as
2279
+ `--instructions` (snapshot and `projmux.io/persona*` annotations, and the same
2280
+ Codex lane rule), its effort is recorded as `projmux.io/effort`, and its model
2281
+ as `projmux.io/model`. On
2282
+ Claude, `allow` and `deny` are passed as `--settings <snapshot>`. Claude does
2283
+ not get `sandbox` (`claude-sandbox-bash-only`: its sandbox confines only Bash)
2284
+ or `approval` (`claude-no-matching-permission-mode`).
2285
+
2286
+ Codex applies `sandbox` and `approval` on every create and resume lane. A
2287
+ prompted native create sends them on `thread/start`, and a native resume sends
2288
+ them on `thread/resume`; a policy mismatch refuses the operation
2289
+ (`codex-thread-policy-mismatch`). Promptless and `--interactive-only` creates
2290
+ and CLI resumes pass `-s <sandbox>` and `-a <approval>` before the workspace
2291
+ and resume arguments. `full-access` is spelled `danger-full-access` for Codex.
2292
+ The CLI accepts `approval = "on-request"` or `"never"`. It refuses a profile
2293
+ with `approval = "untrusted"` before launch
2294
+ (`codex-cli-untrusted-approval-unsupported`); the native lane still accepts it.
2295
+ Codex does not get `allow` or `deny` (`codex-command-rules-unsupported`),
2296
+ which remain visible as skipped items. Codex applies Profile `model` and
2297
+ `effort`. Any other provider refuses a profile with permissions
2298
+ (`profile-permissions-unsupported-provider`) and skips `model` and `effort`
2299
+ (`provider-option-unsupported`). The reply-only activation refuses a profile
2300
+ (`profile-lane-unsupported`).
2301
+
2302
+ The Agent records `projmux.io/profile` and `projmux.io/profile-digest`. The
2303
+ result names the profile and each item that was not applied, with its reason:
2304
+ `profile name=<name> digest=<digest>` and `profile-not-applied item=<item>
2305
+ provider=<provider> reason=<token>` lines after the receipt line, a `profile`
2306
+ object (`name`, `digest`, `notApplied`) in `-o receipt`, and the same lines on
2307
+ stderr for the other projections. Items replaced by a flag are disclosed as
2308
+ `overridden-by-flag`. A create that applies no profile prints exactly what it
2309
+ printed before.
2310
+
2311
+ Every Claude resume of such an Agent -- `agent resume`, Continue/topology
2312
+ replay, and the resume picker -- re-reads the profile by name, passes its
2313
+ current rules as `--settings`, and records the new digest. A profile that is
2314
+ gone or invalid -- including one now marked `profile-role-claimed` -- refuses
2315
+ the resume (`profile-resume-unavailable`, naming the underlying reason); there is no
2316
+ resume without its permissions. `agent resume`, `agent relaunch`, and
2317
+ Continue/topology replay also take the profile's current instructions, model,
2318
+ and effort for the items the Agent does not override
2319
+ ([settings layers](#settings-layers)); the resume picker resolves the values it
2320
+ inherits the same way, each an override of the new Agent. A resume
2321
+ picker selection inherits the profile when every Agent recording the
2322
+ conversation records the same one, and refuses when they disagree.
2323
+
2324
+ A native Codex resume of such an Agent -- `agent resume`, and a resume picker
2325
+ selection of an app-server thread -- re-reads the profile by name the same
2326
+ way, sends its current `sandbox` and `approval` on `thread/resume`, and
2327
+ records the new digest. A thread that is already loaded keeps the policy it
2328
+ runs with, so a resume whose answer reports another policy is refused
2329
+ (`codex-thread-policy-mismatch`) and nothing is committed. Continue/topology
2330
+ replay and a resume picker rollout row resume Codex as `codex resume <id>`,
2331
+ which cannot carry a policy: when the Agent's profile now sets any permission
2332
+ they refuse (`profile-resume-unavailable`, `profile-lane-unsupported`), and a
2333
+ profile without permissions resumes as before. An Agent without a profile
2334
+ sends exactly the request it sent before.
2335
+
2336
+ Each of those settings records where it came from, beside its value, so
2337
+ `describe agent -o json` tells a profile item apart from an override. The
2338
+ keys are `projmux.io/profile-source`, `projmux.io/instructions-source`,
2339
+ `projmux.io/model-source`, and `projmux.io/effort-source`; the values keep
2340
+ their own keys (`projmux.io/profile`, `projmux.io/persona`, `projmux.io/model`,
2341
+ `projmux.io/effort`), whose meaning does not change.
2342
+
2343
+ | Source | Written by |
2344
+ | --- | --- |
2345
+ | `flag` | `create agent` (and a UI create) for `--profile`, `--instructions`, `--model`, and `--effort` |
2346
+ | `role` | `projmux.io/profile-source` only: the profile a `role` label selected |
2347
+ | `profile` | item sources only: the item the create's profile filled in, or that a resume, a relaunch `--reset`, or a relaunch `--profile` switch put in the profile layer |
2348
+ | `inherited` | a resume picker selection, for the profile, instructions, and effort it inherited |
2349
+ | `resume` | `agent resume --model/--effort` |
2350
+ | `relaunch` | `agent relaunch`: `--profile` (for `projmux.io/profile-source`), `--instructions`, `--model`, and `--effort` |
2351
+ | `attach` | `projmux.io/instructions-source` only: the deprecated attach and detach ([Deprecated instruction spellings](#deprecated-instruction-spellings)) |
2352
+
2353
+ An item source other than `profile` means the value overrides the profile.
2354
+ After a detach the Agent records `projmux.io/instructions-source=attach`
2355
+ without `projmux.io/persona`: it was explicitly given no instructions. Every
2356
+ source is written in the same transaction as its value, so a launch that fails
2357
+ rolls back both, a restored attach or detach restores both, and a command that
2358
+ writes no value writes no source. An Agent without a source key recorded its
2359
+ value before sources were, and the source is unknown. The source keys are not
2360
+ part of the resume picker's inheritance agreement: Agents that record the same
2361
+ values with different sources still agree.
2362
+
2363
+ <a id="settings-layers"></a>
2364
+ **Settings layers.** `agent resume`, `agent relaunch`, Continue (the topology
2365
+ replay that brings a Project's Agents back), and a resume-picker create launch
2366
+ an Agent with its settings resolved from two layers: an item the Agent overrides keeps the
2367
+ recorded value, and an item it does not override takes the profile's value as
2368
+ the profile is now (none when the profile sets none). The items are the
2369
+ instructions, the model, and the effort; permissions come only from the
2370
+ profile. So an edit to a profile reaches every Agent that uses it on its next
2371
+ `agent resume`, plain `agent relaunch`, or Continue, except for the items that
2372
+ Agent overrides, and each of those launches of one Agent passes the same
2373
+ model, effort, and instructions:
2374
+
2375
+ - The effort is passed on every launch, as before.
2376
+ - The model is passed only when the resolved model differs from the recorded
2377
+ `projmux.io/model` (a profile whose model changed); an unchanged model is not
2378
+ passed, so the provider restores the conversation's own, a `/model` switch
2379
+ included.
2380
+ - The instructions are passed as a snapshot of their current content, with
2381
+ the system prompt snapshot off, when their name or content changed, as
2382
+ described above. A Codex thread keeps the developer instructions it started
2383
+ with: its resume passes the rest and discloses the instructions it did not
2384
+ apply (`codex-instructions-immutable`), recording nothing for them.
2385
+
2386
+ The launch records each value and source it ran with in its own transaction.
2387
+ An item without a source key predates sources; its layer is decided from its
2388
+ value: equal to the profile's current value means the profile layer, which the
2389
+ launch then records as `profile`, and anything else -- a value the profile does
2390
+ not set, or no value where the profile sets one -- is an override of unknown
2391
+ source that keeps no source key. An Agent without a profile overrides every
2392
+ item. So the first resume after the upgrade launches exactly what the Agent
2393
+ launched before.
2394
+
2395
+ A resume-picker create resolves the Agent it records the same way: the
2396
+ values and the profile it inherits from the Agents that already hold the
2397
+ conversation are that Agent's record, where each inherited value is an
2398
+ override (source `inherited`) and an item nothing inherited follows the
2399
+ profile. Inherited instructions whose file was edited therefore launch as a
2400
+ snapshot of the new content with the system prompt snapshot off, exactly as
2401
+ `agent resume` of the new Agent would. No model is inherited, so none is
2402
+ passed. Which values are inherited, and when holders disagree, is unchanged.
2403
+
2404
+ The layers change only through `agent relaunch` (and the deprecated attach and
2405
+ detach, which run the same restart): `--profile` switches the profile
2406
+ layer and clears the overrides, `--instructions`, `--model`, and `--effort`
2407
+ add overrides, and `--reset` removes them. An item with neither a profile nor
2408
+ an override has no value and no source.
2409
+
1701
2410
  Automation callers get the new pane's handle from `-o pane-id` on the canonical
1702
2411
  create routes: `projmux create agent --provider <p> --placement right -o pane-id`
1703
2412
  and `projmux create pane --placement right -o pane-id` each print exactly the
@@ -1743,7 +2452,7 @@ other case reports review as unavailable without changing the Agent. This route
1743
2452
  projects only the initial response into interaction status. It does not claim
1744
2453
  the later notification-driven completion lifecycle.
1745
2454
 
1746
- Live Antigravity hook/session-state resume metadata remains a separate,
2455
+ Live Antigravity hook resume metadata remains a separate,
1747
2456
  high-confidence lane; it is not enumerated from disk by the picker. Within the
1748
2457
  picker's disk discovery, source order is the workspace-to-latest-UUID mapping
1749
2458
  in `cache/last_conversations.json`, workspace-bearing summarized rows in
@@ -1757,13 +2466,18 @@ conversation history. Cache rows have medium confidence and blank turns;
1757
2466
  summary. Legacy history is low confidence. Missing/malformed cache, stale
1758
2467
  missing-DB mappings, workspace-less metadata, and unknown fields degrade
1759
2468
  without failing Claude/Codex or legacy discovery.
1760
- Settings > AI Settings > Enabled agents controls Claude/Codex/Antigravity launch
1761
- visibility. Disabled agents are hidden from the selective picker and from the
2469
+ `Settings > Global > AI > Enabled providers`, or
2470
+ `projmux config providers [--enable <id> | --disable <id>]` through the same
2471
+ writer, controls Claude/Codex/Antigravity launch visibility. Disabled
2472
+ providers are hidden from the selective picker and from the
1762
2473
  default-mode picker. A saved default that later becomes disabled fails clearly
1763
2474
  instead of falling back to another agent. Direct
1764
2475
  Canonical `create agent --provider <p>` launches and the provider shortcuts also
1765
2476
  fail when disabled. If all AI agents are disabled, the selective picker still offers the
1766
2477
  plain `shell` split and shows guidance to re-enable Claude/Codex/Antigravity.
2478
+ While at least one agent is enabled, the selective picker also offers a `resume`
2479
+ row between the agents and `shell`; it opens the resume session list in the
2480
+ same popup.
1767
2481
  For user-level skill, slash-command, editor, or launcher registrations that
1768
2482
  call this contract, see [AI Agent Shortcuts](ai-agent-shortcuts.md).
1769
2483
 
@@ -1823,22 +2537,21 @@ precedence over catalog `action` for known Claude events too; for example a
1823
2537
  noisy notify event can be made state-only or quiet without changing installed
1824
2538
  Claude hook commands.
1825
2539
 
1826
- `ingest antigravity-hook` is the hook/statusline entrypoint for
2540
+ `ingest antigravity-hook` is the hook entrypoint for
1827
2541
  Antigravity CLI `agy` payloads. Official v1.1.12 hook commands must pass their
1828
2542
  event identity explicitly, for example
1829
2543
  `projmux internal agent-hook ingest antigravity-hook --event Stop`; the official stdin payload
1830
2544
  does not carry an event field. The explicit selector is authoritative, while
1831
2545
  payload `eventName` and its legacy aliases remain fallback inputs for existing
1832
2546
  manual wiring. `projmux agent integrate antigravity` manages exactly the named
1833
- `projmux` entry in `~/.gemini/config/hooks.json` and, separately, exactly the
1834
- `statusLine` member in `~/.gemini/antigravity-cli/settings.json`. The managed
1835
- statusline uses the official v1.1.12 `{type:"command", enabled:true,
1836
- stack_with_default:true}` shape and an absolute direct ingest command whose
1837
- stdout is empty, so the built-in statusline remains visible. It preserves every
2547
+ `projmux` entry in `~/.gemini/config/hooks.json`. It never creates or writes
2548
+ `~/.gemini/antigravity-cli/settings.json` and does not judge its `statusLine`;
2549
+ only `--remove` also strips a `statusLine` that an older projmux installed
2550
+ (its command carries `projmux-managed:antigravity-statusline:v1`), and
2551
+ `projmux config apply` removes that legacy entry on upgrade. It preserves every
1838
2552
  other named entry and unknown JSON value, resolves the running projmux
1839
2553
  executable to a stable absolute path, and supports `--dry-run` and `--remove`.
1840
- An existing unmanaged custom `statusLine` is an actionable conflict and is
1841
- never chained, wrapped, or rewritten. An existing
2554
+ An existing
1842
2555
  unmanaged `projmux` entry, another Antigravity projmux ingest command, malformed
1843
2556
  JSON, symlinks, and read/write permission failures are reported without
1844
2557
  rewriting the file. Doctor and Settings also report a managed entry as `stale`
@@ -1849,8 +2562,8 @@ The embedded v1.1.12 catalog contains the five official events `PreToolUse`,
1849
2562
  `PostToolUse`, `PreInvocation`, `PostInvocation`, and `Stop`. The managed entry
1850
2563
  installs `PreInvocation`, `PostInvocation`, `PostToolUse`, and `Stop`, each with
1851
2564
  an explicit `--event`; `PreToolUse` remains disabled because its response can
1852
- change permission policy. `Statusline` remains an explicit statusline selector
1853
- outside that official hook catalog.
2565
+ change permission policy. A leftover `--event Statusline` call from an older
2566
+ statusLine bridge exits 0 with empty stdout and changes nothing.
1854
2567
 
1855
2568
  `PreInvocation` moves the matched pane to thinking/busy without notifying.
1856
2569
  `PostInvocation` and `PostToolUse` remain quiet bookkeeping paths, with tool
@@ -1858,13 +2571,9 @@ errors retained in ingest diagnostics. `Stop` keeps the completion/error notify
1858
2571
  classification. Hook stdout is `{}` for the three non-Stop managed events and
1859
2572
  `{"decision":"stop"}` for Stop, including a shell fallback if ingest fails, so
1860
2573
  the hook cannot force continuation or synthesize a permission decision.
1861
- Official statusline `agent_state` values `thinking`, `working`, and `tool_use`
1862
- map to thinking/busy unless the pane already holds a terminal completion or
1863
- approval state; this prevents a late statusline refresh from regressing `Stop`.
1864
2574
  A new `PreInvocation` resets the pane to thinking for the next generation.
1865
- `idle` is quiet and does not clear an existing completion or approval state.
1866
- `tool_confirmation_pending=true` produces a stable-ID,
1867
- deduped approval-required row; false never produces a notification.
2575
+ Antigravity has no official approval-required or mid-turn busy event, so
2576
+ projmux reports neither for Antigravity.
1868
2577
 
1869
2578
  The managed JSON is the install source of truth. The command
1870
2579
  `agy -p '/hooks' --output-format json` is a read-only runtime diagnostic for
@@ -1880,19 +2589,11 @@ unknown reasons remain info completions with diagnostic metadata rather than
1880
2589
  being promoted to critical. Official camelCase fields retained by the parser
1881
2590
  also include `artifactDirectoryPath`, `modelName`, `invocationNum`,
1882
2591
  `initialNumSteps`, `toolCall`, `stepIdx`, `executionNum`, and `fullyIdle`.
1883
- Antigravity notify metadata uses `agent=antigravity`. Phase 3 session-state
1884
- restore is included: Antigravity ingest stores `conversationId` as pane thread
1885
- metadata for matching and as session-state resume metadata. Restore uses
1886
- `agy --conversation <uuid>` when that id is present and UUID-shaped; otherwise
1887
- session-state preview/doctor render `resume unavailable`. Structured statusline
1888
- `context_window.used_percentage` is persisted with its conversation id as
1889
- private hook/notify diagnostic metadata and is not surfaced as account usage.
1890
- The official `quota` map is persisted independently and surfaces each valid entry as
1891
- `quota/<exact bucket ID>` with independently retained absolute and relative
1892
- reset values. Bucket IDs are never mapped to `5h`/`weekly`, and account quota
1893
- is never inferred from the conversation-local gauge.
1894
- The earlier string percentage form remains a compatibility fallback.
1895
- Transcript contents are not read.
2592
+ Antigravity notify metadata uses `agent=antigravity`. Antigravity ingest stores
2593
+ `conversationId` as pane thread metadata for matching and as Agent resume
2594
+ metadata. Resume uses `agy --conversation <uuid>` when that id is present and
2595
+ UUID-shaped and is refused otherwise. projmux records no Antigravity usage,
2596
+ context, or quota. Transcript contents are not read.
1896
2597
 
1897
2598
  The canonical `internal agent-hook ingest bell --pane <pane_id>` route is the
1898
2599
  narrow tmux-bell fallback ingest path.
@@ -2119,6 +2820,40 @@ servers before installing current bindings. If the current keymap assigns `C-t`
2119
2820
  to another action, that current action is bound after cleanup and remains the
2120
2821
  owner.
2121
2822
 
2823
+ ## profile
2824
+
2825
+ ```
2826
+ projmux profile list
2827
+ projmux profile show <name>
2828
+ projmux profile set <name> [--file <path> | -]
2829
+ projmux profile delete <name> --yes
2830
+ ```
2831
+
2832
+ A profile is a named set of Agent start settings -- provider, instructions,
2833
+ model, effort, roles, and permissions -- kept in `<config dir>/profiles/<name>.toml`.
2834
+ The file format and vocabulary are in
2835
+ [Configuration](configuration.md#agent-profiles). These commands store and
2836
+ validate profiles; `create agent --profile <name>` applies one (see
2837
+ [Agent profiles at create](#agent-profiles-at-create)).
2838
+
2839
+ - `list` prints `NAME SOURCE PROVIDER INSTRUCTIONS MODEL EFFORT ROLES DIGEST
2840
+ VALID` for every profile. `SOURCE` is `user`, and `DIGEST` is
2841
+ `sha256:<hex>` over the file bytes. An item the profile does not name is
2842
+ `-`; so is `PROVIDER` for a provider-neutral profile. A file that fails
2843
+ validation stays listed as `no (<reason>)` and does not hide the others;
2844
+ when it still parses, it shows what it names, roles included, and a file
2845
+ that does not parse shows `-` for each item.
2846
+ - `show` prints the stored bytes exactly.
2847
+ - `set` validates the whole file first and writes it atomically (0600) only
2848
+ when it is valid; `-` or no `--file` reads stdin. A refusal exits 2, prints
2849
+ one stable reason (`profile-syntax-invalid`, `profile-key-unknown`,
2850
+ `profile-table-unknown`, `profile-value-invalid`, `profile-provider-unknown`,
2851
+ `profile-instructions-not-found`, `profile-role-duplicate`,
2852
+ `profile-role-claimed`, `profile-name-invalid`, `profile-name-reserved`, or
2853
+ `profile-too-large`), and leaves any existing file unchanged.
2854
+ - `delete` removes a user file. A missing profile is `profile-not-found` (exit
2855
+ 1).
2856
+
2122
2857
  ## config
2123
2858
 
2124
2859
  ```
@@ -2236,7 +2971,7 @@ The live tmux inventory is under `runtime`: `runtime sessions`, `runtime
2236
2971
  attach`, `runtime stop`, `runtime tag`, and `runtime prune`. Project pins use
2237
2972
  `pin project list|add|remove|toggle|clear|migrate`; `list` takes `--kind
2238
2973
  project|candidate` and `migrate` takes `--dry-run`. Resource retention uses `prune
2239
- project|snapshot`, while explicit snapshot deletion uses `delete snapshot`.
2974
+ agent|project`.
2240
2975
 
2241
2976
  Popup-marker, preview, status, and tmux configuration plumbing is hidden under
2242
2977
  `internal session-popup`, `internal preview`, `internal status`, `internal
@@ -2249,35 +2984,24 @@ human configuration work should prefer `config render` and `config apply`.
2249
2984
  generated config. The generated app config uses absolute `$SHELL` as the
2250
2985
  tmux default shell when set, otherwise `/bin/sh`. `shell` starts or attaches
2251
2986
  the app session directly after resolving the target app session name and
2252
- startup directory. With no saved startup preference, Alt-1 sidebar project
2253
- open defaults to a two-action picker containing exactly `Continue project`
2254
- and `Recreate Project`; Esc returns to Projects without writing config. Saved `on`
2255
- keeps that picker, while saved `off` skips it and preserves the existing
2256
- automatic registered-Continue/unregistered-Fresh decision. `Continue
2257
- project` restores a deleted Project only from its usable exact snapshot and
2258
- otherwise refuses with zero Registry writes. `Recreate Project` confirms the
2987
+ startup directory. Alt-1 sidebar open of a registered closed Project shows a
2988
+ two-action picker containing exactly `Continue project` and
2989
+ `Clear layout and open`; Esc returns to Projects without writing config. A
2990
+ root that is not a registered Project skips the picker and opens fresh.
2991
+ `Continue
2992
+ project` on a root that is not a registered Project, including a deleted one,
2993
+ refuses with zero Registry writes and points to `Clear layout and open`. `Clear layout and open` confirms the
2259
2994
  exact old Project UID and its counts, then atomically replaces the Project
2260
2995
  with a new Project/Window/shell UID chain and one same-root claimant. A
2261
2996
  declined confirmation returns to the startup rows and writes nothing.
2262
- Repeating it allocates another new identity. Neither action modifies snapshot
2263
- bytes, the project directory, git/worktrees, unrelated roots, or trust state.
2264
- - `quit` — open an action picker with `Save Project snapshots and quit`, `Quit
2265
- without saving`, and `Cancel`. The safe first action takes one complete,
2266
- exact-socket Registry/resource-graph observation, freezes every live managed
2267
- Project session in Project UID/session order, and captures each latest
2268
- snapshot even when auto-save is off. Home/control, ephemeral, unattributed,
2269
- recoverable, foreign, and offline sessions are excluded and reported as
2270
- bounded class counts. Every target is attempted. A failed capture leaves the
2271
- successful per-session atomic files in place, reports the exact failed
2272
- session, and does not stop the app; retry captures every target again. Only an
2273
- all-success ledger reaches the existing physical-socket, app-marker, and
2274
- logical-route guarded shutdown. Named snapshots and Registry bytes are never
2275
- written, and the batch is not a multi-file transaction or topology freeze.
2276
- `Quit without saving` preserves the earlier guarded shutdown behavior:
2277
- missing servers and runtimes without the app marker are no-ops. Existing
2278
- non-interactive `--yes` and `--force` callers retain that same snapshot-free
2279
- behavior and exact shutdown route; the default command always uses the
2280
- action picker.
2997
+ Repeating it allocates another new identity. Neither action modifies the
2998
+ project directory, git/worktrees, unrelated roots, or trust state.
2999
+ - `quit` — open an action picker with `Quit projmux` and `Cancel`. `Quit
3000
+ projmux` runs the physical-socket, app-marker, and logical-route guarded
3001
+ shutdown; missing servers and runtimes without the app marker are no-ops.
3002
+ Quit never saves Project state. Non-interactive `--yes` and
3003
+ `--force` callers use the same shutdown route without the picker; the
3004
+ default command always uses the action picker.
2281
3005
  - `attach project <ref>` — enter a Project runtime from outside tmux.
2282
3006
  Automatic live-runtime attachment is `runtime attach`.
2283
3007
  - `settings` — interactive configuration UI for the project picker, AI
@@ -2296,8 +3020,8 @@ human configuration work should prefer `config render` and `config apply`.
2296
3020
  diagnostics guides: use `projmux setup` for key-delivery diagnosis,
2297
3021
  `projmux setup terminal` for supported terminal remediation, and the
2298
3022
  read-only `projmux doctor` report for dependency/runtime diagnostics. In Project
2299
- Picker, `Project Root` manages the saved
2300
- primary root (`~/.config/projmux/projdir`) and displays whether the effective
3023
+ Picker, `Project Root` manages the saved primary root
3024
+ (`$HOME/.config/projmux/projdir`) and displays whether the effective
2301
3025
  value comes from `PROJMUX_PROJDIR`, tmux `@projmux_projdir`, saved config, or
2302
3026
  no configured source. When no source is configured, the direct-set prompt
2303
3027
  starts with `$HOME` as an editable fallback, but `$HOME` is not used as the