projmux 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README-ko.md CHANGED
@@ -12,7 +12,11 @@ attention까지 함께 다루는 터미널 workspace 도구입니다.
12
12
 
13
13
  [English README](README.md)
14
14
 
15
- ![projmux shell project sidebar demo](docs/assets/projmux-shell-sidebar.gif)
15
+ <p align="center">
16
+ <img src="docs/assets/projmux-ai-attention.gif" alt="projmux AI attention demo" width="820">
17
+ <br>
18
+ <em>다른 프로젝트에서 일하는 동안 agent 작업이 끝나면 notification에서 바로 해당 pane으로 돌아갑니다.</em>
19
+ </p>
16
20
 
17
21
  ## 무엇인가
18
22
 
@@ -88,6 +92,7 @@ projmux shell
88
92
  - [Hooks](docs/hooks.md)
89
93
  - [Usage tracking](docs/usage-tracking.md)
90
94
  - [Agent Workflow](docs/agent-workflow.md)
95
+ - [README Hero GIF Recording](docs/readme-hero-gif-recording.md)
91
96
 
92
97
  ## 개발
93
98
 
package/README.md CHANGED
@@ -4,24 +4,41 @@
4
4
  <img src="docs/assets/projmux-icon.png" alt="projmux icon" width="112">
5
5
  </p>
6
6
 
7
- Project-aware tmux workspaces with fast switching, previews, status context,
8
- and AI-pane attention built in.
7
+ <p align="center">
8
+ <strong>A tmux-native workspace for multi-agent AI development.</strong>
9
+ <br>
10
+ <em>First-class Claude Code and Codex integration with hook-driven attention and agent-aware session resume.</em>
11
+ </p>
9
12
 
