projmux 0.16.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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:
@@ -52,9 +77,12 @@ for large mounts, WSL paths, NFS paths, or temporary project roots.
52
77
  The saved workdir file is:
53
78
 
54
79
  ```text
55
- ~/.config/projmux/workdirs
80
+ $HOME/.config/projmux/workdirs
56
81
  ```
57
82
 
83
+ This file does not follow `XDG_CONFIG_HOME`; see
84
+ [Setting Layers](#setting-layers).
85
+
58
86
  It stores one absolute path per line. Lines beginning with `#` are comments.
59
87
  The file is read only when no env root list is set.
60
88
 
@@ -69,7 +97,7 @@ Projects sidebar registers that exact path. See
69
97
  Pins are presentation preferences, stored typed:
70
98
 
71
99
  ```text
72
- ~/.config/projmux/pins
100
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/pins
73
101
  ```
74
102
 
75
103
  ```text
@@ -117,8 +145,9 @@ terminal-layer remediation, first try the key in `projmux shell`, then run
117
145
  `projmux setup` from the raw terminal, then use `projmux setup terminal` for
118
146
  supported terminal adapters.
119
147
 
120
- `~/.config/projmux/keymap.toml` can also be edited by hand. When the file is
121
- 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.
122
151
 
123
152
  Supported schema:
124
153
 
@@ -223,13 +252,14 @@ Theme is a global user preference. The effective theme resolves from the global
223
252
  user theme plus a built-in fallback only:
224
253
 
225
254
  ```text
226
- ~/.config/projmux/config.toml
255
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/config.toml
227
256
  built-in fallback preset
228
257
  ```
229
258
 
230
- Settings edits the global `[theme]` in `~/.config/projmux/config.toml`. The
231
- Effective theme view shows the final global > built-in fallback value for each
232
- 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
233
263
  value live-applies it: projmux regenerates the generated tmux config and, when
234
264
  Settings runs inside tmux, `tmux source-file`-reloads it so a running server
235
265
  repaints immediately. Outside tmux the save still succeeds and the report
@@ -364,7 +394,7 @@ Preferred interactive path:
364
394
  Global config path:
365
395
 
366
396
  ```text
367
- ~/.config/projmux/config.toml
397
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/config.toml
368
398
  ```
369
399
 
370
400
  Schema:
@@ -442,21 +472,33 @@ or a method-not-found response are reported explicitly as unavailable. The
442
472
  initial `review/start` response is projected into Agent interaction lifecycle;
443
473
  the lifecycle observer described below owns later app-server terminal events.
444
474
 
445
- A natively created or resumed Codex Agent keeps a content-free lifecycle
475
+ A natively created or resumed Codex Agent keeps a lifecycle
446
476
  observer on its exact Agent UID, Pane UID/runtime handle, activation generation,
447
477
  and thread ID. While its initialized proxy connection and snapshot are current,
448
478
  the app server is the only attention authority: active, idle, waiting for input,
449
479
  and exact unresolved approval requests project the Agent interaction and badge.
450
- Only an exact successful `turn/completed` projects response-complete and queues a
451
- 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
452
492
  and thread unload first invalidate the epoch and clear stale attention, then
453
493
  enable hook fallback. A reconnect starts a new epoch from `thread/read`; events
454
494
  from older epochs or other identities are ignored.
455
495
 
456
496
  `describe agent` and the Codex Agent event Settings page report the effective
457
497
  lifecycle source, a closed reason, and active/pending/inactive epoch status.
458
- These diagnostics never retain prompts, reasoning, output, approval reasons, or
459
- 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
460
502
  `mixed` when native and fallback authority coexist.
461
503
 
462
504
  Projmux does not install, bootstrap, restart, stop, or reconfigure the Codex
@@ -479,8 +521,8 @@ one writes only the global `[ai] split_cwd_from`.
479
521
  Config paths (global and project both honored):
480
522
 
481
523
  ```text
482
- ~/.config/projmux/config.toml # global
483
- <project>/.projmux/config.toml # project
524
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/config.toml # global
525
+ <project>/.projmux/config.toml # project
484
526
  ```
485
527
 
486
528
  Schema:
@@ -538,6 +580,27 @@ that re-enables it.
538
580
  `Settings > Global > AI > Enabled providers`. A missing file means every
539
581
  provider is enabled; disabling every provider persists as none enabled.
540
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
+
541
604
  ## AI Resume Picker
542
605
 
543
606
  The Agent resume picker lists the most recent
@@ -552,8 +615,8 @@ Preferred interactive path:
552
615
  Config paths (global and project both honored):
553
616
 
554
617
  ```text
555
- ~/.config/projmux/config.toml # global
556
- <project>/.projmux/config.toml # project
618
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/config.toml # global
619
+ <project>/.projmux/config.toml # project
557
620
  ```
558
621
 
559
622
  Schema:
@@ -616,7 +679,7 @@ to the install path: every installer can be judged on either channel.
616
679
  Files:
617
680
 
618
681
  ```text
619
- ~/.config/projmux/config.toml # global/user
682
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/config.toml # global/user
620
683
  ```
621
684
 
622
685
  Schema:
@@ -650,7 +713,7 @@ installed; that install stays put until its stable line ships.
650
713
 
651
714
  | Variable | Purpose |
652
715
  | --- | --- |
653
- | `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`. The legacy `PROJDIR` and `RP` env vars are no longer honored. |
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. |
654
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. |
655
718
  | `TMUX_SESSIONIZER_ROOTS` | Legacy alias still honored at runtime for managed roots. |
656
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. |
@@ -729,6 +792,134 @@ set-option -g @projmux_projdir /path/to/repos
729
792
  An env `PROJMUX_PROJDIR` value takes priority over the tmux option. The tmux
730
793
  option takes priority over the saved projdir file.
731
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
+
732
923
  ## Notifications
733
924
 
734
925
  When `PROJMUX_NOTIFY_HOOK` is unset, projmux uses:
@@ -813,6 +1004,11 @@ precedence only during hook fallback; catalog defaults do not override this
813
1004
  semantic store. Saving this file does not infer from, rewrite, or normalize the
814
1005
  raw hook override file.
815
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
+
816
1012
  Delivery depends on the event handler. Specialized notify handlers, such as
817
1013
  Codex `PermissionRequest` and `Stop`, can write the in-app notify queue and use
818
1014
  the configured OS desktop notification path. Known Codex events without a
@@ -976,13 +1172,13 @@ Settings > Appearance controls optional icon decoration per surface:
976
1172
  The per-surface saved values live at:
977
1173
 
978
1174
  ```text
979
- ~/.config/projmux/statusbar-decoration-cwd
980
- ~/.config/projmux/statusbar-decoration-git
981
- ~/.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
982
1178
  ```
983
1179
 
984
- The legacy `~/.config/projmux/statusbar-decoration` value is still read as the
985
- 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.
986
1182
 
987
1183
  ## Row 0 HUD Visibility
988
1184
 
@@ -997,20 +1193,22 @@ independent global presentation preferences:
997
1193
  The saved values are `on` or `off` in these files:
998
1194
 
999
1195
  ```text
1000
- ~/.config/projmux/statusbar-visibility-notifications-hud
1001
- ~/.config/projmux/statusbar-visibility-agent-usage-hud
1002
- ~/.config/projmux/statusbar-visibility-agent-usage-provider-claude
1003
- ~/.config/projmux/statusbar-visibility-agent-usage-provider-codex
1004
- ~/.config/projmux/statusbar-visibility-agent-usage-window-claude-5h
1005
- ~/.config/projmux/statusbar-visibility-agent-usage-window-claude-weekly
1006
- ~/.config/projmux/statusbar-visibility-agent-usage-window-codex-5h
1007
- ~/.config/projmux/statusbar-visibility-agent-usage-window-codex-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
1008
1204
  ```
1009
1205
 
1010
- Missing, empty, and invalid values resolve to `on` except the Codex `5h`
1011
- window, whose ambient HUD default is `off`; an explicit saved `on` restores it.
1012
- Settings shows whether the effective value came from `saved` or `default` and
1013
- 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
1014
1212
  and standalone tmux output, and Settings source-reloads the generated app config
1015
1213
  when it is running inside tmux.
1016
1214
 
@@ -1043,15 +1241,18 @@ components independently:
1043
1241
  Their global saved values are `on` or `off` in:
1044
1242
 
1045
1243
  ```text
1046
- ~/.config/projmux/statusbar-visibility-project
1047
- ~/.config/projmux/statusbar-visibility-working-directory
1048
- ~/.config/projmux/statusbar-visibility-git
1049
- ~/.config/projmux/statusbar-visibility-clock
1050
- ~/.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
1051
1249
  ```
1052
1250
 
1053
- Missing, empty, and invalid values resolve to `on`; Settings reports the
1054
- 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
1055
1256
  atomic 0600 replacement, regenerates both app and standalone output, and
1056
1257
  source-loads the generated app config when Settings is inside tmux. Off removes
1057
1258
  the complete segment, including its mouse range and owned spacing. Working
@@ -1060,8 +1261,57 @@ text visible. Settings launcher `off` removes only its mouse chip; CLI and
1060
1261
  keybinding entry remain.
1061
1262
 
1062
1263
  Resources intentionally does not use one of these visibility files. Its
1063
- existing `~/.config/projmux/live-resources` value is the only enabled source
1064
- 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.
1065
1315
 
1066
1316
  ## Live System Resources
1067
1317
 
@@ -1069,7 +1319,7 @@ and controls both the segment and sampler/cache mutation.
1069
1319
  CPU/memory segment on the lower status row. The saved global value is:
1070
1320
 
1071
1321
  ```text
1072
- ~/.config/projmux/live-resources
1322
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/live-resources
1073
1323
  ```
1074
1324
 
1075
1325
  Accepted values are `off` (default) and `on`. A missing, empty, or invalid
@@ -1104,15 +1354,314 @@ The CPU delta cache is internal state at
1104
1354
  CPU reference samples older than 30 seconds are ignored and replaced on the
1105
1355
  next refresh.
1106
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
+
1107
1650
  ## Setting Layers
1108
1651
 
1109
1652
  Settings live in two layers:
1110
1653
 
1111
1654
  | Layer | Where | What |
1112
1655
  | --- | --- | --- |
1113
- | central | `config.toml` central keys (`[ui] locale`, `[update]`, `[startup]`, `[hooks.*]`, `[env]`, `[ai] split_cwd_from`), `ai-enabled-agents`, `live-resources`, `projdir`, `workdirs`, `pins`, `tags`, `project-hooks`, `desktop-notify-mode`, `ai-notify-dedupe-seconds`, `ai-hook-actions.json`, `ai-semantic-policies.json`, `ai-hooks.d/`, `hooks/`, `personas/` | product behavior every surface shares |
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 |
1114
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 |
1115
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
+
1116
1665
  TUI is the front layer: only the front entry points (`settings`, `shell`,
1117
1666
  `switch`, `config render|apply|edit` and the internal namespace) read it. Every
1118
1667
  other public route reads the central layer alone, except that a route opening a