projmux 0.15.2 → 0.15.3

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.
@@ -1008,10 +1008,14 @@ tmux transport mirror:
1008
1008
  recovery route.
1009
1009
  - `rename pane` changes `Pane.metadata.name` and its `@projmux_pane_label`
1010
1010
  mirror only. It never writes the raw tmux `pane_title`.
1011
- - `rename window` is the explicit stable-identity path: it changes only
1012
- `Window.metadata.name`, its root-scoped same-kind name reservation, and the
1013
- exact live `@projmux_window_name` transport mirror. It does not change tmux
1014
- `window_name`.
1011
+ - `rename window` is the explicit stable-identity path: it changes
1012
+ `Window.metadata.name`, its root-scoped same-kind name reservation, the exact
1013
+ live `@projmux_window_name` transport mirror and, when the invocation has a
1014
+ proven runtime route, the tmux tab `window_name` through the canonical
1015
+ `rename-window -t @N -- <name>` -- the same argv shape the rename key and the
1016
+ Window menu Rename item go through. With no route it stays Registry-only and
1017
+ says on stderr that the tab did not converge. It never changes
1018
+ `metadata.displayName`.
1015
1019
  - `rename project` likewise writes only `Project.metadata.name` and the exact
1016
1020
  live session's `@projmux_project_name`; it never renames the tmux session.
1017
1021
  `rebind project` preserves the Project uid and session name while updating
@@ -1906,7 +1910,10 @@ Resource-first create:
1906
1910
  touched.
1907
1911
  - **Everything is detached.** No create path issues `switch-client`,
1908
1912
  `select-window`, `select-pane`, or `attach-session`. `focus pane` and
1909
- `-o pane-id` are how a caller ends up in the new pane.
1913
+ `-o pane-id` are how a caller ends up in the new pane. One exception: the
1914
+ human intent route `internal tmux window-create` (`window.create` key, Window
1915
+ menu New At End) moves exactly the pressing client to the new Window after
1916
+ its create commits; public `create` stays detached.
1910
1917
  - **Focus is navigation-only.** `focus project|window|pane` reads live tmux
1911
1918
  inventory and may move an existing client, but has no Registry store and
1912
1919
  issues no session/Window/Pane creation, identity-marker, rename, respawn, or
@@ -2004,9 +2011,11 @@ Selector and the implicit active target:
2004
2011
 
2005
2012
  Projmux keeps visible naming separate from source metadata:
2006
2013
 
2007
- - **User pane label** is persistent pane-scoped metadata stored in
2008
- `@projmux_pane_label`. The Rename Pane action sets or clears only this field;
2009
- it does not write the AI topic or raw pane title.
2014
+ - **User pane label** is pane-scoped metadata stored in `@projmux_pane_label`,
2015
+ the live mirror of the Pane's Registry `metadata.name`. The Rename Pane action
2016
+ renames the Registry Pane through the same owner as `rename pane`, which
2017
+ writes this mirror; an empty response changes nothing, and the action never
2018
+ writes the AI topic or raw pane title.
2010
2019
  - **Pane border label** is the primary visible pane name. In the app tmux
2011
2020
  config and native previews it resolves to user pane label first, agent AI
2012
2021
  topic second, known interactive shell command (`zsh`, `bash`, `fish`, `sh`,
@@ -127,6 +127,22 @@ failure before any byte is a non-ambiguous `provider-write-zero`; partial bytes,
127
127
  a write error after bytes, or a lost helper response is ambiguous and has
128
128
  `autoResend=false`. A complete write plus helper return is only a transport
129
129
  handoff, not proof that Claude parsed, displayed, processed, or answered it.
130
+ Push content has no length cap of its own: only the 8192-byte serialized
131
+ auth+user frame bounds it, and a size excess ends as
132
+ `provider-frame-too-large: frameBytes=N limitBytes=8192` with zero provider
133
+ bytes; the reply tool argv body stays at 4096 bytes.
134
+
135
+ `agent message send` applies the same budget to a Claude target before
136
+ acceptance, for plain sends and `--reply-to` alike. The sender renders the
137
+ content with the helper's renderer, once with its own executable and once with
138
+ the fixed executable phrase, keeps the longer frame, and counts an assumed
139
+ 48-byte auth token; it never reads a messaging token. A frame over 8192 bytes
140
+ exits nonzero with `provider-frame-too-large: frameBytes=N limitBytes=8192`
141
+ before any receipt is stored or the helper is called. Codex targets are not
142
+ pre-checked. A helper started before this rule still caps push content at 4096
143
+ bytes and fails a larger body with `provider-frame-invalid-content`; the
144
+ sender's receipt then names the rendered content bytes and asks to re-activate
145
+ (restart) the target Agent.
130
146
 
131
147
  The frozen frame is closed to Claude Code `2.1.263`. A different provider
132
148
  version, helper replacement, provider restart, registration replacement, or
@@ -212,16 +228,21 @@ independently.
212
228
  validator's verdict on preserved real frame shapes. Neither it nor L20 proves
213
229
  installed-provider compatibility, value drift (the corpus keeps top-level key
214
230
  shape with placeholder values), or acceptance of unknown frames and fields (the
215
- closed vocabulary rejects them by design). The L20 fixture emits none of the
216
- corpus's dropped side frames. Two recorded real shapes are rejected today:
231
+ closed vocabulary rejects them by design). L20 replays every corpus item whose
232
+ verdict is `drop` through the production reply-only validator: the Claude
233
+ fixture reads the corpus at run time from `PROJMUX_FAKE_CLAUDE_OBSERVED_FRAMES`,
234
+ emits each dropped side frame with its key set unchanged after init and before
235
+ its startup result, and the scenario requires the emitted names to equal the
236
+ corpus drop set. Those frames are key-shape placeholders, not model output. L20
237
+ does not emit the two recorded real shapes that are rejected today:
217
238
  `result-success-25-keys` (the result allowlist lacks `origin`) and