10
- [![npm version](https://img.shields.io/npm/v/projmux?logo=npm)](https://www.npmjs.com/package/projmux)
11
- [![CI](https://github.com/crevissepartners/projmux/actions/workflows/ci.yml/badge.svg)](https://github.com/crevissepartners/projmux/actions/workflows/ci.yml)
13
+ <p align="center">
14
+ <a href="https://www.npmjs.com/package/projmux"><img src="https://img.shields.io/npm/v/projmux?logo=npm" alt="npm version"></a>
15
+ <a href="https://github.com/crevissepartners/projmux/actions/workflows/ci.yml"><img src="https://github.com/crevissepartners/projmux/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
16
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/crevissepartners/projmux" alt="MIT license"></a>
17
+ <a href="README-ko.md"><img src="https://img.shields.io/badge/lang-한국어-blue" alt="Korean README"></a>
18
+ </p>
12
19
 
13
- [Korean README](README-ko.md)
20
+ ```sh
21
+ npm install -g projmux
22
+ projmux shell
23
+ ```
14
24
 
15
- ![projmux shell project sidebar demo](docs/assets/projmux-shell-sidebar.gif)
25
+ <p align="center">
26
+ <img src="docs/assets/projmux-ai-attention.gif" alt="projmux AI attention demo" width="820">
27
+ <br>
28
+ <em>An agent finishes in another project. Open notifications, select it, and jump straight back.</em>
29
+ </p>
16
30
 
17
- ## What It Is
31
+ ## Why
18
32
 
19
- `projmux` turns project directories into durable tmux sessions. It gives you a
20
- keyboard-first workspace app for switching projects, previewing sessions,
21
- opening AI splits, and keeping useful context visible in tmux.
33
+ Six tmux windows. Each one is running Claude Code or Codex on a different
34
+ repo. Three are idle. One is waiting on a permission prompt. One crashed an
35
+ hour ago and you have no idea which.
22
36
 
23
- Use it when you want one command to open your terminal workspace and one set of
24
- keys to move between projects, windows, panes, notifications, and settings.
37
+ projmux ingests Claude Code and Codex hook events directly, shows live
38
+ per-pane state in the tmux status bar, and lets one keystroke take you to
39
+ the pane that actually needs you. It also remembers each agent's resume id,
40
+ so after a reboot every pane comes back as the *same* conversation — not a
41
+ fresh one.
25
42
 
26
43
  ## Requirements
27
44
 
@@ -32,14 +49,12 @@ Run `projmux doctor` after installing to check the local runtime.
32
49
 
33
50
  ## Install
34
51
 
35
- ```sh
36
- npm install -g projmux
37
- projmux version
38
- ```
52
+ The npm package shown above installs a small Node.js shim plus the matching
53
+ projmux binary for Linux and macOS on x64 or arm64. npm is the primary
54
+ distribution path for normal users.
39
55
 
40
- The npm package installs a small Node.js shim plus the matching projmux binary
41
- for Linux and macOS on x64 or arm64. npm is the primary distribution path for
42
- normal users.
56
+ Verify with `projmux version`. Then `projmux doctor` checks the local runtime
57
+ (tmux 3.4+ and hook integration health).
43
58
 
44
59
  Manual Go, source checkout, GitHub Release, and packaging details live in
45
60
  [Install](docs/install.md).
@@ -84,11 +99,13 @@ For update behavior by installer type, see [Upgrading](docs/upgrading.md).
84
99
  - [Install](docs/install.md)
85
100
  - [Configuration](docs/configuration.md)
86
101
  - [Terminal Keybindings](docs/keybindings.md)
102
+ - [AI Agent Shortcuts](docs/ai-agent-shortcuts.md)
87
103
  - [CLI Reference](docs/cli.md)
88
104
  - [Statusbar](docs/statusbar.md)
89
105
  - [Hooks](docs/hooks.md)
90
106
  - [Usage tracking](docs/usage-tracking.md)
91
107
  - [Agent Workflow](docs/agent-workflow.md)
108
+ - [README Hero GIF Recording](docs/readme-hero-gif-recording.md)
92
109
 
93
110
  ## Development
94
111
 
@@ -30,7 +30,10 @@
30
30
  - `make fix`: safe automatic fixes such as `go fix` and repository-approved cleanup steps.
31
31
  - `make npm-pack`: local npm binary package staging and `npm pack --dry-run` for the root package plus platform packages.
32
32
  - `make test`: fast unit coverage for app-layer AI split native agent launch/selective popup-toggle/settings/status/notification parity including AI pane option metadata, watcher metadata bootstrap for existing panes, capture-backed reply detection, missing-pane watcher shutdown, armed focus-only reply badge clearing, busy attention preservation on focus clear, manual AI topic preservation while watcher status still updates, agent-labeled desktop notification message context with pane-title-first body text, global/project-local lifecycle hook dispatch for post-create/pre-create/post-attach/send-noti with project hook and `.projmux/config.toml` trust-store hashing plus env/settings kill-switch gating, declarative startup command and hook run coverage, `send-noti` stdin JSON delivery plus `PROJMUX_NOTIFY_*` env payload, notify queue write success/failure/depth-guard dispatch rules, notify/statusbar/sidebar origin-client focus routing, project config env/kube session environment application, Settings project config env/kube/startup form writes with trust-store refresh and preserved hook commands, startup command send-keys orchestration plus startup pane replay markers, pre-create abort behavior, and shared projmux notification icon paths, and scoped even row/column resizing after shell and agent splits, status-bar git/kube segment parity including branch block styling, statusbar pwd display-only native-framed path popup, no clipboard or tmux buffer copy, and simple Enter-close popup command, statusbar usage native HUD popup alignment/threshold/sync-staleness/fallback coverage without raw CLI popup or popup-toggle stacking, statusbar settings click popup fallback, isolated `projmux shell` tmux app launch/config generation including home fallback plus project-context default session targeting from `PROJMUX_CWD` or nearest project marker, app-owned project-name statusbar layout, distinct project badge color, and quiet debounced session-state autosave command/app-config trigger, first-run/version-bump shell welcome state and inline update handling, shell startup update prompt actions for fresh installer-aware cached updates, pane/window keybindings, keymap.toml tmux override rendering/stale unbinds, Settings Keybindings root/list/detail capture flows including parse-error rows, unsafe raw capture and timeout guards, disable/reset writes, app config regeneration, live tmux source-file reload, and no-live-tmux save behavior, window rename bindings, pane rename helper/binding, pane-exit rebalance command/hooks, hook-pane and after-select-pane based attention focus hooks, attention badge toggle/clear/list/window rendering, attach/current/kill/pin/preview/prune/sessions/session-popup/settings commands, switch, tag, tmux helper commands, update status/check/apply cache and installer detection including GitHub Release binary asset selection/extraction/replacement, doctor install-missing command selection, AI notify integration diagnostics, and Session State resume metadata diagnostics, Settings AI notify integration diagnostics read-only status/conflict/CLI guidance, and Settings About update status/check action wiring, untitled standalone popup-toggle marker close/config install, direct popup minimum sizing, AI picker minimum width and height, sidebar minimum width and compact badge spacing, preview select writes, popup render output after cycling, switch picker pin action behavior without inline settings rows, nested settings hub sections for AI defaults, project picker filesystem scan/pin actions, Project Root settings source/shadowing/set/current/clear flows, app/keybinding info including Ctrl-M rename forwarding, and About version/source rendering, switch picker focused-session kill, switch picker launcher-key abort bindings, switch explicit project-root, unconfigured-root, and weak managed-root heuristic parity, switch popup hiding new-session candidates while sidebar keeps create-capable rows, switch row project-name display with `~` pinned to the top and live-session-first sorting, pretty-path, preview-context including kube context/namespace, switch settings subcommand flows including add-current-pin, interactive add-pin picker, and settings label/preview polish, native preview wiring, baseline picker surface parity including prompt/footer/header fallback without app-name filler and search-key scoped card matching, sidebar compact action-only key footer, sidebar preview-window/start-position behavior without focus-time session switching, sidebar row/window ANSI styling with pane-aggregated attention badge state and AI topic labels, Alt+2/Alt+3 legacy popup row, preview-window, pane metadata, and pane-snapshot parity, switch read0 card rows with active/inactive title styling, right-side status badges, combined directory/git metadata with muted inactive branch styling, statusbar-matched block window tabs with window attention badges, read0 expect-key action parsing, restored pin/tag card badges, and restrained selected-row marker styling, switch preview metadata without duplicated directory/git rows, preview metadata rendering, popup pane display names for AI agents, AI topics, and shell commands, switch preview cycle bindings, sessions picker preview/cycle/open/kill wiring including attached-session fallback behavior, sessions picker launcher-key abort bindings, popup/switch preview summary formatting, popup sessions tmux entry helpers, switch/popup/session rendering, session identity, session-state Claude/Codex resume and declarative startup replay, session snapshot capture/autosave recipe classification including save/autosave pre-capture resume metadata refresh from live AI session ids, Claude transcript paths, and Codex rollout log cwd matching/ambiguity skips, candidate discovery, config path derivation, popup preview read-models, and pure state rules including preview, tag, and lifecycle stores.
33
- - `make test` also covers Settings IA regression guards for `send-noti` visibility in Hooks, no nested Project recipe inside Hooks, Project recipe/AI/Labs view-first detail rows, Notifications root/Desktop notifications/Delivery sources relocation, Delivery sources command-row clipboard copy, and Labs Project Hooks overview-first rows.
33
+ - `make test` also covers direct `projmux ai split --agent <claude|codex|shell|selective>` launches, config-default preservation, extra args appended to resolved agent executables, managed pane metadata, title watcher startup, layout application, plain shell split behavior, selective picker delegation, and invalid direct-agent usage errors.
34
+ - `make test` also covers Settings IA regression guards for `send-noti` visibility in Hooks, no nested Project recipe inside Hooks, Project recipe/AI/Labs view-first detail rows, Appearance Path/Git/Notify icon direct off/symbol/emoji preview selection with no Change page, Notifications root/Desktop notifications/Delivery sources relocation, Delivery sources command-row clipboard copy, and Labs Project Hooks overview-first rows.
35
+ - `make test` also covers AI desktop notification dedupe precedence (env override > Settings saved value > default), configured dedupe-window collapse/send behavior, Settings > Notifications AI dedupe preset/custom rows, explicit notify focus consume rules for selected critical rows and older same-pane non-critical AI cleanup, preservation of critical/permission/stop-failure/external/git/k8s rows during bulk cleanup, OS Toast click-to-focus queue consume, WSL Toast protocol handler hidden-launcher registration with `wsl.exe --exec` URI forwarding, and attention clear paths that do not ack the queue.
36
+ - `make test` also covers AI hook runtime action precedence over catalog defaults, runtime quiet for known Codex notify events, runtime notify for known Claude quiet events, generic in-app-only notify rows for known Codex hook events without specialized handlers, suppression of desktop notification and `send-noti` dispatch on that generic path, separation of runtime hook action from catalog install events, Settings > Notifications hook quiet policy display/write behavior without external install/remove execution, hook desktop notification payload parity with the in-app queue text across the shared OS notification payload, normal/transient OS urgency and expiration for critical AI queue rows, and dormant title/capture fallback gating once a pane is hook-active.
34
37
  - `make test` also covers Settings > Session State as global settings-only UI with default-off auto-save and no window/pane tree, Settings > Project > Session State project-derived identity plus project auto-save override/effective source rows and distinct Save latest snapshot / Save named snapshot labels, closed-project save disabled reasons, named snapshot portable path conversion, project/global auto-save precedence, Projects > Sessions > State read-only latest/named snapshot overview with window/pane cwd/recipe/agent-resume health, user-facing `projmux session-state` status/save/delete/restore dry-run actions including explicit manual save bypass of disabled autosave and agent resume status/confidence preview, and Project open sidebar startup coverage for Labs opt-in `Start project`, default-off empty creation, Latest snapshot, Named snapshot, Empty session, Back, saved-at row metadata, existing-session skip, startup-before-trust ordering, trust approve continuation, and trust deny/cancel no-session behavior.
35
38
  - `make test` also covers `projmux shell` usage without startup selector flags, project-context default target lookup from `PROJMUX_CWD` or nearest project marker, explicit `--session` separation from project-derived defaults, and direct empty attach behavior without shell startup picker/replay.
36
39
  - `make test` also covers manual Session State Save snapshot and restore dry-run preview actions, title-first pane preview labels with legacy snapshot fallback, missing-snapshot messaging, and the absence of the removed statusbar State shortcut.
@@ -42,11 +45,14 @@
42
45
  - `make test` also covers `projmux ai integrate tmux-bell` dry-run/install/remove tmux command planning, managed `alert-bell` hook append/idempotence/removal, preservation of unmanaged bell hooks, and `projmux ai ingest bell --pane` queue push/metadata/dedupe behavior for non-AI-managed panes.
43
46
  - `make test` also covers `projmux ai ingest log` tail/path rendering and bounded JSONL log trimming for ingest diagnostics.
44
47
  - `make test` also now covers onboarding revisit and welcome wiring (`projmux welcome`, `Settings > About > Welcome`, `pending_attach_welcome`, attach-time `welcome --popup` one-time claim/env suppression/tmux popup payload, and generated `client-attached` app config wiring) via shell welcome tests.
48
+ - `make test` also covers `projmux quit` action-picker rows, cancel/close no-op behavior, explicit quit of only app-owned `tmux -L projmux` runtimes marked by `@projmux_app=1`, missing/default runtime no-ops, dispatcher wiring, and `Settings > About > Quit projmux` routing through the same picker before any shutdown side effect.
45
49
  - Current focused unit coverage also includes strict notify SOT behavior
46
50
  (TTL does not remove rows, focus success and target-gone clicks ack,
47
51
  reconcile reports stale rows), `notify list --live` queue/live explanations, notify sidebar
48
52
  two-line card rendering with age/project/window/pane metadata plus focus/ack/clear-all
49
- actions, and `focus` dispatch diagnostics for session fallback, unresolved
53
+ actions, including in-place `x` ack that refreshes the sidebar without
54
+ focusing, preserves selection position where possible, and renders the empty
55
+ state after the last row is acked, and `focus` dispatch diagnostics for session fallback, unresolved
50
56
  targets, window fallback, pane fallback, explicit id failures as unresolved exits, and
51
57
  notify-only fallback.
52
58
  - Picker focused unit coverage includes backend-neutral picker item/action mapping, native title-focused filtering, numeric selection, shared close actions including raw and CSI-u Ctrl-X native custom actions, deprecated picker backend value normalization, AI picker title chrome and stable search-key ordering, Settings title chrome and root section order, Settings Labs shell without backend choices plus keybinding diagnostic list/detail/probe outcome/init delegation coverage, environment override normalization, compact multi-line metadata gutters with one-column-indented metadata, proportional native scrollbar thumb rendering, multiline partial next/previous item row rendering with rendered-row scrollbar units, fixed split-preview and sidebar list viewports with scrollbar tracks, native up/down-family navigation wrap with empty-list safety and PageUp/PageDown/Home/End clamp regression coverage, native mouse down/follow-drag/release behavior, preview tab/control normalization before width clipping, optional native frame titlebars without same-line rule fill and with titlebar border reset guards, titled native Alt-1 sidebar chrome, statusbar-preserving sidebar popup height, native-only compact project sidebar popup sizing, and notify sidebar title/popup sizing.
@@ -0,0 +1,264 @@
1
+ # AI Agent Shortcut Registration
2
+
3
+ `projmux ai split` is intentionally tool-general: user-level shortcuts,
4
+ skills, slash commands, terminal actions, and editor commands can all map to
5
+ the same split contract.
6
+
7
+ ```sh
8
+ projmux ai split --agent <agent> <right|down>
9
+ projmux ai split --agent <agent> <right|down> -- <extra args...>
10
+ ```
11
+
12
+ Use this page for shareable registration patterns. Keep machine-local policy,
13
+ private prompt text, and personal workflow recipes in your own dotfiles or
14
+ local tool configuration, not in tracked repo docs.
15
+
16
+ ## Command Contract
17
+
18
+ Choose a direct agent when a shortcut should always open that agent:
19
+
20
+ ```sh
21
+ projmux ai split --agent codex right
22
+ projmux ai split --agent claude down
23
+ ```
24
+
25
+ Add the separator only when you have extra arguments for the selected agent:
26
+
27
+ ```sh
28
+ projmux ai split --agent codex right -- --model <model>
29
+ projmux ai split --agent claude down -- <agent flags>
30
+ ```
31
+
32
+ The `--` separates projmux arguments from agent arguments. Everything after
33
+ that separator is passed to the resolved selected agent executable. It is not
34
+ an executable override. In the examples above, projmux still chooses the
35
+ configured `codex` or `claude` executable, creates the tmux split, sets pane
36
+ metadata, applies the title watcher, and appends the tail arguments to the
37
+ agent command.
38
+
39
+ Model, permission, and other agent flags are examples to customize privately in
40
+ your user-level config. Avoid treating placeholder flags in this guide as
41
+ project defaults or current recommendations. If there are no private extra
42
+ arguments, omit the separator entirely; do not leave a trailing bare `--`.
43
+
44
+ `shell` and `selective` are not targets for extra agent arguments. Use them
45
+ without a tail:
46
+
47
+ ```sh
48
+ projmux ai split --agent shell right
49
+ projmux ai split --agent selective down
50
+ ```
51
+
52
+ `shell` opens a plain shell split. `selective` opens the existing picker, where
53
+ the user chooses the launch mode interactively.
54
+
55
+ ## Naming Pattern
56
+
57
+ Pick names that encode the target agent and split direction, then keep the
58
+ body as a small command wrapper.
59
+
60
+ For Codex-style skill surfaces, names can follow:
61
+
62
+ ```text
63
+ $projmux-<agent>-right
64
+ $projmux-<agent>-down
65
+ ```
66
+
67
+ Concrete examples:
68
+
69
+ ```text
70
+ $projmux-codex-right
71
+ $projmux-claude-down
72
+ ```
73
+
74
+ For Claude-style slash-command surfaces, names can follow:
75
+
76
+ ```text
77
+ /projmux:<agent>-right
78
+ /projmux:<agent>-down
79
+ ```
80
+
81
+ Concrete examples:
82
+
83
+ ```text
84
+ /projmux:codex-right
85
+ /projmux:claude-down
86
+ ```
87
+
88
+ The same pattern also works for editor commands, launcher actions, shell
89
+ aliases, or terminal custom actions. The important part is that the registered
90
+ surface calls `projmux ai split --agent <agent> <direction>` and passes only
91
+ agent flags after `--`.
92
+
93
+ ### Bare-Name Default
94
+
95
+ When a surface registers a bare agent name without an explicit direction
96
+ suffix, treat it as the `right` variant. `right` is the convention for the
97
+ unqualified shortcut; `down` is always spelled out.
98
+
99
+ For Codex-style skill surfaces:
100
+
101
+ ```text
102
+ $projmux-codex → projmux ai split --agent codex right
103
+ $projmux-claude → projmux ai split --agent claude right
104
+ ```
105
+
106
+ For Claude-style slash-command surfaces:
107
+
108
+ ```text
109
+ /projmux:codex → projmux ai split --agent codex right
110
+ /projmux:claude → projmux ai split --agent claude right
111
+ ```
112
+
113
+ Register the bare name as a thin alias of the `*-right` shortcut so that the
114
+ two surfaces stay in lockstep. The `*-down` variant must be invoked by its
115
+ full name; do not introduce a separate bare default for `down`.
116
+
117
+ ## Skill Template
118
+
119
+ Use this shape when a tool lets you define a user-level skill that tells an
120
+ agent to run a shell command. Actual loader paths vary by installation; the
121
+ intended home is user-level config or dotfiles, not this repository.
122
+
123
+ Example Codex-style skill file:
124
+
125
+ ```text
126
+ ~/.codex/skills/projmux-codex-right/SKILL.md
127
+ ```
128
+
129
+ ````markdown
130
+ ---
131
+ name: projmux-codex-right
132
+ description: Open a projmux-managed Codex split to the right.
133
+ ---
134
+
135
+ Run this command:
136
+
137
+ ```sh
138
+ projmux ai split --agent codex right
139
+ ```
140
+
141
+ If you have private Codex flags, use the explicit extra-args form instead:
142
+
143
+ ```sh
144
+ projmux ai split --agent codex right -- --model <model>
145
+ ```
146
+ ````
147
+
148
+ Non-Codex target example:
149
+
150
+ ```text
151
+ ~/.codex/skills/projmux-claude-down/SKILL.md
152
+ ```
153
+
154
+ ````markdown
155
+ ---
156
+ name: projmux-claude-down
157
+ description: Open a projmux-managed Claude split below.
158
+ ---
159
+
160
+ Run this command:
161
+
162
+ ```sh
163
+ projmux ai split --agent claude down
164
+ ```
165
+
166
+ If you have private Claude flags, use the explicit extra-args form instead:
167
+
168
+ ```sh
169
+ projmux ai split --agent claude down -- <agent flags>
170
+ ```
171
+ ````
172
+
173
+ If your tool stores skills as JSON, TOML, or another format, keep the same
174
+ fields conceptually:
175
+
176
+ - Name: the user-facing shortcut, such as `$projmux-codex-right`.
177
+ - Description: one sentence saying which agent and direction it opens.
178
+ - Command: the `projmux ai split` invocation.
179
+ - Arguments: optional agent arguments placed after `--`.
180
+
181
+ ## Slash Command Template
182
+
183
+ Use this shape when a tool lets you define user-level slash commands. Actual
184
+ loader paths and interpolation variables can vary by installation; user-level
185
+ config or dotfiles is the intended home.
186
+
187
+ ```text
188
+ ~/.claude/commands/projmux/codex-right.md
189
+ ```
190
+
191
+ This maps to a slash command named `/projmux:codex-right`:
192
+
193
+ ````markdown
194
+ Open a Codex split to the right in the current projmux session.
195
+
196
+ Run this command:
197
+
198
+ ```sh
199
+ projmux ai split --agent codex right
200
+ ```
201
+ ````
202
+
203
+ For an argument-aware wrapper, include the separator only when arguments are
204
+ non-empty. Adapt this shell shape to the tool's command-file format:
205
+
206
+ ```sh
207
+ if [ -n "$ARGUMENTS" ]; then
208
+ projmux ai split --agent codex right -- $ARGUMENTS
209
+ else
210
+ projmux ai split --agent codex right
211
+ fi
212
+ ```
213
+
214
+ Then invoke it with private agent flags only when needed, such as
215
+ `/projmux:codex-right --model <model>`.
216
+
217
+ For a Claude target, use a sibling file such as:
218
+
219
+ ```text
220
+ ~/.claude/commands/projmux/claude-down.md
221
+ ```
222
+
223
+ This maps to `/projmux:claude-down`:
224
+
225
+ ````markdown
226
+ Open a Claude split below in the current projmux session.
227
+
228
+ Run this command:
229
+
230
+ ```sh
231
+ projmux ai split --agent claude down
232
+ ```
233
+ ````
234
+
235
+ For an argument-aware wrapper, use the same non-empty check:
236
+
237
+ ```sh
238
+ if [ -n "$ARGUMENTS" ]; then
239
+ projmux ai split --agent claude down -- $ARGUMENTS
240
+ else
241
+ projmux ai split --agent claude down
242
+ fi
243
+ ```
244
+
245
+ Then pass private Claude flags at invocation time only when needed, such as
246
+ `/projmux:claude-down <agent flags>`.
247
+
248
+ If the tool separates command metadata from the shell body, put only the
249
+ `projmux ai split ...` line in the executable body. Avoid embedding
250
+ machine-specific project roots, permission policies, or personal model choices
251
+ in shared docs; put those in your private user-level command files.
252
+
253
+ ## Checklist
254
+
255
+ - Register shortcuts at user level in the AI tool, editor, launcher, or
256
+ terminal that owns the surface.
257
+ - Use `--agent codex` or `--agent claude` when passing extra agent arguments.
258
+ - Put agent flags after the separator, for example `-- --model <model>`.
259
+ - Omit the separator entirely when there are no extra agent arguments.
260
+ - Use `--agent shell` with no tail for a plain shell split.
261
+ - Use `--agent selective` with no tail for the picker.
262
+ - Treat a bare agent name (`/projmux:codex`, `$projmux-claude`) as the
263
+ `right` variant; spell out `*-down` shortcuts in full.
264
+ - Keep tracked project docs and `AGENTS.md` free of private shortcut policy.
package/docs/cli.md CHANGED
@@ -31,6 +31,7 @@ projmux <command> [args...]
31
31
  | `pin` | Manage pinned project directories. |
32
32
  | `preview` | Manage persisted tmux preview selection. |
33
33
  | `prune` | Trim stale tmux lifecycle state. |
34
+ | `quit` | Quit the app-owned projmux tmux runtime. |
34
35
  | `sessions` | Pick and open an existing tmux session. |
35
36
  | `session-popup` | Read tmux popup preview state. |
36
37
  | `settings` | Configure projmux. |
@@ -318,7 +319,7 @@ supplied window.
318
319
  ## ai
319
320
 
320
321
  ```
321
- projmux ai split --inside <right|down> [--agent <name>] ...
322
+ projmux ai split [--agent <claude|codex|shell|selective>] [right|down] [-- <extra-arg>...]
322
323
  projmux ai picker --inside <right|down>
323
324
  projmux ai settings
324
325
  projmux ai status set <thinking|waiting|idle> [--pane <id>]
@@ -340,6 +341,16 @@ notifier. `status set waiting` is the trigger that flips a pane to the
340
341
  reply-ready state — that transition pushes an `ai:<session>:<pane>`
341
342
  entry into the notify queue.
342
343
 
344
+ `ai split right|down` uses the configured default split mode. Add
345
+ `--agent claude`, `--agent codex`, `--agent shell`, or `--agent selective` for
346
+ a one-shot launch without changing that default. `--agent selective` opens the
347
+ existing picker flow; `--agent shell` opens the existing plain shell split.
348
+ Arguments after `--` are extra arguments appended to the resolved `claude` or
349
+ `codex` executable inside the managed wrapper; projmux still sets the context
350
+ directory, tmux title, AI pane metadata, title watcher, and split layout.
351
+ For user-level skill, slash-command, editor, or launcher registrations that
352
+ call this contract, see [AI Agent Shortcuts](ai-agent-shortcuts.md).
353
+
343
354
  `ingest codex-hook` is the hook-facing entrypoint for Codex hooks-engine JSON.
344
355
  It reads one JSON payload from stdin and handles the default Codex hook catalog
345
356
  `PreToolUse`, `PermissionRequest`, `PostToolUse`, `PreCompact`, `PostCompact`,
@@ -357,6 +368,17 @@ to quiet/log-only handling. A local catalog entry with `"action": "quiet"`
357
368
  therefore lets newly discovered events be installed and observed without
358
369
  creating notification noise; `"notify"` and `"state"` still require a built-in
359
370
  handler before they can change pane state or push queue rows.
371
+ Runtime action overrides from
372
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/ai-hook-actions.json` take
373
+ precedence over catalog `action` during ingest, including known events such as
374
+ `Stop` and `PermissionRequest`. These overrides are managed by
375
+ `Settings > Notifications > Hook quiet policy` and do not change the catalog
376
+ `install` field used by `projmux ai integrate codex`. A runtime `notify`
377
+ override for a known Codex event without a specialized handler, such as
378
+ `PreToolUse` or `PostToolUse`, pushes a short generic in-app row like
379
+ `Codex · PreToolUse · Bash`. Generic rows are queue/sidebar/statusbar only and
380
+ do not dispatch OS desktop notifications, `PROJMUX_NOTIFY_HOOK`, or
381
+ `[hooks.send-noti]`.
360
382
 
361
383
  `ingest claude-hook` is the hook-facing entrypoint for Claude Code hooks. It
362
384
  reads one JSON payload from stdin and handles the default Claude Code 2.1.140
@@ -378,6 +400,11 @@ push a queue entry.
378
400
  Unknown Claude events also fall back to quiet/log-only handling after pane
379
401
  matching. Catalog `action` is honored for quiet fallback events; notify/state
380
402
  actions need built-in handlers for event-specific body text and state changes.
403
+ Runtime action overrides from
404
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/ai-hook-actions.json` take
405
+ precedence over catalog `action` for known Claude events too; for example a
406
+ noisy notify event can be made state-only or quiet without changing installed
407
+ Claude hook commands.
381
408
 
382
409
  `ingest bell --pane <pane_id>` is the narrow tmux-bell fallback ingest path.
383
410
  It does not require the pane to be AI-managed. Projmux resolves session,
@@ -653,7 +680,7 @@ flags with the top-level `switch` UX:
653
680
  retention window.
654
681
  - `tag` — manage the tagged-selection set.
655
682
 
656
- ## current / shell / attach / settings
683
+ ## current / shell / attach / settings / quit
657
684
 
658
685
  - `current` — print `pane_current_path` for the active tmux pane (used
659
686
  by the shell jump binding).
@@ -666,6 +693,12 @@ flags with the top-level `switch` UX:
666
693
  snapshot`, and `Empty session` before creating a closed project session.
667
694
  `Latest snapshot` is auto-saved; named snapshots are fixed until the user
668
695
  saves or replaces them.
696
+ - `quit` — open an action picker with `Quit projmux` and `Cancel`. Selecting
697
+ `Quit projmux` terminates only a `tmux -L projmux` runtime whose global
698
+ `@projmux_app` option is set by the generated app config. Missing servers,
699
+ default tmux servers, embedded tmux servers, and other tmux runtimes without
700
+ that marker are no-ops. Non-interactive callers must pass `--yes` or
701
+ `--force`; the default command always goes through the action picker.
669
702
  - `attach auto [--keep=N] [--fallback=home|ephemeral]` — auto-attach to
670
703
  the most recent session, with bounded retention and a fallback policy.
671
704
  - `settings` — interactive configuration UI for the project picker, AI
@@ -686,9 +719,10 @@ flags with the top-level `switch` UX:
686
719
  available for experimental settings. The About section reads the cached
687
720
  update status without network access;
688
721
  selecting Check Updates runs `projmux update check`, and Update Now runs
689
- `projmux update apply`. The same About section also lists the keybinding
690
- diagnostic path: zero-config first, `setup` for swallowed keys, `init` for
691
- supported terminal fallbacks, and `doctor` for dependencies.
722
+ `projmux update apply`. `Settings > About > Quit projmux` routes through the
723
+ same `projmux quit` action picker. The same About section also lists the
724
+ keybinding diagnostic path: zero-config first, `setup` for swallowed keys,
725
+ `init` for supported terminal fallbacks, and `doctor` for dependencies.
692
726
 
693
727
  ## See also
694
728
 
@@ -156,6 +156,7 @@ configured key opens and closes the popup.
156
156
  | `TMUX_SESSIONIZER_ROOTS` | Legacy alias still honored at runtime for managed roots. |
157
157
  | `PROJMUX_NOTIFY_HOOK` | External executable that receives AI desktop notifications instead of the built-in Linux/WSL sender. Separate from declarative `[hooks.send-noti]`. |
158
158
  | `PROJMUX_NOTIFY_HOOK_DEPTH` | Internal recursion guard for `send-noti` hooks. Depth `>= 1` suppresses nested hook dispatch while still allowing the queue write itself. |
159
+ | `PROJMUX_NOTIFY_EXPIRE_MS` | AI desktop notification expiration in milliseconds. Defaults to `5000`; unset, zero, negative, and non-numeric values fall back to the default. |
159
160
  | `PROJMUX_DESKTOP_NOTIFY_MODE` | OS desktop notification mode override. `none` / `notify` / `raise` (case insensitive). When set, this takes priority over every other resolution rung. The in-app notify queue is not affected. |
160
161
  | `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. |
161
162
  | `PROJMUX_WSL_TOAST_ICON_DIR` | Directory used when copying the WSL toast icon into a Windows-readable path. |
@@ -205,7 +206,17 @@ This environment variable remains the imperative "replace desktop notification
205
206
  sender" escape hatch. It does not run through the declarative hook trust/config
206
207
  system and it does not receive the notify-queue JSON payload. For additive
207
208
  forwarding after a successful queue write, prefer `[hooks.send-noti]` in
208
- `config.toml`.
209
+ `config.toml`. The `urgency` argument is the OS notification urgency, not the
210
+ internal notify-queue severity; AI desktop notifications default to OS urgency
211
+ `normal` even when the statusbar, Alt-2, and persistent queue row remain
212
+ critical.
213
+
214
+ AI desktop notifications are transient by default. Linux `notify-send` receives
215
+ `--urgency=normal` and `--expire-time=${PROJMUX_NOTIFY_EXPIRE_MS:-5000}`. WSL
216
+ PowerShell Toasts use `duration="short"` and set `ExpirationTime` explicitly.
217
+ If WSL falls back to `wsl-notify-send.exe`, urgency and expiration are
218
+ best-effort because that adapter does not expose a stable equivalent for every
219
+ host setup.
209
220
 
210
221
  `[hooks.send-noti]` and `PROJMUX_NOTIFY_HOOK` can coexist:
211
222
 
@@ -221,6 +232,38 @@ the Linux `--app-name`, the macOS sender label, and the Windows
221
232
  ships with a one-shot Windows cleanup that removes the legacy Start Menu
222
233
  shortcut and registry entry the first time projmux runs.
223
234
 
235
+ AI desktop notifications collapse repeated pane-local notifications using a
236
+ seconds window. Resolution priority is:
237
+
238
+ 1. `PROJMUX_TMUX_NOTIFY_DEDUPE_SECONDS`
239
+ 2. Settings saved value at
240
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/ai-notify-dedupe-seconds`
241
+ 3. default `120`
242
+
243
+ Settings exposes this at `Settings > Notifications > AI notification dedupe`.
244
+ The value is stored as integer seconds and applies only to AI desktop
245
+ notification dispatch. The tmux bell fallback keeps its fixed 5 second
246
+ dedupe window.
247
+
248
+ AI hook runtime actions are stored at:
249
+
250
+ ```text
251
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/ai-hook-actions.json
252
+ ```
253
+
254
+ Settings exposes this at `Settings > Notifications > Hook quiet policy`.
255
+ The file maps provider/event names to `notify`, `state`, or `quiet` and
256
+ overrides catalog `action` values during ingest, including known Codex and
257
+ Claude events. It does not change hook installation; `projmux ai integrate`
258
+ continues to use the embedded/local catalog `install` fields.
259
+
260
+ Delivery depends on the event handler. Specialized notify handlers, such as
261
+ Codex `PermissionRequest` and `Stop`, can write the in-app notify queue and use
262
+ the configured OS desktop notification path. Known Codex events without a
263
+ specialized handler can be runtime-overridden to `notify`, but that creates
264
+ only a generic in-app queue/sidebar/statusbar row; it does not fire OS toast,
265
+ `notify-send`, `PROJMUX_NOTIFY_HOOK`, or `[hooks.send-noti]`.
266
+
224
267
  ### Desktop notification mode
225
268
 
226
269
  The OS-level dispatch carries three modes. The in-app notify queue, the
@@ -236,7 +279,7 @@ gated here.
236
279
 
237
280
  Click activation is wired only for `raise`. The `projmux://` URI handler is
238
281
  registered on the first `raise` Notify of each tmux server (gated by the
239
- `@projmux_uri_protocol_registered_v2` marker). The
282
+ `@projmux_uri_protocol_registered_v6` marker). The
240
283
  mode only controls whether a toast fires at all and whether to follow it
241
284
  up with an on-push auto-raise.
242
285
 
@@ -276,7 +319,16 @@ the first time a Toast is dispatched on each tmux server. Clicking the
276
319
  toast hands control back to projmux inside WSL via the registered command:
277
320
 
278
321
  ```text
279
- wsl.exe -d $WSL_DISTRO_NAME --exec <absolute-path-to-projmux> focus --uri "%1"
322
+ wscript.exe //B //Nologo "%LOCALAPPDATA%\projmux\projmux-uri-handler.vbs" "%1"
323
+ ```
324
+
325
+ Registration writes the VBScript launcher under `%LOCALAPPDATA%\projmux`.
326
+ The launcher receives `%1` as a WScript argument, caret-escapes command-line
327
+ metacharacters such as `&`, and starts a hidden `%ComSpec% /d /s /c` command
328
+ that invokes `wsl.exe`. Its argv semantics are equivalent to:
329
+
330
+ ```text
331
+ wsl.exe -d $WSL_DISTRO_NAME --exec <absolute-path-to-projmux> focus --uri <uri>
280
332
  ```
281
333
 
282
334
  For click activation to work in our unpackaged Win32 setup, four
@@ -298,13 +350,17 @@ notify path so users do not configure anything:
298
350
  silently quarantines such shortcuts moments after creation, which
299
351
  leaves no AppID-tagged shortcut and breaks both the routing and the
300
352
  click path. `cmd.exe /c exit` is treated as benign and survives.
301
- 4. The WSL handler command uses `--exec`, not `--`. `wsl.exe -- <cmd>`
302
- routes its tail through the user's login shell, which parses `&`
303
- query-string separators as background-job operators (zsh emits
304
- `parse error near '&'`). `--exec` skips the shell and invokes the
305
- binary directly. The absolute WSL filesystem path to the binary is
306
- captured at registration so PATH does not need to be populated under
307
- `--exec`.
353
+ 4. The WSL handler uses a WScript launcher instead of launching `wsl.exe` or
354
+ `powershell.exe` directly, avoiding the transient Windows console flash on
355
+ Toast click. Inside that launcher it still uses `--exec`, not `--`.
356
+ `wsl.exe -- <cmd>` routes its tail through the user's login shell, which
357
+ parses `&` query-string separators as background-job operators (zsh emits
358
+ `parse error near '&'`). `--exec` skips the shell and invokes the binary
359
+ directly. The `%1` URI is passed as a WScript argument and then forwarded
360
+ through a hidden cmd.exe command line with `&` escaped as `^&`, so query
361
+ separators are data instead of PowerShell, cmd, or WSL login-shell syntax.
362
+ The absolute WSL filesystem path to the binary is captured at registration
363
+ so PATH does not need to be populated under `--exec`.
308
364
 
309
365
  The URI carries the originating pane id and tmux socket so the click
310
366
  round-trips back to the exact pane that fired the notification, which
@@ -315,12 +371,15 @@ Registration markers and the writes involved:
315
371
  - Registry keys (HKCU): `SOFTWARE\Classes\projmux\(Default)`,
316
372
  `SOFTWARE\Classes\projmux\URL Protocol`, and
317
373
  `SOFTWARE\Classes\projmux\shell\open\command\(Default)`.
318
- - tmux user-option marker `@projmux_uri_protocol_registered_v2` records that
374
+ - Launcher file: `%LOCALAPPDATA%\projmux\projmux-uri-handler.vbs`.
375
+ - tmux user-option marker `@projmux_uri_protocol_registered_v6` records that
319
376
  registration has been attempted on this server so the script runs at most
320
- once per server boot. (The v1 marker `@projmux_uri_protocol_registered`
321
- was bumped when the registry command switched to `--exec`; existing v1
322
- users re-register transparently on the next Notify after upgrade and the
323
- orphaned v1 key requires no cleanup.)
377
+ once per server boot. (The v5 marker
378
+ `@projmux_uri_protocol_registered_v5` was bumped when the WScript launcher
379
+ added the hidden cmd.exe parser hop; existing v5 users re-register
380
+ transparently on the next Notify after upgrade. After successful v6
381
+ registration, projmux removes legacy URI marker keys from v1 through v5 so
382
+ tmux state reflects only the active handler generation.)
324
383
 
325
384
  Limitations:
326
385
 
@@ -456,7 +515,7 @@ These are intended for debugging or local policy, not routine setup:
456
515
 
457
516
  | Variable | Purpose |
458
517
  | --- | --- |
459
- | `PROJMUX_TMUX_NOTIFY_DEDUPE_SECONDS` | Collapse window for duplicate AI notifications keyed on `(summary, tag)`. |
518
+ | `PROJMUX_TMUX_NOTIFY_DEDUPE_SECONDS` | Override the Settings/default collapse window for duplicate AI desktop notifications keyed on the pane-local AI notification key. |
460
519
  | `PROJMUX_CODEX_TITLE_WATCH_INTERVAL` | Title-watch loop pacing for Codex panes. |
461
520
  | `PROJMUX_CODEX_REPLY_SETTLE_LOOPS` | Reply-detection settle-loop pacing for Codex panes. |
462
521
  | `TMUX_KUBE_CACHE_TTL` | Kubernetes status segment cache TTL. |
package/docs/hooks.md CHANGED
@@ -199,6 +199,13 @@ Claude, and tmux AI notify diagnostics: status, conflicts, config paths, and
199
199
  copyable CLI install/remove/dry-run commands. It does not install or remove
200
200
  external Codex, Claude, or tmux settings.
201
201
 
202
+ `PROJMUX_NOTIFY_HOOK` is separate from `[hooks.send-noti]`: it replaces the
203
+ desktop sender and receives positional arguments
204
+ `summary body urgency app-name tag group icon-path`. That `urgency` value is
205
+ the OS notification urgency, not the notify-queue severity. AI approval,
206
+ input, selection, and confirmation rows can stay critical in the queue and UI
207
+ while the desktop notification hook receives `normal`.
208
+
202
209
  ## Codex Hooks Engine
203
210
 
204
211
  `projmux doctor` reports Codex hooks-engine wiring separately from legacy
@@ -325,6 +332,27 @@ catalog `"action": "quiet"` makes that quiet fallback explicit. Catalog
325
332
  `"notify"` and `"state"` entries still need a built-in handler before they can
326
333
  push queue rows or change pane state.
327
334
 
335
+ Runtime action overrides are stored separately from the install catalog at:
336
+
337
+ ```text
338
+ ${XDG_CONFIG_HOME:-$HOME/.config}/projmux/ai-hook-actions.json
339
+ ```
340
+
341
+ `Settings > Notifications > Hook quiet policy` reads and writes that file. The
342
+ runtime file only changes ingest behavior (`notify`, `state`, or `quiet`);
343
+ `projmux ai integrate codex` still uses the catalog `install` field to decide
344
+ which hooks to write. Runtime overrides also apply to known specialized
345
+ events, so `Stop` or `PermissionRequest` can be made state-only or quiet
346
+ without changing which hook commands are installed. When a known Codex event
347
+ without a specialized handler, such as `PreToolUse` or `PostToolUse`, is set to
348
+ runtime `notify`, projmux pushes a generic in-app notify row such as
349
+ `Codex · PreToolUse · Bash`. That generic path is queue/sidebar/statusbar only:
350
+ it does not dispatch `[hooks.send-noti]`, `PROJMUX_NOTIFY_HOOK`, `notify-send`,
351
+ or Windows toast.
352
+ Generic metadata is limited to safe summary fields such as provider, event,
353
+ tool, cwd, thread, session, turn, and model; raw payloads and tool input are
354
+ not stored.
355
+
328
356
  Codex may require reviewing or trusting hooks through its `/hooks` flow before
329
357
  commands run. Projmux only writes the managed config block; it does not attempt
330
358
  to auto-trust hooks.
@@ -420,7 +448,10 @@ fire at high volume.
420
448
  Pane matching follows the shared AI ingest order: inherited `$TMUX_PANE`, then
421
449
  payload `cwd`, then cached session id pane options. A matched pane is marked
422
450
  with `@projmux_ai_hook_active=1`, so `projmux ai watch-title` skips the pane
423
- and hook payloads become the primary signal.
451
+ after a minimal hook-active gate instead of polling pane title/capture output;
452
+ hook payloads become the primary signal. The tmux bell fallback does not mark
453
+ panes hook-active, so title/capture fallback remains available for panes that
454
+ only emit bells.
424
455
 
425
456
  The Claude hook payload is intentionally accepted directly at the ingest
426
457
  boundary. Core identity fields accept `hook_event_name`/`event_name`,
@@ -558,11 +589,16 @@ and ingest debugging only.
558
589
  ```
559
590
 
560
591
  Claude ingest has built-in notify/state handlers for the known completion,
561
- notification, approval, prompt-submit, error, and teammate-idle events. Events
562
- without a specialized handler, including unknown future events, are
563
- quiet/log-only after pane matching. Catalog `"action": "quiet"` is used for
592
+ notification, approval, prompt-submit, error, subagent-stop, and teammate-idle
593
+ events. Events without a specialized handler, including unknown future events,
594
+ are quiet/log-only after pane matching. Catalog `"action": "quiet"` is used for
564
595
  that fallback; catalog `"notify"` and `"state"` entries still need built-in
565
- handler code for event-specific queue rows or state transitions.
596
+ handler code for event-specific queue rows or state transitions. Runtime action
597
+ overrides live in the same
598
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/ai-hook-actions.json` file used by
599
+ Codex and are managed from `Settings > Notifications > Hook quiet policy`.
600
+ They only affect ingest delivery; `projmux ai integrate claude` still uses the
601
+ catalog `install` field for installed hook events.
566
602
 
567
603
  ## Ingest Debug Log
568
604
 
@@ -80,6 +80,13 @@ These open the projmux popups and the sidebar. No prefix needed.
80
80
  When a pane closes, projmux re-spreads remaining panes so the surviving split
81
81
  does not stretch lopsided.
82
82
 
83
+ The AI split bindings use the configured default mode. For one-shot launches,
84
+ run `projmux ai split --agent claude|codex|shell|selective right|down`. Extra
85
+ args after `--` are appended to the resolved `claude` or `codex` executable for
86
+ a managed pane. To register user-level skills, slash commands, editor actions,
87
+ or launcher shortcuts that call those one-shot launches, see
88
+ [AI Agent Shortcuts](ai-agent-shortcuts.md).
89
+
83
90
  ### Inside the pickers
84
91
 
85
92
  | Surface | Shortcut | Action |
@@ -279,8 +279,10 @@ carries a `launch="projmux://focus?..." activationType="protocol"`
279
279
  attribute, and the first dispatch of a tmux server boot registers the
280
280
  `projmux://` scheme in `HKCU\SOFTWARE\Classes\projmux\…` so Windows
281
281
  routes the click to
282
- `wsl.exe -d <distro> --exec <abs-path> focus --uri "%1"`. Inside WSL,
283
- `projmux focus --uri` parses the URI, resolves the pane id to its
282
+ `powershell.exe -NoProfile -WindowStyle Hidden ... "%1"`. That hidden
283
+ launcher starts `wsl.exe -d <distro> --exec <abs-path> focus --uri <uri>`
284
+ without routing the URI through a shell. Inside WSL, `projmux focus --uri`
285
+ parses the URI, resolves the pane id to its
284
286
  `session:window.%paneID` target via `tmux display-message`, and reuses
285
287
  the existing focus dispatch. This closes the previously-deferred (a)
286
288
  on-push trigger mode in the Windows-only scope: the toast becomes the
@@ -325,13 +327,20 @@ machine is:
325
327
  leaves no AppID-tagged shortcut at all and breaks both the toast
326
328
  routing and (since the AppID has to be live when the toast fires) the
327
329
  click path. `cmd.exe /c exit` is benign and survives.
328
- 4. **WSL handler command uses `--exec` not `--`**. `wsl.exe -- <cmd>`
329
- routes its tail through the user's default login shell, which parses
330
- `&` query-string separators as background-job operators (zsh emits
331
- `parse error near '&'`). `--exec` skips the shell and invokes the
332
- binary directly. PATH is empty under `--exec`, so the registry
333
- command uses the absolute WSL filesystem path captured at registration
334
- time.
330
+ 4. **WSL handler command uses a GUI launcher and keeps `--exec`**. The
331
+ registry protocol handler launches `wscript.exe //B //Nologo` with a
332
+ VBScript launcher written under `%LOCALAPPDATA%\projmux`, so ShellExecute
333
+ does not start a console-subsystem first process. The launcher starts a
334
+ hidden `%ComSpec% /d /s /c` command through `WScript.Shell.Run`; that cmd
335
+ command invokes `wsl.exe` after stripping caret escapes from URI query
336
+ separators. Inside that command, `wsl.exe -- <cmd>` remains forbidden
337
+ because it routes its tail through the user's default login shell, which
338
+ parses `&` query-string separators as background-job operators (zsh emits
339
+ `parse error near '&'`). `--exec` skips the shell and invokes the binary
340
+ directly. PATH is empty under `--exec`, so the registry command uses the
341
+ absolute WSL filesystem path captured at registration time. The `%1` URI is
342
+ passed as a WScript argument and then forwarded as the `--uri` argv value,
343
+ not shell-interpolated.
335
344
 
336
345
  #### Lessons (so future readers don't repeat them)
337
346
 
@@ -345,10 +354,12 @@ machine is:
345
354
  - Do not use `wsl.exe -- projmux ...` in the registry handler.
346
355
  Re-introducing the login-shell hop will surface as `parse error near
347
356
  '&'` from the user's shell at click time.
348
- - The `@projmux_uri_protocol_registered_v2` marker exists because the
349
- v1 marker came before the `--exec` fix. Re-registration is idempotent
350
- so upgrades from v1 transparently install the new handler the old
351
- marker key just goes orphaned.
357
+ - The `@projmux_uri_protocol_registered_v6` marker exists because v5 invoked
358
+ `wsl.exe` directly from WScript with quoted fixed arguments, which avoided
359
+ flash but broke the focus command. Re-registration is idempotent so upgrades
360
+ from v5 transparently install the new handler. Once v6 registration
361
+ succeeds, projmux removes the legacy URI marker keys from v1 through v5 so
362
+ old handler generations do not linger in tmux state.
352
363
 
353
364
  Multi-distro dispatch (one handler per distro, or a distro-selector
354
365
  arg) is a known tier-2 follow-up — current registration captures the
@@ -94,11 +94,14 @@ preserves the stable JSON array used by scripts.
94
94
 
95
95
  `--ui=sidebar` opens the notify queue as an interactive right-side list when
96
96
  run inside the tmux popup surface. Enter focuses the selected target pane and
97
- acks the row after focus succeeds. `x` acks the selected row. `Ctrl-X` clears
98
- all rows via `notify ack --all`. Rows are intentionally compact: the visible
99
- label keeps notification text first, then age, project, window, and pane
100
- metadata; hidden queue ids remain action values but the sidebar has no search
101
- input and intentionally does not expose a separate metadata detail view.
97
+ acks the row after focus succeeds. `x` acks the selected row in place, keeps
98
+ the sidebar open, and refreshes the list from the queue while preserving the
99
+ selection position where possible; acking the last remaining row renders the
100
+ empty state until the popup is closed. `Ctrl-X` clears all rows via `notify ack
101
+ --all` and exits. Rows are intentionally compact: the visible label keeps
102
+ notification text first, then age, project, window, and pane metadata; hidden
103
+ queue ids remain action values but the sidebar has no search input and
104
+ intentionally does not expose a separate metadata detail view.
102
105
 
103
106
  `--live` adds a non-mutating explanation view that reads
104
107
  `tmux list-panes -a` and compares the queue with live reply-state panes. It
@@ -213,13 +216,24 @@ client selection policy.
213
216
 
214
217
  Outcomes:
215
218
 
216
- - **Focus succeeded** — ack the entry. Focus is the single consume path for
217
- routed notification clicks.
219
+ - **Focus succeeded** — ack the selected entry, even when it is critical.
220
+ Then bulk-ack older same-session/same-pane non-critical AI rows. Bulk cleanup
221
+ never consumes `critical`, permission-request, stop-failure, `external`,
222
+ `git`, or `k8s` rows; those remain pending unless the user selected that row
223
+ directly.
218
224
  - **Focus exited 2 (target unresolved)** — ack the entry and toast
219
225
  `notify target gone; cleared`.
220
226
  - **Other failure** — keep the entry, toast `focus failed: <reason>`
221
227
  so the user can retry without losing the row.
222
228
 
229
+ The same consume policy is shared by notify-sidebar Enter and OS
230
+ click-to-focus Toast callbacks after a real tmux focus dispatch succeeds.
231
+ Pane focus hooks and attention clear paths remain live-attention-only and do
232
+ not ack the notify queue. Non-critical AI completion producers also compact
233
+ older same-pane non-critical AI rows after replacing/pushing their latest row,
234
+ so reply-ready/stop/bell-style completion rows stay latest-state centered
235
+ without changing the queue schema or TTL contract.
236
+
223
237
  The handler never returns a non-zero error to tmux's `run-shell`; every
224
238
  failure becomes a `display-message` toast so a transient miss does not
225
239
  trigger a tmux error popup.
@@ -0,0 +1,97 @@
1
+ # README Hero GIF Recording
2
+
3
+ This recipe records the README hero GIF:
4
+
5
+ - `docs/assets/projmux-ai-attention.gif`
6
+
7
+ The maintained recorder is kept in the local dotfiles checkout at:
8
+
9
+ ```sh
10
+ /home/es5h/dotfiles/bin/projmux/projmux-record-readme-gifs.py
11
+ ```
12
+
13
+ ## Prerequisites
14
+
15
+ Install or verify these local tools before recording:
16
+
17
+ - `python3`
18
+ - `git`
19
+ - `tmux`
20
+ - `ffmpeg` and `ffprobe`
21
+ - `Xvfb`
22
+ - `openbox`
23
+ - `ghostty`
24
+ - `xdotool`
25
+ - `xwininfo`
26
+ - `script` from util-linux
27
+ - authenticated `codex`
28
+
29
+ Build the local projmux binary first:
30
+
31
+ ```sh
32
+ make build
33
+ ```
34
+
35
+ The script expects `.bin/projmux` by default. Override paths only when needed:
36
+
37
+ ```sh
38
+ PROJMUX_RECORD_REPO=/path/to/projmux \
39
+ PROJMUX_RECORD_BIN=/path/to/projmux \
40
+ PROJMUX_RECORD_DISPLAY=117 \
41
+ PROJMUX_RECORD_SCREEN=2560x1440x24 \
42
+ PROJMUX_RECORD_KEEP_TMP=1 \
43
+ python3 /home/es5h/dotfiles/bin/projmux/projmux-record-readme-gifs.py
44
+ ```
45
+
46
+ For the normal checkout, run:
47
+
48
+ ```sh
49
+ python3 /home/es5h/dotfiles/bin/projmux/projmux-record-readme-gifs.py
50
+ ```
51
+
52
+ ## Scenario Contract
53
+
54
+ The recording uses a private demo home, XDG config/state dirs, demo git
55
+ projects, and an isolated `CODEX_HOME`. It copies the local Codex auth/config
56
+ into that isolated home, trusts the demo projects/hooks, and seeds usage cache
57
+ data so the tmux status line shows the Codex HUD during the capture.
58
+
59
+ The scenario records the AI attention flow:
60
+
61
+ 1. Start in `mobile-client` with no pending notification.
62
+ 2. Open the AI picker and launch a real Codex pane.
63
+ 3. Ask Codex to do a short task.
64
+ 4. Use the projmux sessionizer sidebar to move to `atlas-api`.
65
+ 5. Keep working in zsh while Codex finishes in the previous project.
66
+ 6. When the Codex completion notification exists, open the notification sidebar.
67
+ 7. Select the notification and return focus to the original Codex pane.
68
+
69
+ ## Visual Guardrails
70
+
71
+ - Keep the native picker UI native. The script runs picker commands through
72
+ `script(1)` with a fixed PTY size so fzf/terminal UI rendering is captured
73
+ instead of degraded line-mode output.
74
+ - Keep the terminal in zsh with the demo prompt so the project and git branch
75
+ are visible.
76
+ - Keep the Codex usage HUD visible in the tmux status line.
77
+ - Use the sessionizer sidebar for project movement in 4a.
78
+ - Capture the Ghostty X11 window geometry with `xwininfo` and feed that exact
79
+ rectangle to ffmpeg. This prevents the GIF from drifting away from `(0, 0)`.
80
+
81
+ ## Verification
82
+
83
+ After recording, inspect the resulting streams:
84
+
85
+ ```sh
86
+ ffprobe -v error -select_streams v:0 \
87
+ -show_entries stream=width,height,nb_frames,duration \
88
+ -of default=noprint_wrappers=1 \
89
+ docs/assets/projmux-ai-attention.gif
90
+ ```
91
+
92
+ Expected final shape is roughly 1110px wide and about 16-18 seconds, with the
93
+ native picker, zsh prompt, Codex pane, notification sidebar, and usage HUD
94
+ visible in the relevant frames.
95
+
96
+ Set `PROJMUX_RECORD_KEEP_TMP=1` when you need to inspect intermediate MP4s,
97
+ Ghostty logs, or palette files under `/tmp/projmux-readme-record-*`.
@@ -38,6 +38,17 @@ unknown sources are low or none. The old statusbar Session State shortcut has
38
38
  been removed; use `Projects > Sessions > State` or the `projmux session-state`
39
39
  CLI for inspection/actions.
40
40
 
41
+ Agent restore direct-starts supported resume commands when creating fresh tmux
42
+ panes, matching the `projmux ai split` wrapper shape: the wrapper prepends the
43
+ agent binary directory to `PATH`, changes to the saved cwd, sets the terminal
44
+ and tmux pane title from the saved agent topic, then execs `codex resume <id>`
45
+ or `claude --resume <id>`. This avoids typing agent resumes with
46
+ `tmux send-keys`. The restore wrapper is still a non-interactive shell command
47
+ tail, so it does not replay the original pane's interactive shell startup,
48
+ environment, shell functions, aliases, or live process state. Startup recipes
49
+ continue to use their saved `send-keys` command replay, and shell recipes only
50
+ restore cwd/layout.
51
+
41
52
  Settings > Session State is global settings only: global auto-save, auto-save
42
53
  interval, and storage/retention policy. It does not show the current
43
54
  snapshot tree. Delete for current-session snapshots and destructive restore
@@ -18,16 +18,25 @@ view-first layout:
18
18
  - `Settings > Keybindings` is the single entry point for keybinding work. The
19
19
  page is split into four chips: `Bindings`, `Diagnostic`, `Probe`, and `Init`.
20
20
  - `Settings > Notifications` owns notification delivery IA. Desktop notification
21
- mode, delivery source diagnostics, in-app queue status, and
21
+ mode, AI desktop notification dedupe duration, delivery source diagnostics,
22
+ AI hook quiet policy, in-app queue status, and
22
23
  `PROJMUX_NOTIFY_HOOK` visibility live together without mixing mutation
23
24
  boundaries.
24
25
  - `Settings > Notifications > Desktop notifications` owns the desktop
25
26
  notification mode. The detail choices are `none`, `notify`, and `raise`.
27
+ - `Settings > Notifications > AI notification dedupe` owns the duplicate
28
+ desktop AI notification collapse window. It stores integer seconds and shows
29
+ the effective source; `PROJMUX_TMUX_NOTIFY_DEDUPE_SECONDS` remains the top
30
+ override. The tmux bell fallback keeps its fixed 5 second window.
26
31
  - `Settings > Notifications > Delivery sources` shows Codex hooks, Claude, and
27
32
  tmux producer diagnostics plus copyable install/remove/dry-run commands.
28
33
  Settings copies command text only; it does not install or remove external
29
34
  notify wiring. The legacy Codex notify source is intentionally omitted from
30
35
  Settings.
36
+ - `Settings > Notifications > Hook quiet policy` shows Codex/Claude hook
37
+ runtime action values and writes only
38
+ `${XDG_CONFIG_HOME:-$HOME/.config}/projmux/ai-hook-actions.json`. It does not
39
+ edit catalog `install` values or run agent install/remove commands.
31
40
  - `Settings > Labs` keeps experimental toggles, but keybindings no longer have a
32
41
  visible Labs row. The hidden compatibility action still redirects to the
33
42
  unified Keybindings page.
@@ -42,9 +51,9 @@ view-first layout:
42
51
  such as `Set startup command...`, `Clear startup command`, kube edits, and env
43
52
  add/remove rows live inside those details.
44
53
  - `Settings > Appearance` is view-first. The root opens `Path icon`, `Git icon`,
45
- and `Notify icon` details. Each detail shows the current mode and off/symbol/
46
- emoji rendered previews first, and its `Change` page contains only the
47
- off/symbol/emoji mutation choices.
54
+ and `Notify icon` details. Each detail shows the current mode plus
55
+ immediately selectable off/symbol/emoji preview rows. There is no separate
56
+ `Change` page for icon decoration.
48
57
 
49
58
  Hooks remain the reference pattern for this IA:
50
59
 
package/docs/statusbar.md CHANGED
@@ -75,6 +75,13 @@ The notify segment renders the newest queued item as a single notification
75
75
  block: project, state (`NEED`/`INFO`/`WARN`/`CRIT`), optional agent, text,
76
76
  age, and `+N` for older pending entries. Window/pane ids are not shown in the
77
77
  compact status segment.
78
+ When the notify block is wider than its cell budget, clipping shrinks the body
79
+ text first and appends an ellipsis while preserving project, state, agent, age,
80
+ and count metadata. If the segment is still too wide, the age is dropped next
81
+ while badges and the `+N` count stay visible when possible. Very narrow widths
82
+ fall back to the severity-colored dot plus clipped text and count; the final
83
+ hard-truncate path still closes with `#[default]` so later status segments do
84
+ not inherit notification styling.
78
85
  `usage` opens a native-framed detail HUD for the compact usage bar. It reads
79
86
  the cached usage state in-process, keeps the existing `projmux usage` CLI
80
87
  output shape unchanged for external consumers, aligns model/window rows with
@@ -96,7 +103,10 @@ needed, and colors that sync line amber once it is more than 60 seconds old.
96
103
  The notification HUD detail surface (`Alt-2` / `User2`) opens the right-side
97
104
  notification popup with newest-first rows and an amber title. When notification
98
105
  icon decoration is `symbol` or `emoji`, the bell appears before the title text.
99
- Selecting a row still focuses and acknowledges that notification.
106
+ Selecting a row still focuses and acknowledges that notification. Pressing `x`
107
+ on a row acknowledges it without focusing, keeps the popup open, and refreshes
108
+ the remaining rows from the queue while preserving the selection position where
109
+ possible.
100
110
 
101
111
  Empty `#{mouse_status_range}` (a click on whitespace) falls through to
102
112
  `select-window -t @<mouse_window>` when `--mouse-window` is non-empty,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projmux",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "tmux project session manager",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/crevissepartners/projmux#readme",
@@ -24,10 +24,10 @@
24
24
  "LICENSE"
25
25
  ],
26
26
  "optionalDependencies": {
27
- "@projmux/darwin-arm64": "0.6.1",
28
- "@projmux/darwin-x64": "0.6.1",
29
- "@projmux/linux-arm64": "0.6.1",
30
- "@projmux/linux-x64": "0.6.1"
27
+ "@projmux/darwin-arm64": "0.6.2",
28
+ "@projmux/darwin-x64": "0.6.2",
29
+ "@projmux/linux-arm64": "0.6.2",
30
+ "@projmux/linux-x64": "0.6.2"
31
31
  },
32
32
  "scripts": {
33
33
  "package:npm": "scripts/package-npm.sh",