projmux 0.15.2 → 0.16.0
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 +3 -4
- package/README.md +3 -3
- package/docs/agent-message-replies.md +82 -2
- package/docs/ai-agent-shortcuts.md +6 -5
- package/docs/architecture.md +149 -63
- package/docs/claude-coordination-endpoints.md +192 -21
- package/docs/cli-guide.md +322 -124
- package/docs/cli.md +605 -500
- package/docs/codex-installed-compatibility.md +6 -11
- package/docs/codex-native-required-migration.md +1 -59
- package/docs/configuration.md +164 -176
- package/docs/globalization.md +11 -1
- package/docs/heterogeneous-dialogue-canary.md +8 -3
- package/docs/hooks.md +83 -32
- package/docs/keybindings.md +108 -3
- package/docs/legacy-cli-retirement.md +3 -3
- package/docs/legacy-diagnostics-inventory.md +4 -4
- package/docs/native-picker.md +3 -5
- package/docs/notify-queue.md +1 -1
- package/docs/operational-diagnostics.md +53 -31
- package/docs/pr-guideline.md +66 -22
- package/docs/release.md +97 -0
- package/docs/replacement-contract.md +66 -58
- package/docs/resource-attribution.md +2 -2
- package/docs/session-restore.md +46 -80
- package/docs/settings-ia.md +43 -20
- package/docs/statusbar.md +25 -22
- package/docs/testing.md +15 -0
- package/docs/theme-palette.md +14 -0
- package/docs/tmux-surface-inventory.md +8 -10
- package/docs/troubleshooting.md +2 -4
- package/docs/upgrading.md +142 -7
- package/docs/usage-tracking.md +56 -53
- package/package.json +5 -5
- package/docs/agent-workflow.md +0 -2123
- package/docs/codex-generation-pool.md +0 -623
- package/docs/codex-stored-qualification.md +0 -45
|
@@ -348,14 +348,19 @@ a recorded verdict moves. Neither it nor L20 proves:
|
|
|
348
348
|
- acceptance of unknown frames or fields, which the closed vocabulary rejects
|
|
349
349
|
by design.
|
|
350
350
|
|
|
351
|
-
|
|
352
|
-
|
|
351
|
+
L20 replays every corpus item whose verdict is `drop` through the production
|
|
352
|
+
reply-only validator. Its Claude fixture reads the corpus at run time, emits each
|
|
353
|
+
dropped side frame with its key set unchanged after init and before its startup
|
|
354
|
+
result, and the scenario requires the emitted names to equal the corpus drop
|
|
355
|
+
set. Those frames are key-shape placeholders, not model output. L20 does not
|
|
356
|
+
emit the recorded real shapes the validator rejects today:
|
|
353
357
|
|
|
354
358
|
- `result-success-25-keys`: the result allowlist lacks `origin`;
|
|
355
359
|
- `system-init-allowlist-diff`: the init allowlist lacks `memory_paths` and
|
|
356
360
|
`terminal_slash_commands`.
|
|
357
361
|
|
|
358
|
-
Shapes without preserved evidence are gaps, not corpus items
|
|
362
|
+
Shapes without preserved evidence are gaps, not corpus items, so neither the
|
|
363
|
+
corpus nor L20 exercises them: `command_lifecycle`
|
|
359
364
|
keys and values; a non-null assistant `context_management` value; `system`
|
|
360
365
|
`thinking_tokens` frames; hook and user `tool_result` frames; the exact real init
|
|
361
366
|
key set; nested values of every frame; `rate_limit_event` envelope keys beyond
|
package/docs/hooks.md
CHANGED
|
@@ -117,10 +117,8 @@ special fields—`[env]` preserves any valid user-supplied key verbatim and no
|
|
|
117
117
|
Global hooks under `$XDG_CONFIG_HOME` are prompt-free.
|
|
118
118
|
|
|
119
119
|
Project-local executable automation is gated by trust-on-first-use. This
|
|
120
|
-
|
|
121
|
-
startup/session environment settings
|
|
122
|
-
`.projmux/layouts/*.toml` named snapshot before projmux replays any declared
|
|
123
|
-
`command`.
|
|
120
|
+
covers `.projmux/config.toml` before projmux runs hooks or applies
|
|
121
|
+
startup/session environment settings.
|
|
124
122
|
Approving "always"
|
|
125
123
|
records the file content hash in:
|
|
126
124
|
|
|
@@ -131,19 +129,13 @@ ${XDG_STATE_HOME:-$HOME/.local/state}/projmux/trusted-projects.json
|
|
|
131
129
|
The trust key is the absolute repository path and each artifact path is stored
|
|
132
130
|
relative to that repository. Each project entry has a
|
|
133
131
|
`trusted_at` timestamp and a `files` map of relative paths to SHA-256 hashes.
|
|
134
|
-
When file content changes
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
read once; those exact bytes are both hashed and parsed, and the resulting
|
|
138
|
-
in-memory snapshot is what restore uses. In non-interactive contexts such as
|
|
139
|
-
tmux run-shell or CI, untrusted or changed project-local executable files fail
|
|
140
|
-
closed with a warning.
|
|
132
|
+
When file content changes, projmux asks again and shows the old and new
|
|
133
|
+
SHA-256 hashes. In non-interactive contexts such as tmux run-shell or CI,
|
|
134
|
+
untrusted or changed project-local executable files fail closed with a warning.
|
|
141
135
|
|
|
142
136
|
Set `PROJMUX_PROJECT_HOOKS=off` to disable project-local hook discovery
|
|
143
137
|
entirely. Project-local hooks can also be disabled from `projmux settings`
|
|
144
|
-
under Labs. The global hook still runs either way.
|
|
145
|
-
or bypass executable named-snapshot commands. A layout without a startup
|
|
146
|
-
`command` does not require executable-artifact approval.
|
|
138
|
+
under Labs. The global hook still runs either way.
|
|
147
139
|
|
|
148
140
|
## Startup Commands
|
|
149
141
|
|
|
@@ -531,6 +523,16 @@ default install catalog is based on Claude Code 2.1.140 and represents the
|
|
|
531
523
|
| `CwdChanged` | marks the matched pane hook-active and writes a quiet ingest diagnostic; no notify queue entry is pushed |
|
|
532
524
|
| `FileChanged` | marks the matched pane hook-active and writes a quiet ingest diagnostic; no notify queue entry is pushed |
|
|
533
525
|
|
|
526
|
+
Current Claude Code (2.1.277) sends no hook when the operator denies a
|
|
527
|
+
permission dialog, so neither `PermissionDenied` nor `Stop` closes it and the
|
|
528
|
+
Agent keeps its `approval_required` observation. The held coordination message
|
|
529
|
+
release is therefore a second transcript tail reader besides `Stop`: while a
|
|
530
|
+
held message waits on that Agent, it reads the tail (at most 256 KiB) of the
|
|
531
|
+
`transcript_path` recorded in the Agent's own Registry binding, and looks only
|
|
532
|
+
at each line's type, subtype, and timestamp and whether an assistant line has a
|
|
533
|
+
`tool_use` item. Nothing it reads is stored, logged, or forwarded. See
|
|
534
|
+
[held messages](claude-coordination-endpoints.md#held-while-the-target-awaits-its-operator).
|
|
535
|
+
|
|
534
536
|
Hook-generated queue rows use the same compact body catalog: agent label,
|
|
535
537
|
event category, then the best available summary (Codex assistant text, Claude
|
|
536
538
|
tool/action summary, transcript summary, error, or teammate labels). Structured
|
|
@@ -695,6 +697,53 @@ Codex and are managed from `Settings > Notifications > Agent event behavior`.
|
|
|
695
697
|
They only affect ingest delivery; `projmux agent integrate claude` still uses the
|
|
696
698
|
catalog `install` field for installed hook events.
|
|
697
699
|
|
|
700
|
+
### Answering AskUserQuestion From The Command Line
|
|
701
|
+
|
|
702
|
+
`projmux agent integrate claude` also installs one `PreToolUse` entry with
|
|
703
|
+
`"matcher": "AskUserQuestion"` that runs
|
|
704
|
+
`projmux internal claude-question-hook` (marker
|
|
705
|
+
`projmux-managed:claude-question:v1`, `"timeout": 315`). Unlike the ingest
|
|
706
|
+
command its stdout is not discarded, because that is where an answer is handed
|
|
707
|
+
to Claude Code. Re-running the integration keeps exactly one such entry,
|
|
708
|
+
`--remove` deletes it, and `config apply` never adds or changes it.
|
|
709
|
+
|
|
710
|
+
The hook does nothing unless the Claude Agent that asks was opted in:
|
|
711
|
+
|
|
712
|
+
```sh
|
|
713
|
+
projmux agent question enable <agent-ref>
|
|
714
|
+
projmux agent question disable <agent-ref>
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
For every other Agent, and for a subagent's question, the hook prints nothing
|
|
718
|
+
and exits at once, so Claude Code shows its usual question prompt.
|
|
719
|
+
|
|
720
|
+
For an opted-in Agent the hook records the question and holds the tool call
|
|
721
|
+
open for up to 300 seconds. While it waits, Claude Code shows the hook's status
|
|
722
|
+
message instead of the question prompt; pressing Esc cancels the wait and
|
|
723
|
+
declines the question. Answer it from any shell:
|
|
724
|
+
|
|
725
|
+
```sh
|
|
726
|
+
projmux agent question list <agent-ref> [-o json]
|
|
727
|
+
projmux agent question answer <agent-ref> <question-id> --option 1=<label> --index 2=<n> --text 3=<free text>
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
Questions are numbered from 1 in the order Claude asked them, and so are the
|
|
731
|
+
options of each question. `--option <n>=<label>` picks an option by its exact
|
|
732
|
+
label, `--index <n>=<k>` by its number, and `--text <n>=<text>` answers with
|
|
733
|
+
free text; a label that is not one of the options is refused rather than taken
|
|
734
|
+
as free text. A multi-select question takes several `--option`/`--index`
|
|
735
|
+
occurrences, which are joined with `", "` in option order; a single-select
|
|
736
|
+
question takes exactly one. Every question needs an answer. A refused answer
|
|
737
|
+
changes nothing and names one reason token: `question-not-found`,
|
|
738
|
+
`question-not-pending` (already answered), `question-expired`,
|
|
739
|
+
`question-closed`, `question-invalid-answer`, `question-channel-off`, or
|
|
740
|
+
`question-provider-unsupported`.
|
|
741
|
+
|
|
742
|
+
If nobody answers within 300 seconds, the question expires and Claude Code
|
|
743
|
+
shows its own prompt as usual. `agent question disable` also hands every
|
|
744
|
+
question the Agent is still holding back to that prompt immediately. Records
|
|
745
|
+
live in `<state dir>/agent-questions/` and settled ones are kept for a day.
|
|
746
|
+
|
|
698
747
|
## Antigravity Hook Ingest
|
|
699
748
|
|
|
700
749
|
`projmux internal agent-hook ingest antigravity-hook --event <event> < payload.json` accepts
|
|
@@ -702,19 +751,24 @@ Antigravity CLI `agy` hook payloads. Antigravity v1.1.12 stdin does
|
|
|
702
751
|
not include the event name, so the command's `--event` value is authoritative.
|
|
703
752
|
Payload event aliases remain a compatibility fallback when `--event` is
|
|
704
753
|
omitted. `projmux agent integrate antigravity [--dry-run|--remove]` owns exactly
|
|
705
|
-
the named `projmux` entry in `~/.gemini/config/hooks.json
|
|
706
|
-
|
|
707
|
-
|
|
754
|
+
the named `projmux` entry in `~/.gemini/config/hooks.json`. Other named hooks,
|
|
755
|
+
their fields, and unknown JSON values remain untouched. projmux does not
|
|
756
|
+
install, read, or judge the Antigravity `statusLine` in
|
|
757
|
+
`~/.gemini/antigravity-cli/settings.json`, and never creates that file. The generated commands
|
|
708
758
|
use the stable absolute projmux executable because Antigravity runs handlers
|
|
709
759
|
with the config directory as cwd. The command refuses unmanaged name/command
|
|
710
760
|
conflicts, malformed JSON, symlink paths, and permission failures with an
|
|
711
761
|
actionable diagnostic. Doctor/Settings distinguish installed, missing,
|
|
712
762
|
conflicting, and stale managed entries; stale covers executable, event/schema,
|
|
713
763
|
or stdout-fallback drift and is refreshed by the install command.
|
|
714
|
-
|
|
715
|
-
`
|
|
716
|
-
|
|
717
|
-
|
|
764
|
+
|
|
765
|
+
Older releases also installed a `statusLine` bridge. `projmux config apply`
|
|
766
|
+
(and so `make install`) removes only a `statusLine` whose `command` carries the
|
|
767
|
+
`projmux-managed:antigravity-statusline:v1` marker, byte-preserving the rest of
|
|
768
|
+
the file; `agent integrate antigravity --remove` removes it too. Any other
|
|
769
|
+
`statusLine` value is left untouched and never produces a conflict. Until that
|
|
770
|
+
removal runs, the leftover bridge's `--event Statusline` call exits 0 with
|
|
771
|
+
empty stdout and changes nothing.
|
|
718
772
|
|
|
719
773
|
The default Antigravity catalog records the five official v1.1.12 events and
|
|
720
774
|
installs four non-permission events:
|
|
@@ -726,18 +780,16 @@ installs four non-permission events:
|
|
|
726
780
|
| `PostInvocation` | marks the matched pane hook-active and writes a quiet bookkeeping diagnostic; no notify queue entry is pushed |
|
|
727
781
|
| `PostToolUse` | marks the matched pane hook-active, retains tool error metadata in quiet diagnostics, and pushes no notify queue entry |
|
|
728
782
|
| `Stop` | pushes an info completion unless an explicit error signal requires a critical error row |
|
|
729
|
-
| `Statusline` with `tool_confirmation_pending=true` | pushes/replaces a deduped critical approval-required row outside the hook catalog |
|
|
730
|
-
| `Statusline` with `agent_state=thinking|working|tool_use` | moves the matched pane to thinking/busy without notifying, unless a terminal completion/approval state must be preserved from a late refresh; a new `PreInvocation` resets the next generation to busy |
|
|
731
|
-
| `Statusline` with `agent_state=idle` or `tool_confirmation_pending=false` | quiet update; does not clear completion/approval attention and creates no notification |
|
|
732
783
|
| unknown events | mark the matched pane hook-active and write quiet ingest diagnostics only |
|
|
733
784
|
|
|
734
|
-
Antigravity
|
|
785
|
+
Antigravity has no official approval-required or mid-turn busy event, so
|
|
786
|
+
projmux shows neither for Antigravity. Antigravity notify rows use
|
|
787
|
+
`agent=antigravity` metadata. The v1.1.12 parser
|
|
735
788
|
retains common camelCase `conversationId`, `workspacePaths`, `transcriptPath`,
|
|
736
789
|
`artifactDirectoryPath`, and `modelName`; invocation `invocationNum` and
|
|
737
790
|
`initialNumSteps`; post-tool `toolCall`, `stepIdx`, and `error`; and Stop
|
|
738
791
|
`executionNum`, `terminationReason`, `error`, and `fullyIdle`. Existing aliases
|
|
739
|
-
such as `conversation_id`, `cwd`, `workspace.path
|
|
740
|
-
`statusline.tool_confirmation_pending` remain accepted. The first non-empty
|
|
792
|
+
such as `conversation_id`, `cwd`, and `workspace.path` remain accepted. The first non-empty
|
|
741
793
|
`workspacePaths` value is only a cwd fallback candidate; empty/absent arrays do
|
|
742
794
|
not become the process cwd, and inherited `$TMUX_PANE` still wins attribution.
|
|
743
795
|
`NO_TOOL_CALL`, `MODEL_STOP`, and known normal reasons are info completions.
|
|
@@ -756,9 +808,9 @@ The named entry in `hooks.json` remains the install source of truth. Use
|
|
|
756
808
|
`agy -p '/hooks' --output-format json` only as a read-only runtime diagnosis of
|
|
757
809
|
loaded sources/events; its result is never used to generate or rewrite config.
|
|
758
810
|
Antigravity ingest uses `conversationId` as pane thread metadata for matching
|
|
759
|
-
and as
|
|
811
|
+
and as Agent resume metadata. Resume uses
|
|
760
812
|
`agy --conversation <uuid>` only when that id is present and UUID-shaped;
|
|
761
|
-
otherwise
|
|
813
|
+
otherwise the resume is refused rather than starting a fresh Agent. Official snake_case
|
|
762
814
|
`cwd`, `conversation_id`, `transcript_path`, `agent_state`,
|
|
763
815
|
`tool_confirmation_pending`, and structured `context_window.used_percentage`
|
|
764
816
|
plus token fields are parsed directly. The structured percentage is persisted
|
|
@@ -824,13 +876,12 @@ empty.
|
|
|
824
876
|
| `PROJMUX_SESSION_KIND` | `persistent` or `ephemeral` | `persistent` or `ephemeral` | empty | empty |
|
|
825
877
|
| `PROJMUX_VERSION` | projmux version | projmux version | projmux version | projmux version |
|
|
826
878
|
| `PROJMUX_SOCKET` | app socket metadata (`projmux`) | app socket metadata (`projmux`) | app socket metadata (`projmux`) | queue-entry socket when known; otherwise omitted |
|
|
827
|
-
| `PROJMUX_PANE` | omitted: no pane exists yet | exact id returned by standard persistent/ephemeral `tmux new-session`, such as `%7
|
|
879
|
+
| `PROJMUX_PANE` | omitted: no pane exists yet | exact id returned by standard persistent/ephemeral `tmux new-session`, such as `%7` | omitted | target pane when known; otherwise omitted |
|
|
828
880
|
|
|
829
881
|
`pre-create` intentionally has no `PROJMUX_PANE`: it runs before
|
|
830
882
|
`tmux new-session` creates the first pane. Standard persistent and ephemeral
|
|
831
883
|
`post-create` paths run after creation and therefore receive that exact pane
|
|
832
|
-
id.
|
|
833
|
-
returned pane at its lifecycle boundary, so it omits `PROJMUX_PANE`.
|
|
884
|
+
id.
|
|
834
885
|
`PROJMUX_SOCKET` is routing metadata for hook commands; it does not imply that
|
|
835
886
|
the tmux client itself adds `-L` to its commands. The `post-attach` and
|
|
836
887
|
`send-noti` cells describe their existing contexts; this contract adds no pane
|
package/docs/keybindings.md
CHANGED
|
@@ -194,8 +194,9 @@ Optional direct keys can be added for actions such as:
|
|
|
194
194
|
| `AIResumePickerToggle` | AI resume session picker; default `Alt-4`; pressing again closes the picker popup |
|
|
195
195
|
| `ai-split-right` | Open a new direct AI split to the right |
|
|
196
196
|
| `ai-split-down` | Open a new direct AI split below |
|
|
197
|
-
| `new-window` | New tmux window in the current pane directory |
|
|
198
|
-
| `rename-window` | Rename the current
|
|
197
|
+
| `new-window` | New tmux window in the current pane directory, opened with the saved launch default |
|
|
198
|
+
| `rename-window` | Rename the current Window in the Registry; see [Rename keys](#rename-keys) |
|
|
199
|
+
| `rename-pane-label` | Rename the current Pane in the Registry; see [Rename keys](#rename-keys) |
|
|
199
200
|
|
|
200
201
|
`AISplitPickerToggle` is the `Alt-7` popup picker toggle. It opens or closes
|
|
201
202
|
the picker UI where the user chooses the AI split mode. It is separate from
|
|
@@ -205,6 +206,70 @@ The direct AI split actions create a new managed AI pane each time they run.
|
|
|
205
206
|
Existing AI panes are left in place; the requested direction controls where the
|
|
206
207
|
new pane is created.
|
|
207
208
|
|
|
209
|
+
A UI split focuses the new Pane. This covers the saved-default split key, the
|
|
210
|
+
provider and shell direct keys, a selection in the `Alt-7` picker or the resume
|
|
211
|
+
picker (including its `new` row), and the Pane menu's Horizontal Split /
|
|
212
|
+
Vertical Split. Once the create commits, the new Pane becomes the Window's
|
|
213
|
+
active Pane, but only when the client that pressed the key or clicked the menu
|
|
214
|
+
is still attached and still showing that Window. If that client has detached
|
|
215
|
+
or moved to another Window, focus is left alone and the new Pane stays. The
|
|
216
|
+
client is never moved to the Window. If the focus step itself fails, the Pane
|
|
217
|
+
is kept and that client sees one line:
|
|
218
|
+
`Created Pane, but projmux could not focus it: <reason>`. The public
|
|
219
|
+
`projmux create pane` and `create agent` commands never change focus.
|
|
220
|
+
|
|
221
|
+
A selection in the `Alt-7` picker or the resume picker closes its popup at
|
|
222
|
+
once. The picker hands the selection to a detached job on the same tmux server
|
|
223
|
+
and exits, and that job runs the same create the picker used to run while the
|
|
224
|
+
popup stayed up as an empty frame. The new Pane therefore appears a moment
|
|
225
|
+
after the popup closes. A successful split still shows nothing else; a refused
|
|
226
|
+
create, a failed focus, or a split start notice reaches the client that pressed
|
|
227
|
+
the key as one line. Every picker row travels this way: a selection is a plain
|
|
228
|
+
value -- a provider, and for a resume the conversation it names. The provider
|
|
229
|
+
picker offers one row per enabled provider plus the shell row; it has no
|
|
230
|
+
per-launch model or effort row.
|
|
231
|
+
|
|
232
|
+
### The new Window's first Pane
|
|
233
|
+
|
|
234
|
+
`window.create` (v0 id `new-window`) and the Window menu's New At End decide the
|
|
235
|
+
new Window's first Pane before the Window exists, following the saved launch
|
|
236
|
+
default -- the same setting the saved-default split key reads (Settings > AI
|
|
237
|
+
Settings, stored in `$XDG_CONFIG_HOME/projmux/tmux-ai-split-mode`). The order is:
|
|
238
|
+
|
|
239
|
+
1. Ask. A picker mode opens its picker on the Pane the key was pressed in; a
|
|
240
|
+
provider mode and `shell` are already the answer and open nothing.
|
|
241
|
+
2. Create the Window with one shell Pane.
|
|
242
|
+
3. Fill it: an Agent answer is created in that Window first, and the shell is
|
|
243
|
+
then removed through the canonical Pane delete.
|
|
244
|
+
4. Move the pressing client onto the finished Window.
|
|
245
|
+
|
|
246
|
+
The client therefore never sees a shell Pane that is about to be replaced.
|
|
247
|
+
|
|
248
|
+
| Saved default | The new Window ends up with |
|
|
249
|
+
| --- | --- |
|
|
250
|
+
| `shell` | the shell Pane the create made; nothing else runs |
|
|
251
|
+
| `claude`, `codex`, `antigravity` | exactly that Agent Pane, with no picker |
|
|
252
|
+
| `selective` (also the unset default) | whatever the `Alt-7` picker chose: that Agent Pane, or the shell Pane for the shell row; its `resume` row opens the resume session list in the same popup |
|
|
253
|
+
| `resume` | whatever the resume picker chose, on the same terms |
|
|
254
|
+
|
|
255
|
+
Cancelling the picker creates nothing: no Window, and the client stays where it
|
|
256
|
+
was. If the picker cannot be opened, nothing is created either. An Agent answer
|
|
257
|
+
is committed with its Window in one transaction, so a provider that Settings has
|
|
258
|
+
since disabled or an Agent that could not be created leaves no Window behind.
|
|
259
|
+
Both report one line on the pressing client instead of the usual
|
|
260
|
+
`Created Window`:
|
|
261
|
+
`projmux Create Window failed; no Window was created: <reason>`. The line is
|
|
262
|
+
fitted to that client's width (80 cells when the width cannot be read). The
|
|
263
|
+
outcome is never cut; a reason too long to fit keeps its front, which names the
|
|
264
|
+
step that failed, and its end, where tmux's own cause is, and loses its middle
|
|
265
|
+
to one `…`. A create whose pressing client could not be moved still fills the
|
|
266
|
+
Window with what was chosen and shows the existing `Created Window, but
|
|
267
|
+
projmux could not move this client to it` line.
|
|
268
|
+
|
|
269
|
+
The typed `projmux create window` and `projmux create agent --create-window`
|
|
270
|
+
are unchanged and never read the saved default: a typed command's outcome
|
|
271
|
+
stays visible in its own argv.
|
|
272
|
+
|
|
208
273
|
Pane switching is catalogued as transport-dependent and the generated app tmux
|
|
209
274
|
config binds `M-Left`, `M-Right`, `M-Up`, and `M-Down` to `select-pane`
|
|
210
275
|
movement. Previous/next window remain transport-dependent and the generated app
|
|
@@ -295,7 +360,47 @@ write; the projmux process never issues `kill-pane` or `kill-window`.
|
|
|
295
360
|
|
|
296
361
|
A mouse menu acts on what was clicked, not on what is focused: Kill, Rename, and
|
|
297
362
|
New At End in the status-line Window menu act on the clicked Window, and the
|
|
298
|
-
Rename prompt starts with that Window's name.
|
|
363
|
+
Rename prompt starts with that Window's name. New At End opens the new Window's
|
|
364
|
+
first Pane with the saved launch default; see
|
|
365
|
+
[The new Window's first Pane](#the-new-windows-first-pane).
|
|
366
|
+
|
|
367
|
+
## Rename keys
|
|
368
|
+
|
|
369
|
+
`rename-window` (`window.rename`) and the Window menu Rename item run
|
|
370
|
+
`internal tmux window-rename`; `rename-pane-label` (`pane.rename`) runs
|
|
371
|
+
`internal tmux pane-rename`. Neither has a default key. Both are Registry
|
|
372
|
+
renames through the same owner as `projmux rename window` and
|
|
373
|
+
`projmux rename pane`: the Pane the key was pressed in, or the menu target,
|
|
374
|
+
resolves to its exact Registry Window or Pane, its `metadata.name` changes, and
|
|
375
|
+
its mirror converges with it. A Window rename writes `@projmux_window_name`
|
|
376
|
+
and, after the Registry commit, the tmux `window_name`; a Pane rename writes
|
|
377
|
+
`@projmux_pane_label`. A Continue that rebuilds the session from the Registry
|
|
378
|
+
therefore keeps the new name, including for the first Window of a session.
|
|
379
|
+
|
|
380
|
+
The prompt response is used exactly as typed:
|
|
381
|
+
|
|
382
|
+
- An empty or whitespace-only response changes nothing, not even the label,
|
|
383
|
+
and the client is told nothing was changed.
|
|
384
|
+
- A response that is not a valid name, such as one with a space, leading or
|
|
385
|
+
trailing whitespace, or a character like `'`, `"`, `$`, `;`, `%`, or `#`, is
|
|
386
|
+
refused with the reason and the usable spelling projmux would accept, for
|
|
387
|
+
example `a-b` for `a b`. Nothing is written.
|
|
388
|
+
- A name already used by another Window of the same Project or ControlSession,
|
|
389
|
+
or by another Pane of the same root, is refused. No suffix is added.
|
|
390
|
+
- A Pane with no Registry identity, such as one on a server projmux does not
|
|
391
|
+
manage, is refused with no write.
|
|
392
|
+
- A name a launcher chose, such as an Agent Pane's, renames like any other.
|
|
393
|
+
|
|
394
|
+
Every result is one line on the client that pressed the key. The response
|
|
395
|
+
reaches projmux on stdin inside a quoted here-document, so no shell parses it.
|
|
396
|
+
tmux still format-expands the `run-shell` command before any shell runs, as it
|
|
397
|
+
does at its own `:` prompt: a `#{...}` sequence in a response is substituted and
|
|
398
|
+
a `#(...)` sequence is run by tmux as a format job. Names cannot contain `#`, so
|
|
399
|
+
a response that still holds one is refused.
|
|
400
|
+
|
|
401
|
+
`internal tmux rename-pane <pane> <label>` is a separate label-only helper with
|
|
402
|
+
no generated binding. It writes `@projmux_pane_label` without touching the
|
|
403
|
+
Registry, so the next Continue restores the Registry name.
|
|
299
404
|
|
|
300
405
|
The standalone `~/.tmux.conf` snippet keeps tmux's stock `prefix <`, `prefix >`,
|
|
301
406
|
`MouseDown3Status`, `M-MouseDown3Status`, and `M-MouseDown3Pane` menus; it
|
|
@@ -32,12 +32,12 @@ unknown-command contract.
|
|
|
32
32
|
| `notify push`, `notify list`, `notify ack`, `notify reconcile` | `create notification`, `get notifications`, `notification ack`, `notification reconcile` |
|
|
33
33
|
| direct `pin list|add|remove|toggle|clear` | `pin project ...` |
|
|
34
34
|
| `prune ephemeral` | `runtime prune` |
|
|
35
|
-
| `prune session-state ...` |
|
|
36
|
-
| `session-state status|save|delete|restore|preview|popup` |
|
|
35
|
+
| `prune session-state ...` | None. Project snapshots were removed; `registry.json` is the only saved Project state |
|
|
36
|
+
| `session-state status|save|delete|restore|preview|popup` | None. The interim `create|get|delete|restore|prune snapshot` replacements were removed with Project snapshots; Continue project and Clear layout and open start closed Projects from the Registry |
|
|
37
37
|
| direct `tag list|toggle|clear`, `tag project ...` | `runtime tag ...` |
|
|
38
38
|
|
|
39
39
|
The surviving mixed-root commands are exactly `attach project`, `focus
|
|
40
|
-
project|window|pane`, `pin project`, and `prune project
|
|
40
|
+
project|window|pane`, `pin project`, and `prune agent|project`. The Shortcut
|
|
41
41
|
routes `doctor`, `quit`, `resources`, `settings`, `shell`, `switch`, and
|
|
42
42
|
`welcome` remain. Singular/plural resource-kind aliases remain.
|
|
43
43
|
|
|
@@ -7,11 +7,11 @@ CLI, config action, output format, permission, or retention contract.
|
|
|
7
7
|
|
|
8
8
|
| Surface | Producer / reader files | Current consumer and data boundary | Candidate and rationale | Separate follow-up |
|
|
9
9
|
| --- | --- | --- | --- | --- |
|
|
10
|
-
| `PROJMUX_USAGE_DEBUG` | `internal/app/usagecmd/usage.go`; adapter contract in `internal/core/usage/registry.go` and safe token helper in `internal/core/usage/adapters/claude/claude.go` | `projmux internal status usage` operator stderr; documented by `
|
|
11
|
-
| `PROJMUX_SESSIONSTATE_DEBUG` |
|
|
12
|
-
| `PROJMUX_FOCUS_DEBUG` | read/output gate in `internal/app/focus.go` | Operator stderr one-line raw target/session/window/pane/socket/client/source/kind; documented in `
|
|
10
|
+
| `PROJMUX_USAGE_DEBUG` | `internal/app/usagecmd/usage.go`; adapter contract in `internal/core/usage/registry.go` and safe token helper in `internal/core/usage/adapters/claude/claude.go` | `projmux internal status usage` operator stderr; documented by `docs/configuration.md` and `docs/usage-tracking.md`; `internal/app/usagecmd/usage_test.go` fixes the opt-in behavior; adapter errors are otherwise swallowed on the status hot path | **Keep.** Usage adapters are not adopted by the common journal and this opt-in stderr is the only immediate adapter failure consumer. | No removal follow-up. Re-evaluate only with a separately scoped usage diagnostics adoption. |
|
|
11
|
+
| `PROJMUX_SESSIONSTATE_DEBUG` | none; the autosave route that read it is now a no-op | Ignored; `docs/configuration.md` lists it as ignored | **Removed.** Autosave no longer exists, so there is no quiet error left to surface. The variable was dropped in the breaking change that removed autosave. | No. |
|
|
12
|
+
| `PROJMUX_FOCUS_DEBUG` | read/output gate in `internal/app/focus.go` | Operator stderr one-line raw target/session/window/pane/socket/client/source/kind; documented in `docs/cli.md`, `docs/configuration.md`, and `docs/operational-diagnostics.md`; `internal/app/focus_test.go` fixes the byte contract | **Deprecate candidate.** Phase 4 common focus events are safer for support, but the raw routing line remains a distinct local troubleshooting consumer. | Yes: publish safe replacement guidance and remove only through a breaking deprecation roadmap. |
|
|
13
13
|
| `PROJMUX_NATIVE_DEBUG_LOG` | `internal/ui/picker/backend.go` and `colorgrid.go` append native picker actions/query/value/errors; `internal/app/tmux.go` inherits it into popup environments | Developer-selected file path; popup inheritance is covered in `internal/app/tmux_test.go`; no public CLI/support reader, retention bound, or privacy redaction | **Remove candidate.** The opt-in trace can contain user query/value/error text and is not bounded. Current behavior remains intact because a safe bounded replacement and migration notice are outside Phase 6. | Yes: design a bounded private picker trace or common closed events, document migration, then ship removal as breaking. |
|
|
14
|
-
| bounded `ai-ingest.log` | Codex producer `internal/app/ai_ingest_codex.go`; Claude producer `internal/app/ai_ingest_claude.go`; Antigravity producer `internal/app/ai_ingest_antigravity.go`; tmux-bell producer plus shared `appendAIIngestLog`, path, cap, and trim in `internal/app/ai_ingest.go`; common projection in `internal/app/ai_ingest_diagnostics.go` | Canonical reader `projmux diagnostics agent-hook`; count-only support reader `internal/app/diagnostics_report.go`; docs consumers `docs/cli.md`, `docs/hooks.md`, `docs/configuration.md`, `docs/operational-diagnostics.md
|
|
14
|
+
| bounded `ai-ingest.log` | Codex producer `internal/app/ai_ingest_codex.go`; Claude producer `internal/app/ai_ingest_claude.go`; Antigravity producer `internal/app/ai_ingest_antigravity.go`; tmux-bell producer plus shared `appendAIIngestLog`, path, cap, and trim in `internal/app/ai_ingest.go`; common projection in `internal/app/ai_ingest_diagnostics.go` | Canonical reader `projmux diagnostics agent-hook`; count-only support reader `internal/app/diagnostics_report.go`; docs consumers `docs/cli.md`, `docs/hooks.md`, `docs/configuration.md`, and `docs/operational-diagnostics.md`; `internal/app/ai_ingest_test.go`, `internal/app/ai_ingest_diagnostics_test.go`, `internal/app/diagnostics_report_test.go`, and `test/integration/linux-smoke.sh` cover retention/consumer/corrupt/permission behavior | **Keep behind canonical diagnostics.** Phase 5 common events cover anomalous classification but intentionally omit normal state/notify/quiet/dedupe detail and all identity. | Re-evaluate only if the detailed local diagnostic requirement changes. |
|
|
15
15
|
|
|
16
16
|
The separate host resource status path is not a legacy debug surface:
|
|
17
17
|
`internal/app/status.go` invokes `internal/systemstatus.Sampler` for
|
package/docs/native-picker.md
CHANGED
|
@@ -17,7 +17,7 @@ picker process. `internal/ui/picker` owns the interaction contract and
|
|
|
17
17
|
| Deferred state | Deferred and event-triggered updates preserve query and selection by value, can repeat, and may explicitly choose a new focus value. | `TestNativeInteractiveDeferredUpdateTriggerRefreshesRepeatedly`; switch and notify sidebar mutable-refresh app tests |
|
|
18
18
|
| Preview | Popup previews use a right split, sidebar previews use a bottom split, control bytes and tabs are normalized before clipping, and preview scrolling/cycling rerenders in place. | `TestNativeInteractiveRendersWidePreviewBesideList`; `TestNativeInteractiveRendersDownPreviewBelowList`; `TestRenderSplitPreviewRowsNormalizesPreviewTabsBeforeTruncating`; `TestNativeInteractiveRendersPreviewOffset` |
|
|
19
19
|
| Mouse | SGR mouse input focuses on primary down, follows drag, accepts on matching release, and scrolls with the wheel. | `TestNativeInteractiveSelectsOnMouseRelease`; `TestNativeInteractiveMouseDragFollowsSelection`; `TestNativeInteractiveSupportsMouseWheelSelection` |
|
|
20
|
-
| Lifecycle | Interactive runs use the alternate screen, synchronized/coalesced frame updates, controlling-TTY fallback, and deterministic reader cleanup. | `TestNativeInteractiveUsesAlternateScreen`; `TestNativeInteractiveWrapsRedrawsInSynchronizedUpdates`; picker/setup lifecycle tests in `
|
|
20
|
+
| Lifecycle | Interactive runs use the alternate screen, synchronized/coalesced frame updates, controlling-TTY fallback, and deterministic reader cleanup. | `TestNativeInteractiveUsesAlternateScreen`; `TestNativeInteractiveWrapsRedrawsInSynchronizedUpdates`; picker/setup lifecycle tests in `internal/ui/picker/backend_test.go` and `internal/app/native_picker_test.go` |
|
|
21
21
|
|
|
22
22
|
## Rendering And Popup Chrome
|
|
23
23
|
|
|
@@ -97,7 +97,5 @@ saved-selector access, propagation, or external picker launch path.
|
|
|
97
97
|
|
|
98
98
|
## Maintenance
|
|
99
99
|
|
|
100
|
-
Update this document
|
|
101
|
-
|
|
102
|
-
coverage level, gains a new product flow, or changes input/render/action
|
|
103
|
-
semantics.
|
|
100
|
+
Update this document whenever picker behavior changes coverage level, gains a
|
|
101
|
+
new product flow, or changes input/render/action semantics.
|
package/docs/notify-queue.md
CHANGED
|
@@ -73,7 +73,7 @@ routing/debug context such as `agent`, `thread_id`, `turn_id`, `cwd`,
|
|
|
73
73
|
`teammate_name`. Antigravity hook rows carry `agent=antigravity`,
|
|
74
74
|
`conversation_id`, `termination_reason`, `fully_idle`,
|
|
75
75
|
`tool_confirmation_pending`, `agent_state`, and `context_window` when present.
|
|
76
|
-
The same `conversation_id` can seed
|
|
76
|
+
The same `conversation_id` can seed an Agent resume via
|
|
77
77
|
`agy --conversation <uuid>` when it is UUID-shaped. Antigravity
|
|
78
78
|
account quota remains outside notify attention semantics: `context_window` is a
|
|
79
79
|
separate conversation-local gauge and is never treated as quota data.
|
|
@@ -41,7 +41,7 @@ Project lifecycle operator diagnostics also keep plans mutually exclusive:
|
|
|
41
41
|
classes. Startup and unregister failures print the closed action, failing
|
|
42
42
|
stage, old Project UID, and new Project UID (or `-` when absent). These opaque
|
|
43
43
|
UIDs and stage labels are bounded control data; root paths, pane content,
|
|
44
|
-
history, prompts,
|
|
44
|
+
history, prompts, and transcripts are never identity or
|
|
45
45
|
intent authority.
|
|
46
46
|
|
|
47
47
|
Automatic Window teardown decisions use `component=topology` and
|
|
@@ -58,29 +58,52 @@ optional opaque `window_uid` (`win-…`) and `pane_uid` (`pane-…`) Registry UI
|
|
|
58
58
|
tmux `%N`/`@N`/`$N` handles, socket paths, session names, cwd, argv, and free
|
|
59
59
|
text are never recorded, and every other event family rejects these fields.
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
per
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
`
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
`
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
61
|
+
Create transactions use `component=create` and `event=create.outcome`: one
|
|
62
|
+
record per create transaction, written under the process `run_id`. It is
|
|
63
|
+
measurement only and changes nothing about the create itself. The kind of the
|
|
64
|
+
create is carried in the closed `operation` field: `window` (`create window`
|
|
65
|
+
and the UI new Window, including one whose answer is an Agent), `pane`
|
|
66
|
+
(`create pane`, the split UI's shell Pane, and the pane-menu split), `agent`
|
|
67
|
+
(`create agent` and the split UI's Agent Pane, including a resume-picker
|
|
68
|
+
pick, which creates a new Agent), or `resume` (`agent resume`, including the
|
|
69
|
+
resume `agent persona` runs). A successful transaction is `info`/`success`;
|
|
70
|
+
a failed one, including one that was rolled back, is `error`/`error` with
|
|
71
|
+
`kind=runtime`, so the support report's existing error-only projection
|
|
72
|
+
carries it. The record adds only two timings:
|
|
73
|
+
|
|
74
|
+
- `duration_ms` runs from entering the create transaction to its return. It
|
|
75
|
+
includes the runtime route bind, the wait for the Registry lock, the time
|
|
76
|
+
the lock is held, and on failure the rollback, and in every case the
|
|
77
|
+
create-operation lease clear. It excludes everything outside the
|
|
78
|
+
transaction: process start and exit, argument parsing, scope and selector
|
|
79
|
+
resolution, the Settings enabled-agents gate, the time a picker or prompt
|
|
80
|
+
waits for the operator, the result line printed after the commit, and
|
|
81
|
+
Agent activation observed after the transaction returns.
|
|
82
|
+
- `lock_held_ms` runs from entering the Registry mutation to the Registry
|
|
83
|
+
update returning. It includes the create's guards, reconciliation, Registry
|
|
84
|
+
and tmux mutations, the store's own validate and write, and the unlock. It
|
|
85
|
+
excludes the wait for the lock and the Registry read before the mutation
|
|
86
|
+
starts. It is absent when the transaction failed before it entered the
|
|
87
|
+
mutation, and `0 <= lock_held_ms <= duration_ms` always holds.
|
|
88
|
+
|
|
89
|
+
The record is appended after the transaction returns, so never while the
|
|
90
|
+
Registry lock is held, and a journal failure never changes the create's
|
|
91
|
+
result, exit status, stdout, or stderr. It does not replace the invocation's
|
|
92
|
+
`command.outcome`, and it does not count guard reads or time individual
|
|
93
|
+
guards. The generated Window rename also runs through the same transaction
|
|
94
|
+
and is not recorded, because it is not a create. Every other event family
|
|
95
|
+
rejects `lock_held_ms` and the `create` component.
|
|
96
|
+
|
|
97
|
+
projmux no longer emits `session-state.outcome` records. Project snapshots
|
|
98
|
+
were removed, and the retained `internal tmux autosave-session-state` route is
|
|
99
|
+
a no-op that writes nothing. Records written by older versions keep their
|
|
100
|
+
closed vocabulary: the `session-state.outcome` event, the
|
|
101
|
+
`session-state.save`, `session-state.autosave`, `session-state.restore`, and
|
|
102
|
+
`session-state.delete` operations with their `.failed` codes, the sources
|
|
103
|
+
`manual`, `settings-latest`, `settings-named`, `autosave`, `startup-latest`,
|
|
104
|
+
`startup-named`, and `prune`, and the aggregate `window_count`, `pane_count`,
|
|
105
|
+
`shell_recipe_count`, `agent_recipe_count`, `startup_recipe_count`, and
|
|
106
|
+
`item_count` fields still validate and parse when the journal is read.
|
|
84
107
|
|
|
85
108
|
Notify and focus transitions use the same process `run_id` and add only closed
|
|
86
109
|
`transition`, `disposition`, `provider`, `category`, and `route` enums. Notify
|
|
@@ -119,8 +142,9 @@ is the generic `ai`; ingest providers are `codex`, `claude`, `antigravity`, or
|
|
|
119
142
|
for example, `tmux-bell` can only emit `bell`, while watcher events can only use
|
|
120
143
|
the generic `ai` provider and `watcher` kind. Provider event names are projected
|
|
121
144
|
into semantic kinds such as `prompt`, `permission`, `stop`, `notification`,
|
|
122
|
-
`tool`, `session`, `compact`, `subagent`, `teammate`, `
|
|
123
|
-
`lifecycle`, `bell`, `payload`, or `unknown`.
|
|
145
|
+
`tool`, `session`, `compact`, `subagent`, `teammate`, `invocation`,
|
|
146
|
+
`lifecycle`, `bell`, `payload`, or `unknown`. `statusline` is still accepted
|
|
147
|
+
when reading older records but is no longer written. A raw or future event name can
|
|
124
148
|
therefore be diagnosed as `unknown` but can never extend the journal schema.
|
|
125
149
|
|
|
126
150
|
One watcher process emits at most one `started` transition, one terminal
|
|
@@ -288,22 +312,20 @@ before the next append, and the reader skips malformed or truncated records.
|
|
|
288
312
|
Classification is intentionally conservative for mutation-capable interactive
|
|
289
313
|
commands: opening session/project/settings/popup flows is treated as changing
|
|
290
314
|
even when a user cancels. Explicit read variants (`internal status`, `list`,
|
|
291
|
-
`get`,
|
|
315
|
+
`get`, config rendering, plain welcome, and the diagnostics viewer) remain
|
|
292
316
|
read-only. The successful automatic hook/poll paths `internal agent-hook ingest`, `attention
|
|
293
317
|
arm`, `attention clear`, `attention window`, `internal tmux autosave-session-state`, and
|
|
294
318
|
`window record` are also read-only so high-frequency operation does not append
|
|
295
319
|
to the journal; an error from any of them still records exactly one safe error
|
|
296
320
|
outcome. Explicit user mutations such as `attention toggle` retain their
|
|
297
321
|
state-changing success record. Direct top-level help and explicit preview-only intents (`update
|
|
298
|
-
apply --dry-run
|
|
299
|
-
`--dry-run`) are also read-only. Approved snapshot projection restore is a
|
|
300
|
-
state-changing operation. Doctor is a stricter
|
|
322
|
+
apply --dry-run` and AI integration dry-runs) are also read-only. Doctor is a stricter
|
|
301
323
|
boundary: successes and errors never append to this journal, so diagnostics do
|
|
302
324
|
not make its filesystem contract self-defeating. Support report success and
|
|
303
325
|
errors likewise never append; its strict reader shares the viewer's tolerant
|
|
304
326
|
decoder but never creates/locks/chmods/repairs/truncates the source journal.
|
|
305
327
|
Multi-mode commands such as AI status/topic,
|
|
306
|
-
terminal apply,
|
|
328
|
+
terminal apply, update check, and welcome popup inspect only
|
|
307
329
|
allowlisted mode/flag names; boolean `=false` values retain mutation-capable
|
|
308
330
|
classification, and no flag values are ever recorded. Help-looking tokens
|
|
309
331
|
after the direct command position stay conservatively mutation-capable because
|