projmux 0.4.4 → 0.4.6
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 +58 -269
- package/README.md +57 -259
- package/docs/agent-workflow.md +56 -0
- package/docs/architecture.md +199 -0
- package/docs/assets/projmux-icon.png +0 -0
- package/docs/assets/projmux-shell-sidebar.gif +0 -0
- package/docs/cli.md +429 -0
- package/docs/configuration.md +127 -0
- package/docs/hooks.md +118 -0
- package/docs/install.md +99 -0
- package/docs/keybindings.md +337 -0
- package/docs/migration-plan.md +82 -0
- package/docs/notify-queue.md +199 -0
- package/docs/npm-distribution.md +86 -0
- package/docs/picker-ui-plan.md +111 -0
- package/docs/pr-guideline.md +106 -0
- package/docs/repo-layout.md +50 -0
- package/docs/roadmap.md +95 -0
- package/docs/shell-autostart.md +33 -0
- package/docs/statusbar.md +151 -0
- package/docs/testing.md +57 -0
- package/docs/upgrading.md +100 -0
- package/docs/usage-tracking.md +153 -0
- package/package.json +7 -5
package/docs/cli.md
ADDED
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
# CLI Reference
|
|
2
|
+
|
|
3
|
+
Every subcommand exposed by the `projmux` binary as of v0.4.0. Run
|
|
4
|
+
`projmux help` for the live top-level list, or `projmux <cmd> --help` /
|
|
5
|
+
`projmux <cmd> help` for the per-command usage string.
|
|
6
|
+
|
|
7
|
+
Exit codes:
|
|
8
|
+
|
|
9
|
+
- `0` — success.
|
|
10
|
+
- `1` — runtime failure.
|
|
11
|
+
- `2` — usage error (unknown flag, bad enum, missing required flag) or a
|
|
12
|
+
deterministic semantic exit (e.g. `focus` cannot resolve the target).
|
|
13
|
+
|
|
14
|
+
## Top-level
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
projmux <command> [args...]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
| Command | Purpose |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| `ai` | Manage tmux AI splits (Codex/Claude) and per-pane status. |
|
|
23
|
+
| `attention` | View and manage live tmux pane attention state. |
|
|
24
|
+
| `attach` | Open tmux lifecycle entry helpers. |
|
|
25
|
+
| `current` | Resolve the active tmux pane path. |
|
|
26
|
+
| `doctor` | Diagnose runtime dependencies. |
|
|
27
|
+
| `focus` | Switch the active client to a session/window/pane target. |
|
|
28
|
+
| `init` | Apply supported terminal keybinding fallbacks. |
|
|
29
|
+
| `kill` | Terminate tagged tmux sessions. |
|
|
30
|
+
| `notify` | Manage the pending AI notify queue (push/list/ack/reconcile). |
|
|
31
|
+
| `pin` | Manage pinned project directories. |
|
|
32
|
+
| `preview` | Manage persisted tmux preview selection. |
|
|
33
|
+
| `prune` | Trim stale tmux lifecycle state. |
|
|
34
|
+
| `sessions` | Pick and open an existing tmux session. |
|
|
35
|
+
| `session-popup` | Read tmux popup preview state. |
|
|
36
|
+
| `settings` | Configure projmux. |
|
|
37
|
+
| `setup` | Probe terminal key delivery for projmux bindings. |
|
|
38
|
+
| `shell` | Open the isolated projmux tmux app. |
|
|
39
|
+
| `status` | Render tmux status bar segments. |
|
|
40
|
+
| `statusbar` | Dispatch projmux status bar clicks and shortcuts. |
|
|
41
|
+
| `switch` | Pick and open a project tmux session. |
|
|
42
|
+
| `tag` | Manage tagged tmux sessions. |
|
|
43
|
+
| `tmux` | Open tmux popup entry helpers / install generated config. |
|
|
44
|
+
| `update` | Check installer-aware GitHub release update status. |
|
|
45
|
+
| `upgrade` | Self-update via `go install`. |
|
|
46
|
+
| `usage` | Report AI token usage across 5h and weekly windows. |
|
|
47
|
+
| `version` | Print the current version. |
|
|
48
|
+
|
|
49
|
+
## switch
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
projmux switch [path]
|
|
53
|
+
projmux switch toggle-tag | toggle-pin | kill | settings | preview
|
|
54
|
+
projmux switch cycle-pane | cycle-window | sidebar-focus
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Project picker. With no positional argument, opens the fzf-driven popup or
|
|
58
|
+
sidebar (depending on entry helper). With a path, jumps directly. The
|
|
59
|
+
sub-verbs are entry hooks invoked by tmux keybindings (e.g.
|
|
60
|
+
`sidebar-focus` is wired to the sidebar's focus binding so navigation keeps
|
|
61
|
+
the active session in sync).
|
|
62
|
+
|
|
63
|
+
`PROJMUX_PICKER_BACKEND=native` opts the switcher into the experimental native
|
|
64
|
+
picker backend. fzf remains the default and the only backend with full preview
|
|
65
|
+
pane, sidebar focus, and key-action parity. Native currently provides
|
|
66
|
+
multiline card rendering, title-focused search, numeric selection, and the
|
|
67
|
+
shared close-action contract.
|
|
68
|
+
|
|
69
|
+
## setup
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
projmux setup [--timeout DURATION] [--non-interactive]
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Probes which projmux key sequences (`Alt-1..5`, `Ctrl-N`, `Ctrl-Shift-{R,L,M}`,
|
|
76
|
+
`Ctrl-M`, `Alt-Shift-{Left,Right}`) reach this process and which the
|
|
77
|
+
terminal swallows. Reports `plain`, `csi-u`, `unknown`, or `timeout` for
|
|
78
|
+
each. `--non-interactive` skips the TTY probe and prints the expected key
|
|
79
|
+
map. Default `--timeout` is `5s`. Run it outside tmux after trying
|
|
80
|
+
`projmux shell`; keys reported as `plain` or `csi-u` already work with zero
|
|
81
|
+
terminal config.
|
|
82
|
+
|
|
83
|
+
## init
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
projmux init [terminal] [--apply | --dry-run] [--config <path>]
|
|
87
|
+
[--allow-symlink]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Applies a terminal-specific fallback for shortcuts that `projmux setup`
|
|
91
|
+
reports as swallowed. When `terminal` is omitted, autodetects from
|
|
92
|
+
`$TERM_PROGRAM`/`$TERMINAL_EMULATOR`.
|
|
93
|
+
Known terminals: `ghostty`, `windows-terminal`. Default is dry-run; pass
|
|
94
|
+
`--apply` to write (timestamped `.bak.<timestamp>` is created). Refuses to
|
|
95
|
+
write through a symlink unless `--allow-symlink` is passed (dotfiles repos).
|
|
96
|
+
`--config <path>` overrides the candidate list when the adapter has more
|
|
97
|
+
than one default location (Ghostty `config` vs `config.ghostty`). If setup
|
|
98
|
+
shows every key arriving, skip init.
|
|
99
|
+
|
|
100
|
+
## doctor
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
projmux doctor [--json]
|
|
104
|
+
projmux doctor --install-missing [--dry-run] [--include-optional]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Runs a dependency check: `tmux ≥ 3.4`, `fzf ≥ 0.65.0`, `git`, `stty` (POSIX
|
|
108
|
+
only), and `kubectl` (optional). Exit code `0` even when optional deps are
|
|
109
|
+
missing; non-zero only when a required dep is missing or stale. `--json`
|
|
110
|
+
emits a machine-readable array; the default is the human report with
|
|
111
|
+
suggested install commands per platform. `--install-missing` is explicit
|
|
112
|
+
opt-in and runs generated install commands only for missing or stale required
|
|
113
|
+
dependencies. `--dry-run` prints those commands without executing them.
|
|
114
|
+
`--include-optional` also includes optional missing dependencies such as
|
|
115
|
+
`kubectl` when an install command is available. Install flags cannot be
|
|
116
|
+
combined with `--json`. Doctor does not diagnose terminal key delivery; use
|
|
117
|
+
`projmux setup` for that. For fzf, doctor requires the junegunn/fzf CLI
|
|
118
|
+
executable on `PATH` to report at least 0.65.0 from `fzf --version`; the npm
|
|
119
|
+
package `fzf` is a JavaScript library and is not a valid CLI install path for
|
|
120
|
+
projmux.
|
|
121
|
+
|
|
122
|
+
## focus
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
projmux focus --target SESSION[:WINDOW[.PANE]] [--socket <path>]
|
|
126
|
+
[--source ai|status-bar|external|os-notification]
|
|
127
|
+
[--kind reply-ready|busy-cleared|segment-click|custom]
|
|
128
|
+
[--json]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Unified switch-client dispatch. Resolves the session against the live tmux
|
|
132
|
+
inventory (with prefix/fuzzy fallback), then redirects one suitable attached
|
|
133
|
+
client on the selected socket. It never force-detaches other clients. If no
|
|
134
|
+
client is attached on that socket, it emits the configured desktop
|
|
135
|
+
notification instead. `--socket` is explicit; when omitted, the socket is
|
|
136
|
+
derived from `$TMUX`.
|
|
137
|
+
|
|
138
|
+
Exit codes:
|
|
139
|
+
|
|
140
|
+
- `0` — focused (or the notify-only fallback fired).
|
|
141
|
+
- `2` — target session could not be resolved (`focusExitNotResolved`).
|
|
142
|
+
|
|
143
|
+
`--source`/`--kind` are telemetry labels logged when
|
|
144
|
+
`PROJMUX_FOCUS_DEBUG` is set. `--json` prints a single-line JSON payload
|
|
145
|
+
with `{ok, fallback, target, socket, resolved_session, client, dispatch,
|
|
146
|
+
session_state, window_state, pane_state, reason, note}`. Callers can
|
|
147
|
+
distinguish unresolved sessions (`reason=session-unresolved`, exit 2),
|
|
148
|
+
session rename/prefix fallback (`session_state=fallback`), window index
|
|
149
|
+
fallback (`window_state=index-fallback-session`), pane index fallback
|
|
150
|
+
(`pane_state=index-fallback-window`), and explicit id failures
|
|
151
|
+
(`window-id-unresolved` / `pane-id-unresolved`).
|
|
152
|
+
|
|
153
|
+
## notify
|
|
154
|
+
|
|
155
|
+
Pending AI notify queue. `attention` is live tmux pane state; `notify` is
|
|
156
|
+
the explicit-ack pending notification source of truth used by the status-bar
|
|
157
|
+
notify segment and notify sidebar. It is not the source of truth for all live pane attention. See
|
|
158
|
+
[notify-queue.md](notify-queue.md) for the full data model.
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
projmux notify push --text <s> --target <SESSION[:WINDOW[.PANE]]>
|
|
162
|
+
[--socket <s>] [--severity info|warn|critical]
|
|
163
|
+
[--source ai|k8s|git|external] [--ttl <seconds>]
|
|
164
|
+
[--id <s>] [--json]
|
|
165
|
+
projmux notify list [--live] [--json] [--limit N] [--ui table|sidebar]
|
|
166
|
+
[--severity ...] [--source ...]
|
|
167
|
+
projmux notify ack <id> | --all
|
|
168
|
+
projmux notify reconcile [--json]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
- `push` — append (or refresh, with `--id`) one entry. `--ttl` defaults to
|
|
172
|
+
`600` seconds as freshness metadata; it does not remove rows from
|
|
173
|
+
`notify list`. `--text` is hard-capped to 80 runes (longer text is
|
|
174
|
+
truncated server-side).
|
|
175
|
+
- `list` — newest-first pending queue table `ID AGE SEV SRC TARGET TEXT`
|
|
176
|
+
(or JSON). `--severity` and `--source` are repeatable filters.
|
|
177
|
+
`--live` adds a non-mutating explanation table (or JSON report) that
|
|
178
|
+
compares queued entries with live pane attention. It calls out manual
|
|
179
|
+
reply badges that do not queue because no AI agent is attached, live AI
|
|
180
|
+
reply panes missing a queue entry, matched AI reply entries, and stale
|
|
181
|
+
queue entries whose live pane no longer matches. `--ui=sidebar` opens the
|
|
182
|
+
compact interactive notify list where Enter focuses and acks a target, `a`
|
|
183
|
+
acks the selected row, and `Ctrl-A` clears all; opening or navigating the
|
|
184
|
+
sidebar does not ack. The sidebar uses two-line cards with notification text
|
|
185
|
+
first and compact age/project/window/pane metadata below, while keeping ids,
|
|
186
|
+
source, severity, and target details searchable.
|
|
187
|
+
- `ack <id>` removes one entry; `--all` flushes the queue.
|
|
188
|
+
- `reconcile` — walks `tmux list-panes -a` and back-fills entries for
|
|
189
|
+
panes whose attention state is `reply` AND whose AI agent option is
|
|
190
|
+
set, reporting stale `ai:` entries that no longer match a live pane without
|
|
191
|
+
acking them.
|
|
192
|
+
Soft-fails (no error, populated `errors` field in the summary) when
|
|
193
|
+
tmux is not running. Use this as the recovery path when the queue and
|
|
194
|
+
live pane state drift.
|
|
195
|
+
|
|
196
|
+
## usage
|
|
197
|
+
|
|
198
|
+
Authoritative AI token usage. See [usage-tracking.md](usage-tracking.md)
|
|
199
|
+
for adapter detail.
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
projmux usage [--model codex|claude|all] [--window 5h|weekly|all]
|
|
203
|
+
[--json] [--force|-f]
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Renders a tab-aligned `MODEL WINDOW PCT RESETS_AT STALE` table; appends a
|
|
207
|
+
backoff note when an adapter is in 429 cooldown. `--force` clears any
|
|
208
|
+
active backoff and bypasses the per-adapter throttle floor (Claude `5m`,
|
|
209
|
+
Codex shares the global `30s`). `--json` emits the snapshot array; when
|
|
210
|
+
backoff is active the wrapper `{snapshots, backoff}` object is emitted
|
|
211
|
+
instead.
|
|
212
|
+
|
|
213
|
+
## status
|
|
214
|
+
|
|
215
|
+
Per-segment status-bar renderers. All four are silent on failure — the
|
|
216
|
+
tmux status interval polls them and must never produce a stack trace.
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
projmux status git [path]
|
|
220
|
+
projmux status kube [session]
|
|
221
|
+
projmux status usage [--max-width N] [--force|-f]
|
|
222
|
+
projmux status notify [--max-width N]
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
- `git` — `#[bold,fg=colour16,bg=colour45] <branch> #[default]` for the
|
|
226
|
+
pane's `pane_current_path` (or the supplied path). Empty when not in a
|
|
227
|
+
repo.
|
|
228
|
+
- `kube` — `⎈ <context>/<namespace>` segment. Reads
|
|
229
|
+
`~/.cache/tmux/kube-segment-<session>.txt` first (TTL governed by
|
|
230
|
+
`TMUX_KUBE_CACHE_TTL`, default `5s`). Picks up a per-session
|
|
231
|
+
`KUBECONFIG` from `${XDG_RUNTIME_DIR:-~/.cache}/kube-sessions/<session>.yaml`.
|
|
232
|
+
- `usage` — HUD-style `Claude (Nm) 5h [bar] N% · weekly [bar] N% Codex 5h
|
|
233
|
+
[bar] N% · weekly [bar] N%`. Degrades through six tiers as `--max-width`
|
|
234
|
+
shrinks. Triggers an opportunistic, throttled refresh (per-adapter
|
|
235
|
+
throttle, `30s` floor) so a stale cache self-heals.
|
|
236
|
+
- `notify` — newest-first HUD block with project, state, optional agent, text,
|
|
237
|
+
age, and `+<extras>`. Window/pane ids remain routable metadata but are not
|
|
238
|
+
displayed in the compact HUD. Degrades through width tiers; default
|
|
239
|
+
`--max-width` is `200` runes.
|
|
240
|
+
|
|
241
|
+
## statusbar
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
projmux statusbar click <range-id> [--socket <s>] [--mouse-window <id>]
|
|
245
|
+
[--mouse-x N] [--mouse-y N]
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Click/keyboard dispatcher for the two-line status bar. Implemented range ids:
|
|
249
|
+
`session pwd kube git usage notify`. The bare `window` /
|
|
250
|
+
`window|<idx>` token (tmux's built-in window-list range) and the empty
|
|
251
|
+
range fall through to `select-window -t @<mouse_window>` so the native
|
|
252
|
+
click-to-switch tab affordance is preserved on row 0. Unknown range ids are
|
|
253
|
+
non-specialized placeholders and no-op. `session` opens the existing-session
|
|
254
|
+
popup; `pwd` copies the current pane path to the tmux paste buffer and shows
|
|
255
|
+
it in a compact popup; `kube` and `git` open the project switcher popup;
|
|
256
|
+
`usage` opens the detailed `projmux usage` table popup; `notify` focuses and
|
|
257
|
+
acks the newest actionable queue target.
|
|
258
|
+
`MouseDown1Status` errors are
|
|
259
|
+
swallowed and surfaced as `display-message` toasts so a transient
|
|
260
|
+
failure does not raise a tmux error popup. See [statusbar.md](statusbar.md).
|
|
261
|
+
|
|
262
|
+
## attention
|
|
263
|
+
|
|
264
|
+
```
|
|
265
|
+
projmux attention toggle [pane]
|
|
266
|
+
projmux attention clear [pane]
|
|
267
|
+
projmux attention arm [pane]
|
|
268
|
+
projmux attention list [--json] [--all]
|
|
269
|
+
projmux attention window [window]
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Toggles the `✳` pane title prefix and the `@projmux_attention_state` pane
|
|
273
|
+
option. `toggle` flips between cleared and `reply`; `clear` always
|
|
274
|
+
clears; `arm` sets a pre-reply armed state used by the AI flow. The
|
|
275
|
+
producer side pushes the matching entry into the notify queue when the pane
|
|
276
|
+
has an associated AI agent option; clearing attention does not ack the queue
|
|
277
|
+
row (manual toggles on shell panes do not push). `list` reads `tmux list-panes -a` and shows live pane
|
|
278
|
+
attention state without reading or mutating the notify queue; by default
|
|
279
|
+
it shows panes with an attention option or title marker, and `--all`
|
|
280
|
+
includes every pane. `window` renders the status-bar window badge for the
|
|
281
|
+
supplied window.
|
|
282
|
+
|
|
283
|
+
## ai
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
projmux ai split --inside <right|down> [--agent <name>] ...
|
|
287
|
+
projmux ai picker --inside <right|down>
|
|
288
|
+
projmux ai settings
|
|
289
|
+
projmux ai status set <thinking|waiting|idle> [--pane <id>]
|
|
290
|
+
projmux ai notify <reset|notify> [--pane <id>]
|
|
291
|
+
projmux ai watch-title [--pane <id>]
|
|
292
|
+
projmux ai topic ...
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Manages the AI split lifecycle and the per-pane state machine that drives
|
|
296
|
+
the `attention` badge, the `notify` queue producer, and the desktop
|
|
297
|
+
notifier. `status set waiting` is the trigger that flips a pane to the
|
|
298
|
+
reply-ready state — that transition pushes an `ai:<session>:<pane>`
|
|
299
|
+
entry into the notify queue.
|
|
300
|
+
|
|
301
|
+
## tmux
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
projmux tmux popup-toggle <mode>
|
|
305
|
+
projmux tmux popup-switch
|
|
306
|
+
projmux tmux popup-sessions
|
|
307
|
+
projmux tmux popup-preview <session>
|
|
308
|
+
projmux tmux rebalance-panes
|
|
309
|
+
projmux tmux rename-pane <pane> <title>
|
|
310
|
+
projmux tmux print-config [--bin <path>]
|
|
311
|
+
projmux tmux print-app-config [--bin <path>]
|
|
312
|
+
projmux tmux install [--bin <path>] [--config <path>] [--include <path>]
|
|
313
|
+
projmux tmux install-app [--bin <path>] [--config <path>]
|
|
314
|
+
projmux tmux apply
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Helpers tmux's keybindings and the install pipeline call into. Modes
|
|
318
|
+
accepted by `popup-toggle` mirror the historical sessionizer surface:
|
|
319
|
+
`session-popup`, `sessionizer`, `sessionizer-sidebar`,
|
|
320
|
+
`ai-split-picker-right`, `ai-split-picker-down`, `ai-split-settings`.
|
|
321
|
+
`apply` reloads the live `-L projmux` server's config without restarting
|
|
322
|
+
it; `make install` and `projmux upgrade` invoke it after replacing the
|
|
323
|
+
binary.
|
|
324
|
+
|
|
325
|
+
## update
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
projmux update status [--json]
|
|
329
|
+
projmux update check [--json]
|
|
330
|
+
projmux update apply [--dry-run] [--no-apply]
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Installer-aware update status foundation. `status` is read-only: it
|
|
334
|
+
prints the current version, cached latest GitHub Release tag when present,
|
|
335
|
+
cache freshness (`fresh`, `stale`, or `unknown`), update state, detected
|
|
336
|
+
installer source, and cache path. It never reaches the network, so it is
|
|
337
|
+
safe for interactive use and shell startup paths.
|
|
338
|
+
|
|
339
|
+
`check` fetches the latest GitHub Release metadata for
|
|
340
|
+
`crevissepartners/projmux`, atomically writes
|
|
341
|
+
`${XDG_CACHE_HOME:-~/.cache}/projmux/update.json`, then prints the concise
|
|
342
|
+
latest/update/cache result. `--json` emits the same machine-readable
|
|
343
|
+
status shape for both subcommands.
|
|
344
|
+
|
|
345
|
+
`projmux shell` reads the same cache before opening the isolated tmux app.
|
|
346
|
+
When the cache is fresh, an update is available, and the installer supports
|
|
347
|
+
`update apply`, shell startup shows a small picker with Update Now, Later,
|
|
348
|
+
and Skip This Version actions. This startup prompt never reaches the network;
|
|
349
|
+
run `projmux update check` first when you want it to see the newest release.
|
|
350
|
+
|
|
351
|
+
Installer detection honors
|
|
352
|
+
`PROJMUX_INSTALLER=npm|go|github-release|source`. When unset or invalid,
|
|
353
|
+
the source is reported as `unknown` with guidance to set the variable.
|
|
354
|
+
`apply` is installer-aware and only runs after explicit user selection.
|
|
355
|
+
For npm installs, it runs `npm update -g projmux` and then
|
|
356
|
+
`projmux tmux apply` unless `--no-apply` is set. For Go installs, it
|
|
357
|
+
delegates to the existing atomic `projmux upgrade` flow. For
|
|
358
|
+
`github-release` installs, it downloads the latest matching
|
|
359
|
+
`projmux_<version>_<goos>_<goarch>.tar.gz` release asset, extracts the
|
|
360
|
+
binary, atomically replaces the current executable, then applies tmux
|
|
361
|
+
configuration unless `--no-apply` is set. `source` installs report an
|
|
362
|
+
actionable error because they must be updated from the source checkout.
|
|
363
|
+
|
|
364
|
+
## upgrade
|
|
365
|
+
|
|
366
|
+
```
|
|
367
|
+
projmux upgrade [--ref @latest|@<tag>|@<branch>]
|
|
368
|
+
[--target <path>] [--no-apply] [--dry-run]
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
`go install`s the binary, atomically replaces the on-disk file, then
|
|
372
|
+
runs `projmux tmux apply` (skipped with `--no-apply`). Reads
|
|
373
|
+
`PROJMUX_PROJDIR` from the calling shell and memoizes the primary entry
|
|
374
|
+
to `~/.config/projmux/projdir`. npm-installed binaries reject this
|
|
375
|
+
command; use `projmux update apply` or `npm update -g projmux` for npm
|
|
376
|
+
installs.
|
|
377
|
+
|
|
378
|
+
## sessions / session-popup / preview / pin / kill / prune / tag
|
|
379
|
+
|
|
380
|
+
The lifecycle helpers retained from earlier releases. They share their
|
|
381
|
+
flags with the top-level `switch` UX:
|
|
382
|
+
|
|
383
|
+
- `sessions` — list/pick existing tmux sessions, supports `--ui=popup`.
|
|
384
|
+
- `session-popup` — read/write the popup-marker state used during
|
|
385
|
+
preview cycling.
|
|
386
|
+
- `preview` — manage the persisted window/pane preview selection.
|
|
387
|
+
- `pin add|remove|toggle|list|clear` — pin set CRUD, persisted under
|
|
388
|
+
`~/.config/projmux/pins`.
|
|
389
|
+
- `kill <session>` / `kill tagged` — terminate sessions; `tagged`
|
|
390
|
+
consumes the active tagged-selection set.
|
|
391
|
+
- `prune ephemeral` — drop ephemeral sessions older than the configured
|
|
392
|
+
retention window.
|
|
393
|
+
- `tag` — manage the tagged-selection set.
|
|
394
|
+
|
|
395
|
+
## current / shell / attach / settings
|
|
396
|
+
|
|
397
|
+
- `current` — print `pane_current_path` for the active tmux pane (used
|
|
398
|
+
by the shell jump binding).
|
|
399
|
+
- `shell` — boot the isolated `-L projmux` tmux server with the
|
|
400
|
+
generated config. The generated app config uses absolute `$SHELL` as the
|
|
401
|
+
tmux default shell when set, otherwise `/bin/sh`.
|
|
402
|
+
- `attach auto [--keep=N] [--fallback=home|ephemeral]` — auto-attach to
|
|
403
|
+
the most recent session, with bounded retention and a fallback policy.
|
|
404
|
+
- `settings` — interactive configuration UI for the project picker, AI
|
|
405
|
+
splits, Status Bar cwd/git decoration, Project Root management, the
|
|
406
|
+
switcher's saved workdirs list, and About/Update status. In Project Picker,
|
|
407
|
+
`Project Root` manages the saved
|
|
408
|
+
primary root (`~/.config/projmux/projdir`) and displays whether the effective
|
|
409
|
+
value comes from `PROJMUX_PROJDIR`, tmux `@projmux_projdir`, saved config, or
|
|
410
|
+
no configured source. When no source is configured, the direct-set prompt
|
|
411
|
+
starts with `$HOME` as an editable fallback, but `$HOME` is not used as the
|
|
412
|
+
effective root unless saved. `Workdirs` remains separate: those entries are
|
|
413
|
+
additional search roots, not the primary root. Status Bar stores
|
|
414
|
+
`~/.config/projmux/statusbar-decoration` as `off` (default), `symbol`, or
|
|
415
|
+
`emoji` and updates the live tmux option when available. The About section
|
|
416
|
+
reads the cached update status without network access;
|
|
417
|
+
selecting Check Updates runs `projmux update check`, and Update Now runs
|
|
418
|
+
`projmux update apply`. The same About section also lists the keybinding
|
|
419
|
+
diagnostic path: zero-config first, `setup` for swallowed keys, `init` for
|
|
420
|
+
supported terminal fallbacks, and `doctor` for dependencies.
|
|
421
|
+
|
|
422
|
+
## See also
|
|
423
|
+
|
|
424
|
+
- [npm-distribution.md](npm-distribution.md) — npm binary package layout.
|
|
425
|
+
- [statusbar.md](statusbar.md) — two-line layout and click range catalogue.
|
|
426
|
+
- [notify-queue.md](notify-queue.md) — queue file format and lifecycle.
|
|
427
|
+
- [usage-tracking.md](usage-tracking.md) — adapter HTTP/file behaviour.
|
|
428
|
+
- [keybindings.md](keybindings.md) — terminal key delivery and CSI-u.
|
|
429
|
+
- [hooks.md](hooks.md) — `post-create` hook contract.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Most users can configure projmux from `projmux settings`. Environment variables
|
|
4
|
+
are available for repeatable shell setup, managed machines, or advanced
|
|
5
|
+
overrides.
|
|
6
|
+
|
|
7
|
+
## Project Discovery
|
|
8
|
+
|
|
9
|
+
`projmux switch` combines pinned directories, live tmux sessions, and
|
|
10
|
+
discovered project roots.
|
|
11
|
+
|
|
12
|
+
When no explicit roots are configured, discovery uses weak probes only when
|
|
13
|
+
those folders exist:
|
|
14
|
+
|
|
15
|
+
- `~/source`
|
|
16
|
+
- `~/work`
|
|
17
|
+
- `~/projects`
|
|
18
|
+
- `~/src`
|
|
19
|
+
- `~/code`
|
|
20
|
+
|
|
21
|
+
It does not assume a canonical repo root.
|
|
22
|
+
|
|
23
|
+
Use Settings > Project Picker for the normal interactive flow:
|
|
24
|
+
|
|
25
|
+
- `Project Root` sets, changes, or clears the saved primary root.
|
|
26
|
+
- `+ Add Workdir...` appends one directory to the saved workdirs list.
|
|
27
|
+
- `Workdirs` reviews and removes saved workdirs.
|
|
28
|
+
|
|
29
|
+
`Add Workdir > Type path manually...` skips the filesystem scan and is useful
|
|
30
|
+
for large mounts, WSL paths, NFS paths, or temporary project roots.
|
|
31
|
+
|
|
32
|
+
The saved workdir file is:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
~/.config/projmux/workdirs
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
It stores one absolute path per line. Lines beginning with `#` are comments.
|
|
39
|
+
The file is read only when no env root list is set.
|
|
40
|
+
|
|
41
|
+
## Environment Variables
|
|
42
|
+
|
|
43
|
+
| Variable | Purpose |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `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`. |
|
|
46
|
+
| `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. |
|
|
47
|
+
| `TMUX_SESSIONIZER_ROOTS` | Legacy alias still honored at runtime for managed roots. |
|
|
48
|
+
| `PROJMUX_NOTIFY_HOOK` | External executable that receives AI desktop notifications instead of the built-in Linux/WSL sender. |
|
|
49
|
+
| `PROJMUX_WSL_TOAST_ICON_DIR` | Directory used when copying the WSL toast icon into a Windows-readable path. |
|
|
50
|
+
| `PROJMUX_USAGE_STATE_DIR` | Override directory for AI usage snapshots. Defaults to `<state>/projmux/usage`. Point this at a synced directory to share authoritative usage across machines. |
|
|
51
|
+
| `PROJMUX_USAGE_DEBUG` | When non-empty, prints adapter errors from `projmux status usage` to stderr. |
|
|
52
|
+
| `PROJMUX_USAGE_LIMITS_PATH` | Deprecated. Read but ignored; limits now come from upstream APIs and local Codex rollout state. |
|
|
53
|
+
| `PROJMUX_FOCUS_DEBUG` | When non-empty, `projmux focus` prints one telemetry line to stderr. |
|
|
54
|
+
| `PROJMUX_PICKER_BACKEND` | Set to `native` to opt into the experimental native picker backend. `fzf` remains the default and stable backend. |
|
|
55
|
+
| `PROJMUX_INSTALLER` | Installer source hint used by update flows. npm installs set this automatically; advanced release installs can set `github-release`. |
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
export PROJMUX_PROJDIR="/main/repos:/srv/work/repos"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
On Linux and macOS the separator is `:`. On Windows-style paths the separator
|
|
64
|
+
is `;`.
|
|
65
|
+
|
|
66
|
+
## tmux Project Root Option
|
|
67
|
+
|
|
68
|
+
The switch command also reads this tmux option:
|
|
69
|
+
|
|
70
|
+
```tmux
|
|
71
|
+
set-option -g @projmux_projdir /path/to/repos
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
An env `PROJMUX_PROJDIR` value takes priority over the tmux option. The tmux
|
|
75
|
+
option takes priority over the saved projdir file.
|
|
76
|
+
|
|
77
|
+
## Notifications
|
|
78
|
+
|
|
79
|
+
When `PROJMUX_NOTIFY_HOOK` is unset, projmux uses:
|
|
80
|
+
|
|
81
|
+
- `notify-send` on Linux.
|
|
82
|
+
- PowerShell toasts on WSL.
|
|
83
|
+
|
|
84
|
+
When the hook is set, projmux invokes it with positional arguments:
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
summary body urgency app-name tag group icon-path
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Hook details for new-session lifecycle hooks live in [Hooks](hooks.md).
|
|
91
|
+
|
|
92
|
+
## Usage Tracking
|
|
93
|
+
|
|
94
|
+
`projmux usage` and the status-bar usage segment store snapshots under:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
${PROJMUX_USAGE_STATE_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}/projmux/usage}/snapshots.json
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
See [Usage tracking](usage-tracking.md) for adapter behavior, throttling, and
|
|
101
|
+
failure handling.
|
|
102
|
+
|
|
103
|
+
## Status Bar Decoration
|
|
104
|
+
|
|
105
|
+
Settings > Status Bar controls the optional cwd/git leading decoration:
|
|
106
|
+
|
|
107
|
+
- `off` is the default and avoids icon-font assumptions.
|
|
108
|
+
- `symbol` restores the Nerd Font-style folder/git icons.
|
|
109
|
+
- `emoji` uses emoji decorators.
|
|
110
|
+
|
|
111
|
+
The saved value lives at:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
~/.config/projmux/statusbar-decoration
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Rare Tunables
|
|
118
|
+
|
|
119
|
+
These are intended for debugging or local policy, not routine setup:
|
|
120
|
+
|
|
121
|
+
| Variable | Purpose |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `PROJMUX_TMUX_NOTIFY_DEDUPE_SECONDS` | Collapse window for duplicate AI notifications keyed on `(summary, tag)`. |
|
|
124
|
+
| `PROJMUX_CODEX_TITLE_WATCH_INTERVAL` | Title-watch loop pacing for Codex panes. |
|
|
125
|
+
| `PROJMUX_CODEX_REPLY_SETTLE_LOOPS` | Reply-detection settle-loop pacing for Codex panes. |
|
|
126
|
+
| `TMUX_KUBE_CACHE_TTL` | Kubernetes status segment cache TTL. |
|
|
127
|
+
| `TMUX_KUBE_TIMEOUT` | kubectl invocation budget for the Kubernetes status segment. |
|
package/docs/hooks.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Hooks
|
|
2
|
+
|
|
3
|
+
projmux runs an optional user script when it creates a new tmux session. The
|
|
4
|
+
hook is the project-agnostic extension point for things projmux itself stays out of:
|
|
5
|
+
injecting per-session env via `tmux set-environment`, picking a `GH_TOKEN` for
|
|
6
|
+
the repo, exporting a Kubernetes context, kicking off a background sync, etc.
|
|
7
|
+
projmux never ships behavior specific to any of those — that lives in the
|
|
8
|
+
hook.
|
|
9
|
+
|
|
10
|
+
## Where it lives
|
|
11
|
+
|
|
12
|
+
Global hook:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
${XDG_CONFIG_HOME:-$HOME/.config}/projmux/hooks/post-create
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Project-local hooks, discovered from the new session's `PROJMUX_CWD`:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
<repo>/.projmux/post-create
|
|
22
|
+
<repo>/.projmux/hooks/post-create
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Each hook file must exist, be a regular file or symlink (not a directory), and
|
|
26
|
+
have the owner-execute bit set. Anything else is silently skipped — no warning,
|
|
27
|
+
no log. There is no enable flag.
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
mkdir -p ~/.config/projmux/hooks
|
|
31
|
+
chmod +x ~/.config/projmux/hooks/post-create
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
For project-local hooks, projmux runs at most one file: first
|
|
35
|
+
`.projmux/post-create` if executable, otherwise `.projmux/hooks/post-create` if
|
|
36
|
+
executable. Discovery does not walk parent directories and does not run hooks
|
|
37
|
+
from status, preview, or picker hot paths.
|
|
38
|
+
|
|
39
|
+
## When it runs
|
|
40
|
+
|
|
41
|
+
After projmux creates a brand-new tmux session via `EnsureSession` (the
|
|
42
|
+
persistent path used by `current` and `switch`) or `CreateEphemeralSession`
|
|
43
|
+
(used by `attach`). It does **not** run when projmux attaches to an existing
|
|
44
|
+
session.
|
|
45
|
+
|
|
46
|
+
If both a global hook and a project-local hook exist, projmux runs the global
|
|
47
|
+
hook first, then the project-local hook. A failure or timeout in either hook is
|
|
48
|
+
logged once and does not block session creation or the other hook.
|
|
49
|
+
|
|
50
|
+
The hook's exit code is ignored — session creation always succeeds.
|
|
51
|
+
Hook stdout and stderr are forwarded to projmux's stderr line-by-line,
|
|
52
|
+
prefixed with `[post-create] `. The hook is killed after 5 seconds.
|
|
53
|
+
|
|
54
|
+
## Environment
|
|
55
|
+
|
|
56
|
+
The hook inherits projmux's environment, plus:
|
|
57
|
+
|
|
58
|
+
| Variable | Always set | Description |
|
|
59
|
+
| --- | --- | --- |
|
|
60
|
+
| `PROJMUX_SESSION` | yes | tmux session name |
|
|
61
|
+
| `PROJMUX_CWD` | yes | absolute working directory of the new session |
|
|
62
|
+
| `PROJMUX_SESSION_KIND` | yes | `persistent` or `ephemeral` |
|
|
63
|
+
| `PROJMUX_VERSION` | yes | projmux version string |
|
|
64
|
+
| `PROJMUX_SOCKET` | only if projmux used `tmux -L <socket>` | tmux socket name |
|
|
65
|
+
|
|
66
|
+
## Examples
|
|
67
|
+
|
|
68
|
+
### Global stub
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
#!/usr/bin/env bash
|
|
72
|
+
echo "session=$PROJMUX_SESSION cwd=$PROJMUX_CWD kind=$PROJMUX_SESSION_KIND"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Project-local stub
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
mkdir -p .projmux
|
|
79
|
+
cat > .projmux/post-create <<'EOF'
|
|
80
|
+
#!/usr/bin/env bash
|
|
81
|
+
echo "project hook for $PROJMUX_CWD"
|
|
82
|
+
EOF
|
|
83
|
+
chmod +x .projmux/post-create
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Per-session GH_TOKEN by repo
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
#!/usr/bin/env bash
|
|
90
|
+
set -euo pipefail
|
|
91
|
+
|
|
92
|
+
case "$PROJMUX_CWD" in
|
|
93
|
+
"$HOME"/source/repos/personal/*) token=$GH_TOKEN_PERSONAL ;;
|
|
94
|
+
"$HOME"/source/repos/work/*) token=$GH_TOKEN_WORK ;;
|
|
95
|
+
*) exit 0 ;;
|
|
96
|
+
esac
|
|
97
|
+
|
|
98
|
+
tmux set-environment -t "$PROJMUX_SESSION" GH_TOKEN "$token"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`set-environment` only seeds the session env that newly-spawned panes inherit;
|
|
102
|
+
it does not retroactively change the current shell. Open new panes via tmux
|
|
103
|
+
(`Ctrl-b c`, `Ctrl-b "`, etc.) to pick up the value.
|
|
104
|
+
|
|
105
|
+
## Troubleshooting
|
|
106
|
+
|
|
107
|
+
- **Nothing happens.** Check the execute bit on the global hook
|
|
108
|
+
(`ls -l ~/.config/projmux/hooks/post-create`) or the project hook
|
|
109
|
+
(`ls -l .projmux/post-create .projmux/hooks/post-create`). A missing bit
|
|
110
|
+
makes projmux skip silently by design.
|
|
111
|
+
- **`projmux: post-create hook: ... timed out after 5s`.** Long-running work
|
|
112
|
+
belongs in a backgrounded child (`(slow-thing &) >/dev/null 2>&1`). The hook
|
|
113
|
+
itself must return within 5s or projmux kills it.
|
|
114
|
+
- **`projmux: post-create hook: hook ... exited with status N`.** The script
|
|
115
|
+
returned non-zero. projmux logs it once and moves on; the session is still
|
|
116
|
+
created.
|
|
117
|
+
- **Lines appear with `[post-create] ` prefix.** Expected — that is how the
|
|
118
|
+
hook's stdout/stderr is multiplexed into projmux's stderr stream.
|