218
239
  `system-init-allowlist-diff` (the init allowlist lacks `memory_paths` and
219
240
  `terminal_slash_commands`). Shapes without preserved evidence are gaps, not
220
- items: `command_lifecycle` keys and values, a non-null assistant
221
- `context_management`, `system` `thinking_tokens`, hook and user `tool_result`
222
- frames, the exact real init key set, every nested value, `rate_limit_event`
223
- envelope keys beyond `type` and `rate_limit_info`, and the lost earlier shape
224
- inventories.
241
+ items, so neither the corpus nor L20 exercises them: `command_lifecycle` keys
242
+ and values, a non-null assistant `context_management`, `system`
243
+ `thinking_tokens`, hook and user `tool_result` frames, the exact real init key
244
+ set, every nested value, `rate_limit_event` envelope keys beyond `type` and
245
+ `rate_limit_info`, and the lost earlier shape inventories.
225
246
 
226
247
  Provider sources: [SessionStart and Stop hooks](https://code.claude.com/docs/en/hooks)
227
248
  and [cross-session messaging](https://code.claude.com/docs/en/cross-session-messaging).
package/docs/cli-guide.md CHANGED
@@ -252,8 +252,27 @@ The contract:
252
252
  `create window|pane|agent|<provider>` is resource-backed on every spelling.
253
253
  There is no mode flag and no second parser: the same argv means the same thing
254
254
  whether or not `--project` is present, and `-w`, `--create-window`, `--pane`,
255
- `--selector`, `--placement`, `--name`, `--label`, `--cwd`, `--add-dir`, `-o`,
256
- and the `--` payload all reach the same parser either way.
255
+ `--selector`, `--placement`, `--cwd-from`, `--name`, `--label`, `-o`, and the
256
+ `--` payload all reach the same parser either way. `--cwd` and `--add-dir` are
257
+ provider create flags: they are defined on `create agent` and the three provider
258
+ shortcuts, not on `create window` or `create pane`.
259
+
260
+ `--cwd-from project|pane` selects where the new split starts. `project` (the
261
+ default) starts it in the owner Project root. `pane` starts it in the active
262
+ Pane's live directory while that directory is inside the owner Project root, and
263
+ otherwise starts it in the root and says so in one stderr line; it never
264
+ refuses. The flag cannot be combined with `--cwd`, which names an Agent working
265
+ directory outright.
266
+
267
+ On the CLI the flag is the only input: `create pane`, `create agent`, and the
268
+ provider shortcuts never read `[ai] split_cwd_from`, so with no `--cwd-from`
269
+ they always start in the owner Project root, whatever the global or project
270
+ config says. A CLI result is determined by its arguments, and scripts must not
271
+ change behavior because someone changed a Settings value. That config (and the
272
+ `AI > New splits start in` Settings row that writes it) only decides splits
273
+ started from the UI -- keybinding splits, the launcher, the resume picker's new
274
+ row, and the Pane menu -- in the order flag > project config > global config >
275
+ default. See [configuration.md](configuration.md).
257
276
 
258
277
  The scope resolves in two branches:
259
278
 
@@ -339,7 +358,10 @@ they name `--project` as the fix:
339
358
  gone — a `recoverable` runtime is reported, never adopted.
340
359
 
341
360
  Every create is **detached**: no create moves the client. Use `focus pane` or
342
- `-o pane-id` when you want to end up in the new pane. A natural create validates
361
+ `-o pane-id` when you want to end up in the new pane. One exception: the human
362
+ intent route `internal tmux window-create` (the `window.create` key and the
363
+ 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
343
365
  the inherited exact route and Pane containment. An explicit resource scope
344
366
  binds the selected app resource route without letting unrelated inherited
345
367
  `TMUX`/`TMUX_PANE` choose or change the resource target; exact Project plus
@@ -415,12 +437,20 @@ disabling the keys.
415
437
  ### Rename and rebind live convergence
416
438
 
417
439
  `rename project|window|pane` commits the selected Registry `metadata.name` and
418
- then updates only its exact UID-bound live transport field:
440
+ then updates only its exact UID-bound live transport fields:
419
441
 
420
442
  - Project: `@projmux_project_name` (never the tmux session name)
421
- - Window: `@projmux_window_name` (never tmux `window_name`)
443
+ - Window: `@projmux_window_name` and the tmux tab `window_name` (never
444
+ `displayName`)
422
445
  - Pane: `@projmux_pane_label` (never raw `pane_title`)
423
446
 
447
+ The Window tab converges only when the invocation has a proven runtime route,
448
+ which is what running inside the projmux tmux runtime gives it. Outside one the
449
+ rename is Registry-only: it exits zero and prints one line on stderr saying the
450
+ tab still shows the old name until a rename runs inside that runtime. There is
451
+ no flag for either behavior; the next time that Window is materialized from the
452
+ Registry, the tab carries the committed name.
453
+
424
454
  `rename agent` changes only the Agent's stable root-scoped `metadata.name`.
425
455
  It does not change the Agent topic, provider, lifecycle state, or managed Pane
426
456
  name/title. `create agent` derives the managed Pane's name from the Agent's
@@ -2046,6 +2076,8 @@ projmux internal tmux popup-sessions
2046
2076
  projmux internal tmux popup-preview <session>
2047
2077
  projmux internal tmux rebalance-panes
2048
2078
  projmux internal tmux rename-pane <pane> <label>
2079
+ projmux internal tmux window-rename --client <key> --anchor <%pane> (--name-stdin | -- <name>)
2080
+ projmux internal tmux pane-rename --client <key> --anchor <%pane> (--name-stdin | -- <name>)
2049
2081
  projmux internal tmux print-config [--bin <path>]
2050
2082
  projmux internal tmux print-app-config [--bin <path>]
2051
2083
  projmux internal tmux install [--bin <path>] [--config <path>] [--include <path>]
@@ -2059,10 +2091,18 @@ accepted by `popup-toggle` mirror the historical sessionizer surface:
2059
2091
  `notify-sidebar`, `recent-windows`, `resource-inspector`, `ai-split-picker-right`,
2060
2092
  `ai-split-picker-down`, `ai-split-resume-right`, `ai-split-resume-down`,
2061
2093
  `ai-split-settings`.
2062
- `rename-pane` sets only the pane-scoped user label
2063
- `@projmux_pane_label`; an empty label clears the option. It does not change the
2064
- raw tmux pane title, AI topic, or AI topic manual-ownership flag. The canonical
2065
- keybinding action id is `rename-pane-label`. The retired `rename-pane-topic`
2094
+ `rename-pane` is a label-only helper: it sets only the pane-scoped
2095
+ `@projmux_pane_label`, and an empty label clears the option. It does not change
2096
+ the Registry Pane name, so the next Continue restores that name, and it does not
2097
+ change the raw tmux pane title, AI topic, or AI topic manual-ownership flag. No
2098
+ generated binding uses it.
2099
+ `window-rename` and `pane-rename` are the generated rename routes behind the
2100
+ `rename-window` and `rename-pane-label` keybinding actions and the Window menu
2101
+ Rename item. They resolve the anchor Pane to its exact Registry Window or Pane
2102
+ and rename it through the same owner as `projmux rename window|pane`, then
2103
+ report one line to the client. The generated bindings pass the prompt response
2104
+ with `--name-stdin` inside a quoted here-document; see
2105
+ [keybindings.md](keybindings.md#rename-keys) for the input rules. The retired `rename-pane-topic`
2066
2106
  keymap action is no longer accepted: replace a stale
2067
2107
  `[bindings.rename-pane-topic]` table with `[bindings.rename-pane-label]`.
2068
2108
  The `projmux agent topic set/clear` commands keep
package/docs/cli.md CHANGED
@@ -39,7 +39,7 @@ Root parser bridges outside the route graph are censused from their parser token
39
39
 
40
40
  Every route declares one allowed-effect record over seven independent resource axes. A pipe separates conditional success outcomes; preflight refusal remains zero-effect. `domain-effect=null` means the route has no typed extension beyond this resource tuple.
41
41
 
42
- The machine-readable manifest contains 190 route-effect records, including hidden plumbing that the public route sections omit.
42
+ The machine-readable manifest contains 191 route-effect records, including hidden plumbing that the public route sections omit.
43
43
 
44
44
  | Axis | Closed vocabulary |
45
45
  | --- | --- |
@@ -75,7 +75,7 @@ projmux <command> [args...]
75
75
  | [`projmux notification`](#projmux-notification) | canonical | Manage pending notification workflow state |
76
76
  | [`projmux open`](#projmux-open) | canonical | Open a Project runtime and move the current client to it |
77
77
  | [`projmux pin`](#projmux-pin) | canonical | Manage pinned project directories |
78
- | [`projmux prune`](#projmux-prune) | canonical | Prune stale Projects and snapshots |
78
+ | [`projmux prune`](#projmux-prune) | canonical | Prune stale Projects, Agents, and snapshots |
79
79
  | [`projmux quit`](#projmux-quit) | shortcut | Quit the app-owned projmux tmux runtime |
80
80
  | [`projmux reconcile`](#projmux-reconcile) | canonical | Preview or repair Registry and exact tmux resource drift |
81
81
  | [`projmux rebind`](#projmux-rebind) | canonical | Rebind a Project to a new absolute root without moving files |
@@ -761,7 +761,7 @@ Subcommands:
761
761
 
762
762
  | Route | Summary |
763
763
  | --- | --- |
764
- | [`projmux agent message send`](#projmux-agent-message-send) | Submit bounded peer coordination; --source selects a source Agent anchor, not caller authentication (default: active Pane) |
764
+ | [`projmux agent message send`](#projmux-agent-message-send) | Submit bounded peer coordination; --source selects a source Agent anchor, not caller authentication (default: active Pane); exits nonzero after printing a failed, refused, expired, or stale receipt |
765
765
  | [`projmux agent message status`](#projmux-agent-message-status) | Read a payload-free broker delivery receipt |
766
766
  | [`projmux agent message qualify`](#projmux-agent-message-qualify) | Explicitly qualify one exact Claude target using owned current-version isolation evidence and one marker push |
767
767
 
@@ -769,7 +769,7 @@ Canonical spelling: `projmux agent message send`, `projmux agent message status`
769
769
 
770
770
  #### `projmux agent message send`
771
771
 
772
- Submit bounded peer coordination; --source selects a source Agent anchor, not caller authentication (default: active Pane)
772
+ Submit bounded peer coordination; --source selects a source Agent anchor, not caller authentication (default: active Pane); exits nonzero after printing a failed, refused, expired, or stale receipt
773
773
 
774
774
  Selectorless authority: `explicit-target` — the route or caller must name the exact target.
775
775
 
@@ -1215,10 +1215,10 @@ Allowed effects:
1215
1215
  ```
1216
1216
  projmux create project --root <absolute-path> [--name <name>] [--label key=value]... [-o <mode>]
1217
1217
  projmux create window [--project <ref> | -p <ref>] [--name <name>] [--label key=value]... [-o <mode>] [-- <payload>]
1218
- projmux create pane [--project <ref> | -p <ref>] [--window <ref> | -w <ref>]... [--pane <ref>]... [--create-window] [--all-windows | --primary-window] [--placement right|down] [-o <mode>] [-- <payload>]
1219
- projmux create agent --provider <provider> [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--interactive-only] [--window <ref> | -w <ref>]... [--pane <ref>]... [--create-window] [--all-windows | --primary-window] [--placement right|down] [-o <mode>] [-- <payload>]
1220
- projmux create codex [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--interactive-only] [--window <ref> | -w <ref>]... [--create-window] [--all-windows | --primary-window] [--placement right|down] [-o <mode>] [-- <payload>]
1221
- projmux create claude|antigravity [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--window <ref> | -w <ref>]... [--create-window] [--all-windows | --primary-window] [--placement right|down] [-o <mode>] [-- <payload>]
1218
+ projmux create pane [--project <ref> | -p <ref>] [--window <ref> | -w <ref>]... [--pane <ref>]... [--create-window] [--all-windows | --primary-window] [--placement right|down] [--cwd-from project|pane] [-o <mode>] [-- <payload>]
1219
+ projmux create agent --provider <provider> [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--interactive-only] [--window <ref> | -w <ref>]... [--pane <ref>]... [--create-window] [--all-windows | --primary-window] [--placement right|down] [--cwd-from project|pane] [-o <mode>] [-- <payload>]
1220
+ projmux create codex [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--interactive-only] [--window <ref> | -w <ref>]... [--create-window] [--all-windows | --primary-window] [--placement right|down] [--cwd-from project|pane] [-o <mode>] [-- <payload>]
1221
+ projmux create claude|antigravity [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--window <ref> | -w <ref>]... [--create-window] [--all-windows | --primary-window] [--placement right|down] [--cwd-from project|pane] [-o <mode>] [-- <payload>]
1222
1222
  projmux create notification --text <s> --target <SESSION[:WINDOW[.PANE]]> [--socket <s>]
1223
1223
  projmux create snapshot
1224
1224
  ```
@@ -1308,7 +1308,7 @@ Allowed effects:
1308
1308
  - `domain-effect=null`
1309
1309
 
1310
1310
  ```
1311
- projmux create pane [--project <ref> | -p <ref>] [--window <ref> | -w <ref>]... [--pane <ref>]... [--selector key=value]... [--create-window] [--all-windows | --primary-window] [--name <name>] [--label key=value]... [--placement right|down] [-o <mode>] [-- <payload>]
1311
+ projmux create pane [--project <ref> | -p <ref>] [--window <ref> | -w <ref>]... [--pane <ref>]... [--selector key=value]... [--create-window] [--all-windows | --primary-window] [--name <name>] [--label key=value]... [--placement right|down] [--cwd-from project|pane] [-o <mode>] [-- <payload>]
1312
1312
  ```
1313
1313
 
1314
1314
  Output modes (`-o`): `uid`, `name`, `ref`, `metadata`, `json`, `pane-id`, `none`, `receipt`
@@ -1331,7 +1331,7 @@ Allowed effects:
1331
1331
  - `domain-effect=null`
1332
1332
 
1333
1333
  ```
1334
- projmux create agent --provider <provider> [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--interactive-only] [--window <ref> | -w <ref>]... [--pane <ref>]... [--selector key=value]... [--create-window] [--all-windows | --primary-window] [--name <name>] [--label key=value]... [--placement right|down] [-o <mode>] [-- <payload>]
1334
+ projmux create agent --provider <provider> [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--interactive-only] [--window <ref> | -w <ref>]... [--pane <ref>]... [--selector key=value]... [--create-window] [--all-windows | --primary-window] [--name <name>] [--label key=value]... [--placement right|down] [--cwd-from project|pane] [-o <mode>] [-- <payload>]
1335
1335
  ```
1336
1336
 
1337
1337
  Output modes (`-o`): `uid`, `name`, `ref`, `metadata`, `json`, `pane-id`, `none`, `receipt`
@@ -1396,7 +1396,7 @@ Allowed effects:
1396
1396
  - `domain-effect=null`
1397
1397
 
1398
1398
  ```
1399
- projmux create codex [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--interactive-only] [--window <ref> | -w <ref>]... [--pane <ref>]... [--selector key=value]... [--create-window] [--all-windows | --primary-window] [--name <name>] [--label key=value]... [--placement right|down] [-o <mode>] [-- <payload>]
1399
+ projmux create codex [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--interactive-only] [--window <ref> | -w <ref>]... [--pane <ref>]... [--selector key=value]... [--create-window] [--all-windows | --primary-window] [--name <name>] [--label key=value]... [--placement right|down] [--cwd-from project|pane] [-o <mode>] [-- <payload>]
1400
1400
  ```
1401
1401
 
1402
1402
  Output modes (`-o`): `uid`, `name`, `ref`, `metadata`, `json`, `pane-id`, `none`, `receipt`
@@ -1419,7 +1419,7 @@ Allowed effects:
1419
1419
  - `domain-effect=null`
1420
1420
 
1421
1421
  ```
1422
- projmux create claude [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--window <ref> | -w <ref>]... [--pane <ref>]... [--selector key=value]... [--create-window] [--all-windows | --primary-window] [--name <name>] [--label key=value]... [--placement right|down] [-o <mode>] [-- <payload>]
1422
+ projmux create claude [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--window <ref> | -w <ref>]... [--pane <ref>]... [--selector key=value]... [--create-window] [--all-windows | --primary-window] [--name <name>] [--label key=value]... [--placement right|down] [--cwd-from project|pane] [-o <mode>] [-- <payload>]
1423
1423
  ```
1424
1424
 
1425
1425
  Output modes (`-o`): `uid`, `name`, `ref`, `metadata`, `json`, `pane-id`, `none`, `receipt`
@@ -1442,7 +1442,7 @@ Allowed effects:
1442
1442
  - `domain-effect=null`
1443
1443
 
1444
1444
  ```
1445
- projmux create antigravity [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--window <ref> | -w <ref>]... [--pane <ref>]... [--selector key=value]... [--create-window] [--all-windows | --primary-window] [--name <name>] [--label key=value]... [--placement right|down] [-o <mode>] [-- <payload>]
1445
+ projmux create antigravity [--project <ref> | -p <ref>] [--cwd <path>] [--add-dir <path>]... [--window <ref> | -w <ref>]... [--pane <ref>]... [--selector key=value]... [--create-window] [--all-windows | --primary-window] [--name <name>] [--label key=value]... [--placement right|down] [--cwd-from project|pane] [-o <mode>] [-- <payload>]
1446
1446
  ```
1447
1447
 
1448
1448
  Output modes (`-o`): `uid`, `name`, `ref`, `metadata`, `json`, `pane-id`, `none`, `receipt`
@@ -2600,7 +2600,7 @@ projmux pin project list|add|remove|toggle|clear
2600
2600
 
2601
2601
  ## `projmux prune`
2602
2602
 
2603
- Prune stale Projects and snapshots
2603
+ Prune stale Projects, Agents, and snapshots
2604
2604
 
2605
2605
  Selectorless authority: `refusal` — there is no safe selectorless action; refuse before output or mutation.
2606
2606
 
@@ -2618,16 +2618,39 @@ Allowed effects:
2618
2618
  ```
2619
2619
  projmux prune snapshot [--older-than <duration>]
2620
2620
  projmux prune project --missing --older-than <duration> [--yes]
2621
+ projmux prune agent --older-than <duration> [--no-session-ref] [--no-pane] [--exclude <agent-ref>]... [--yes]
2621
2622
  ```
2622
2623
 
2623
2624
  Subcommands:
2624
2625
 
2625
2626
  | Route | Summary |
2626
2627
  | --- | --- |
2628
+ | [`projmux prune agent`](#projmux-prune-agent) | Delete Offline or Failed Agents past a bounded age whose session ref or managed Panes are gone; live Panes and Running Agents are never selected |
2627
2629
  | [`projmux prune project`](#projmux-prune-project) | Delete Projects whose spec.root has been missing for a bounded age |
2628
2630
  | [`projmux prune snapshot`](#projmux-prune-snapshot) | Inspect or delete preserved session snapshots (canonical spelling) |
2629
2631
 
2630
- Canonical spelling: `projmux prune project`, `projmux prune snapshot`
2632
+ Canonical spelling: `projmux prune agent`, `projmux prune project`, `projmux prune snapshot`
2633
+
2634
+ ### `projmux prune agent`
2635
+
2636
+ Delete Offline or Failed Agents past a bounded age whose session ref or managed Panes are gone; live Panes and Running Agents are never selected
2637
+
2638
+ Selectorless authority: `explicit-fan-out` — the route spelling is an intentional global or whole-set opt-in.
2639
+
2640
+ Allowed effects:
2641
+
2642
+ - `identity=removed`
2643
+ - `address=released`
2644
+ - `topology=removed`
2645
+ - `desired-state=removed`
2646
+ - `runtime=unchanged`
2647
+ - `focus=unchanged`
2648
+ - `cardinality=zero-or-more`
2649
+ - `domain-effect=null`
2650
+
2651
+ ```
2652
+ projmux prune agent --older-than <duration> [--no-session-ref] [--no-pane] [--exclude <agent-ref>]... [--yes]
2653
+ ```
2631
2654
 
2632
2655
  ### `projmux prune project`
2633
2656
 
@@ -2847,7 +2870,7 @@ Subcommands:
2847
2870
  | Route | Summary |
2848
2871
  | --- | --- |
2849
2872
  | [`projmux rename project`](#projmux-rename-project) | Rename a Projmux Project resource; with no selector inside tmux, the active Project |
2850
- | [`projmux rename window`](#projmux-rename-window) | Rename a Projmux Window resource; inside tmux a reference resolves within the active Project or ControlSession and no selector means the active Window |
2873
+ | [`projmux rename window`](#projmux-rename-window) | Rename a Projmux Window resource; inside tmux a reference resolves within the active Project or ControlSession, no selector means the active Window, and the tmux tab is renamed with it |
2851
2874
  | [`projmux rename pane`](#projmux-rename-pane) | Rename a Projmux Pane resource; inside tmux a reference resolves within the active Project or ControlSession and no selector means the active Pane; does not change tmux pane_title |
2852
2875
  | [`projmux rename agent`](#projmux-rename-agent) | Rename an Agent stable resource name within the active Project or ControlSession without changing its topic, provider, or managed Pane |
2853
2876
 
@@ -2880,7 +2903,7 @@ Output modes (`-o`): `receipt`, `none`
2880
2903
 
2881
2904
  ### `projmux rename window`
2882
2905
 
2883
- Rename a Projmux Window resource; inside tmux a reference resolves within the active Project or ControlSession and no selector means the active Window
2906
+ Rename a Projmux Window resource; inside tmux a reference resolves within the active Project or ControlSession, no selector means the active Window, and the tmux tab is renamed with it
2884
2907
 
2885
2908
  Selectorless authority: `natural-omitted` — omission resolves one predictable current resource or documented contextual read/scope; any selector replaces it.
2886
2909
 
@@ -342,6 +342,7 @@ success = "#5faf87"
342
342
  action_required = "#ffaf00"
343
343
  pane_active_bg = "default"
344
344
  focus = "#00ffff"
345
+ provenance = "#ff8700"
345
346
  ```
346
347
 
347
348
  `text_primary` controls primary content text in native terminal-rendered UI.
@@ -360,6 +361,13 @@ active-pane background tint, and `focus` is the active-pane border color. Each
360
361
  of these is a public token: leave it unset to keep the historical built-in
361
362
  color, or set it to repaint the matching chrome.
362
363
 
364
+ `provenance` is the compact usage label color for a provider row whose numbers
365
+ came from a fallback data source rather than its authoritative one (today: a
366
+ Codex row outside a healthy app-server). It is independent of `warning` and
367
+ `critical`, which stay reserved for usage thresholds, and of the ordinary AI
368
+ label color; the fallback value is orange. See `docs/usage-tracking.md` for what
369
+ the label looks like and `docs/theme-palette.md` for the preset contract.
370
+
363
371
  Supported presets are `projmux`, `high-contrast`, `blue-hour`, `carbon-violet`,
364
372
  `daylight`, `ember`, `forest`, and `rose`. `daylight` is the fully-light
365
373
  preset; the others are dark. Preset colors paint projmux chrome only (status
@@ -517,6 +525,63 @@ desktop intent for both app-server and hook-fallback authority. Existing
517
525
  runtime override exists, take precedence only while hook fallback is current;
518
526
  they are never inferred or copied into the semantic policy store.
519
527
 
528
+ ## Split Start Directory
529
+
530
+ New splits start in the owner Project root. `[ai] split_cwd_from = "pane"`
531
+ starts UI splits in the active Pane's live directory instead, while that
532
+ directory is inside the owner Project root. Settings exposes the same value as
533
+ `AI > New splits start in` (`Project root` / `Current Pane directory`); choosing
534
+ one writes only the global `[ai] split_cwd_from`.
535
+
536
+ Config paths (global and project both honored):
537
+
538
+ ```text
539
+ ~/.config/projmux/config.toml # global
540
+ <project>/.projmux/config.toml # project
541
+ ```
542
+
543
+ Schema:
544
+
545
+ ```toml
546
+ [ai]
547
+ split_cwd_from = "project" # project|pane; where a new shell or Agent split starts
548
+ ```
549
+
550
+ Resolution depends on who starts the split.
551
+
552
+ **CLI** (`create pane`, `create agent`, and the provider shortcuts) — the flag
553
+ only:
554
+
555
+ 1. `--cwd-from project|pane`
556
+ 2. otherwise `project`
557
+
558
+ The CLI opens no config file for this decision. A CLI result is determined by
559
+ its arguments, so scripts and automation keep starting in the Project root when
560
+ someone changes this setting.
561
+
562
+ **UI** (keybinding splits, the launcher, the resume picker's new row, and the
563
+ Pane menu) — the config tiers:
564
+
565
+ 1. an explicit per-call value (flag)
566
+ 2. project `[ai] split_cwd_from`, read from the owner Project root
567
+ 3. global/user `[ai] split_cwd_from`
568
+ 4. built-in default (`project`)
569
+
570
+ There is no environment override, and an unknown value skips its own tier. The
571
+ project tier is always read from the owner Project root, so where a Pane sits
572
+ never changes which config decides. The Settings row shows the UI result and the
573
+ tier that decided it (`project`, `global`, or `default`).
574
+
575
+ With `pane` selected, the active Pane is the origin of the split: the Pane a
576
+ keybinding ran in, the Pane a right-click menu was opened on, or the anchor Pane
577
+ a CLI create resolved. Its live directory is used only when it is inside the
578
+ owner Project root. `$HOME`, another registered Project tree, a directory that no
579
+ longer exists, and an unreadable directory all start in the Project root and
580
+ report one line naming the reason and that root — on stderr for a CLI create
581
+ with `--cwd-from pane`, and as one client message for a split started from the
582
+ UI. A split is never refused for this reason. `--cwd` on `create agent` still
583
+ names the Agent working directory outright and ignores this setting.
584
+
520
585
  ## AI Resume Picker
521
586
 
522
587
  The Agent resume picker lists the most recent
@@ -348,14 +348,19 @@ a recorded verdict moves. Neither it nor L20 proves:
348
348
  - acceptance of unknown frames or fields, which the closed vocabulary rejects
349
349
  by design.
350
350
 
351
- The L20 fixture emits none of the corpus's dropped side frames. Recorded real
352
- shapes the validator rejects today:
351
+ L20 replays every corpus item whose verdict is `drop` through the production
352
+ reply-only validator. Its Claude fixture reads the corpus at run time, emits each
353
+ dropped side frame with its key set unchanged after init and before its startup
354
+ result, and the scenario requires the emitted names to equal the corpus drop
355
+ set. Those frames are key-shape placeholders, not model output. L20 does not
356
+ emit the recorded real shapes the validator rejects today:
353
357
 
354
358
  - `result-success-25-keys`: the result allowlist lacks `origin`;
355
359
  - `system-init-allowlist-diff`: the init allowlist lacks `memory_paths` and
356
360
  `terminal_slash_commands`.
357
361
 
358
- Shapes without preserved evidence are gaps, not corpus items: `command_lifecycle`
362
+ Shapes without preserved evidence are gaps, not corpus items, so neither the
363
+ corpus nor L20 exercises them: `command_lifecycle`
359
364
  keys and values; a non-null assistant `context_management` value; `system`
360
365
  `thinking_tokens` frames; hook and user `tool_result` frames; the exact real init
361
366
  key set; nested values of every frame; `rate_limit_event` envelope keys beyond
@@ -195,7 +195,8 @@ Optional direct keys can be added for actions such as:
195
195
  | `ai-split-right` | Open a new direct AI split to the right |
196
196
  | `ai-split-down` | Open a new direct AI split below |
197
197
  | `new-window` | New tmux window in the current pane directory |
198
- | `rename-window` | Rename the current tmux window |
198
+ | `rename-window` | Rename the current Window in the Registry; see [Rename keys](#rename-keys) |
199
+ | `rename-pane-label` | Rename the current Pane in the Registry; see [Rename keys](#rename-keys) |
199
200
 
200
201
  `AISplitPickerToggle` is the `Alt-7` popup picker toggle. It opens or closes
201
202
  the picker UI where the user chooses the AI split mode. It is separate from
@@ -297,6 +298,44 @@ A mouse menu acts on what was clicked, not on what is focused: Kill, Rename, and
297
298
  New At End in the status-line Window menu act on the clicked Window, and the
298
299
  Rename prompt starts with that Window's name.
299
300
 
301
+ ## Rename keys
302
+
303
+ `rename-window` (`window.rename`) and the Window menu Rename item run
304
+ `internal tmux window-rename`; `rename-pane-label` (`pane.rename`) runs
305
+ `internal tmux pane-rename`. Neither has a default key. Both are Registry
306
+ renames through the same owner as `projmux rename window` and
307
+ `projmux rename pane`: the Pane the key was pressed in, or the menu target,
308
+ resolves to its exact Registry Window or Pane, its `metadata.name` changes, and
309
+ its mirror converges with it. A Window rename writes `@projmux_window_name`
310
+ and, after the Registry commit, the tmux `window_name`; a Pane rename writes
311
+ `@projmux_pane_label`. A Continue that rebuilds the session from the Registry
312
+ therefore keeps the new name, including for the first Window of a session.
313
+
314
+ The prompt response is used exactly as typed:
315
+
316
+ - An empty or whitespace-only response changes nothing, not even the label,
317
+ and the client is told nothing was changed.
318
+ - A response that is not a valid name, such as one with a space, leading or
319
+ trailing whitespace, or a character like `'`, `"`, `$`, `;`, `%`, or `#`, is
320
+ refused with the reason and the usable spelling projmux would accept, for
321
+ example `a-b` for `a b`. Nothing is written.
322
+ - A name already used by another Window of the same Project or ControlSession,
323
+ or by another Pane of the same root, is refused. No suffix is added.
324
+ - A Pane with no Registry identity, such as one on a server projmux does not
325
+ manage, is refused with no write.
326
+ - A name a launcher chose, such as an Agent Pane's, renames like any other.
327
+
328
+ Every result is one line on the client that pressed the key. The response
329
+ reaches projmux on stdin inside a quoted here-document, so no shell parses it.
330
+ tmux still format-expands the `run-shell` command before any shell runs, as it
331
+ does at its own `:` prompt: a `#{...}` sequence in a response is substituted and
332
+ a `#(...)` sequence is run by tmux as a format job. Names cannot contain `#`, so
333
+ a response that still holds one is refused.
334
+
335
+ `internal tmux rename-pane <pane> <label>` is a separate label-only helper with
336
+ no generated binding. It writes `@projmux_pane_label` without touching the
337
+ Registry, so the next Continue restores the Registry name.
338
+
300
339
  The standalone `~/.tmux.conf` snippet keeps tmux's stock `prefix <`, `prefix >`,
301
340
  `MouseDown3Status`, `M-MouseDown3Status`, and `M-MouseDown3Pane` menus; it
302
341
  carries only the `MouseDown3Pane` menu. A `keymap.toml` that assigns a managed
@@ -37,7 +37,7 @@ unknown-command contract.
37
37
  | direct `tag list|toggle|clear`, `tag project ...` | `runtime tag ...` |
38
38
 
39
39
  The surviving mixed-root commands are exactly `attach project`, `focus
40
- project|window|pane`, `pin project`, and `prune project|snapshot`. The Shortcut
40
+ project|window|pane`, `pin project`, and `prune agent|project|snapshot`. The Shortcut
41
41
  routes `doctor`, `quit`, `resources`, `settings`, `shell`, `switch`, and
42
42
  `welcome` remain. Singular/plural resource-kind aliases remain.
43
43
 
@@ -88,6 +88,12 @@ step, never a silent no-op.
88
88
  - `Default launch target [Choice]` — an Agent Provider, a Shell Pane, or
89
89
  choose-at-launch. It is a keybinding/picker preference and does not weaken
90
90
  the canonical `create agent` explicit-provider requirement.
91
+ - `New splits start in [Choice]` — `Project root` (default) or
92
+ `Current Pane directory`, shown with the tier that decided it (`project`,
93
+ `global`, `default`). It writes only the global `[ai] split_cwd_from` and
94
+ decides UI splits only; the Pane directory is used only inside the Project
95
+ root, and the CLI does not follow this setting (`create pane|agent` obey
96
+ `--cwd-from` alone).
91
97
  - `Enabled providers [View]` — Claude, Codex, and Antigravity are Providers;
92
98
  `Shell`, `Selective` and `Resume` are not Providers and never appear here.
93
99
  - `Agent Resume Picker [View]` — states that resume targets an existing Agent
@@ -220,6 +226,31 @@ step, never a silent no-op.
220
226
  Without an actionable project context the Project surface renders a single
221
227
  passive guidance row rather than repeating a disabled reason per row.
222
228
 
229
+ ## Search
230
+
231
+ Search reaches every setting from the Settings root. A non-empty query at the
232
+ root lists the current scope's settings as one `path > label` list (rendered
233
+ with `›`) built by walking the navigation catalog, and choosing a result opens
234
+ the owning View with the cursor on that row without running its control --
235
+ Confirm and Action rows included, so `Quit Projmux` and `Reset theme` are
236
+ focused and never fired. The list is scope-pure: a Global query never returns
237
+ Project nodes and a Project query never returns Global ones, and with no project
238
+ context the Project tab returns nothing. User-data collection items -- an
239
+ individual discovery root, pinned Project, candidate or snapshot -- are data
240
+ rather than settings, so results stop at their parent View and at the
241
+ collection-level controls. Inside a View the query still filters that View's
242
+ rows, and category rows carry their members' search text so search crosses
243
+ categories.
244
+
245
+ The result rows are built from the catalog alone: no Registry, tmux,
246
+ filesystem or snapshot read participates, because a result is a destination
247
+ rather than a rendered value. Where that leaves a row unnameable -- a saved
248
+ user path, a command whose row spelling depends on whether a command is
249
+ already stored, a read-only state row that stands for several rendered lines --
250
+ the result still appears and opens the owning View on its first row instead of
251
+ guessing a row. The same happens when the target row is simply not rendered any
252
+ more: the View opens, unfocused, and nothing errors.
253
+
223
254
  ## Vocabulary and compatibility
224
255
 
225
256
  Visible nouns follow the shared resource vocabulary: `Project`, `Window`,
package/docs/statusbar.md CHANGED
@@ -254,10 +254,16 @@ bind-key -n MouseDown1Status if-shell -F "#{==:#{mouse_status_range},window}" \
254
254
  ## Usage element drop order
255
255
 
256
256
  The compact Codex provider identity is native-first. An authoritative healthy
257
- app-server snapshot renders as `Codex`; only degraded lanes are qualified as
258
- `Codex [fallback]` or `Codex [stale]`. Unknown non-stale provenance uses the
259
- conservative fallback label. These labels are locale-invariant, including on
260
- en-US and ko-KR narrow rows. The full Usage table, JSON, and diagnostics retain
257
+ app-server snapshot renders as `Codex`; a retained last-known-good snapshot is
258
+ qualified as `Codex [stale]`. A fallback lane carries no text qualifier: it
259
+ keeps the bare `Codex` label, painted in the `provenance` theme color (user
260
+ decision: *"codex[fallback] 하단 status 바대신 주황색의 Codex가나오는게어때"* →
261
+ *"B로 가자"*, a role color of its own rather than a reused threshold color, with
262
+ `[stale]` kept). The text tiers below the bars emit no color, so the same row
263
+ spells `Codex^ 5h:17%` / `X^ 5h:17%` — one ASCII cell instead of the former
264
+ 11-cell ` [fallback]` tag. Unknown non-stale provenance uses that same
265
+ conservative fallback presentation. These labels are locale-invariant,
266
+ including on en-US and ko-KR narrow rows. The full Usage table, JSON, and diagnostics retain
261
267
  the raw source and closed reason; the statusbar label is presentation only.
262
268
 
263
269
  The usage segment does not pick a whole-segment tier. It starts from its