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/README.md
CHANGED
|
@@ -1,311 +1,109 @@
|
|
|
1
1
|
# projmux
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="docs/assets/projmux-icon.png" alt="projmux icon" width="112">
|
|
5
|
+
</p>
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
attention signals. It can run as its own tmux app (`projmux shell`) or install
|
|
8
|
-
the same behavior into your existing tmux server.
|
|
7
|
+
Project-aware tmux workspaces with fast switching, previews, status context,
|
|
8
|
+
and AI-pane attention built in.
|
|
9
9
|
|
|
10
10
|
[](https://www.npmjs.com/package/projmux)
|
|
11
11
|
[](https://github.com/crevissepartners/projmux/actions/workflows/ci.yml)
|
|
12
12
|
|
|
13
|
-
[
|
|
13
|
+
[Korean README](README-ko.md)
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+

|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
`projmux` treats that as the foundation, then adds the app-level pieces needed
|
|
19
|
-
for a daily terminal workspace:
|
|
17
|
+
## What It Is
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
sessions, windows, panes, git branch, Kubernetes context, and pane metadata.
|
|
25
|
-
- **The tmux layer is generated, not hand-spliced.** `projmux` writes the tmux
|
|
26
|
-
config it needs for popup launchers, window/pane rename flows, status
|
|
27
|
-
segments, pane borders, attention badges, and app mode.
|
|
28
|
-
- **AI panes are first-class.** Codex and Claude panes can be launched,
|
|
29
|
-
labeled, tracked as thinking or waiting, surfaced in pane/window/session
|
|
30
|
-
badges, and announced through desktop notifications.
|
|
31
|
-
- **You can choose isolation or integration.** Use `projmux shell` as a
|
|
32
|
-
self-contained tmux app, or install the generated snippet into your normal
|
|
33
|
-
tmux server.
|
|
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.
|
|
34
22
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- Creates or switches to tmux sessions from project directories.
|
|
38
|
-
- Shows existing sessions with window and pane previews.
|
|
39
|
-
- Provides popup and sidebar navigation surfaces backed by `fzf`.
|
|
40
|
-
- Pins important projects and scans common source roots for new ones.
|
|
41
|
-
- Persists preview selection for fast window and pane cycling.
|
|
42
|
-
- Generates tmux bindings for launchers, rename prompts, pane borders, status
|
|
43
|
-
segments, and attention hooks.
|
|
44
|
-
- Displays git branch and Kubernetes context/namespace in the status area.
|
|
45
|
-
- Renders a two-line clickable status bar with click-to-switch tabs on
|
|
46
|
-
row 0 and HUD-style notify (left) and AI usage (right) segments on
|
|
47
|
-
row 1.
|
|
48
|
-
- Launches AI splits and keeps their agent name, topic, status, and
|
|
49
|
-
notification state visible in tmux.
|
|
50
|
-
|
|
51
|
-
## Typical Workflow
|
|
52
|
-
|
|
53
|
-
```sh
|
|
54
|
-
projmux shell
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Open the app once, then use its generated tmux bindings to:
|
|
58
|
-
|
|
59
|
-
- jump between projects from a sidebar or popup,
|
|
60
|
-
- inspect sessions before attaching,
|
|
61
|
-
- split Codex, Claude, or a plain shell into the current workspace,
|
|
62
|
-
- rename windows and AI pane topics without losing metadata,
|
|
63
|
-
- see which panes need review from badges and desktop notifications.
|
|
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.
|
|
64
25
|
|
|
65
26
|
## Requirements
|
|
66
27
|
|
|
67
|
-
- [Node.js](https://nodejs.org/) and npm
|
|
68
|
-
|
|
69
|
-
- [
|
|
70
|
-
`go install` or building from source.
|
|
71
|
-
- [tmux](https://github.com/tmux/tmux/wiki/Installing) **≥ 3.4** — the workspace runtime. Earlier versions miss `display-popup -T` and other features projmux depends on.
|
|
72
|
-
- [fzf](https://github.com/junegunn/fzf#installation) **≥ 0.55** — interactive popup/sidebar pickers. The multiline picker uses `--marker-multi-line`, `--gap-line`, and `--highlight-line`, which landed by 0.55.
|
|
73
|
-
- A Unix shell such as `bash`, `zsh`, or `sh` — `projmux shell` uses your
|
|
74
|
-
absolute `$SHELL` for the generated app config, falling back to `/bin/sh`.
|
|
75
|
-
- [git](https://git-scm.com/downloads) — branch/status metadata.
|
|
76
|
-
- `stty` — POSIX terminal control, used by `projmux setup`. Already shipped by every macOS / Linux base system; not applicable on Windows hosts.
|
|
77
|
-
- [kubectl](https://kubernetes.io/docs/tasks/tools/) — optional, only for the Kubernetes status segment.
|
|
78
|
-
|
|
79
|
-
Desktop notifications: Linux uses `notify-send`; WSL routes Windows toasts via
|
|
80
|
-
`powershell.exe`. Override either with `PROJMUX_NOTIFY_HOOK`.
|
|
28
|
+
- [Node.js](https://nodejs.org/) and npm, for the main install path.
|
|
29
|
+
- [tmux](https://github.com/tmux/tmux/wiki/Installing) **3.4 or newer**.
|
|
30
|
+
- [fzf](https://github.com/junegunn/fzf#installation) **0.65.0 or newer**.
|
|
81
31
|
|
|
82
|
-
Run `projmux doctor`
|
|
83
|
-
|
|
84
|
-
|
|
32
|
+
Run `projmux doctor` after installing to check the local runtime. The `fzf`
|
|
33
|
+
requirement is the junegunn/fzf CLI binary; `npm i fzf` is a different
|
|
34
|
+
JavaScript library.
|
|
85
35
|
|
|
86
36
|
## Install
|
|
87
37
|
|
|
88
38
|
```sh
|
|
89
39
|
npm install -g projmux
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
npm installs a small Node.js shim plus the matching platform binary package
|
|
93
|
-
for Linux and macOS on x64 or arm64. The shim marks the install as npm-managed
|
|
94
|
-
so `projmux update` and the Settings About screen can use the right upgrade
|
|
95
|
-
path.
|
|
96
|
-
|
|
97
|
-
Verify:
|
|
98
|
-
|
|
99
|
-
```sh
|
|
100
40
|
projmux version
|
|
101
41
|
```
|
|
102
42
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
go install github.com/crevissepartners/projmux/cmd/projmux@latest
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
This drops the binary in `$(go env GOBIN)` (when set) or `$(go env GOPATH)/bin`
|
|
110
|
-
(default `~/go/bin`). Make sure that directory is on your `PATH`.
|
|
111
|
-
|
|
112
|
-
### Optional: `PROJMUX_PROJDIR`
|
|
113
|
-
|
|
114
|
-
`PROJMUX_PROJDIR` is the primary project root projmux uses for picker and
|
|
115
|
-
discovery when you explicitly configure it. It is optional; when unset,
|
|
116
|
-
projmux does not assume a canonical repo root. Discovery still uses pins, live
|
|
117
|
-
sessions, saved workdirs, and weak common-folder probes (`~/source`, `~/work`,
|
|
118
|
-
`~/projects`, `~/src`, `~/code`) when they exist.
|
|
119
|
-
|
|
120
|
-
```sh
|
|
121
|
-
export PROJMUX_PROJDIR="/your/path"
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Add the line to `~/.bashrc`, `~/.zshrc`, or your shell's rc file. The resolved value is
|
|
125
|
-
memoized to `~/.config/projmux/projdir` after first use, so later shells keep
|
|
126
|
-
the same root even without the env var.
|
|
127
|
-
|
|
128
|
-
`PROJMUX_PROJDIR` accepts an OS-native PATH-style multi-value (`:` on
|
|
129
|
-
Linux/macOS, `;` on Windows). The first non-empty entry is the primary
|
|
130
|
-
project root; any additional entries are prepended to the managed-roots
|
|
131
|
-
search list, so they participate in discovery just like
|
|
132
|
-
`PROJMUX_MANAGED_ROOTS`. Only the primary path is memoized to
|
|
133
|
-
`~/.config/projmux/projdir`.
|
|
134
|
-
|
|
135
|
-
```sh
|
|
136
|
-
# Linux/macOS — primary repo + secondary search root
|
|
137
|
-
export PROJMUX_PROJDIR="/main/repos:/srv/work/repos"
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
#### Set the project root during setup
|
|
141
|
-
|
|
142
|
-
```sh
|
|
143
|
-
PROJMUX_PROJDIR=/your/path projmux shell
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
The first invocation that sees the env var writes
|
|
147
|
-
`~/.config/projmux/projdir`, so later shells without the env var still
|
|
148
|
-
resolve the same root.
|
|
149
|
-
|
|
150
|
-
### From source
|
|
151
|
-
|
|
152
|
-
```sh
|
|
153
|
-
git clone https://github.com/crevissepartners/projmux.git
|
|
154
|
-
cd projmux
|
|
155
|
-
make install
|
|
156
|
-
```
|
|
43
|
+
The npm package installs a small Node.js shim plus the matching projmux binary
|
|
44
|
+
for Linux and macOS on x64 or arm64. npm is the primary distribution path for
|
|
45
|
+
normal users.
|
|
157
46
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
without a restart. Override the destination with `INSTALL_DIR=/usr/local/bin`.
|
|
47
|
+
Manual Go, source checkout, GitHub Release, and packaging details live in
|
|
48
|
+
[Install](docs/install.md).
|
|
161
49
|
|
|
162
50
|
## Quick Start
|
|
163
51
|
|
|
164
|
-
|
|
52
|
+
Open the isolated projmux tmux app:
|
|
165
53
|
|
|
166
54
|
```sh
|
|
167
55
|
projmux shell
|
|
168
56
|
```
|
|
169
57
|
|
|
170
|
-
|
|
171
|
-
bindings. Cooperative terminals get `Alt-1`..`Alt-5` immediately, with no
|
|
172
|
-
terminal config. The left status badge shows the current project name; the
|
|
173
|
-
right side shows path, kube segment, git segment, and clock.
|
|
174
|
-
|
|
175
|
-
If a key does not fire, run `projmux setup` outside tmux to see which
|
|
176
|
-
sequences your terminal swallows. For supported terminals, preview the
|
|
177
|
-
fallback with `projmux init [terminal]`, then apply it with
|
|
178
|
-
`projmux init [terminal] --apply` (auto-detects when no terminal is given).
|
|
179
|
-
Dotfiles users on multi-machine setups should pass
|
|
180
|
-
`--allow-symlink` or `--config <path>` to make their intent explicit. Full
|
|
181
|
-
flow and the manual CSI-u fallback are in
|
|
182
|
-
[Terminal Keybindings](docs/keybindings.md).
|
|
183
|
-
|
|
184
|
-
If anything looks off, `projmux doctor` reports which dependency is
|
|
185
|
-
missing or stale and how to install it. See [Requirements](#requirements)
|
|
186
|
-
for the supported versions.
|
|
187
|
-
|
|
188
|
-
## Upgrading
|
|
189
|
-
|
|
190
|
-
The Settings About screen is the normal interactive update surface: it shows
|
|
191
|
-
cached release status, installer source, Check Updates, Update Now, and
|
|
192
|
-
release notes. The startup update prompt uses the same cache and never reaches
|
|
193
|
-
the network.
|
|
194
|
-
To refresh the cached release status manually, run:
|
|
195
|
-
|
|
196
|
-
```sh
|
|
197
|
-
projmux update check
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
Use Settings > About > Update or `projmux update apply` to update through the
|
|
201
|
-
detected installer. See [Upgrading](docs/upgrading.md) for npm, Go, GitHub
|
|
202
|
-
Release, and source-checkout details.
|
|
203
|
-
|
|
204
|
-
## Usage
|
|
205
|
-
|
|
206
|
-
Day-to-day, projmux is driven by tmux keybindings inside `projmux shell` — see
|
|
207
|
-
[Terminal Keybindings](docs/keybindings.md). For the full CLI surface (pins,
|
|
208
|
-
preview state, status helpers, updates, etc.), run `projmux help` or
|
|
209
|
-
`<command> --help`.
|
|
210
|
-
|
|
211
|
-
## How It Finds Projects
|
|
212
|
-
|
|
213
|
-
`projmux switch` combines pinned directories, live tmux sessions, and discovered
|
|
214
|
-
project roots. When no explicit search roots are configured, discovery uses
|
|
215
|
-
weak common-folder probes such as `~/source`, `~/work`, `~/projects`, `~/src`,
|
|
216
|
-
and `~/code` if they exist; it does not assume a canonical `~/source/repos`
|
|
217
|
-
root. `projmux settings` also has `Project Picker > Add Project...`, which
|
|
218
|
-
scans filesystem roots up to depth 3 so projects outside the weak probes can be
|
|
219
|
-
added to the picker. Session names are derived from normalized directory paths,
|
|
220
|
-
so a project keeps the same tmux session name across launches.
|
|
221
|
-
|
|
222
|
-
For permanent search-root customization, the Project Picker section also
|
|
223
|
-
includes:
|
|
224
|
-
|
|
225
|
-
- `+ Add Workdir...` - append a single directory to the saved workdirs list.
|
|
226
|
-
- `Workdirs` - review and remove saved workdirs. The same picker also surfaces
|
|
227
|
-
any active `PROJMUX_MANAGED_ROOTS` / `TMUX_SESSIONIZER_ROOTS` env values as
|
|
228
|
-
read-only rows so you can see why an env list might be overriding the saved
|
|
229
|
-
file.
|
|
230
|
-
|
|
231
|
-
`Add Workdir > Type path manually...` gives you a typed entry that skips the
|
|
232
|
-
filesystem scan. Use it for paths you do not want crawled, e.g. WSL mounts
|
|
233
|
-
(`/mnt/c/Users/...`), large NFS mounts, or per-project temp roots.
|
|
234
|
-
|
|
235
|
-
The saved file lives at `~/.config/projmux/workdirs` (one absolute path per
|
|
236
|
-
line, `#` comments allowed). It is consulted only when the env vars are unset.
|
|
58
|
+
Inside the app:
|
|
237
59
|
|
|
238
|
-
|
|
60
|
+
- `Alt-1` opens the project sidebar.
|
|
61
|
+
- `Alt-2` opens the notification list.
|
|
62
|
+
- `Alt-3` opens the existing-session picker.
|
|
63
|
+
- `Alt-4` opens the AI split picker.
|
|
64
|
+
- `Alt-5` opens settings.
|
|
65
|
+
- `Alt-6` opens the project switcher popup.
|
|
239
66
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
`
|
|
243
|
-
Missing or non-executable hooks are skipped silently; failures never block
|
|
244
|
-
session creation. See [Hooks](docs/hooks.md) for the env contract, examples,
|
|
245
|
-
and troubleshooting.
|
|
67
|
+
See [Terminal Keybindings](docs/keybindings.md) for the full key map. If a key
|
|
68
|
+
does not fire, run `projmux setup` outside tmux, then use
|
|
69
|
+
`projmux init [terminal] --apply` for supported terminal fallbacks.
|
|
246
70
|
|
|
247
|
-
##
|
|
71
|
+
## Day-To-Day Use
|
|
248
72
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
| `PROJMUX_USAGE_LIMITS_PATH` | Deprecated. Limits now come from the upstream APIs (Anthropic OAuth usage endpoint, Codex `rate_limits`); this variable is read but ignored. |
|
|
73
|
+
- Pick a project directory and projmux creates or reuses its tmux session.
|
|
74
|
+
- Pin important projects so they stay easy to reach.
|
|
75
|
+
- Preview windows, panes, git branch, Kubernetes context, and AI pane state
|
|
76
|
+
before switching.
|
|
77
|
+
- Use Settings > Project Picker to add roots and workdirs without editing env
|
|
78
|
+
vars.
|
|
79
|
+
- Use Settings > About > Update or `projmux update apply` to upgrade.
|
|
257
80
|
|
|
258
|
-
|
|
81
|
+
For detailed configuration, including `PROJMUX_PROJDIR`, managed roots,
|
|
82
|
+
notifications, and usage tracking, see [Configuration](docs/configuration.md).
|
|
83
|
+
For update behavior by installer type, see [Upgrading](docs/upgrading.md).
|
|
259
84
|
|
|
260
|
-
|
|
261
|
-
Claude Code and the Codex CLI. Both adapters read from the upstream's own
|
|
262
|
-
view of your account so the percentages match what `claude /usage` and
|
|
263
|
-
`codex` show natively:
|
|
85
|
+
## More Docs
|
|
264
86
|
|
|
265
|
-
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
Snapshots are persisted under `<state>/projmux/usage/snapshots.json` (or
|
|
274
|
-
`PROJMUX_USAGE_STATE_DIR`) and refreshed at most every 30 seconds when
|
|
275
|
-
`projmux status usage` runs in the tmux status bar.
|
|
276
|
-
|
|
277
|
-
## Scope
|
|
278
|
-
|
|
279
|
-
`projmux` owns the portable session-management core: naming, discovery, pins,
|
|
280
|
-
preview state, tmux orchestration, status segments, and generated tmux bindings.
|
|
87
|
+
- [Install](docs/install.md)
|
|
88
|
+
- [Configuration](docs/configuration.md)
|
|
89
|
+
- [Terminal Keybindings](docs/keybindings.md)
|
|
90
|
+
- [CLI Reference](docs/cli.md)
|
|
91
|
+
- [Statusbar](docs/statusbar.md)
|
|
92
|
+
- [Hooks](docs/hooks.md)
|
|
93
|
+
- [Usage tracking](docs/usage-tracking.md)
|
|
94
|
+
- [Agent Workflow](docs/agent-workflow.md)
|
|
281
95
|
|
|
282
96
|
## Development
|
|
283
97
|
|
|
284
|
-
Useful commands:
|
|
285
|
-
|
|
286
98
|
```sh
|
|
287
99
|
make build
|
|
288
100
|
make fmt
|
|
289
101
|
make fix
|
|
290
102
|
make test
|
|
291
|
-
make test-integration
|
|
292
|
-
make test-e2e
|
|
293
|
-
make verify
|
|
294
103
|
```
|
|
295
104
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
- [Architecture](docs/architecture.md)
|
|
299
|
-
- [CLI Reference](docs/cli.md)
|
|
300
|
-
- [Statusbar](docs/statusbar.md)
|
|
301
|
-
- [Notify queue](docs/notify-queue.md)
|
|
302
|
-
- [Usage tracking](docs/usage-tracking.md)
|
|
303
|
-
- [Upgrading](docs/upgrading.md)
|
|
304
|
-
- [Hooks](docs/hooks.md)
|
|
305
|
-
- [Migration Plan](docs/migration-plan.md)
|
|
306
|
-
- [Repo Layout](docs/repo-layout.md)
|
|
307
|
-
- [Terminal Keybindings](docs/keybindings.md)
|
|
308
|
-
- [Agent Workflow](docs/agent-workflow.md)
|
|
105
|
+
See [Testing](docs/testing.md), [Architecture](docs/architecture.md), and
|
|
106
|
+
[Repo Layout](docs/repo-layout.md) for contributor details.
|
|
309
107
|
|
|
310
108
|
## License
|
|
311
109
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Agent Workflow
|
|
2
|
+
|
|
3
|
+
## Parallel Work With `wt`
|
|
4
|
+
- Start with `wt --version` and `wt list`.
|
|
5
|
+
- Create the task path with `wt path --create <branch>`.
|
|
6
|
+
- Work only inside the returned path.
|
|
7
|
+
- Keep file ownership clear. If two agents need the same file, one should finish or hand off before the other edits it.
|
|
8
|
+
- Use `wt cleanup` or `wt prune` only after previewing what will be removed.
|
|
9
|
+
|
|
10
|
+
## Branch Naming
|
|
11
|
+
- `feat/<topic>` for new behavior.
|
|
12
|
+
- `fix/<topic>` for bug fixes.
|
|
13
|
+
- `docs/<topic>` for documentation-only changes.
|
|
14
|
+
- `refactor/<topic>` for structure changes without intended behavior changes.
|
|
15
|
+
- `chore/<topic>` for maintenance or tooling.
|
|
16
|
+
|
|
17
|
+
## Standard Development Loop
|
|
18
|
+
1. Sync the branch context and inspect `git status --short`.
|
|
19
|
+
2. Implement the smallest coherent change.
|
|
20
|
+
3. Run `make fmt`.
|
|
21
|
+
4. Run `make fix`.
|
|
22
|
+
5. Run `make test`.
|
|
23
|
+
6. Run `make test-integration`.
|
|
24
|
+
7. Run `make test-e2e`.
|
|
25
|
+
8. Update the maintained test list below if behavior or coverage expectations changed.
|
|
26
|
+
9. Prepare review notes with parity status, commands run, and remaining risks.
|
|
27
|
+
|
|
28
|
+
## Maintained Test List
|
|
29
|
+
- `make fmt`: repository formatting for Go, shell snippets, and generated docs where applicable.
|
|
30
|
+
- `make fix`: safe automatic fixes such as `go fix` and repository-approved cleanup steps.
|
|
31
|
+
- `make npm-pack`: local npm binary package staging and `npm pack --dry-run` for the root package plus platform packages.
|
|
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 post-create hook dispatch, and agent-specific notification icons, and scoped even row/column resizing after shell and agent splits, status-bar git/kube segment parity including branch block styling, statusbar pwd click path popup/buffer-copy fallback, isolated `projmux shell` tmux app launch/config generation including home-project default session targeting, app-owned project-name statusbar layout, and distinct project badge color, shell startup update prompt actions for fresh installer-aware cached updates, pane/window keybindings, 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, 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, fzf preview wiring, fzf baseline 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, candidate discovery, config path derivation, popup preview read-models, and pure state rules including preview, tag, and lifecycle stores.
|
|
33
|
+
- Current focused unit coverage also includes strict notify SOT behavior
|
|
34
|
+
(TTL does not remove rows, focus success acks, reconcile reports stale
|
|
35
|
+
rows), `notify list --live` queue/live explanations, notify sidebar
|
|
36
|
+
two-line card rendering with age/project/window/pane metadata plus focus/ack/clear-all
|
|
37
|
+
actions, and `focus` dispatch diagnostics for session fallback, unresolved
|
|
38
|
+
targets, window fallback, pane fallback, explicit id failures, and
|
|
39
|
+
notify-only fallback.
|
|
40
|
+
- Picker focused unit coverage includes backend-neutral picker item/action mapping, fzf adapter output, native title-focused filtering, numeric selection, and shared close actions.
|
|
41
|
+
- `make test-integration`: Docker-backed Linux integration smoke with real `tmux`, `fzf`, `git`, and `stty`; covers `doctor`, tmux config print/install/apply, and notify queue CRUD against isolated HOME/XDG paths.
|
|
42
|
+
- `make test-install-smoke`: Docker-backed source install smoke; covers `make install`, atomic binary replacement, `tmux apply` against a live `projmux` socket, and post-install notify queue initialization.
|
|
43
|
+
- `make test-e2e`: Docker-backed real-tmux workflow smoke for session/pane setup, app config sourcing, reply-state notify reconciliation, focus notify fallback, and status notify rendering with contextual project/state/agent badges. Host-only terminal, WSL, macOS, and GUI notification behavior remains outside Docker; see [docs/testing.md](testing.md).
|
|
44
|
+
|
|
45
|
+
## When To Update This List
|
|
46
|
+
- A feature moves between unit, integration, and e2e coverage levels.
|
|
47
|
+
- A new subsystem introduces a new validation target or removes one.
|
|
48
|
+
- Behavior changes require new parity assertions or a different e2e scenario.
|
|
49
|
+
- A target stops being authoritative and must be replaced.
|
|
50
|
+
|
|
51
|
+
## Review Checklist
|
|
52
|
+
- The branch stays within its stated scope.
|
|
53
|
+
- The change preserves boundaries between portable `projmux` behavior and local machine policy.
|
|
54
|
+
- The required `make` targets were run in order.
|
|
55
|
+
- Test inventory updates are included when behavior changed.
|
|
56
|
+
- Known parity gaps are explicit.
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Core model
|
|
4
|
+
|
|
5
|
+
`projmux` is built around a small set of domain objects:
|
|
6
|
+
|
|
7
|
+
- `ProjectRoot`: a directory that may map to a tmux session
|
|
8
|
+
- `SessionIdentity`: the stable session name derived from a directory
|
|
9
|
+
- `SessionTarget`: the current selected session/window/pane target
|
|
10
|
+
- `CandidateSet`: the ordered list of project directories presented to the user
|
|
11
|
+
- `PinSet`: user-curated candidate priority state
|
|
12
|
+
- `PreviewState`: selected window/pane state used by popup and session previews
|
|
13
|
+
|
|
14
|
+
## Layers
|
|
15
|
+
|
|
16
|
+
### 1. Core
|
|
17
|
+
Pure rules and state transitions.
|
|
18
|
+
|
|
19
|
+
Responsibilities:
|
|
20
|
+
- directory normalization
|
|
21
|
+
- session naming
|
|
22
|
+
- candidate ordering
|
|
23
|
+
- pin state changes
|
|
24
|
+
- tagged selection state
|
|
25
|
+
- lifecycle decisions such as reuse, create, kill, fallback
|
|
26
|
+
|
|
27
|
+
This layer should not shell out directly.
|
|
28
|
+
|
|
29
|
+
### 2. Integrations
|
|
30
|
+
Adapters for external systems.
|
|
31
|
+
|
|
32
|
+
Initial adapters:
|
|
33
|
+
- tmux
|
|
34
|
+
- kubeconfig per-session state
|
|
35
|
+
- filesystem
|
|
36
|
+
- git metadata for preview enrichment
|
|
37
|
+
|
|
38
|
+
Responsibilities:
|
|
39
|
+
- execute commands
|
|
40
|
+
- parse command output
|
|
41
|
+
- convert failures into typed errors
|
|
42
|
+
|
|
43
|
+
### 3. UI orchestration
|
|
44
|
+
Picker data is modeled independently from fzf rows. The app builds
|
|
45
|
+
backend-neutral `picker.Item` values (`Title`, `Value`, `SearchText`,
|
|
46
|
+
`MetaLines`, `Badges`, `PreviewTarget`) and then adapts them to the selected
|
|
47
|
+
backend. `fzf` remains the default, stable backend; the native backend is
|
|
48
|
+
opt-in through `PROJMUX_PICKER_BACKEND=native` while it reaches full parity.
|
|
49
|
+
|
|
50
|
+
Responsibilities:
|
|
51
|
+
- rows for popup and sidebar views
|
|
52
|
+
- preview rendering
|
|
53
|
+
- keybind-to-action dispatch
|
|
54
|
+
- selection handoff into core actions
|
|
55
|
+
- picker-agnostic close/dismiss actions
|
|
56
|
+
|
|
57
|
+
Picker-specific display and search rules are tracked in
|
|
58
|
+
[picker-ui-plan.md](picker-ui-plan.md).
|
|
59
|
+
|
|
60
|
+
This keeps parity with the existing shell workflow while moving state and behavior into Go.
|
|
61
|
+
|
|
62
|
+
### 4. Local environment
|
|
63
|
+
This repo owns the portable application behavior and generated tmux config.
|
|
64
|
+
|
|
65
|
+
Responsibilities that remain outside `projmux`:
|
|
66
|
+
- terminal emulator key dispatch
|
|
67
|
+
- shell startup policy
|
|
68
|
+
- install-time package checks
|
|
69
|
+
- machine-specific path and symlink choices
|
|
70
|
+
|
|
71
|
+
## Configuration model
|
|
72
|
+
|
|
73
|
+
Config should be explicit and file-backed.
|
|
74
|
+
|
|
75
|
+
Candidate areas:
|
|
76
|
+
- managed roots
|
|
77
|
+
- default home-like roots
|
|
78
|
+
- preview preferences
|
|
79
|
+
- session naming exceptions
|
|
80
|
+
- kube session settings
|
|
81
|
+
- ephemeral session retention defaults
|
|
82
|
+
|
|
83
|
+
## State model
|
|
84
|
+
|
|
85
|
+
Persistent state:
|
|
86
|
+
- pins
|
|
87
|
+
- lightweight user preferences
|
|
88
|
+
|
|
89
|
+
Ephemeral runtime state:
|
|
90
|
+
- preview selection
|
|
91
|
+
- popup marker files
|
|
92
|
+
- current tagged selection set
|
|
93
|
+
|
|
94
|
+
## Notify queue
|
|
95
|
+
|
|
96
|
+
`projmux` keeps a single JSON-backed queue of pending notifications at
|
|
97
|
+
`<state>/projmux/notify.json` (typically `~/.local/state/projmux/notify.json`,
|
|
98
|
+
following XDG). Writes go through an `O_CREATE|O_EXCL` lock file
|
|
99
|
+
(`notify.json.lock`) with bounded retry + jittered backoff so the queue
|
|
100
|
+
is safe across concurrent producers (the AI flow, the manual `attention
|
|
101
|
+
toggle`, the `notify push` CLI) on a local filesystem.
|
|
102
|
+
|
|
103
|
+
Attention and notify are intentionally separate surfaces: attention is live
|
|
104
|
+
tmux pane state, while notify is the explicit-ack pending queue derived from
|
|
105
|
+
AI reply panes and explicit pushes. The queue helps clicks route to work; it
|
|
106
|
+
does not own the truth of every live badge.
|
|
107
|
+
|
|
108
|
+
- **Push** — `projmux notify push` (or the in-process producer in
|
|
109
|
+
`internal/app/notify_producer.go`) appends an entry. Entries carry a
|
|
110
|
+
stable id (caller-supplied or `ai:<session>:<pane>` for the producer
|
|
111
|
+
path), text (capped at 80 runes), severity (`info|warn|critical`),
|
|
112
|
+
source (`ai|k8s|git|external`), TTL freshness metadata (default 600s), and a
|
|
113
|
+
`Target{Socket, Session, Window, Pane}`. Re-pushing an existing id
|
|
114
|
+
refreshes the entry's text and timestamp.
|
|
115
|
+
- **List** — `projmux notify list` returns newest-first until explicit ack.
|
|
116
|
+
TTL is not a removal condition. `projmux notify list --live` adds a
|
|
117
|
+
read-only comparison against live pane state, explaining manual reply
|
|
118
|
+
badges without queue entries, live AI replies with/missing queue entries,
|
|
119
|
+
and stale `ai:` entries.
|
|
120
|
+
- **Ack** — `projmux notify ack <id>` removes one entry; `--all`
|
|
121
|
+
flushes everything. Focus/click handlers do not ack rows.
|
|
122
|
+
- **Reconcile** — `projmux notify reconcile` walks
|
|
123
|
+
`tmux list-panes -a` and back-fills entries for panes whose
|
|
124
|
+
attention state is `reply` AND whose AI agent option is set,
|
|
125
|
+
reporting stale `ai:` entries that no longer match a live pane without
|
|
126
|
+
acking them.
|
|
127
|
+
`make install` and `projmux upgrade` invoke it so the queue
|
|
128
|
+
recovers from any drift introduced by a lost daemon.
|
|
129
|
+
|
|
130
|
+
The producer is wired to the attention state machine: a pane
|
|
131
|
+
transitioning to `reply` with an AI agent option set pushes an
|
|
132
|
+
`ai:<session>:<pane>` entry; the matching `clear` (or the AI
|
|
133
|
+
flow's `status set idle`) leaves it pending until explicit ack. Manual `attention toggle` on a
|
|
134
|
+
shell pane does not push because the agent option is empty —
|
|
135
|
+
the queue is intentionally AI-driven only.
|
|
136
|
+
|
|
137
|
+
See [notify-queue.md](notify-queue.md) for the full reference.
|
|
138
|
+
|
|
139
|
+
## Usage snapshots
|
|
140
|
+
|
|
141
|
+
`projmux usage` and `projmux status usage` share a single `Manager`
|
|
142
|
+
that walks two registered adapters (Claude, Codex) and persists the
|
|
143
|
+
result to `<state>/projmux/usage/snapshots.json` (or
|
|
144
|
+
`PROJMUX_USAGE_STATE_DIR`). The cache file is the authoritative source
|
|
145
|
+
for the HUD render path so the tmux status interval never blocks on a
|
|
146
|
+
network call.
|
|
147
|
+
|
|
148
|
+
- **Per-adapter throttle** — Claude reports a 5-minute hint via the
|
|
149
|
+
`ThrottleHinter` interface; Codex falls through to the global
|
|
150
|
+
`30s` floor used by `status usage`. `MaybeCollect` only invokes an
|
|
151
|
+
adapter when `now - last_collect >= throttle`. `--force` bypasses the
|
|
152
|
+
gate.
|
|
153
|
+
- **429 backoff** — Claude implements `BackoffStater`. On HTTP 429
|
|
154
|
+
the adapter persists `BackoffState{Until, Consecutive}`: the
|
|
155
|
+
default cooldown is 30 minutes, doubling per consecutive 429 up to a
|
|
156
|
+
60-minute cap. A `Retry-After` header (when present) raises the floor.
|
|
157
|
+
During backoff `Collect` short-circuits (no network call). A clean
|
|
158
|
+
200 resets the streak. `--force` clears the persisted state via the
|
|
159
|
+
`BackoffResetter` interface so the next call attempts the network
|
|
160
|
+
call regardless of streak.
|
|
161
|
+
- **Failure preservation** — adapter failures do not erase prior
|
|
162
|
+
rows. The Manager merges new snapshots over the on-disk slice, so a
|
|
163
|
+
transient 429 keeps the last known good numbers visible.
|
|
164
|
+
|
|
165
|
+
See [usage-tracking.md](usage-tracking.md) for adapter detail (token
|
|
166
|
+
refresh, rollout schema).
|
|
167
|
+
|
|
168
|
+
## Two-line clickable status bar
|
|
169
|
+
|
|
170
|
+
projmux configures tmux with `status 2`. Line 0 is the existing
|
|
171
|
+
session/window/path/git/kube/clock row. Line 1 splits the notification bar
|
|
172
|
+
(left half, capped at 80 cells) and the AI usage HUD (right half, capped at
|
|
173
|
+
120 cells) using tmux `#[align=left]` / `#[align=right]`. Each clickable
|
|
174
|
+
segment is wrapped in a tmux user-defined range (`#[range=user|<id>]...
|
|
175
|
+
#[norange]`) and dispatched through `projmux statusbar click <range-id>`. A
|
|
176
|
+
single `bind -n MouseDown1Status` covers both lines because tmux fires
|
|
177
|
+
`MouseDown1Status` from any line of a multi-line status bar with
|
|
178
|
+
`#{mouse_status_range}` resolving to whichever range the cursor was over.
|
|
179
|
+
|
|
180
|
+
| Range id | Line | Click action | Keybinding |
|
|
181
|
+
|----------|------|-------------------------------------------|--------------|
|
|
182
|
+
| session | 0 | popup `projmux sessions --ui=popup` | prefix+s s |
|
|
183
|
+
| pwd | 0 | copy pane_current_path and show path popup | prefix+s p |
|
|
184
|
+
| kube | 0 | popup `projmux switch --ui=popup` | prefix+s k |
|
|
185
|
+
| git | 0 | popup `projmux switch --ui=popup` | prefix+s g |
|
|
186
|
+
| usage | 1 | popup `projmux usage` | prefix+s u |
|
|
187
|
+
| notify | 1 | focus origin pane of newest notification | prefix+s n |
|
|
188
|
+
|
|
189
|
+
The keyboard chord uses `bind-key s switch-client -T projmux-status` so the
|
|
190
|
+
prefix-then-`s`-then-letter shortcut routes through the same dispatcher as
|
|
191
|
+
the mouse click. Empty `#{mouse_status_range}` (clicks on whitespace) is a
|
|
192
|
+
no-op so the binding never flashes a spurious error.
|
|
193
|
+
|
|
194
|
+
## Non-goals
|
|
195
|
+
|
|
196
|
+
- replacing tmux
|
|
197
|
+
- owning terminal emulator bindings
|
|
198
|
+
- becoming a generic worktree orchestrator
|
|
199
|
+
- implementing a fully custom TUI before parity is reached
|
|
Binary file
|
|
Binary file
|