projmux 0.16.0 → 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.
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,6 +111,21 @@ 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
 
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
+
100
129
  The resource routes (`get`, `describe`, `create`, `rename`, `label`, `rebind`,
101
130
  `delete`, `agent resume`) address stored resources through one shared selector
102
131
  grammar.
@@ -149,9 +178,12 @@ The contract:
149
178
  partially specified selector. The active *Project* is a separate rule and does
150
179
  apply to a reference -- see [Reference scope](#reference-scope-the-active-project-namespace)
151
180
  below.
152
- - **Only the singular routes and `create`.** The plural reads (`get
153
- projects|windows|panes|agents`) stay 0..N inventories over their whole scope,
154
- 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 --
155
187
  see [Create scope](#create-scope) -- because a create resolves a scope to put
156
188
  something *into* rather than a target to act *on*.
157
189
  - **Inside tmux is decided by `$TMUX_PANE` plus `$TMUX`**, not by whether a tmux
@@ -172,6 +204,28 @@ and `@projmux_window_uid` on its window — and derives every ancestor from
172
204
  registry `ownerRef`. The session-scoped `@projmux_project_uid` is deliberately
173
205
  not consulted.
174
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
+
175
229
  ### Plural read scope: the active managed root
176
230
 
177
231
  Inside tmux, selector-omitted `get windows|panes|agents` derives one exact
@@ -509,6 +563,18 @@ Two properties follow from that grammar and are worth stating outright:
509
563
  `create --label` has never had them and one field must not have two contracts
510
564
  depending on which route wrote it.
511
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
+
512
578
  What belongs in a label is decided by one question: is this a value you will
513
579
  ever filter on? `--selector key=value` reads labels and only labels, so
514
580
  classification that selects (`role=epic-owner`, `phase=task-0`) belongs there.
@@ -530,6 +596,15 @@ current Registry-backed `available`, and
530
596
  `completionPrecision` are separate fields. Use `-o json` for the stable machine
531
597
  projection.
532
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
+
533
608
  The closed static modes are `generic-registry`, `provider-resume`,
534
609
  `native-exact-control`, `provider-hook`, `read-only-adapter`, and
535
610
  `unsupported`. `message.send`, `message.status`, and `wait.idle` are provider-neutral commands whose availability is decided from
@@ -557,6 +632,20 @@ correlated model reply is a separate envelope with the original
557
632
  self-claims that envelope. Message lifecycle updates neither Agent interaction
558
633
  state nor tmux badges.
559
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
+
560
649
  Claude messaging is opt-in through `projmux agent integrate claude`. The
561
650
  integration installs no receiver waiter or `asyncRewake`; ingress is immediate
562
651
  through the exact registered provider socket. Capability JSON keeps Claude
@@ -576,8 +665,11 @@ and connection epoch still match exactly. `start` sends only the exact thread
576
665
  id and one text input. Immediately before that write it reads one bounded,
577
666
  content-free lifecycle snapshot: fresh active/in-progress returns
578
667
  `turn-in-progress`, fresh idle/terminal repairs stale cached state and starts
579
- once, and an unavailable or inconsistent snapshot returns
580
- `turn-state-unavailable` with no turn mutation. Broker read admission refusals
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
581
673
  remain visible as `lifecycle-retry` or `lifecycle-busy`. `steer` also reads that
582
674
  content-free snapshot before any write and submits exactly once only when it
583
675
  still proves the same exact active turn. Fresh idle, terminal, or different-turn
@@ -609,6 +701,39 @@ identity mismatch produces no provider write. Approval queue rows advertise
609
701
  advertise the exact-Agent `Open Codex` focus fallback; resolution removes the
610
702
  row. Neither route stores prompt, command, path, permission, or request content.
611
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
+
612
737
  `agent topic get|set|clear` and `agent status get|set` resolve exactly one
613
738
  Agent, either from an explicit Agent reference or from the Agent-owned active
614
739
  managed Pane. Topic is a non-identifying Registry annotation. Interaction is a
@@ -961,7 +1086,7 @@ the server, and no write verb is ever sent.
961
1086
  ## runtime diagnostics
962
1087
 
963
1088
  ```text
964
- projmux runtime diagnostics [--socket <name> | --socket-path <absolute>] [--ui=popup|sidebar]
1089
+ projmux runtime diagnostics [--socket <name> | --socket-path <absolute>] [--ui popup|sidebar]
965
1090
  ```
966
1091
 
967
1092
  The interactive half of the same read. It lists every tmux object on the exact
@@ -1115,10 +1240,17 @@ operator's question, so they stay reachable only as `projmux internal tmux ...`.
1115
1240
  ## switch
1116
1241
 
1117
1242
  ```
1118
- projmux switch [--ui=popup|sidebar]
1243
+ projmux switch [--ui popup|sidebar] [--anchor <pane>]
1119
1244
  projmux switch open <path>
1120
- projmux switch toggle-tag | toggle-pin | kill | settings | preview
1121
- 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>]
1122
1254
  ```
1123
1255
 
1124
1256
  Project picker. With no positional argument, opens the configured picker popup
@@ -1252,7 +1384,7 @@ than a standalone Settings row.
1252
1384
 
1253
1385
  ```
1254
1386
  projmux diagnostics log [--tail N] [--json]
1255
- [--level info|error] [--component NAME] [--path]
1387
+ [--level info|warn|error] [--component NAME] [--path]
1256
1388
  projmux diagnostics report [--output <path>]
1257
1389
  ```
1258
1390
 
@@ -1345,16 +1477,16 @@ which of them a command had touched.
1345
1477
  | `create project` | creates or reuses the Project, its canonical Window, and its shell | not started | not moved |
1346
1478
  | `start project` | unchanged | materialized when offline | not moved |
1347
1479
  | `open project` | unchanged | materialized when offline | moved to the Project |
1348
- | `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 |
1349
1481
  | `focus project` | unchanged | never materialized | moved to the Project |
1350
1482
  | `stop project` | unchanged | the exact session ends | existing safe fallback |
1351
1483
  | `unregister project` | the Project subtree is removed | **preserved** | not moved |
1352
1484
 
1353
1485
  `open project` and `attach project` are the same operation seen from the two
1354
1486
  sides of a tmux client. Inside tmux, `open` moves the client you are in and
1355
- `attach` refuses with a pointer at `open`; outside tmux, `attach` attaches the
1356
- caller and `open` refuses with a pointer at `attach`. Both refusals happen
1357
- 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.
1358
1490
 
1359
1491
  `stop project` refuses an offline target rather than succeeding silently: it
1360
1492
  declares exactly one runtime outcome, and reporting `runtime=stopped` for a
@@ -1368,7 +1500,13 @@ one `compatibilityWarnings` entry in the receipt. It is not scheduled for
1368
1500
  removal in this release.
1369
1501
 
1370
1502
  The reference for a Project can be `uid:<uid>`, a bare `metadata.name`, or the
1371
- 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`.
1372
1510
 
1373
1511
  A Project registered without `--name` -- by `create project`, by opening an
1374
1512
  unregistered directory, or by `Clear layout and open` -- is named after its root
@@ -1471,8 +1609,8 @@ projmux notification reconcile [--json]
1471
1609
  `get notifications` and is considered only by reconcile together with a gone
1472
1610
  target. Reconcile also retains only the newest 256 rows. `--text` is hard-capped to 80 runes (longer text is
1473
1611
  truncated server-side). After a successful queue write, projmux sends a
1474
- best-effort refresh event to open native notify sidebars and fires
1475
- 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
1476
1614
  failure does not fail the queue write; reopening the sidebar still shows the
1477
1615
  latest queue. The hook gets a JSON payload on stdin plus
1478
1616
  `PROJMUX_NOTIFY_*` env vars, and it does not replace the normal desktop
@@ -1629,19 +1767,21 @@ projmux internal status resources
1629
1767
  ## internal statusbar
1630
1768
 
1631
1769
  ```
1632
- projmux internal statusbar click <range-id> [--socket <s>] [--mouse-window <id>]
1633
- [--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]
1634
1772
  projmux internal statusbar usage-refresh
1635
1773
  ```
1636
1774
 
1637
1775
  Click/keyboard dispatcher for the two-line status bar. Implemented range ids:
1638
- `session pwd git resources usage notify settings`. The bare `window` /
1639
- `window|<idx>` token (tmux's built-in window-list range) and the empty
1640
- range fall through to `select-window -t @<mouse_window>` so the native
1641
- click-to-switch tab affordance is preserved on row 1. Unknown range ids are
1642
- non-specialized placeholders and no-op. `session` opens the existing-session
1643
- popup; `pwd` shows the current pane path in a native-framed display-only
1644
- 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;
1645
1785
  `settings` toggles the settings popup for the tmux client; `usage` opens the
1646
1786
  detailed cached account-usage popup. Legacy context rows are suppressed and
1647
1787
  named quotas retain exact identity/reset/freshness values. Claude model-scoped
@@ -1664,7 +1804,7 @@ projmux attention toggle [pane]
1664
1804
  projmux attention clear [pane]
1665
1805
  projmux attention arm [pane]
1666
1806
  projmux attention list [--json] [--all]
1667
- projmux attention window [window]
1807
+ projmux attention window [window] [style]
1668
1808
  ```
1669
1809
 
1670
1810
  Toggles the `✳` pane title prefix and the `@projmux_attention_state` pane
@@ -1695,6 +1835,7 @@ projmux agent status [get [<agent-ref>] | set <unknown|idle|in_progress|approval
1695
1835
  projmux agent topic get|clear [<agent-ref>] [--agent <ref>]
1696
1836
  projmux agent topic set <text> [<agent-ref>] [--agent <ref>]
1697
1837
  projmux agent capabilities [<agent-ref> | --provider <codex|claude|antigravity>] [-o json]
1838
+ projmux agent models [--provider claude] [-o json]
1698
1839
  projmux internal agent-hook watch-title [pane]
1699
1840
  projmux internal agent-hook ingest codex-hook [--pane <pane_uid|pane_id>] < payload.json
1700
1841
  projmux internal agent-hook ingest claude-hook [--pane <pane_uid|pane_id>] < payload.json
@@ -1761,107 +1902,261 @@ plain Agent on purpose; it is Codex-only and equivalent on `create agent
1761
1902
  multi-operand payloads, `agent resume`, Claude, and Antigravity are unaffected.
1762
1903
  See [Codex Native-Required Create Migration](codex-native-required-migration.md).
1763
1904
 
1764
- An Agent can be given a persona: `create agent --provider claude
1765
- --persona <name>` (and `create claude --persona <name>`) appends the stored
1766
- persona to the new session's system prompt through Claude's
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
1767
1908
  `--append-system-prompt-file`; it never replaces the system prompt, so Claude
1768
- Code's own tool instructions stay. Personas are files in
1769
- `<config dir>/personas/<name>.md` (by default `~/.config/projmux/personas/`),
1770
- at most 64 KiB each, managed with `projmux persona list|show|edit|set|delete`
1771
- (`edit` opens `$EDITOR`, then `$VISUAL`; `set <name> --file <path>` or `-` is
1772
- the non-interactive write). A persona's content is fixed when it is given: the create
1773
- copies the content to a content-addressed snapshot
1774
- `<state dir>/personas/sha256-<hex>.md`, passes only that path on the Claude
1775
- command line, and records `projmux.io/persona` and `projmux.io/persona-digest`
1776
- on the Agent. `agent resume` and Continue/topology replay pass that same
1777
- snapshot again, found from the recorded digest and never from the persona file,
1778
- so editing or deleting the persona file later never changes an existing Agent.
1779
- If the snapshot is gone, the resume still proceeds without the persona and
1780
- discloses one `persona-unavailable` line (on stderr for `agent resume`, among
1781
- the replay notices for Continue). A missing, oversized, or badly named persona
1782
- refuses with `persona-not-found`, `persona-too-large`, or
1783
- `persona-name-invalid`, all with zero Registry, tmux, and snapshot writes.
1784
-
1785
- A Codex Agent can be given a persona too, on one lane: a create that carries a
1786
- prompt (`create agent --provider codex --persona <name> -- <prompt>`, and
1787
- `create codex --persona <name> -- <prompt>`). That is the lane that opens a
1788
- thread of its own, and starting the thread is the only moment Codex accepts a
1789
- persona: the create sends the snapshot content as the thread's
1790
- `developerInstructions`, and the shared app server records it once as the
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
1791
1953
  thread's `developer` message. The content goes over that connection and
1792
1954
  nowhere else -- never onto a command line, where `ps` would publish it -- and
1793
1955
  the create records the same `projmux.io/persona` and `projmux.io/persona-digest`
1794
- annotations Claude records. From then on the thread carries the persona
1795
- itself: `agent resume`, Continue/topology replay, and a resume picked from the
1796
- Codex catalog re-send nothing and disclose nothing, because nothing was lost.
1797
- A conversation opened from the resume picker inherits the two persona keys
1798
- from the Agents that already record it, so the new Agent reports the persona
1799
- its thread is running; it inherits no other launch value. A Codex Agent's
1800
- persona cannot be changed afterwards: the instructions are fixed when the
1801
- thread starts, `agent persona attach|detach` stays Claude-only, and starting
1802
- over means a new Agent.
1803
-
1804
- Every other `--persona` create refuses with `persona-provider-unsupported` and
1805
- zero Registry, tmux, and snapshot writes: a Codex create with no prompt or with
1806
- `--interactive-only` (its plain lane would have to spell the persona into
1807
- argv), `--dialogue-reply-only`, and any other provider.
1808
-
1809
- An existing Claude Agent can take on a persona later, or drop it:
1810
- `projmux agent persona attach <agent-ref> <persona>` and
1811
- `projmux agent persona detach <agent-ref>` (both with `[--project <ref>]
1812
- [--window <ref>] [--yes] [--dry-run] [-o json]`). The Agent keeps its uid and
1813
- its provider conversation. A Running Agent's managed Pane is closed through
1814
- `delete pane`, which leaves it Offline, and the Agent is resumed through the
1815
- same rebind `agent resume` uses, on a new managed Pane; an Offline or Failed
1816
- Agent is only resumed. Before that the command writes the snapshot and records
1817
- `projmux.io/persona`, `projmux.io/persona-digest`, and
1818
- `projmux.io/system-prompt-snapshot=off` in one Registry change (detach removes
1819
- the first two). The last key is sticky and makes every later resume of that
1820
- Agent pass `--system-prompt-snapshot off`: Claude records the system prompt of
1821
- a conversation's first request and replays that record on resume, so without
1822
- it a persona attached after the conversation started would be ignored on the
1823
- next resume. In steady state that costs little: each resume re-creates a
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
1824
1986
  byte-identical system prompt, so the prompt cache still hits and the extra cost
1825
1987
  is a few dozen cache-creation tokens per resume (measured +4 to +45); after the
1826
1988
  environment context in the system prompt changes (date, git state, CLAUDE.md),
1827
- the first resume can re-cache the prompt prefix once. A Running Agent whose
1828
- interaction is not `idle` or
1829
- `response_complete` -- `unknown` included -- is refused with
1830
- `persona-agent-busy` unless `--yes` confirms cutting its turn, and `--dry-run`
1831
- (`-o json` for scripts) reports the target, its interaction, the current and
1832
- new persona, and whether that confirmation is required without changing
1833
- anything. The Agent owning the Pane the command runs in is refused with
1834
- `persona-self-target`; an Agent with no stored conversation is refused with
1835
- `persona-no-conversation`. Attaching the persona an Agent already runs with,
1836
- same name and same content digest, reports `unchanged` and restarts nothing;
1837
- after the persona file is edited the digest differs and the attach restarts
1838
- with the new snapshot. Outside tmux the stop needs `--socket <name>` or
1839
- `--socket-path <absolute>`, exactly as `delete pane` does. Refusals leave no
1840
- snapshot, Registry, or Pane change. If the resume fails after the stop, the
1841
- Agent stays Offline with its new annotations and stderr prints the
1842
- `projmux agent resume uid:<agent> --project uid:<project> --window uid:<window>`
1843
- command that finishes the job with the persona. If closing the managed Pane
1844
- reports an error, the command checks whether that Pane is still alive: if it
1845
- is, the previous annotations are restored; if it is already closed, the new
1846
- annotations are kept and the resume proceeds with a warning on stderr (a failed
1847
- resume prints the recovery command above); if it cannot tell, the previous
1848
- annotations are restored and stderr prints the command to re-run.
1989
+ the first resume can re-cache the prompt prefix once.
1849
1990
 
1850
1991
  A Claude Agent created with `--effort <level>` records it as `projmux.io/effort`
1851
1992
  on the Agent, because Claude does not restore a conversation's effort on
1852
1993
  resume. Every resume passes it again as `--effort <level>`: `agent resume`,
1853
- Continue/topology replay, and the restart of `agent persona attach|detach`. A
1854
- recorded value that is not one of `low`, `medium`, `high`, `xhigh`, or `max` is
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
1855
1996
  skipped, the resume still proceeds, and one `effort-invalid` line is disclosed
1856
- where a `persona-unavailable` line would be. The model given with `--model` is
1857
- not recorded or passed again: Claude restores the conversation's model itself
1858
- on resume, and passing the create-time model would override a `/model` switch
1859
- made in the session.
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.
1860
2155
 
1861
2156
  A Claude conversation opened from the resume picker creates a new Agent, and
1862
2157
  when Agents in the Registry already record that conversation (in any Project or
1863
- Window, live or not) the new Agent inherits their launch values: the persona
1864
- and its snapshot (`projmux.io/persona`, `projmux.io/persona-digest`), the
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
1865
2160
  system prompt snapshot mode (`projmux.io/system-prompt-snapshot`), and the
1866
2161
  effort (`projmux.io/effort`). It launches with them and records them, so its own
1867
2162
  later resumes behave like theirs; a snapshot that is gone or an effort Claude
@@ -1870,10 +2165,247 @@ on `agent resume`. Inheritance happens only when every such Agent records the
1870
2165
  same values; if they disagree, nothing is inherited and one
1871
2166
  `launch-values-ambiguous` notice names them. The creator, topic, and
1872
2167
  labels of those Agents are never inherited, and they keep their conversation
1873
- and annotations. A Codex picker selection inherits the two persona keys under
1874
- the same agreement rule and nothing else -- the snapshot mode and the effort
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
1875
2170
  are Claude launch options -- and it changes no argv, because the thread
1876
- already carries the persona. Antigravity picker selections inherit nothing.
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.
1877
2409
 
1878
2410
  Automation callers get the new pane's handle from `-o pane-id` on the canonical
1879
2411
  create routes: `projmux create agent --provider <p> --placement right -o pane-id`
@@ -2288,6 +2820,40 @@ servers before installing current bindings. If the current keymap assigns `C-t`
2288
2820
  to another action, that current action is bound after cleanup and remains the
2289
2821
  owner.
2290
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
+
2291
2857
  ## config
2292
2858
 
2293
2859
  ```
@@ -2454,8 +3020,8 @@ human configuration work should prefer `config render` and `config apply`.
2454
3020
  diagnostics guides: use `projmux setup` for key-delivery diagnosis,
2455
3021
  `projmux setup terminal` for supported terminal remediation, and the
2456
3022
  read-only `projmux doctor` report for dependency/runtime diagnostics. In Project
2457
- Picker, `Project Root` manages the saved
2458
- 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
2459
3025
  value comes from `PROJMUX_PROJDIR`, tmux `@projmux_projdir`, saved config, or
2460
3026
  no configured source. When no source is configured, the direct-set prompt
2461
3027
  starts with `$HOME` as an editable fallback, but `$HOME` is not used as the