projmux 0.15.3 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README-ko.md +3 -4
  2. package/README.md +3 -3
  3. package/docs/agent-message-replies.md +149 -6
  4. package/docs/ai-agent-shortcuts.md +6 -5
  5. package/docs/architecture.md +467 -66
  6. package/docs/claude-coordination-endpoints.md +192 -20
  7. package/docs/cli-guide.md +872 -148
  8. package/docs/cli.md +1459 -485
  9. package/docs/codex-installed-compatibility.md +6 -11
  10. package/docs/codex-native-required-migration.md +1 -59
  11. package/docs/configuration.md +694 -222
  12. package/docs/globalization.md +18 -5
  13. package/docs/hooks.md +529 -62
  14. package/docs/keybindings.md +74 -4
  15. package/docs/legacy-cli-retirement.md +3 -3
  16. package/docs/legacy-diagnostics-inventory.md +4 -4
  17. package/docs/native-picker.md +3 -5
  18. package/docs/notify-queue.md +1 -1
  19. package/docs/npm-distribution.md +4 -0
  20. package/docs/operational-diagnostics.md +319 -34
  21. package/docs/pr-guideline.md +66 -22
  22. package/docs/release.md +101 -0
  23. package/docs/replacement-contract.md +72 -58
  24. package/docs/repo-layout.md +3 -0
  25. package/docs/resource-attribution.md +6 -2
  26. package/docs/session-restore.md +50 -80
  27. package/docs/settings-ia.md +14 -22
  28. package/docs/statusbar.md +38 -37
  29. package/docs/testing.md +83 -18
  30. package/docs/theme-palette.md +6 -6
  31. package/docs/tmux-surface-inventory.md +21 -10
  32. package/docs/troubleshooting.md +2 -4
  33. package/docs/upgrading.md +161 -24
  34. package/docs/usage-tracking.md +40 -49
  35. package/package.json +5 -5
  36. package/docs/agent-workflow.md +0 -2596
  37. package/docs/codex-generation-pool.md +0 -623
  38. package/docs/codex-stored-qualification.md +0 -45
@@ -4,6 +4,31 @@ Most users can configure projmux from `projmux settings`. Environment variables
4
4
  are available for repeatable shell setup, managed machines, or advanced
5
5
  overrides.
6
6
 
7
+ ## XDG Base Directories
8
+
9
+ Paths in this guide written as `${XDG_CONFIG_HOME:-$HOME/.config}` and the like
10
+ follow one rule for `XDG_CONFIG_HOME`, `XDG_STATE_HOME`, `XDG_DATA_HOME`, and
11
+ `XDG_CACHE_HOME`. Surrounding whitespace is trimmed, and the value is used only
12
+ when it is an absolute path. An unset, empty, blank, or relative value
13
+ (`rel`, `./rel`, or an unexpanded `~/x`) is ignored as unset, as the
14
+ [XDG Base Directory specification](https://specifications.freedesktop.org/basedir-spec/latest/)
15
+ requires, and the default under `$HOME` applies instead:
16
+
17
+ | Variable | Default |
18
+ | --- | --- |
19
+ | `XDG_CONFIG_HOME` | `$HOME/.config` |
20
+ | `XDG_STATE_HOME` | `$HOME/.local/state` |
21
+ | `XDG_DATA_HOME` | `$HOME/.local/share` |
22
+ | `XDG_CACHE_HOME` | `$HOME/.cache` |
23
+
24
+ When `HOME` is unset or empty and the variable a path needs is not an
25
+ absolute path, that path has no location, and projmux never falls back to a
26
+ path relative to the working directory. A read of saved settings or state
27
+ keeps the built-in default and touches no file. A write writes nothing and
28
+ exits non-zero with a one-line reason naming the variables, such as
29
+ `HOME or an absolute XDG_CONFIG_HOME is required`. A path display such as
30
+ `projmux hook list` shows that reason in place of the path.
31
+
7
32
  ## Operational diagnostics state
8
33
 
9
34
  Projmux keeps a private bounded operational journal at:
@@ -38,25 +63,30 @@ those folders exist:
38
63
 
39
64
  It does not assume a canonical repo root.
40
65
 
41
- Use Settings > Project Picker for the normal interactive flow:
66
+ Use `Settings > Global > Projects` for the normal interactive flow:
42
67
 
43
- - `Project Root` sets, changes, or clears the saved primary root.
44
- - `+ Add Workdir...` appends one directory to the saved workdirs list.
45
- - `Workdirs` reviews and removes saved workdirs.
68
+ - `Primary discovery root` sets, changes, or clears the saved primary root.
69
+ - `Additional discovery roots > Add path` appends one directory to the saved
70
+ workdirs list.
71
+ - `Additional discovery roots` reviews saved workdirs; each root's
72
+ `Remove discovery root` removes it.
46
73
 
47
- `Add Workdir > Type path manually...` skips the filesystem scan and is useful
74
+ `Add path > Type path manually...` skips the filesystem scan and is useful
48
75
  for large mounts, WSL paths, NFS paths, or temporary project roots.
49
76
 
50
77
  The saved workdir file is:
51
78
 
52
79
  ```text
53
- ~/.config/projmux/workdirs
80
+ $HOME/.config/projmux/workdirs
54
81
  ```
55
82
 
83
+ This file does not follow `XDG_CONFIG_HOME`; see
84
+ [Setting Layers](#setting-layers).
85
+
56
86
  It stores one absolute path per line. Lines beginning with `#` are comments.
57
87
  The file is read only when no env root list is set.
58
88
 
59
- Workdirs are a **scan source and nothing else**. Adding a root, and scanning one,
89
+ Saved workdirs are a **scan source and nothing else**. Adding a root, and scanning one,
60
90
  never registers a Registry Project: a discovered child is an unregistered
61
91
  candidate until `projmux create project --root <path>` or opening it once from the
62
92
  Projects sidebar registers that exact path. See
@@ -67,7 +97,7 @@ Projects sidebar registers that exact path. See
67
97
  Pins are presentation preferences, stored typed:
68
98
 
69
99
  ```text
70
- ~/.config/projmux/pins
100
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/pins
71
101
  ```
72
102
 
73
103
  ```text
@@ -92,51 +122,11 @@ request with `projmux pin project migrate`; see
92
122
  [upgrading.md](upgrading.md#pins-are-typed-and-migrate-on-request) for the
93
123
  per-line outcomes and the ambiguity refusal.
94
124
 
95
- ## Legacy Project Layout Snapshots
96
-
97
- Older checkouts may already have named layout snapshots in the legacy storage
98
- directory:
99
-
100
- ```text
101
- <project>/.projmux/layouts/<name>.toml
102
- ```
103
-
104
- The project context comes from `PROJMUX_CWD` when set, otherwise projmux walks
105
- upward from the current directory to the nearest `.projmux` or `.git` marker.
106
- Files outside that project tree are not discovered. This storage is treated as
107
- legacy import data for explicit conversion and preview. Closed-Project startup
108
- does not expose legacy snapshot choices; current user-facing surfaces describe
109
- the restore unit as a snapshot, not as a separate layout or preset feature.
110
-
111
- The legacy schema is intentionally close to the session-state snapshot shape:
125
+ ## Legacy Project Layout Files
112
126
 
113
- ```toml
114
- schema_version = 1
115
- description = "Daily dev"
116
- mode = "inherit-autosave" # default; or "fresh-each-time"
117
- default_cwd = "${PROJMUX_CWD}"
118
-
119
- [[windows]]
120
- index = 0
121
- name = "main"
122
- layout = "..."
123
- active_pane_index = 0
124
-
125
- [[windows.panes]]
126
- index = 0
127
- cwd = "${PROJMUX_CWD}"
128
- command = "make watch"
129
- ```
130
-
131
- `command` records a startup recipe, matching the supported session-state replay
132
- recipe. Panes without `command` may use `recipe = "shell"`. Supported
133
- interpolation placeholders are limited to `${PROJMUX_CWD}` and
134
- `${PROJMUX_SESSION}`; other `${...}` values are rejected during load.
135
-
136
- Unknown fields and unknown sections are ignored so future schema additions do
137
- not break older files. The built-in parser only accepts quoted strings and
138
- integer values for the known fields above; it does not implement the full TOML
139
- language.
127
+ Older checkouts may still have named layout files under
128
+ `<project>/.projmux/layouts/*.toml`. projmux no longer reads, writes, trusts,
129
+ or deletes them; they have no effect and can be removed by hand.
140
130
 
141
131
  ## Keymap File
142
132
 
@@ -155,8 +145,9 @@ terminal-layer remediation, first try the key in `projmux shell`, then run
155
145
  `projmux setup` from the raw terminal, then use `projmux setup terminal` for
156
146
  supported terminal adapters.
157
147
 
158
- `~/.config/projmux/keymap.toml` can also be edited by hand. When the file is
159
- absent, generated tmux config stays on the built-in defaults.
148
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/keymap.toml` can also be edited by
149
+ hand. When the file is absent, generated tmux config stays on the built-in
150
+ defaults.
160
151
 
161
152
  Supported schema:
162
153
 
@@ -234,7 +225,7 @@ popup action with no built-in shortcut. Every configured alias renders the
234
225
  canonical client-scoped body
235
226
  `projmux internal tmux popup-toggle --client #{client_tty} resource-inspector`; pressing
236
227
  the same alias again closes only that client's popup. It remains available on
237
- Linux/tmux even when the Labs live-resource status segment is off.
228
+ Linux/tmux even when the `Status Bar > Resources` live-resource segment is off.
238
229
 
239
230
  The Settings writer is deterministic and rewrites the supported saved subset
240
231
  only. If the existing file has parse errors or unknown action IDs, Settings
@@ -261,13 +252,14 @@ Theme is a global user preference. The effective theme resolves from the global
261
252
  user theme plus a built-in fallback only:
262
253
 
263
254
  ```text
264
- ~/.config/projmux/config.toml
255
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/config.toml
265
256
  built-in fallback preset
266
257
  ```
267
258
 
268
- Settings edits the global `[theme]` in `~/.config/projmux/config.toml`. The
269
- Effective theme view shows the final global > built-in fallback value for each
270
- field with source labels: `global` or `fallback`. Saving or resetting a theme
259
+ Settings edits the global `[theme]` in
260
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/config.toml`. The Effective theme
261
+ view shows the final global > built-in fallback value for each field with
262
+ source labels: `global` or `fallback`. Saving or resetting a theme
271
263
  value live-applies it: projmux regenerates the generated tmux config and, when
272
264
  Settings runs inside tmux, `tmux source-file`-reloads it so a running server
273
265
  repaints immediately. Outside tmux the save still succeeds and the report
@@ -402,7 +394,7 @@ Preferred interactive path:
402
394
  Global config path:
403
395
 
404
396
  ```text
405
- ~/.config/projmux/config.toml
397
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/config.toml
406
398
  ```
407
399
 
408
400
  Schema:
@@ -465,30 +457,11 @@ in-flight process decision, then retries proxy initialization with a bounded
465
457
  backoff. Projmux never automatically stops, kills, restarts, adopts, or enables
466
458
  remote control on the shared app server.
467
459
 
468
- The default `Codex` row in the provider picker launches immediately through the
460
+ The `Codex` row in the provider picker launches immediately through the
469
461
  canonical create route. It does not start or probe the app-server, call
470
462
  `model/list`, or add `--model` or `model_reasoning_effort`; the Codex process
471
- therefore keeps its own configured defaults.
472
-
473
- The separate `Codex advanced launch` action uses the readiness path to read
474
- every page of the current app-server `model/list`. Its second picker shows only
475
- visible models and their advertised reasoning efforts. The display also carries
476
- the advertised default, supported input modalities, and whether personality is
477
- supported; the boolean personality capability is not expanded into invented
478
- personality choices. The selected model and effort are launch-only CLI
479
- overrides (`--model` and `--config model_reasoning_effort=...`); Projmux never
480
- writes a Codex configuration file. Each normalized catalog is tied to its live
481
- connection and negotiated-version epoch. Projmux retains that connection from
482
- picker render through pre-create validation and refreshes `model/list` before
483
- building argv, so a disconnect or removed option invalidates the selection. If
484
- advanced discovery fails, is empty, or comes from an older Codex, that action
485
- reports the exact unavailable reason and creates nothing; the separate default
486
- `Codex` row remains available.
487
-
488
- Picker chrome and semantic annotations such as default, unspecified modality,
489
- and personality support use the Projmux message catalog. Model display names,
490
- effort identifiers, and advertised modality tags remain exact provider data and
491
- are not translated.
463
+ therefore keeps its own configured defaults. The picker has no per-launch model
464
+ or effort row.
492
465
 
493
466
  `projmux agent review` starts `review/start` only for a Running Codex Agent whose
494
467
  Registry Agent, owned Pane, activation generation, stored thread, and live Pane
@@ -499,21 +472,33 @@ or a method-not-found response are reported explicitly as unavailable. The
499
472
  initial `review/start` response is projected into Agent interaction lifecycle;
500
473
  the lifecycle observer described below owns later app-server terminal events.
501
474
 
502
- A natively created or resumed Codex Agent keeps a content-free lifecycle
475
+ A natively created or resumed Codex Agent keeps a lifecycle
503
476
  observer on its exact Agent UID, Pane UID/runtime handle, activation generation,
504
477
  and thread ID. While its initialized proxy connection and snapshot are current,
505
478
  the app server is the only attention authority: active, idle, waiting for input,
506
479
  and exact unresolved approval requests project the Agent interaction and badge.
507
- Only an exact successful `turn/completed` projects response-complete and queues a
508
- completion notification; failed and interrupted turns become idle. Disconnect
480
+ The native observer refreshes a continuing turn or wait before the 30-minute
481
+ interaction freshness window expires. A `requestUserInput` request projects
482
+ `input_required` even before a separate thread-status update arrives; its
483
+ resolution or the turn's completion releases that state. When the question
484
+ channel is on, blocking Codex questions can be listed and answered through
485
+ `agent question list` and `agent question answer`.
486
+ An exact successful `turn/completed` projects response-complete and queues a
487
+ completion notification with the last agent message (or `Ready` if none is
488
+ available). A failed turn or `systemError` queues a critical `error` notification
489
+ and sends an OS notification when desktop delivery is enabled. HTTP 401 is
490
+ identified without copying the provider error text or credentials. Interrupted
491
+ turns become idle. Disconnect
509
492
  and thread unload first invalidate the epoch and clear stale attention, then
510
493
  enable hook fallback. A reconnect starts a new epoch from `thread/read`; events
511
494
  from older epochs or other identities are ignored.
512
495
 
513
496
  `describe agent` and the Codex Agent event Settings page report the effective
514
497
  lifecycle source, a closed reason, and active/pending/inactive epoch status.
515
- These diagnostics never retain prompts, reasoning, output, approval reasons, or
516
- diff content. Settings aggregates multiple live Codex Panes as counts and says
498
+ The observer holds the latest agent message only until completion delivery;
499
+ the notify queue applies its 80-rune text limit. These diagnostics never retain
500
+ prompts, reasoning, output, approval reasons, or diff content. Settings
501
+ aggregates multiple live Codex Panes as counts and says
517
502
  `mixed` when native and fallback authority coexist.
518
503
 
519
504
  Projmux does not install, bootstrap, restart, stop, or reconfigure the Codex
@@ -536,8 +521,8 @@ one writes only the global `[ai] split_cwd_from`.
536
521
  Config paths (global and project both honored):
537
522
 
538
523
  ```text
539
- ~/.config/projmux/config.toml # global
540
- <project>/.projmux/config.toml # project
524
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/config.toml # global
525
+ <project>/.projmux/config.toml # project
541
526
  ```
542
527
 
543
528
  Schema:
@@ -582,6 +567,40 @@ with `--cwd-from pane`, and as one client message for a split started from the
582
567
  UI. A split is never refused for this reason. `--cwd` on `create agent` still
583
568
  names the Agent working directory outright and ignores this setting.
584
569
 
570
+ ## Enabled AI Providers
571
+
572
+ Disabled providers are a central policy, stored in
573
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/ai-enabled-agents`, that the CLI
574
+ honors as well as the UI: `create agent`, `create window --provider`, and
575
+ `agent resume` refuse a disabled provider, and the refusal names the command
576
+ that re-enables it.
577
+ `projmux config providers` lists every provider as `<id> enabled` or
578
+ `<id> disabled`; `projmux config providers --enable <id>` and
579
+ `--disable <id>` change one through the same writer as
580
+ `Settings > Global > AI > Enabled providers`. A missing file means every
581
+ provider is enabled; disabling every provider persists as none enabled.
582
+
583
+ ## New AI Window Default
584
+
585
+ The mode a new AI window opens with has a central default, one word stored
586
+ at:
587
+
588
+ ```text
589
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/ai-new-window-mode
590
+ ```
591
+
592
+ The word is one of `claude`, `codex`, `antigravity`, `selective`, `resume`,
593
+ or `shell`. In the terminal the mode resolves in this order: the TUI split
594
+ default `tmux-ai-split-mode` when it holds one of those words, then this
595
+ central file, then `selective`. A missing, empty, or invalid TUI value falls
596
+ through to the central file; a missing, empty, or invalid central file means
597
+ not set.
598
+
599
+ `projmux settings` and `projmux config edit --set` keep writing
600
+ `tmux-ai-split-mode`. `projmux config edit --set` rejects any other word with
601
+ exit 2 and leaves the file unchanged. No command writes the central file yet;
602
+ edit it by hand or from another front end.
603
+
585
604
  ## AI Resume Picker
586
605
 
587
606
  The Agent resume picker lists the most recent
@@ -591,13 +610,13 @@ the defaults are 30 rows and depth 0 (the current directory only).
591
610
 
592
611
  Preferred interactive path:
593
612
 
594
- - `Settings > AI Settings > Resume picker`
613
+ - `Settings > Global > AI > Agent Resume Picker` (`Picker limit`, `Scan depth`)
595
614
 
596
615
  Config paths (global and project both honored):
597
616
 
598
617
  ```text
599
- ~/.config/projmux/config.toml # global
600
- <project>/.projmux/config.toml # project
618
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/config.toml # global
619
+ <project>/.projmux/config.toml # project
601
620
  ```
602
621
 
603
622
  Schema:
@@ -649,17 +668,8 @@ existence/mtime. They do not open SQLite content and do not treat `.db-wal`,
649
668
  latest-session floor rather than complete history. Missing/malformed cache,
650
669
  workspace-less metadata, and stale mappings degrade to legacy `history.jsonl`
651
670
  without changing the shared exact/depth/sort/cap behavior.
652
- Live hook/session-state resume metadata is a separate high-confidence lane and
653
- is not a disk-picker candidate. When a disk picker selection creates a pane,
654
- its source is persisted so Session State preview and doctor can report medium
655
- confidence for DB-validated cache sources or low confidence for legacy history.
656
-
657
- Session State saves the exact bound Codex session/thread id before considering
658
- discovery. An existing bound session id or persisted resume id is replayed
659
- without an app-server read. Only a thread-only candidate is validated with
660
- `thread/read` and `includeTurns=false`; this validation is probe-only and never
661
- starts the shared daemon. Failure retains the persisted id or uses the current
662
- rollout fallback, and a read response can never substitute a different id.
671
+ Live hook resume metadata is a separate high-confidence lane and is not a
672
+ disk-picker candidate.
663
673
 
664
674
  ## Release channel
665
675
 
@@ -669,7 +679,7 @@ to the install path: every installer can be judged on either channel.
669
679
  Files:
670
680
 
671
681
  ```text
672
- ~/.config/projmux/config.toml # global/user
682
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/config.toml # global/user
673
683
  ```
674
684
 
675
685
  Schema:
@@ -703,7 +713,7 @@ installed; that install stays put until its stable line ships.
703
713
 
704
714
  | Variable | Purpose |
705
715
  | --- | --- |
706
- | `PROJMUX_PROJDIR` | Explicit primary project root. Accepts an OS-native PATH-style multi-value: the first non-empty entry is the primary root and later entries are prepended to managed-root discovery. The primary value is memoized to `~/.config/projmux/projdir`. |
716
+ | `PROJMUX_PROJDIR` | Explicit primary project root. Accepts an OS-native PATH-style multi-value: the first non-empty entry is the primary root and later entries are prepended to managed-root discovery. The primary value is memoized to `$HOME/.config/projmux/projdir` (see [Setting Layers](#setting-layers)). The legacy `PROJDIR` and `RP` env vars are no longer honored. |
707
717
  | `PROJMUX_MANAGED_ROOTS` | Search-root override. Uses the OS-native path-list separator and takes priority over the saved workdirs file and default weak probes. |
708
718
  | `TMUX_SESSIONIZER_ROOTS` | Legacy alias still honored at runtime for managed roots. |
709
719
  | `PROJMUX_LOCALE` | UI locale override. `auto` resumes detection; `en-US` and `ko-KR` pin supported locales. Unsupported tags fall back to `en-US` and surface a Settings warning. |
@@ -715,12 +725,12 @@ installed; that install stays put until its stable line ships.
715
725
  | `PROJMUX_DESKTOP_NOTIFY_MODE` | OS desktop notification mode override. `off` / `none` / `notify` (case insensitive). When set, this takes priority over every other resolution rung. The in-app notify queue is not affected. The retired `raise` / `auto-raise` / `autoraise` literals are still accepted and read as `notify`. |
716
726
  | `PROJMUX_DESKTOP_NOTIFY` | Legacy on/off override kept for backward compatibility. `on` maps to `notify`, `off` maps to `none`. Honored only when `PROJMUX_DESKTOP_NOTIFY_MODE` is unset. |
717
727
  | `PROJMUX_WSL_TOAST_ICON_DIR` | Directory used when copying the WSL toast icon into a Windows-readable path. |
718
- | `PROJMUX_USAGE_STATE_DIR` | Override directory for AI usage snapshots. Defaults to `<state>/projmux/usage`. Point this at a synced directory to share authoritative usage across machines. |
728
+ | `PROJMUX_USAGE_STATE_DIR` | Override directory for AI usage snapshots. Defaults to `<state>/projmux/usage`. Point this at a synced directory to share authoritative usage across machines. The value is used as given, with no `~` expansion. |
719
729
  | `PROJMUX_USAGE_DEBUG` | When non-empty, prints adapter errors from the `projmux internal status usage` renderer to stderr. |
720
730
  | `PROJMUX_USAGE_LIMITS_PATH` | Deprecated. Read but ignored; limits now come from upstream APIs and local Codex rollout state. |
721
- | `PROJMUX_SESSIONSTATE_AUTOSAVE` | Session snapshot autosave override for the global fallback. Values such as `off`, `false`, or `0` disable autosave for projects that inherit the global setting; explicit project auto-save `on`/`off` still takes precedence. |
722
- | `PROJMUX_SESSIONSTATE_DEBUG` | When non-empty, quiet autosave surfaces suppressed session-state errors to stderr. |
723
- | `PROJMUX_FOCUS_DEBUG` | When non-empty, `projmux focus` prints one telemetry line to stderr. |
731
+ | `PROJMUX_SESSIONSTATE_AUTOSAVE` | Ignored. Project snapshots and their auto-save were removed. |
732
+ | `PROJMUX_SESSIONSTATE_DEBUG` | Ignored. It only gated stderr for the removed quiet autosave. |
733
+ | `PROJMUX_FOCUS_DEBUG` | When non-empty, `projmux focus` prints one telemetry line to stderr with the target, session, window, pane, socket, client, source, and kind. |
724
734
  | `PROJMUX_INSTALLER` | Installer source hint used by update flows. npm installs set this automatically; advanced release installs can set `github-release`. |
725
735
  | `PROJMUX_RELEASE_CHANNEL` | Release channel the update judgment is made against, orthogonal to `PROJMUX_INSTALLER`. Only an exact `rc` opts in; unset, empty, and unrecognised values all mean the default `stable` channel, which never sees a prerelease. An rc install is answered with whichever of the stable and rc lines is newer, so it returns to stable as soon as that line ships. Read only until `[update] release_channel` exists; see [Release channel](#release-channel). |
726
736
  | `PROJMUX_SHELL_UPDATE_CHECK_TIMEOUT_MS` | Timeout in milliseconds for the best-effort release check attempted by `projmux shell` when the update cache is missing or stale. Invalid, zero, or negative values use the default. |
@@ -771,7 +781,7 @@ export PROJMUX_PROJDIR="/main/repos:/srv/work/repos"
771
781
  On Linux and macOS the separator is `:`. On Windows-style paths the separator
772
782
  is `;`.
773
783
 
774
- ## tmux Project Root Option
784
+ ## tmux Primary Discovery Root Option
775
785
 
776
786
  The switch command also reads this tmux option:
777
787
 
@@ -782,6 +792,134 @@ set-option -g @projmux_projdir /path/to/repos
782
792
  An env `PROJMUX_PROJDIR` value takes priority over the tmux option. The tmux
783
793
  option takes priority over the saved projdir file.
784
794
 
795
+ The saved projdir file is `$HOME/.config/projmux/projdir`. It does not follow
796
+ `XDG_CONFIG_HOME`; see [Setting Layers](#setting-layers).
797
+
798
+ ## Agent Question Answering
799
+
800
+ How a Claude Agent's `AskUserQuestion` or a Codex Agent's blocking
801
+ `requestUserInput` is answered is one word stored at:
802
+
803
+ ```text
804
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/agent-question-answering
805
+ ```
806
+
807
+ | Value | Way | Meaning |
808
+ | --- | --- | --- |
809
+ | `claude` (default) | 1 | The provider shows its own question prompt; projmux stays out of it |
810
+ | `projmux` | 2 | projmux records the question for `projmux agent question list` and `answer`; Claude and native Codex also open the question picker in a tmux popup |
811
+
812
+ Set it with `projmux config agent-questions --answering <claude|projmux>`,
813
+ or write the file. The setting applies to every Claude and native Codex Agent on this machine. The value
814
+ is read case-insensitively with surrounding whitespace ignored. A
815
+ missing, empty, or unreadable file, and any other value, is way 1. An Agent
816
+ opted in with `projmux agent question enable` is way 2 whatever the file
817
+ says. Codex handles only blocking app-server requests; a Codex Agent on the
818
+ plain CLI lane has no app-server question channel. A Codex question set with an
819
+ `isSecret` question stays in Codex's own input surface: projmux does not open
820
+ an unmasked popup. `agent question list` points the operator to that window,
821
+ and `agent question answer` refuses that set so secret text is not passed in
822
+ command arguments. Other blocking Codex questions use the same popup and CLI
823
+ answer paths as Claude. For Claude, the setting
824
+ applies only to a projmux Agent's own conversation; other Claude sessions and
825
+ subagents always get way 1. See
826
+ [hooks.md](hooks.md#answering-askuserquestion-in-projmux).
827
+
828
+ ## Agent Question Window
829
+
830
+ In way 2 the Claude question hook or Codex native observer holds the question
831
+ for a command-line answer for a seconds window stored at:
832
+
833
+ ```text
834
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/agent-question-window-seconds
835
+ ```
836
+
837
+ Set it with `projmux config agent-questions --window <seconds|unlimited>`, or
838
+ write the file. The value is integer seconds, default `900`, in `60`–`86400`, or the
839
+ word `unlimited` (case-insensitive), which holds the question until it is
840
+ answered. Claude Code has no "no timeout" hook value, so `unlimited` is
841
+ effectively capped at `604785` seconds (about 7 days): the installed hook
842
+ timeout ceiling less the 15 second margin that lets the hook, not Claude Code,
843
+ end the wait. A value outside the range, or a file that holds neither one
844
+ integer nor `unlimited`, reads as `900`; a projmux older than the word also
845
+ reads `unlimited` as `900`, and a projmux from before the maximum was raised
846
+ from `3600` reads a value above `3600` as `900`, so downgrading only shortens
847
+ the wait. It applies only in way 2 (see
848
+ [Agent Question Answering](#agent-question-answering)); way 1 never waits.
849
+ For Codex, an expired or disabled held request is closed in the question list.
850
+ The same question remains visible and answerable in Codex's own input surface;
851
+ projmux does not send a substitute answer. The Codex turn continues when the
852
+ operator answers there.
853
+ If Codex's input surface answers first, the question list records
854
+ `answered-elsewhere`, and a later `agent question answer` is refused with that
855
+ reason. A resolution after the command-line deadline remains `expired`.
856
+
857
+ The installed Claude Code hook `timeout` is the fixed ceiling `604800` seconds
858
+ (7 days) and does not depend on this file. The ceiling is the safety net for a
859
+ stuck hook, and this hook has no recover: 7 days is 7 times the longest
860
+ bounded window (86400 seconds), so it never cuts a normal window, while a
861
+ broken hook is reclaimed within a week. The hook rereads the window for every
862
+ question, so a changed window applies to the next question without re-running
863
+ `projmux agent integrate claude`.
864
+
865
+ Hooks installed by an older projmux carry an old timeout: the window read at
866
+ integration plus 15 seconds (`915` by default), or the earlier, longer
867
+ ceiling of about 25 days. After installing this version, run
868
+ `projmux agent integrate claude` once to rewrite either entry to the
869
+ ceiling; until then Claude Code still ends the hook at the old timeout and a
870
+ longer window gives the question back to the ordinary prompt then.
871
+ See [hooks.md](hooks.md#answering-askuserquestion-in-projmux).
872
+
873
+ ## Agent Approval Answering
874
+
875
+ How an Agent's permission request ("Do you want to proceed?") is answered is
876
+ one word stored at:
877
+
878
+ ```text
879
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/agent-approval-answering
880
+ ```
881
+
882
+ It is a separate setting from [Agent Question Answering](#agent-question-answering).
883
+ Its effect is to capture Claude permission requests and to allow remote
884
+ (non-interactive) answers with `projmux agent approval answer` for both Claude
885
+ and Codex Agents. Codex approvals are never captured, since the Codex
886
+ app-server holds them: `projmux agent approval list` shows them and
887
+ `projmux agent approval review` answers them in either way.
888
+
889
+ | Value | Meaning |
890
+ | --- | --- |
891
+ | `claude` (default) | Claude Code shows its own permission prompt; the permission hook prints nothing and records nothing; `projmux agent approval answer` is refused for Claude and Codex Agents |
892
+ | `projmux` | projmux also records a Claude request, and `projmux agent approval answer` can allow or deny it once; it can also allow once (`accept`) or deny a pending Codex approval (`decline` when offered, otherwise `cancel`, which also interrupts the turn). The provider's own prompt stays usable, and the first answer wins |
893
+
894
+ Set it with `projmux config agent-approvals --answering <claude|projmux>`, or
895
+ write the file. The value is read case-insensitively with surrounding
896
+ whitespace ignored; a missing, empty, or unreadable file, and any other value,
897
+ is `claude`. It applies to every Claude Agent on this machine, but only to
898
+ requests from a projmux Claude Agent's own conversation, including its
899
+ subagents; other Claude sessions, and a session in `bypassPermissions` or
900
+ `dontAsk` mode, never have a request captured. See
901
+ [hooks.md](hooks.md#answering-claude-permission-requests-in-projmux).
902
+
903
+ ## Agent Approval Window
904
+
905
+ While the setting is `projmux`, the permission hook holds each request open
906
+ for an answer for a seconds window stored at:
907
+
908
+ ```text
909
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/agent-approval-window-seconds
910
+ ```
911
+
912
+ Set it with `projmux config agent-approvals --window <seconds>`, or write the
913
+ file. The value is integer seconds in `60`–`3600`, default `900`. There is no
914
+ `unlimited` value: a value outside the range, `unlimited`, and a file that does
915
+ not hold one integer read as `900`. A request nobody answers in the window
916
+ expires with no decision, and Claude Code's own prompt decides it.
917
+
918
+ The installed hook `timeout` is the fixed ceiling `3615` seconds (the longest
919
+ window plus a 15 second margin) and does not depend on this file. The hook
920
+ rereads the window for every request, so a changed window applies to the next
921
+ request without re-running `projmux agent integrate claude`.
922
+
785
923
  ## Notifications
786
924
 
787
925
  When `PROJMUX_NOTIFY_HOOK` is unset, projmux uses:
@@ -833,7 +971,8 @@ seconds window. Resolution priority is:
833
971
  `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/ai-notify-dedupe-seconds`
834
972
  3. default `120`
835
973
 
836
- Settings exposes this at `Settings > Notifications > AI notification dedupe`.
974
+ Settings exposes this at
975
+ `Settings > Global > Notifications > Desktop delivery > Dedupe window`.
837
976
  The value is stored as integer seconds and applies only to AI desktop
838
977
  notification dispatch. The tmux bell fallback keeps its fixed 5 second
839
978
  dedupe window.
@@ -865,6 +1004,11 @@ precedence only during hook fallback; catalog defaults do not override this
865
1004
  semantic store. Saving this file does not infer from, rewrite, or normalize the
866
1005
  raw hook override file.
867
1006
 
1007
+ Codex native failures are always delivered as critical `error` notifications,
1008
+ independent of those two completion/approval policy choices. A hook fallback
1009
+ `Stop` uses Codex's `last-assistant-message` payload when present; without it,
1010
+ the completion text is `Ready`.
1011
+
868
1012
  Delivery depends on the event handler. Specialized notify handlers, such as
869
1013
  Codex `PermissionRequest` and `Stop`, can write the in-app notify queue and use
870
1014
  the configured OS desktop notification path. Known Codex events without a
@@ -918,7 +1062,7 @@ Settings press through the new row writes `desktop-notify-mode`, mirrors the
918
1062
  new value into `@projmux_desktop_notify_mode` when tmux is live, and leaves the
919
1063
  legacy key unused. No eager rewrite of tmux state.
920
1064
 
921
- Toggle from Settings > Notifications > `Desktop notifications`. The
1065
+ Choose it from `Settings > Global > Notifications > Desktop delivery > Delivery mode`. The
922
1066
  Settings info row labels the effective source as `env`, `env (legacy)`,
923
1067
  `setting`, `setting (legacy)`, or `default` so users see which rung of
924
1068
  the cascade pinned the value. `projmux config apply` regenerates the live tmux
@@ -964,28 +1108,35 @@ ${PROJMUX_USAGE_STATE_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}/projmux/usage}/
964
1108
  See [Usage tracking](usage-tracking.md) for adapter behavior, throttling, and
965
1109
  failure handling.
966
1110
 
967
- ## Session State
968
-
969
- `projmux shell` autosaves session snapshots from the app tmux status tick. The
970
- autosave command is quiet and debounced per session, and stores snapshots under
971
- `${XDG_STATE_HOME:-$HOME/.local/state}/projmux/sessions`.
972
-
973
- Global auto-save defaults to `off` on a fresh install. Project auto-save is an
974
- override with `inherit`, `on`, and `off`; `inherit` follows the global value,
975
- while `on` and `off` take precedence. Auto-save only updates the latest
976
- snapshot. Named snapshots are manual and are never updated by auto-save.
977
-
978
- With no saved preference, Project open from the Alt-1 sidebar shows a native
979
- `Start project` step with exactly `Continue project` and `Recreate Project`.
980
- Settings > Projects > Project Sidebar > Closed Project startup reports this as
981
- `Continue project / Recreate Project - default`. A saved `on` keeps the same explicit
982
- choice and reports `Continue project / Recreate Project - on - saved`. A saved `off`
983
- reports `Continue project - off - saved` and skips the picker: a registered root
984
- continues, while an unregistered root follows the existing Fresh adjudication.
985
- Resolving or cancelling the missing-file default never creates the preference
986
- file or changes saved bytes or mtime. `Recreate Project` confirms first, then atomically replaces the old Project graph
1111
+ ## Project Startup
1112
+
1113
+ The Registry (`registry.json`) is the only saved Project state; see
1114
+ [session-restore.md](session-restore.md). projmux keeps no separate Project
1115
+ snapshot store. Nothing reads the former
1116
+ `${XDG_STATE_HOME:-$HOME/.local/state}/projmux/sessions/*.json` snapshot
1117
+ files; they are removed by `config apply`. The app tmux status tick saves
1118
+ nothing: generated status lines carry no auto-save job, and the hidden
1119
+ `internal tmux autosave-session-state` route that older generated configs
1120
+ still call is a silent no-op that writes nothing and records no diagnostics.
1121
+ The `sessionstate-autosave` and `sessionstate-autosave-interval` files and the
1122
+ per-Project `sessionstate-projects/<session>/autosave` files are removed by
1123
+ `config apply`, together with the `sessions/` and `sessionstate-projects/`
1124
+ directories once they are empty. Any other entry there is kept, and listed
1125
+ by the apply that removes the files.
1126
+ `PROJMUX_SESSIONSTATE_AUTOSAVE` is still ignored without a warning.
1127
+
1128
+ Opening a registered closed Project from the Alt-1 sidebar shows a native
1129
+ `Start project` step with exactly `Continue project` and
1130
+ `Clear layout and open`. A root that is not a registered Project skips that
1131
+ step and opens fresh, which registers it. There is no setting that skips the
1132
+ step for a registered Project.
1133
+ An explicit `Continue project` on a root that is not a registered Project
1134
+ refuses with zero writes and points to `Clear layout and open`.
1135
+ `Clear layout and open` clears only the saved Window and Agent layout: the
1136
+ folder, its files, `.projmux/config.toml`, and trust stay. It confirms first,
1137
+ then atomically replaces the old Project graph
987
1138
  with a new Project UID and a new canonical Window/shell UID pair. Exactly one
988
- same-root Project claimant remains. Snapshot bytes, the root directory,
1139
+ same-root Project claimant remains. The root directory,
989
1140
  Git/worktree data, and the trust decision remain unchanged. Esc returns to
990
1141
  Projects with zero writes. After
991
1142
  the startup mode is selected, project automation trust is evaluated if needed.
@@ -997,62 +1148,17 @@ Deny/cancel refreshes the original sidebar query/selection context with a
997
1148
  visible status message. Existing sessions switch directly without a startup
998
1149
  picker.
999
1150
 
1000
- Default `projmux shell` no longer opens a startup picker or replays session-state
1001
- snapshots before attach. It still derives the default app session identity and
1002
- startup directory from the current project context when available; otherwise it
1003
- uses the `home` target and home directory. Snapshot restore is an explicit CLI
1004
- operation that requires both the source session and the exact target Project;
1005
- it is not a Project-startup choice.
1006
-
1007
- Settings > Session State is global settings only: global auto-save, auto-save
1008
- interval, and storage/retention policy. Settings > Project > Session State
1009
- is override/effective-focused: project identity, project auto-save
1010
- `inherit`/`on`/`off`, effective auto-save value/source, and snapshot save
1011
- actions. Snapshot inspection lives under `Projects > Sessions > State`, whose
1012
- overview shows latest/named snapshot status and the window -> pane read model
1013
- without immediate mutation.
1014
-
1015
- The saved global toggles live under
1016
- `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/sessionstate-autosave`,
1017
- `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/sessionstate-autosave-interval`, and
1018
- `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/sidebar-startup-picker`. Project
1019
- auto-save overrides live under
1020
- `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/sessionstate-projects/<session>/autosave`.
1021
- The environment variables above override the global files.
1022
- `sidebar-startup-picker` accepts the existing `on` and `off` bytes; absence is a
1023
- read-only effective `on - default`, not a migration or an implicit write.
1024
-
1025
- Manual snapshot actions are available from the CLI:
1151
+ Default `projmux shell` does not open a startup picker before attach. It
1152
+ derives the default app session identity and startup directory from the
1153
+ current project context when available; otherwise it uses the `home` target
1154
+ and home directory.
1026
1155
 
1027
- ```sh
1028
- projmux get snapshots
1029
- projmux create snapshot
1030
- projmux delete snapshot [--session <name>]
1031
- projmux restore snapshot --session <snapshot-session> [--project <ref> | -p <ref>] --dry-run
1032
- projmux restore snapshot --session <snapshot-session> [--project <ref> | -p <ref>] --yes [--client <tmux-client>]
1033
- ```
1156
+ The retired closed-Project startup setting's file under
1157
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/` is not read, and `config apply`
1158
+ removes it; see [Upgrading](upgrading.md#closed-project-startup-setting-removed).
1034
1159
 
1035
- `status` prints the source label (`autosave`, `layout(<name>)`, or `fresh`), the
1036
- effective auto-save state, and a compact snapshot preview for the
1037
- target session. Older snapshots without a source field display as `autosave`.
1038
- `save` captures the current tmux session immediately and intentionally bypasses
1039
- the autosave debounce and disabled-autosave gate; it still requires a current
1040
- tmux session. `delete` removes the target snapshot without an interactive
1041
- confirmation. Restore treats the snapshot as desired-state input for one exact
1042
- closed Project, never as a global Registry replacement or tmux replay.
1043
- `--dry-run` prints scoped projection counts with zero writes. `--yes` commits
1044
- that target subtree atomically, runs the ordinary materializer, and performs an
1045
- explicit client handoff last when `--client` is present. Restore never modifies
1046
- or deletes the source snapshot.
1047
-
1048
- Interactive `projmux quit` also offers `Save Project snapshots and quit`. It
1049
- recaptures the latest snapshot for every live Registry-bound Project on the
1050
- exact app server, regardless of the global or Project auto-save toggle, and
1051
- stops the server only after all captures succeed. A partial failure keeps the
1052
- server running and keeps each successful atomic snapshot for inspection or
1053
- retry. Control/Home, ephemeral, unmanaged, conflicted, and sibling-server
1054
- sessions are never promoted into Project snapshots. `Quit without saving`,
1055
- `quit --yes`, and `quit --force` perform no snapshot inventory or store I/O.
1160
+ Interactive `projmux quit` offers only the quit row and `Cancel`. Neither it
1161
+ nor `quit --yes` / `quit --force` saves Project state.
1056
1162
 
1057
1163
  ## Decoration Mode
1058
1164
 
@@ -1066,13 +1172,13 @@ Settings > Appearance controls optional icon decoration per surface:
1066
1172
  The per-surface saved values live at:
1067
1173
 
1068
1174
  ```text
1069
- ~/.config/projmux/statusbar-decoration-cwd
1070
- ~/.config/projmux/statusbar-decoration-git
1071
- ~/.config/projmux/statusbar-decoration-notify
1175
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-decoration-cwd
1176
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-decoration-git
1177
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-decoration-notify
1072
1178
  ```
1073
1179
 
1074
- The legacy `~/.config/projmux/statusbar-decoration` value is still read as the
1075
- fallback default when a per-surface file is absent.
1180
+ The legacy `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-decoration`
1181
+ value is still read as the fallback default when a per-surface file is absent.
1076
1182
 
1077
1183
  ## Row 0 HUD Visibility
1078
1184
 
@@ -1081,29 +1187,28 @@ independent global presentation preferences:
1081
1187
 
1082
1188
  - `Notifications HUD > Visible`
1083
1189
  - `Agent Usage HUD > Visible`
1084
- - `Agent Usage HUD > Claude|Codex|Antigravity > Visible`
1085
- - each provider's supported HUD windows (`Claude`/`Codex`: `5h`, `Weekly`;
1086
- `Antigravity`: `Weekly`)
1190
+ - `Agent Usage HUD > Claude|Codex > Visible`
1191
+ - each provider's supported HUD windows (`5h`, `Weekly`)
1087
1192
 
1088
1193
  The saved values are `on` or `off` in these files:
1089
1194
 
1090
1195
  ```text
1091
- ~/.config/projmux/statusbar-visibility-notifications-hud
1092
- ~/.config/projmux/statusbar-visibility-agent-usage-hud
1093
- ~/.config/projmux/statusbar-visibility-agent-usage-provider-claude
1094
- ~/.config/projmux/statusbar-visibility-agent-usage-provider-codex
1095
- ~/.config/projmux/statusbar-visibility-agent-usage-provider-antigravity
1096
- ~/.config/projmux/statusbar-visibility-agent-usage-window-claude-5h
1097
- ~/.config/projmux/statusbar-visibility-agent-usage-window-claude-weekly
1098
- ~/.config/projmux/statusbar-visibility-agent-usage-window-codex-5h
1099
- ~/.config/projmux/statusbar-visibility-agent-usage-window-codex-weekly
1100
- ~/.config/projmux/statusbar-visibility-agent-usage-window-antigravity-weekly
1196
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-notifications-hud
1197
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-agent-usage-hud
1198
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-agent-usage-provider-claude
1199
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-agent-usage-provider-codex
1200
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-agent-usage-window-claude-5h
1201
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-agent-usage-window-claude-weekly
1202
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-agent-usage-window-codex-5h
1203
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-agent-usage-window-codex-weekly
1101
1204
  ```
1102
1205
 
1103
- Missing, empty, and invalid values resolve to `on` except the Codex `5h`
1104
- window, whose ambient HUD default is `off`; an explicit saved `on` restores it.
1105
- Settings shows whether the effective value came from `saved` or `default` and
1106
- marks an invalid saved value as ignored. Saving a toggle regenerates the app
1206
+ Missing, empty, and invalid values fall back to the
1207
+ [central status bar default](#central-status-bar-defaults) for that file, and
1208
+ without one resolve to `on` except the Codex `5h` window, whose ambient HUD
1209
+ default is `off`; an explicit saved `on` restores it. Settings shows whether
1210
+ the effective value came from `saved`, `central`, or `default` and marks an
1211
+ invalid saved value as ignored. Saving a toggle regenerates the app
1107
1212
  and standalone tmux output, and Settings source-reloads the generated app config
1108
1213
  when it is running inside tmux.
1109
1214
 
@@ -1111,8 +1216,9 @@ Parent visibility gates only the effective projection. Turning the overall HUD
1111
1216
  or a provider off does not rewrite its provider/window leaf files; turning the
1112
1217
  parent back on restores the saved child selection. Provider rows follow the
1113
1218
  usage-supported provider catalog. Window rows come only from the explicit HUD
1114
- capability map, so opaque quota buckets never create settings and Antigravity
1115
- never gains a fabricated `5h` row.
1219
+ capability map, so opaque quota buckets never create settings. Antigravity has
1220
+ no usage source; `statusbar-visibility-agent-usage-*-antigravity*` files left by
1221
+ older releases are ignored and never deleted.
1116
1222
 
1117
1223
  Visibility does not enable or disable either producer. Hiding Notifications HUD
1118
1224
  does not change the persistent queue, desktop delivery, or Notification
@@ -1135,15 +1241,18 @@ components independently:
1135
1241
  Their global saved values are `on` or `off` in:
1136
1242
 
1137
1243
  ```text
1138
- ~/.config/projmux/statusbar-visibility-project
1139
- ~/.config/projmux/statusbar-visibility-working-directory
1140
- ~/.config/projmux/statusbar-visibility-git
1141
- ~/.config/projmux/statusbar-visibility-clock
1142
- ~/.config/projmux/statusbar-visibility-settings-launcher
1244
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-project
1245
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-working-directory
1246
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-git
1247
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-clock
1248
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-visibility-settings-launcher
1143
1249
  ```
1144
1250
 
1145
- Missing, empty, and invalid values resolve to `on`; Settings reports the
1146
- effective value and whether it came from `saved` or `default`. Each save is an
1251
+ Missing, empty, and invalid values fall back to the
1252
+ [central status bar default](#central-status-bar-defaults) for that file, and
1253
+ without one resolve to `on`; the settings launcher has no central default.
1254
+ Settings reports the effective value and whether it came from `saved`,
1255
+ `central`, or `default`. Each save is an
1147
1256
  atomic 0600 replacement, regenerates both app and standalone output, and
1148
1257
  source-loads the generated app config when Settings is inside tmux. Off removes
1149
1258
  the complete segment, including its mouse range and owned spacing. Working
@@ -1152,8 +1261,57 @@ text visible. Settings launcher `off` removes only its mouse chip; CLI and
1152
1261
  keybinding entry remain.
1153
1262
 
1154
1263
  Resources intentionally does not use one of these visibility files. Its
1155
- existing `~/.config/projmux/live-resources` value is the only enabled source
1156
- and controls both the segment and sampler/cache mutation.
1264
+ existing `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/live-resources` value is
1265
+ the only enabled source and controls both the segment and sampler/cache
1266
+ mutation.
1267
+
1268
+ ## Central Status Bar Defaults
1269
+
1270
+ The status bar visibility files above, except the settings launcher, have a
1271
+ central default layer under them in:
1272
+
1273
+ ```text
1274
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/statusbar-defaults.json
1275
+ ```
1276
+
1277
+ It holds `on` or `off` per visibility file, keyed by the file name without its
1278
+ `statusbar-visibility-` prefix (`clock`, `agent-usage-window-codex-5h`):
1279
+
1280
+ ```json
1281
+ {
1282
+ "visibility": {
1283
+ "clock": "off"
1284
+ }
1285
+ }
1286
+ ```
1287
+
1288
+ A visibility value resolves in this order: a valid value in the file above,
1289
+ then its central default, then the built-in default. Values other than `on` or
1290
+ `off` in the central file are ignored.
1291
+
1292
+ Nothing edits the central file yet. `projmux config apply` fills it once from
1293
+ the valid values of the visibility files, so it starts out matching what the
1294
+ status bar shows:
1295
+
1296
+ - Once. A record at
1297
+ `${XDG_STATE_HOME:-~/.local/state}/projmux/statusbar-defaults-seeded` marks
1298
+ the copy done, and later applies copy nothing, whatever the visibility files
1299
+ say by then. The two copies may drift apart after that.
1300
+ - Per key, never overwriting. A central value already stored stays.
1301
+ - Valid values only. A missing, empty, or invalid visibility file copies
1302
+ nothing, so that key keeps following the built-in default.
1303
+
1304
+ When it copies anything, the apply prints one
1305
+ `seeded central status bar defaults: copied N TUI value(s)` line. A failure is
1306
+ reported on the same line, never fails the apply, and writes no record, so the
1307
+ next apply tries again. Deleting both the central file and the record makes the
1308
+ next apply copy again.
1309
+
1310
+ `make install` and `projmux update apply` run `projmux config apply`, so an
1311
+ install through either copies right away. A plain `npm install -g projmux` runs
1312
+ no install script, so it copies on the next `projmux config apply`. Until then
1313
+ the central file is empty and the status bar is unchanged, because the
1314
+ visibility files still decide.
1157
1315
 
1158
1316
  ## Live System Resources
1159
1317
 
@@ -1161,7 +1319,7 @@ and controls both the segment and sampler/cache mutation.
1161
1319
  CPU/memory segment on the lower status row. The saved global value is:
1162
1320
 
1163
1321
  ```text
1164
- ~/.config/projmux/live-resources
1322
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/live-resources
1165
1323
  ```
1166
1324
 
1167
1325
  Accepted values are `off` (default) and `on`. A missing, empty, or invalid
@@ -1196,12 +1354,326 @@ The CPU delta cache is internal state at
1196
1354
  CPU reference samples older than 30 seconds are ignored and replaced on the
1197
1355
  next refresh.
1198
1356
 
1357
+ ## Agent Profiles
1358
+
1359
+ An Agent profile is a named set of Agent start settings stored at
1360
+ `<config dir>/profiles/<name>.toml` (by default
1361
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/profiles/`).
1362
+ Manage profiles with `projmux profile list|show|set|delete`, and start an
1363
+ Agent from one with `projmux create agent --profile <name>` or a `role` label
1364
+ (see [CLI guide](cli-guide.md#agent-profiles-at-create)).
1365
+
1366
+ A profile is one combination: the provider it is for, the stored instructions
1367
+ it starts with, its model and effort, the roles that select it, and its
1368
+ permissions. Every key is optional. Which items each provider applies, and
1369
+ which it discloses as not applied or refuses, is in the
1370
+ [CLI guide](cli-guide.md#agent-profiles-at-create).
1371
+
1372
+ A profile file is a strict subset of TOML:
1373
+
1374
+ - blank lines and `#` comments, on their own line or after a value;
1375
+ - top-level `key = value` lines with a bare key;
1376
+ - at most one `[permissions]` table; every key after it belongs to that table;
1377
+ - values that are double-quoted strings or arrays of them. The only escapes are
1378
+ `\"` and `\\`; tabs, other control characters, and line breaks inside a
1379
+ string are refused. An array may span lines, hold comments, and end with a
1380
+ trailing comma.
1381
+
1382
+ Everything else is refused: unknown keys or tables, a second `[permissions]`, a
1383
+ key given twice, quoted or dotted keys, literal or multi-line strings, numbers,
1384
+ booleans, and inline tables. The file limit is 64 KiB.
1385
+
1386
+ | Key | Value |
1387
+ | --- | --- |
1388
+ | `provider` | the Agent provider the profile is for: one of the ids `create agent --provider` accepts (`claude`, `codex`, `antigravity`), spelled exactly. Omitted, the profile is provider-neutral |
1389
+ | `instructions` | the name of stored instructions (`projmux instructions list`); the file must exist |
1390
+ | `model` | a Claude model alias or name, the same shape `create --model` accepts; `projmux agent models` lists suggestions, and names outside that list are accepted too |
1391
+ | `effort` | `low`, `medium`, `high`, `xhigh`, or `max` |
1392
+ | `roles` | array of role names; each non-empty, without surrounding whitespace, listed once, and not listed by another profile |
1393
+ | `[permissions]` `sandbox` | `read-only`, `workspace-write`, or `full-access` |
1394
+ | `[permissions]` `approval` | `never`, `on-request`, or `untrusted` |
1395
+ | `[permissions]` `allow`, `deny` | arrays of Claude permission rules: a tool name (`[A-Za-z][A-Za-z0-9_-]*`) optionally followed by one non-empty `(...)` specifier, such as `Edit`, `Bash(git status *)`, `Read(./docs/**)`, `WebFetch(domain:example.com)`, or `mcp__srv__tool` |
1396
+
1397
+ ```toml
1398
+ provider = "claude"
1399
+ instructions = "reviewer"
1400
+ model = "opus"
1401
+ effort = "high"
1402
+ roles = ["review"]
1403
+
1404
+ [permissions]
1405
+ sandbox = "workspace-write"
1406
+ approval = "on-request"
1407
+ allow = ["Bash(git status *)", "Read(./docs/**)"]
1408
+ deny = ["WebFetch(domain:example.com)"]
1409
+ ```
1410
+
1411
+ `provider` binds the profile to one provider. A create of any other provider
1412
+ -- `create agent --provider`, a `create <provider>` shortcut, a `role` label,
1413
+ or a create from the UI -- refuses with exit 2 (`profile-provider-mismatch`,
1414
+ naming both providers) before anything is written. A profile without
1415
+ `provider` applies to every provider, and parses, digests, and applies exactly
1416
+ as it did before the key existed. `create agent` may omit `--provider` when
1417
+ the profile it selects names one: the profile's `provider` is then the Agent's
1418
+ provider. A provider-neutral profile does not choose one, so `create agent`
1419
+ still needs `--provider` with it. `profile set` refuses an unknown value with
1420
+ exit 2 (`profile-provider-unknown`, listing the accepted providers) and writes
1421
+ nothing. `model` is checked only for its shape, whatever the provider, and
1422
+ `effort` takes the one vocabulary above.
1423
+
1424
+ `instructions` names the stored files `projmux instructions` manages: one
1425
+ store, `<config dir>/personas/<name>.md`, and one profile key. What the
1426
+ instructions do depends on the lane, exactly as for `create --instructions`:
1427
+ Claude appends them to the system prompt, and
1428
+ Codex takes them only on a prompted create that opens its own thread (see
1429
+ [CLI guide](cli-guide.md#agent-profiles-at-create)); a promptless Codex create
1430
+ with Profile instructions is refused before creating anything. Codex keeps
1431
+ the developer instructions recorded when the thread started; a relaunch and a
1432
+ resume cannot replace them (`codex-instructions-immutable`). A profile
1433
+ keeps the instructions it names: `instructions delete <name>` refuses with
1434
+ exit 2 (`profile-instructions-in-use`) while any stored profile that parses
1435
+ names them, valid or not, and names each such profile. Change the profile with
1436
+ `projmux profile set <name>` or remove it with `projmux profile delete <name>
1437
+ --yes` first. Instructions removed by hand still make the profile invalid
1438
+ (`profile-instructions-not-found`), and Agents that record it then refuse to
1439
+ resume (`profile-resume-unavailable`) rather than resume without its
1440
+ permissions.
1441
+
1442
+ Roles fail closed. Every profile that parses holds the roles it lists, valid
1443
+ or not: `profile set` refuses a role another profile lists
1444
+ (`profile-role-claimed`), `profile list` shows an invalid profile's roles, and
1445
+ a `role` label whose one listing profile is invalid refuses the create
1446
+ (`profile-role-profile-invalid`, naming the profile and its reason) instead of
1447
+ creating the Agent without a profile. A valid profile that shares a role with
1448
+ an invalid one is marked `profile-role-claimed`; the invalid one keeps its own
1449
+ reason. Pass `--profile none` to create without a profile.
1450
+
1451
+ Profile names follow the instructions name rule, and `none` is reserved.
1452
+ No profile is compiled into projmux: every profile is a file in
1453
+ `<config dir>/profiles/`, and a name without a file is `profile-not-found`.
1454
+ A profile that lets an Agent read and never write lists no roles and sets
1455
+ only its permissions:
1456
+
1457
+ ```toml
1458
+ # readonly.toml
1459
+ [permissions]
1460
+ sandbox = "read-only"
1461
+ approval = "never"
1462
+ deny = ["Edit", "Write", "NotebookEdit"]
1463
+ ```
1464
+
1465
+ Store it with `projmux profile set readonly --file readonly.toml`.
1466
+
1467
+ When a profile with `allow` or `deny` rules is applied to a Claude Agent, its
1468
+ rules are written as a Claude settings file,
1469
+ `{"permissions":{"allow":[...],"deny":[...]}}` (an empty list left out), to
1470
+ `${XDG_STATE_HOME:-~/.local/state}/projmux/profile-settings/sha256-<hex>.json`
1471
+ (directory 0700, file 0600, named by the sha256 of the bytes), and Claude is
1472
+ started with `--settings <that file>`. Each resume writes it again from the
1473
+ current profile.
1474
+
1475
+ When a profile with `sandbox` or `approval` is applied to a Codex Agent, the
1476
+ native lane sends them as the thread's `sandbox` and `approvalPolicy` on
1477
+ `thread/start` and every native `thread/resume`. The thread's answer must
1478
+ report the same policy, or create or resume is refused
1479
+ (`codex-thread-policy-mismatch`). Promptless and `--interactive-only` creates,
1480
+ and CLI resumes, pass the current profile policy as `codex -s <sandbox> -a
1481
+ <approval>` or `codex -s <sandbox> -a <approval> resume`. On both lanes,
1482
+ `full-access` becomes Codex's `danger-full-access`. Codex CLI accepts
1483
+ `approval = "on-request"` and `"never"`; a profile with `approval = "untrusted"`
1484
+ is refused on CLI lanes (`codex-cli-untrusted-approval-unsupported`) before
1485
+ creating a Pane or resuming the Agent. The native lane still accepts it.
1486
+ `allow` and `deny` are not given to Codex and appear as not applied in create
1487
+ receipts.
1488
+
1489
+ ## Project Link Rules
1490
+
1491
+ Project link rules turn a Project's labels into links, for example a
1492
+ `jira=ABC-123` label into `https://jira.example.com/browse/ABC-123`. Each
1493
+ Project has at most one rule file, `<config dir>/project-links/<project-uid>.json`
1494
+ (by default `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/project-links/`), named
1495
+ by the Project UID (`proj-...`) so renaming the Project or moving its root
1496
+ keeps its rules. The rules belong to the Project, and every surface shares
1497
+ them: a Claude Agent's system prompt shows them (see below), and a client that
1498
+ edits them, such as the web client, reads and writes this same file. There is
1499
+ no CLI command that edits them. A missing file means the Project has no rules.
1500
+
1501
+ ```json
1502
+ {
1503
+ "jira": ["https://jira.example.com", "https://jira.partner.example.com"],
1504
+ "repo": ["https://github.com/example/repo"],
1505
+ "urls": {"wiki": "https://wiki.example.com/spaces/APP"},
1506
+ "links": [
1507
+ {"labelKey": "jira", "template": "{jira}/browse/{value}"},
1508
+ {"labelKey": "partner", "template": "{jira[1]}/browse/{value}"},
1509
+ {"labelKey": "pr", "template": "{repo}/pull/{value}"},
1510
+ {"labelKey": "doc", "template": "{wiki}/{project.labels.team}/{value}"}
1511
+ ]
1512
+ }
1513
+ ```
1514
+
1515
+ `jira` and `repo` are lists of base URLs, and `urls` names more base URLs.
1516
+ projmux always writes all four fields.
1517
+
1518
+ | Placeholder | Becomes |
1519
+ | --- | --- |
1520
+ | `{value}` | The label value, path-escaped (`a/b c` becomes `a%2Fb%20c`). Required in every template. |
1521
+ | `{jira[N]}`, `{repo[N]}` | The `N`th URL of `jira` or `repo`, counting from 0. `N` is decimal with no leading zero (`{jira[01]}` is refused). |
1522
+ | `{jira}`, `{repo}` | The same as `{jira[0]}` and `{repo[0]}`. |
1523
+ | `{<name>}` | The URL `urls` names `<name>`, such as `{wiki}`. |
1524
+ | `{project.uid}` | The Project UID, path-escaped. |
1525
+ | `{project.name}` | The Project name, path-escaped. |
1526
+ | `{project.labels.<key>}` | The value of the Project's label `<key>`, path-escaped. |
1527
+
1528
+ A base URL is substituted with any trailing `/` trimmed. Every placeholder is
1529
+ substituted in one pass, so text a substitution inserts is never expanded
1530
+ again. A label value is one value: `a,b` makes one link (`a%2Cb`), not two.
1531
+
1532
+ The Project variables are the Project's UID, name and labels in the Registry,
1533
+ and nothing else: its root directory, its annotations and its Windows are not
1534
+ placeholders, and `{project.root}` is refused. A label whose rule uses a
1535
+ Project label the Project does not have, or has empty, gets no link.
1536
+
1537
+ A rule file must pass these checks, both when it is written and when it is
1538
+ read; a file that fails them, is not one JSON object of exactly these fields,
1539
+ or is larger than 64 KiB is an error, never treated as empty. An error names
1540
+ the field as a JSON path, such as `jira[3]`, `urls.wiki` or
1541
+ `links[2].template`.
1542
+
1543
+ - `jira` and `repo` hold at most 16 URLs each, and `urls` at most 32. Each
1544
+ URL is an absolute `http` or `https` URL with a host, at most 2048 bytes,
1545
+ with no credentials (`user@`), no query, no fragment and no `{` or `}`.
1546
+ - A `urls` name is a lowercase ASCII letter followed by at most 31 lowercase
1547
+ letters, digits, `_` or `-`. `value`, `jira`, `repo` and `project` are
1548
+ reserved and refused.
1549
+ - `links` holds at most 64 rules.
1550
+ - `labelKey` is 1 to 64 ASCII letters, digits, `.`, `_` or `-`, compared
1551
+ exactly (case-sensitive), and unique in the file.
1552
+ - `template` is at most 2048 bytes, contains `{value}`, has no `{` or `}`
1553
+ outside a placeholder, and uses only the placeholders above: an index within
1554
+ its list (`{jira}` needs at least one Jira URL), a name `urls` defines, and
1555
+ a Project field that exists. `{project.labels.<key>}` is checked only for
1556
+ its key's syntax (the `labelKey` rules), because the label may be added
1557
+ later. Expanded with a sample value and a sample Project, the template is an
1558
+ absolute `http` or `https` URL without credentials.
1559
+
1560
+ Removing a URL that a template still uses is refused, like any other invalid
1561
+ rule set, and leaves the file as it was.
1562
+
1563
+ ### Rules in a Claude Agent's system prompt
1564
+
1565
+ A Claude Agent gets its Project's current rules in its system prompt: the
1566
+ heading, the placeholders, the Jira and Repo URLs with their indices, the
1567
+ named URLs, the Project variables with their current values, and each rule
1568
+ with an example link resolved for that Project, as text appended with
1569
+ `--append-system-prompt-file`. The Project is the one that owns
1570
+ the Agent's Window in the Registry, never the one its working directory is
1571
+ under. Only Claude Agents get the rules; Codex Agents and the Claude
1572
+ reply-only lane do not.
1573
+
1574
+ - Create passes the rules and records their digest on the Agent
1575
+ (`projmux.io/project-link-rules-digest`). With instructions too, Claude is
1576
+ given one file holding the instructions, a `---` separator, and the rules,
1577
+ because Claude keeps only the last `--append-system-prompt-file`. A
1578
+ resume-picker create also runs with the system prompt snapshot off, since
1579
+ the picked conversation recorded a prompt without the rules.
1580
+ - A running Agent is not restarted when the rules change. The change applies
1581
+ from its next resume (`agent resume`, Continue, or the resume picker): when
1582
+ the Project's rules differ from the recorded digest (added, changed or
1583
+ removed, or the Project renamed or its labels changed, since the Project
1584
+ variables are part of the rendered rules), that resume passes the current
1585
+ rules, runs with `--system-prompt-snapshot off`, and records the new digest
1586
+ and `projmux.io/system-prompt-snapshot=off`, which stays off from then on.
1587
+ Rules equal to the recorded digest change nothing.
1588
+ - A rule file that cannot be read does not stop the Agent: it starts without
1589
+ the rules, one `project-link-rules-unavailable` line on stderr says so, and
1590
+ its recorded digest is left as it was.
1591
+
1592
+ The rendered rules and the instructions-and-rules files are content-addressed
1593
+ below the state directory, in `project-links/`.
1594
+
1595
+ ## Agent Guidance
1596
+
1597
+ Every managed Claude Agent gets a short agent guidance text at the front of
1598
+ its system prompt, and a Codex Agent gets it at the front of its thread's
1599
+ developer instructions when it starts its own thread. It tells the Agent to
1600
+ create other agents with `projmux create agent` instead of a subagent built
1601
+ into its provider, and to
1602
+ message them with `projmux agent message send` instead of a message channel
1603
+ local to its provider. The guidance lives in one file,
1604
+ `<config dir>/agent-guidance.md` (by default
1605
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/agent-guidance.md`), and there is no
1606
+ CLI command that edits it.
1607
+
1608
+ | File | Guidance |
1609
+ | --- | --- |
1610
+ | Missing | The built-in default text. This is the state of a new install. |
1611
+ | Only whitespace (an empty file included) | Off: nothing is added and nothing is recorded. |
1612
+ | Any other content | That content, byte for byte, in place of the default. |
1613
+
1614
+ To turn the guidance off, leave the file empty (`: > agent-guidance.md`). To
1615
+ use your own text, write it to the file. To go back to the default, delete
1616
+ the file. The file is at most 64 KiB.
1617
+
1618
+ - The guidance, the instructions and the Project's label link rules reach Claude
1619
+ as one `--append-system-prompt-file`, in that order, each present only when
1620
+ the Agent has it and separated by a `---` line, because Claude keeps only
1621
+ the last file it is given.
1622
+ - Create passes the current guidance and records its digest on the Agent
1623
+ (`projmux.io/agent-guidance-digest`).
1624
+ - A change applies from the next Claude create or resume (`agent resume`,
1625
+ `agent relaunch`, Continue, or the resume picker). Running sessions are not
1626
+ restarted. A resume whose guidance differs from the recorded digest (changed,
1627
+ added to an Agent created before the guidance existed, or turned off) passes
1628
+ the current guidance, runs with `--system-prompt-snapshot off`, and records
1629
+ the new digest (or removes it) and `projmux.io/system-prompt-snapshot=off`.
1630
+ A resume-picker create always runs with the snapshot off while the guidance
1631
+ is on, since the picked conversation's recorded prompt cannot be shown to
1632
+ hold it. Guidance equal to the recorded digest changes nothing.
1633
+ - A guidance file that cannot be read, is not a regular file, or is larger
1634
+ than 64 KiB does not stop the Agent: it starts without the guidance, one
1635
+ `agent-guidance-unavailable` line on stderr says so, and nothing is
1636
+ recorded.
1637
+ - A Codex Agent receives the guidance on a fresh create that starts its own
1638
+ thread (a create with a prompt): the guidance and the instructions go to that
1639
+ thread as its developer instructions, in that order, each present only when
1640
+ the Agent has it and separated by the same `---` line, and the Agent records
1641
+ the guidance digest. A Codex resume, and a Codex create without a prompt or
1642
+ with `--interactive-only`, do not receive it. A thread keeps the developer
1643
+ instructions it was started with, so a changed guidance reaches a Codex
1644
+ Agent only through a new create.
1645
+ - The Claude reply-only lane does not receive the guidance.
1646
+
1647
+ The guidance and the files composed from it are content-addressed below the
1648
+ state directory, in `agent-guidance/`.
1649
+
1650
+ ## Setting Layers
1651
+
1652
+ Settings live in two layers:
1653
+
1654
+ | Layer | Where | What |
1655
+ | --- | --- | --- |
1656
+ | central | `config.toml` central keys (`[ui] locale`, `[update]`, `[startup]`, `[hooks.*]`, `[env]`, `[ai] split_cwd_from`), `ai-enabled-agents`, `ai-new-window-mode`, `live-resources`, `statusbar-defaults.json`, `projdir`, `workdirs`, `pins`, `tags`, `project-hooks`, `desktop-notify-mode`, `ai-notify-dedupe-seconds`, `agent-question-window-seconds`, `agent-question-answering`, `agent-approval-window-seconds`, `agent-approval-answering`, `ai-hook-actions.json`, `ai-semantic-policies.json`, `ai-hooks.d/`, `hooks/`, `personas/`, `profiles/`, `project-links/` | product behavior every surface shares |
1657
+ | TUI | `statusbar-visibility-*`, `statusbar-decoration*`, `ai-badge-style`, `runtime-diagnostics-visibility`, `keymap.toml`, `tmux-ai-split-mode`, `config.toml` `[theme]`, `[ui] native_keys`, `[ai] resume_*` | how the terminal looks and launches |
1658
+
1659
+ Central files live under `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/`, except
1660
+ `projdir` and `workdirs`, which always live under `$HOME/.config/projmux/` and
1661
+ do not follow `XDG_CONFIG_HOME`.
1662
+
1663
+ Named Agent instructions continue to use the central `personas/` directory, which keeps its older name. The `projmux instructions` commands read and write its files.
1664
+
1665
+ TUI is the front layer: only the front entry points (`settings`, `shell`,
1666
+ `switch`, `config render|apply|edit` and the internal namespace) read it. Every
1667
+ other public route reads the central layer alone, except that a route opening a
1668
+ picker may read that picker's theme and keys to paint it.
1669
+
1670
+
1199
1671
  ## Rare Tunables
1200
1672
 
1201
1673
  These are intended for debugging or local policy, not routine setup:
1202
1674
 
1203
1675
  | Variable | Purpose |
1204
1676
  | --- | --- |
1205
- | `PROJMUX_TMUX_NOTIFY_DEDUPE_SECONDS` | Override the Settings/default collapse window for duplicate AI desktop notifications keyed on the pane-local AI notification key. |
1677
+ | `PROJMUX_TMUX_NOTIFY_DEDUPE_SECONDS` | Override the Settings/default collapse window for duplicate AI desktop notifications keyed on the pane-local AI notification key. The Settings value and default apply only when this env is unset or not a positive integer. |
1206
1678
  | `PROJMUX_CODEX_TITLE_WATCH_INTERVAL` | Title-watch loop pacing for Codex panes. |
1207
1679
  | `PROJMUX_CODEX_REPLY_SETTLE_LOOPS` | Reply-detection settle-loop pacing for Codex panes. |