acstack 0.0.0-stage → 0.47.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.
Files changed (143) hide show
  1. package/.claude-plugin/plugin.json +19 -0
  2. package/LICENSE +21 -0
  3. package/README.md +389 -2
  4. package/THIRD_PARTY_NOTICES +14 -0
  5. package/TROUBLESHOOTING.md +225 -0
  6. package/agents/codex/frontend-verifier.toml +352 -0
  7. package/agents/codex/task-checker.toml +345 -0
  8. package/agents/codex/task-executor.toml +157 -0
  9. package/agents/codex/test-writer.toml +149 -0
  10. package/agents/frontend-verifier.md +351 -0
  11. package/agents/task-checker.md +344 -0
  12. package/agents/task-executor.md +156 -0
  13. package/agents/test-writer.md +148 -0
  14. package/assets/playwriter-bridge/build-launcher.ps1 +32 -0
  15. package/assets/playwriter-bridge/doctor.ps1 +450 -0
  16. package/assets/playwriter-bridge/launcher-src.cs +131 -0
  17. package/assets/playwriter-bridge/opener.js +330 -0
  18. package/assets/playwriter-bridge/opener.ps1 +63 -0
  19. package/assets/playwriter-bridge/register-tasks.ps1 +328 -0
  20. package/assets/playwriter-bridge/relay.ps1 +50 -0
  21. package/assets/playwriter-bridge/stop.ps1 +125 -0
  22. package/assets/playwriter-bridge/sync.ps1 +271 -0
  23. package/assets/playwriter-bridge/tunnel.ps1 +325 -0
  24. package/assets/playwriter-bridge/vm-free-port.sh +166 -0
  25. package/assets/terminal-workspace/client-keybindings.md +87 -0
  26. package/assets/terminal-workspace/config.example.yaml +329 -0
  27. package/assets/terminal-workspace/setup.sh +4317 -0
  28. package/cli/README.md +47 -0
  29. package/cli/bin/acstack.js +3 -0
  30. package/cli/dist/index.js +25984 -0
  31. package/cli/dist/index.js.map +7 -0
  32. package/cli/package.json +59 -0
  33. package/docs/adr/0001-ste-writing-standard.md +16 -0
  34. package/docs/adr/0002-version-gate-not-auto-bump.md +35 -0
  35. package/docs/adr/0003-handoff-ack-command.md +19 -0
  36. package/docs/adr/0004-dev-setup-per-host.md +13 -0
  37. package/docs/adr/0005-two-orchestrators-per-host.md +25 -0
  38. package/docs/adr/0006-document-opener-service.md +89 -0
  39. package/docs/adr/0007-lead-check-reads-the-transcript.md +87 -0
  40. package/docs/adr/0008-cli-audits-skill-interviews.md +37 -0
  41. package/docs/adr/0009-verify-the-write-not-the-writer.md +51 -0
  42. package/docs/adr/0010-promote-dev-to-main-by-fast-forward.md +115 -0
  43. package/docs/adr/0011-node-header-is-the-edge-encoding.md +20 -0
  44. package/docs/adr/0012-node-kind-is-a-closed-set-of-five.md +31 -0
  45. package/docs/adr/0013-the-diagram-renderer-is-pure.md +23 -0
  46. package/docs/adr/0014-reading-a-node-hides-its-generated-diagram.md +29 -0
  47. package/docs/adr/0015-a-node-id-links-to-its-issue-through-an-anchor.md +37 -0
  48. package/docs/adr/0016-the-map-root-carries-no-status-of-its-own.md +21 -0
  49. package/docs/adr/0017-call-impeccable-copy-only-its-questions.md +13 -0
  50. package/docs/adr/index.md +17 -0
  51. package/docs/config-reference.md +572 -0
  52. package/docs/dev-setups.md +164 -0
  53. package/docs/migrate-0.8.md +28 -0
  54. package/docs/playwriter-bridge-windows.md +15 -0
  55. package/docs/terminal-workspace-keys.md +137 -0
  56. package/docs/terminal-workspace.md +1774 -0
  57. package/docs/workflows.md +309 -0
  58. package/hooks/ac-writing-style-reminder.sh +86 -0
  59. package/hooks/context-pressure.sh +583 -0
  60. package/hooks/hooks.json +50 -0
  61. package/hooks/session-start-handoff.sh +165 -0
  62. package/hooks/session-start.sh +214 -0
  63. package/orchestrator/AGENTS.md +532 -0
  64. package/output-styles/ac-writing-style.md +286 -0
  65. package/package.json +50 -4
  66. package/pi/agents/frontend-verifier.md +357 -0
  67. package/pi/agents/task-checker.md +348 -0
  68. package/pi/agents/task-executor.md +160 -0
  69. package/pi/agents/test-writer.md +154 -0
  70. package/pi/extension.ts +723 -0
  71. package/profiles/fullstack-python.yaml +29 -0
  72. package/profiles/node-typescript.yaml +23 -0
  73. package/profiles/python.yaml +24 -0
  74. package/skills/archive/SKILL.md +160 -0
  75. package/skills/bootstrap/SKILL.md +109 -0
  76. package/skills/bridge/HANDOFF.md +93 -0
  77. package/skills/bridge/SKILL-VM.md +292 -0
  78. package/skills/bridge/SKILL-WINDOWS.md +526 -0
  79. package/skills/bridge/SKILL.md +121 -0
  80. package/skills/browser-verify/SKILL.md +229 -0
  81. package/skills/code-review/SKILL.md +44 -0
  82. package/skills/commit/SKILL.md +106 -0
  83. package/skills/compact-and-continue/SKILL.md +241 -0
  84. package/skills/explore/SKILL.md +149 -0
  85. package/skills/grilling/SKILL.md +134 -0
  86. package/skills/handoff/SKILL.md +250 -0
  87. package/skills/handoff/launch-herdr.md +197 -0
  88. package/skills/handoff/launch-without-herdr.md +30 -0
  89. package/skills/handoff/lead-check.md +59 -0
  90. package/skills/handoff/outcomes.md +162 -0
  91. package/skills/handoff/running-agent.md +50 -0
  92. package/skills/handoff/watch.md +115 -0
  93. package/skills/host/SKILL.md +247 -0
  94. package/skills/host/detect-host.sh +297 -0
  95. package/skills/host/herdr.md +79 -0
  96. package/skills/host/install-herdr-block.sh +467 -0
  97. package/skills/host/install-orca.sh +512 -0
  98. package/skills/host/notes.md +97 -0
  99. package/skills/host/orca.md +160 -0
  100. package/skills/host/questions.md +163 -0
  101. package/skills/host/report.md +42 -0
  102. package/skills/implement/SKILL.md +230 -0
  103. package/skills/implement/decision-log.md +62 -0
  104. package/skills/implement/design-pass.md +32 -0
  105. package/skills/implement/relaxed-tdd.md +28 -0
  106. package/skills/map/SKILL.md +250 -0
  107. package/skills/map/frontend.md +227 -0
  108. package/skills/map/trackers/files.md +74 -0
  109. package/skills/map/trackers/github.md +180 -0
  110. package/skills/map/visuals.md +387 -0
  111. package/skills/new-worktree/SKILL.md +155 -0
  112. package/skills/new-worktree/detect-orchestrator.sh +328 -0
  113. package/skills/new-worktree/detect-orchestrator.test.sh +894 -0
  114. package/skills/new-worktree/herdr.md +84 -0
  115. package/skills/new-worktree/orca.md +101 -0
  116. package/skills/pre-commit-review/SKILL.md +242 -0
  117. package/skills/pre-commit-review/auto-fix.md +19 -0
  118. package/skills/pre-commit-review/interactive.md +35 -0
  119. package/skills/quick-fix/SKILL.md +125 -0
  120. package/skills/record-context/SKILL.md +106 -0
  121. package/skills/setup/SKILL.md +250 -0
  122. package/skills/setup/browser.md +123 -0
  123. package/skills/setup/design-review.md +97 -0
  124. package/skills/setup/first-run.md +114 -0
  125. package/skills/setup/report.md +68 -0
  126. package/skills/setup/row-fixes.md +196 -0
  127. package/skills/setup/terminal-workspace.md +153 -0
  128. package/skills/sync/SKILL.md +171 -0
  129. package/skills/teardown-worktree/SKILL.md +245 -0
  130. package/skills/teardown-worktree/detector.md +39 -0
  131. package/skills/teardown-worktree/herdr.md +113 -0
  132. package/skills/teardown-worktree/orca.md +61 -0
  133. package/skills/terminal-workspace/SKILL.md +249 -0
  134. package/skills/terminal-workspace/components.md +36 -0
  135. package/skills/terminal-workspace/config-choices.md +69 -0
  136. package/skills/terminal-workspace/emulator-keys.md +48 -0
  137. package/skills/terminal-workspace/headless-clipboard.md +175 -0
  138. package/skills/terminal-workspace/turn-off-and-update.md +104 -0
  139. package/skills/test-conventions/SKILL.md +59 -0
  140. package/skills/visual-docs/SKILL.md +246 -0
  141. package/skills/writing/SKILL.md +231 -0
  142. package/skills/writing/examples.md +153 -0
  143. package/skills/writing/vocabulary.md +96 -0
@@ -0,0 +1,249 @@
1
+ ---
2
+ name: terminal-workspace
3
+ description: "Install and configure the optional terminal workspace, which runs several coding agents side by side in one terminal. It installs five tools the user drives – herdr, gh-dash, diffnav, lazygit and harlequin – plus five that support them, two helpers of ACStack's own, and the pi coding agent with ACStack installed into it. One YAML file holds every config. Use when the user asks to set up parallel agents in the terminal, or mentions herdr, gh-dash, diffnav, yazi, harlequin or pi. Use it too when the user wants agents that keep running after they close the terminal, or asks to turn any of these on or off. Every component toggles on its own, and every change is reversible."
4
+ argument-hint: "[status | apply | outdated | upgrade [tool...] | disable <component> | uninstall]"
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ ## User input
9
+
10
+ ```text
11
+ $ARGUMENTS
12
+ ```
13
+
14
+ # Terminal workspace
15
+
16
+ The user drives several coding agents from one terminal, on a machine they reach
17
+ over the network. Every agent dies when the connection drops, and the tools that
18
+ read diffs and pull requests expect a desktop that machine does not have. What
19
+ does that machine need?
20
+
21
+ This skill installs herdr, a terminal multiplexer that keeps sessions alive
22
+ after a disconnect. It adds the tools that read diffs, pull requests and files
23
+ around it, and writes every config from one YAML file.
24
+
25
+ ACStack does not need any of this. Offer it, do not assume it.
26
+
27
+ ```mermaid
28
+ flowchart TD
29
+ IN["Twelve components, one YAML file<br/>(machine-level, not per-project)"] --> ST["See what this machine has<br/>(setup.sh status)"]
30
+ ST --> CF["Copy the config, walk the choices<br/>(~/.config/acstack/terminal-workspace.yaml)"]
31
+ CF --> AP["Install binaries, write the keys<br/>(setup.sh apply)"]
32
+ AP --> Q{"How does the user reach<br/>this machine?"}
33
+ Q -->|"an SSH shell"| KB["Free the keys the emulator swallows<br/>(client-keybindings.md)"]
34
+ Q -->|"a herdr client on their own machine"| RM["Attach with the server keymap<br/>(herdr --remote)"]
35
+ RM --> KB
36
+ KB --> FB["Copy, open or download fails<br/>(read the last lines of status)"]
37
+ AP --> OFF["Turn one component off<br/>(setup.sh disable, uninstall)"]
38
+ ST --> UP["Fetch what has moved on<br/>(setup.sh outdated, upgrade)"]
39
+ UP --> AP
40
+ ```
41
+
42
+ | Step in the diagram | Detail |
43
+ | ------------------------------------- | --------- |
44
+ | Twelve components, one YAML file | section 1 |
45
+ | See what this machine has | section 2 |
46
+ | Copy the config, walk the choices | section 3 |
47
+ | Install binaries, write the keys | section 4 |
48
+ | How does the user reach this machine? | section 5 |
49
+ | Attach with the server keymap | section 5 |
50
+ | Free the keys the emulator swallows | section 6 |
51
+ | Copy, open or download fails | section 7 |
52
+ | Turn one component off | section 8 |
53
+ | Fetch what has moved on | section 9 |
54
+
55
+ ## 1. Twelve components, installed for a user account and not for a project
56
+
57
+ *Twelve config components install thirteen tools. herdr holds the terminals and pi is a coding agent. The rest read diffs, pull requests, files and databases, and commit the result.*
58
+
59
+ This is **machine-level, not per-project**. It installs binaries and writes
60
+ keybindings for the user account, so it does not belong in
61
+ `acstack/project.yaml`.
62
+
63
+ Count components when you mean config keys, and tools when you mean binaries.
64
+ The config holds twelve component sections, plus an `enabled` master switch
65
+ above them. Eleven of those sections install thirteen tools between them:
66
+
67
+ - Five tools the user drives day to day: herdr, gh-dash, diffnav, lazygit and harlequin. tuicr joins them once a review starts
68
+ - Five tools that support them: delta, tuicr, yazi, mermaid-ascii and glow
69
+ - Two helpers of ACStack's own: acstack-md, and the acstack-clip and acstack-open pair
70
+ - The pi coding agent, with ACStack and pi-subagents installed into it
71
+
72
+ The twelfth, `neovim`, installs nothing. It writes one file into a neovim config
73
+ the user already has. `neovim` and `pi` both start off, because each writes into a config the user built.
74
+
75
+ Read [`components.md`](components.md) when the user asks what a component does, which key turns it on, or why a key sits where it does. It holds the table of all twelve and the two letters the setup reserves.
76
+
77
+ The two files this skill works with:
78
+
79
+ - **Config**: `~/.config/acstack/terminal-workspace.yaml`, copied from `assets/terminal-workspace/config.example.yaml`
80
+ - **Script**: `assets/terminal-workspace/setup.sh` in this plugin
81
+
82
+ The keys, on one page: [docs/terminal-workspace-keys.md](../../docs/terminal-workspace-keys.md).
83
+
84
+ Background and why each piece is there:
85
+ [docs/terminal-workspace.md](../../docs/terminal-workspace.md).
86
+
87
+ ## 2. Run `status` first, always
88
+
89
+ *`status` reports what this machine already has, before anything changes it.*
90
+
91
+ The script takes six commands, and this skill uses all of them.
92
+
93
+ Section 2 runs `status` to report, and section 4 runs `apply` to install.
94
+ Section 8 runs `disable <component>` and `uninstall` to undo. Section 9 runs `outdated`
95
+ and `upgrade` to fetch what has moved on.
96
+
97
+ Run the script from the plugin directory. Resolve the path rather than
98
+ guessing it:
99
+
100
+ ```bash
101
+ PLUGIN=$(dirname "$(dirname "$(dirname "$(readlink -f ~/.claude/acstack/bin/acstack)")")")
102
+ SETUP="$PLUGIN/assets/terminal-workspace/setup.sh"
103
+ bash "$SETUP" status
104
+ ```
105
+
106
+ The SessionStart hook repoints that CLI symlink at every start, so it names
107
+ the newest installed version. The `host` skill resolves its own script the
108
+ same way.
109
+
110
+ It reports three things.
111
+
112
+ Which binaries this machine has. Which components the config enables. Whether
113
+ the herdr config still holds the managed block, meaning the region between the
114
+ `# >>> acstack terminal-workspace >>>` and
115
+ `# <<< acstack terminal-workspace <<<` comment lines that `apply` writes.
116
+
117
+ Its last lines say where a copy and an open will land on this machine. Section
118
+ 7 reads them.
119
+
120
+ ## 3. Copy the config, then walk the user through the choices
121
+
122
+ *The config exposes far more keys than this. Fourteen of them are worth raising with the user, and the two that need no new vocabulary come first.*
123
+
124
+ Copy the example config before the first `apply`:
125
+
126
+ ```bash
127
+ cp "$(dirname "$SETUP")/config.example.yaml" ~/.config/acstack/terminal-workspace.yaml
128
+ ```
129
+
130
+ Then read [`config-choices.md`](config-choices.md) and ask about the settings it lists, in its order.
131
+
132
+ ## 4. `apply` installs the binaries and writes the keys
133
+
134
+ *One command, safe to repeat. Run it again after every config edit.*
135
+
136
+ ```bash
137
+ bash "$SETUP" apply
138
+ ```
139
+
140
+ `apply` installs any missing binary for an enabled component.
141
+
142
+ It writes the helper scripts and the herdr keymap. It writes the gh-dash
143
+ sections and keybindings. It sets delta as the git pager.
144
+
145
+ Running it again after a config edit updates every managed region in place.
146
+
147
+ The master switch comes first. With `enabled: false` at the top of the config,
148
+ `apply` exits without installing anything.
149
+
150
+ ### 4.1. What `apply` never overwrites
151
+
152
+ *Marked regions only. Whatever the user wrote outside them survives every re-apply.*
153
+
154
+ - Every edit sits between `# >>> acstack terminal-workspace >>>` and `# <<< acstack terminal-workspace <<<` markers. Hand-written config around them survives, and re-applying replaces only the managed region
155
+ - The herdr config carries up to five managed regions, one each inside `[keys]`, `[ui]`, `[theme]` and `[ui.toast]`, plus one at the end for `[[keys.command]]` and `[worktrees]`
156
+ - A key inside a marked region is acstack's, whatever table it sits in
157
+ - A table gets a region only when the config names a value for it
158
+ - So a user who asks for no theme keeps the one they wrote
159
+ - `apply` replaces a value the user set by hand on a key it manages, rather than joining it
160
+ - TOML forbids two of one key, and yazi and herdr both answer an unparseable config by throwing the whole file away
161
+ - `apply` drops a hand-written `[[mgr.prepend_keymap]]` on a key it claims, for the same reason: yazi would otherwise list two entries for one key
162
+ - `apply` merges the gh-dash config rather than overwriting it. It keeps the sections, themes and keybindings the user added
163
+ - Never edit the user's herdr or gh-dash config outside the managed markers
164
+
165
+ ### 4.2. Confirm the config still loads
166
+
167
+ *Two commands prove the install took. Stop if the second one does not print `config: ok`.*
168
+
169
+ ```bash
170
+ bash "$SETUP" status # components installed and enabled
171
+ herdr config check # config: ok
172
+ ```
173
+
174
+ `herdr config check` must print `config: ok` after `apply`. If it prints
175
+ anything else, report the error and stop rather than reloading.
176
+
177
+ Then tell the user where each key list lives. In herdr, press `prefix+?`. In
178
+ gh-dash, press `?`. diffnav lists its keys in its footer.
179
+
180
+ ## 5. How the user attaches, and why `--remote-keybindings server` is not optional
181
+
182
+ *The keymap lives on this machine. Only that flag makes herdr read it.*
183
+
184
+ The keymap this skill writes lives on the machine it runs on. How the user
185
+ reaches that machine is theirs to choose, and that choice changes what the
186
+ setup can do. Raise it once during `apply` rather than leaving them to find
187
+ out.
188
+
189
+ Recommend attaching from their own machine:
190
+
191
+ ```bash
192
+ herdr --remote <host> --remote-keybindings server
193
+ ```
194
+
195
+ Say what it buys and what it costs. Three points cover it:
196
+
197
+ - The client runs beside their clipboard and browser. Pasting a clipboard image into an agent pane works only on this path, and an SSH shell cannot do it at all
198
+ - `--remote-keybindings server` is not optional
199
+ - Without it herdr resolves chords from the client's config. It then ignores everything `apply` just wrote, and every chord looks broken
200
+ - This is the first thing they will report as a bug
201
+ - The gh-dash keybindings still work, because gh-dash reads its own config where it runs
202
+ - It needs herdr on their own machine too, and key authentication through an agent. That is because herdr reuses one connection only on Unix, and a Windows client authenticates more than once per attach
203
+
204
+ Then offer the shortcut, because the command is long and they will run it many
205
+ times a day. On Windows it has to be a function, not an alias or a symlink.
206
+ Both map one name to another, so the target would arrive as an argument to
207
+ `herdr` itself, and `herdr` would reject it.
208
+
209
+ ```powershell
210
+ function herdr-dev {
211
+ & "$env:LOCALAPPDATA\Programs\Herdr\bin\herdr.exe" `
212
+ --remote <host> --remote-keybindings server @args
213
+ }
214
+ ```
215
+
216
+ A hyphenated name tab-completes where the second word of a two-word command
217
+ never will. On macOS or Linux the same thing is a shell function in their
218
+ profile.
219
+
220
+ Do not write any of this for them. The profile and the SSH config live on the
221
+ machine they type at, which this skill cannot reach. Hand them the lines, the
222
+ same way section 6 hands them a prompt.
223
+
224
+ ## 6. Free the keys the user's terminal emulator swallows
225
+
226
+ *`apply` binds keys on this machine. The emulator the user types in may claim the same ones first.*
227
+
228
+ Read [`emulator-keys.md`](emulator-keys.md) after `apply`, and whenever the user reports a key doing nothing.
229
+
230
+ ## 7. Copy, open and download, on a machine with no display
231
+
232
+ *Three gh-dash keys break there, and a file has no way off the machine at all. `apply` writes a route for each. The last lines of `status` say where a copy and an open will land.*
233
+
234
+ Read [`headless-clipboard.md`](headless-clipboard.md) when the user asks how to copy, open or download from this machine, or `o`, `y` or `Y` fails. It covers sections 7, 7.1 and 7.2. When neovim's `:%y+` fails, read section 3.5 of `docs/terminal-workspace.md` instead.
235
+
236
+ ## 8. Turning one component off, or all of them
237
+
238
+ *`disable` undoes one component. `uninstall` undoes the managed config. harlequin is the one binary either of them removes.*
239
+
240
+ Read [`turn-off-and-update.md`](turn-off-and-update.md) when the user asks to turn a component off or uninstall.
241
+
242
+ ## 9. Keeping it current
243
+
244
+ *`outdated` reports what has moved on. `upgrade` fetches it.*
245
+
246
+ Run `outdated` first whenever the user invokes this skill on a machine that
247
+ already has the workspace. It only reads, and it costs one round trip per tool.
248
+
249
+ Then read [`turn-off-and-update.md`](turn-off-and-update.md) for the command, the exit codes, the four kinds of finding, and `upgrade`.
@@ -0,0 +1,36 @@
1
+ # Components and reserved keys
2
+
3
+ Read this file when the user asks what a component does, which key turns it on, or why a key sits where it does.
4
+
5
+ ## 1. Twelve components, installed for a user account and not for a project
6
+
7
+ | Component | What it gives the user | Config key |
8
+ |---|---|---|
9
+ | herdr | A terminal multiplexer. It holds many terminal sessions and keeps them running after the user disconnects. | `herdr.enabled` |
10
+ | gh-dash | A pull request dashboard, in the terminal. | `gh_dash.enabled` |
11
+ | diffnav | A diff viewer with a file tree, on one key. | `diffnav.enabled` |
12
+ | delta | The diff renderer git pages through. | `delta.enabled` |
13
+ | tuicr | Reviews a pull request inside the terminal. | `tuicr.enabled` |
14
+ | lazygit | Stages, commits, amends and pushes, on one key. | `lazygit.enabled` |
15
+ | harlequin | A SQL editor in the terminal, on one key. Installed by uv, and launched by acstack-db. | `harlequin.enabled` |
16
+ | pi | A coding agent in the terminal, with ACStack, pi-subagents and the user's own pi settings installed into it. Installed by npm, and starts off. | `pi.enabled` |
17
+ | neovim | A dot in the LazyVim statusline for a buffer with unsaved changes, and copy over SSH through OSC 52. Installs nothing, writes one file, and starts off. | `neovim.enabled` |
18
+ | yazi | A file manager, with markdown drawn live by acstack-md. One key sends the hovered file to the machine the user sits at. | `yazi.enabled` |
19
+ | markdown | Markdown with its mermaid diagrams drawn as text, or served to a browser. Installs acstack-md, mermaid-ascii and glow. | `markdown.enabled` |
20
+ | remote | Copy and open, on a machine with no display of its own. Installs acstack-clip and acstack-open. | `remote.enabled` |
21
+
22
+ A config key never carries a hyphen, so gh-dash is `gh_dash`. The last two rows
23
+ name a feature rather than a binary, so each of those cells names its tools.
24
+ The `neovim` row names an editor this setup never installs, and only configures.
25
+
26
+ The `pi` row and the `neovim` row both start off, because each writes into a
27
+ config the user built.
28
+
29
+ ### 1.1. `g` belongs to git, and `e` means edit
30
+
31
+ The setup reserves two letters across the whole workspace, so the same key does
32
+ the same thing wherever the user is standing:
33
+
34
+ - `alt+g` opens lazygit and `alt+shift+g` opens it in a tab, so herdr's `goto` sits on `prefix+t` and `new_worktree` keeps only its chord
35
+ - `e` opens `$EDITOR` in yazi and in both of tuicr's panels, which is why tuicr's file tree filters are `x` and `X`
36
+ - diffnav is the exception, because it spends `e` on its file tree and puts the editor on `o`
@@ -0,0 +1,69 @@
1
+ # Config choices
2
+
3
+ `SKILL.md` decides when to read this file: before walking the user through the config, on a first setup or when they change a setting.
4
+
5
+ ## 3. Copy the config, then walk the user through the choices
6
+
7
+ Then ask about these settings, in this order:
8
+
9
+ - **`herdr.integration`**: which agent reports its state to herdr. Set it to the agent the user actually runs, or `none`. Without it, herdr infers state by reading the screen
10
+ - **`gh_dash.repo_paths`**: map each repository to its local clone. Without it, checkout fails. So does any keybinding using `{{.RepoPath}}`, the placeholder gh-dash fills in with that clone's path
11
+ - **`herdr.chord_modifier`**: `alt` (default), `ctrl+alt`, or `none`. A chord is one key combination, such as `alt+f`
12
+ - Recommend `alt`. It is the only family measured to work whichever way the user connects
13
+ - The herdr documentation recommends `ctrl+alt`. That does reach herdr over a plain SSH shell
14
+ - A Windows client attaching with `herdr --remote` never delivers `ctrl+alt`. Every such chord goes silently dead
15
+ - Suggest `ctrl+alt` only to a user who attaches exactly one way and has tested it
16
+ - `none` keeps herdr's prefix-only keymap. The user presses a prefix key first
17
+ - **`herdr.worktrees_directory`**: keep it absolute. A worktree is a second checkout of the same repository on its own branch.
18
+
19
+ A relative value resolves against the herdr session's base directory, not the repository you point at. Worktrees for a second repository then land inside the first
20
+
21
+ - **`herdr.theme.name`**: leave it empty unless the user asks for a theme, and `apply` then writes none
22
+ - Set `herdr.theme.light` too for a user who attaches from two devices with different backgrounds, such as a dark terminal and an e-ink panel
23
+ - `auto_switch` asks each attached client for its background colour over OSC 11, an escape sequence a terminal answers with the colour it paints
24
+ - herdr then picks the dark or the light theme from that answer
25
+ - Without a light theme there is nothing to switch to, so `apply` writes the name alone
26
+ - **`herdr.toast_delivery`** and **`herdr.agent_panel_sort`**: empty by default, and `apply` writes neither
27
+ - Set `toast_delivery` to `herdr` on a machine reached over SSH, where the terminal is the only surface herdr can draw a message on
28
+ - Set `agent_panel_sort` to `priority` to put the agents waiting on the user at the top
29
+ - **`herdr.agent_labels_on_pane_borders`**: leave it `true`. Several agents in several panes is what this workspace is for, and an unlabelled pane does not say which agent it holds
30
+ - **`tuicr.build_from_fork`**: leave it `false`
31
+ - Set it `true` for the two unmerged upstream pull requests, #607 stats and #633 resize
32
+ - Set it `true` also for the fork's own fix for blank `+N -N` counts in pull request review mode
33
+ - `true` needs cargo, the Rust build tool, and takes a few minutes to build
34
+ - Tell the user it is temporary. `status` tracks the two upstream pull requests, not the local fix
35
+ - **`tuicr.appearance`**: pin it to `dark` or `light` on any machine the user reaches over the network
36
+ - Detection asks the terminal for its background colour over OSC 11, and nothing answers under `herdr --remote`
37
+ - tuicr then falls back to a desktop setting that a headless machine reports as light, and paints dark text on a black terminal
38
+ - Empty leaves the detection in place, which is right on a machine the user sits at
39
+ - **`gh_dash.keybindings.agent_review`**: hands the selected pull request to an agent. Leave it empty if the user does not want that key. Avoid `R`, which is gh-dash's built-in refresh-all
40
+ - **`yazi.download_target`**: the Tailscale node name of the machine the user sits at. Setting it puts a download key in yazi. Leave it empty for a user who does not run Tailscale, and `apply` writes no key
41
+ - Ask for the name `tailscale status` prints on **this** machine, not the name the user calls their laptop
42
+ - Taildrop sends only between devices one Tailscale account owns on one tailnet, so confirm both ends match before setting it
43
+ - Tell them to run `sudo tailscale set --operator=$USER` once on this machine, because `tailscale file cp` refuses a non-root caller without it
44
+ - **`neovim.enabled`**: off by default, like `pi.enabled`. Turn it on for a user who edits in LazyVim, and always on a machine they reach over SSH
45
+ - Over SSH, LazyVim turns clipboard sync off and `:%y+` fails with `clipboard: No provider`
46
+ - `neovim.osc52_clipboard`, on by default, sends each copy to the user's own clipboard over OSC 52
47
+ - `p` pastes what neovim copied last, because Windows Terminal refuses OSC 52 reads
48
+ - The file does nothing on a machine with a display or inside tmux
49
+ - `apply` leaves it out when a file the user wrote already sets `vim.g.clipboard`, and names that file
50
+ - LazyVim recolours the filename and shows no sign of its own, so a modified buffer is easy to miss
51
+ - `apply` writes `~/.config/nvim/lua/plugins/acstack.lua` and edits nothing the user wrote
52
+ - `apply` leaves the dot out when a lualine override the user wrote already marks a modified buffer, and names that file
53
+ - The statusline would otherwise carry two dots side by side
54
+ - Tell such a user to delete their own file to hand the dot to this component
55
+ - **`pi.enabled`**: off by default. Turn it on for a user who runs pi, the coding agent, or wants ACStack inside it
56
+ - `apply` installs pi with npm when it is missing, then installs ACStack into it, pinned to this plugin's version
57
+ - `apply` always installs `pi-subagents` too, because ACStack on pi cannot launch a subagent without it
58
+ - `apply` adds one line to pi's context file in `~/.pi/agent` (`AGENTS.md` by default) that lets pi delegate when an ACStack skill says to
59
+ - `pi.compact_tools` and `pi.agentic_retro` add pi-compact-tools and agentic-retro's pi extension, both on by default
60
+ - agentic-retro's extension needs the agentic-retro plugin first, and `apply` says so when it is missing
61
+ - `pi.settings` writes four keys into `~/.pi/agent/settings.json`, and an empty value leaves pi's own
62
+ - Tell the user to run `pi`, then `/login`, themselves, because `apply` never handles a credential
63
+ - Tell them to restart any pi session that was running during `apply`
64
+ - **`remote.clipboard_shim`**: leave it `true` on any machine reached over SSH. It puts an `xclip` on `$PATH`, backed by `acstack-clip`. That stand-in is the only reason gh-dash's `y` and `Y` work there. `apply` skips it when the machine has a real `xclip` or a display
65
+
66
+ One setting sits outside the config. `acstack-md --serve` takes its port from
67
+ `$ACSTACK_MD_PORT` and falls back to 6419. Tell the user to forward whichever
68
+ port they serve on, or the link `--serve` prints is unreachable from their
69
+ laptop.
@@ -0,0 +1,48 @@
1
+ # Emulator keys
2
+
3
+ `SKILL.md` decides when to read this file: after `apply`, and whenever the user reports a key doing nothing.
4
+
5
+ ## 6. Free the keys the user's terminal emulator swallows
6
+
7
+ *`apply` binds keys on this machine. The emulator the user types in may claim the same ones first.*
8
+
9
+ `apply` binds the keymap on **this** machine. The terminal emulator on the
10
+ machine the user types on intercepts the chords first.
11
+
12
+ Windows Terminal binds `alt+shift+d` to "duplicate pane" by default and never
13
+ forwards it, so a binding on that chord does nothing here. The diff keys avoid
14
+ it by sitting on `alt+f` and `alt+shift+f`. Other emulators claim other chords.
15
+
16
+ When the user reports a key doing nothing, have them run `cat -v` in any pane
17
+ and press it. A chord that arrives prints an escape sequence. One that prints
18
+ nothing never left their machine, so the fix belongs in the emulator.
19
+
20
+ After `apply`, work out which case you are in.
21
+
22
+ **Running on the user's own desktop**, meaning macOS, or Linux with a desktop
23
+ session. The terminal emulator is right here. Read
24
+ [assets/terminal-workspace/client-keybindings.md](../../assets/terminal-workspace/client-keybindings.md)
25
+ and do the work yourself.
26
+
27
+ Find the emulator's config, and back it up. Unbind only the chords the emulator
28
+ actually holds. Show the diff, and verify.
29
+
30
+ **Running on a remote or headless host**, meaning no `DISPLAY`, or an
31
+ `SSH_CONNECTION` in the environment. You cannot reach the emulator from here.
32
+ Ask first:
33
+
34
+ > Do you SSH into this machine from a Windows, macOS, or Linux desktop? If so
35
+ > I can give you a prompt to hand to an agent there, which frees the keys their
36
+ > terminal is swallowing.
37
+
38
+ Only if they say yes, print the contents of `client-keybindings.md` verbatim for
39
+ them to paste. Do not summarise it. Do not rewrite it for their emulator.
40
+
41
+ It already covers the common ones. The agent on that machine can see which
42
+ emulator the user actually runs.
43
+
44
+ If they say no, or the terminal is on this machine, say nothing further about
45
+ it. A user on a plain Linux console has nothing to fix.
46
+
47
+ **Never** try to edit a client-side terminal config from a remote host. Never
48
+ ask the user to paste their local config here so you can rewrite it.
@@ -0,0 +1,175 @@
1
+ # Headless clipboard, open and download
2
+
3
+ `SKILL.md` decides when to read this file: when the user asks how to copy, open or download from this machine, or `o`, `y` or `Y` fails.
4
+
5
+ ## 7. Copy, open and download, on a machine with no display
6
+
7
+ *Three gh-dash keys break there, and a file has no way off the machine at all. `apply` writes a route for each. The last lines of `status` say where a copy and an open will land.*
8
+
9
+ The dev machine – the remote machine the user's agents run on, a virtual machine
10
+ in this setup – has no display and no clipboard. Two gaps, and three gh-dash
11
+ keys fall into them.
12
+
13
+ The `o` key fails with `exit status 1`, because `xdg-open` has no display. The
14
+ `y` and `Y` keys fail with `Failed copying to clipboard`, because gh-dash shells
15
+ out to `xclip`, `xsel` or `wl-copy`, and the machine has none of them.
16
+
17
+ `apply` closes both gaps. Setting a second machine up needs nothing extra:
18
+
19
+ ```bash
20
+ bash "$SETUP" apply
21
+ bash "$SETUP" status # read the last lines
22
+ ```
23
+
24
+ `y` and `Y` keep gh-dash's own behaviour, backed by an `xclip` stand-in that
25
+ copies over OSC 52. OSC 52 is an escape sequence a terminal reads as "put this
26
+ text on the clipboard of the machine I am running on".
27
+
28
+ The `o` key becomes a keybinding running `acstack-open`, because gh-dash runs
29
+ `$BROWSER` with its output discarded and the dashboard still drawn. A route that
30
+ must hand you a link then has nowhere to draw it.
31
+
32
+ The last lines of `status` say where a copy and an open will actually land on
33
+ **this** machine:
34
+
35
+ ```
36
+ clipboard: xclip stand-in, copying to your terminal over OSC 52
37
+ browser: none - o hands you a ctrl+clickable link and copies it
38
+ last open: 2026-08-21T03:23:07+00:00 link: https://github.com/owner/repo/pull/30
39
+ ```
40
+
41
+ Read them before debugging anything else. What each means:
42
+
43
+ Every line `status` can print is here, in the order the code tries the routes:
44
+
45
+ | Line | What happened | What to do |
46
+ |---|---|---|
47
+ | `clipboard: this machine has a display` | It has a real clipboard | Nothing |
48
+ | `clipboard: xclip stand-in` | Copy reaches your terminal over OSC 52 | Nothing |
49
+ | `clipboard: none` | `apply` has not run, or `remote.clipboard_shim` is false | Run `apply` |
50
+ | `neovim clipboard: OSC 52, written by this setup` | neovim copies to your terminal over OSC 52 | Nothing |
51
+ | `neovim clipboard: set by <file>` | The user's own lua sets `vim.g.clipboard` | Nothing |
52
+ | `neovim clipboard: none` | `neovim.enabled` is true and the file lacks the clipboard | Run `apply` |
53
+ | `browser: $ACSTACK_OPEN_CMD = ...` | The user set an override, and it wins over every route below | Nothing |
54
+ | `browser: xdg-open on this machine` | The machine has a desktop of its own | Nothing |
55
+ | `browser: the Windows side of this machine` | This is WSL, and Windows opens the page | Nothing |
56
+ | `browser: your default browser on your laptop` | The opener is up and holds the token | Nothing |
57
+ | `browser: Chrome on your laptop` | The Playwriter bridge is up and proven attached | Nothing |
58
+ | `browser: none - o hands you a link` | The normal case over SSH. ctrl+click it | Nothing |
59
+ | `browser: none, and no terminal either` | `o` copies and reports failure | Below |
60
+ | `browser: unknown` | `acstack-open` did not answer, so it is missing or broken | Run `apply` |
61
+
62
+ Two of those rows name services this skill does not install. The opener is a
63
+ small service on the user's laptop that opens a page in their default browser.
64
+ The Playwriter bridge lets this machine drive Chrome on that same laptop, and
65
+ the `bridge` skill covers it.
66
+
67
+ Each runs on its own reverse tunnel, port 19988 for the bridge and port 19989
68
+ for the opener. One can be up while the other is down.
69
+
70
+ The opener has no key in this config, so do not invent one. `acstack-open` takes
71
+ that route only when two things hold. A token file sits at
72
+ `~/.config/acstack/opener.token`. The service answers on
73
+ `http://127.0.0.1:19989` with that token.
74
+
75
+ Setting `ACSTACK_OPEN_OPENER=off` in the environment skips the route.
76
+
77
+ `browser: none` is not a fault. Nothing on that machine can open a page, so `o`
78
+ hands the terminal a link instead. That link is the one route that works over
79
+ any number of SSH hops.
80
+
81
+ To make it a real one-key open, give it a command that can:
82
+
83
+ ```bash
84
+ export ACSTACK_OPEN_CMD="ssh laptop open" # any command taking a URL
85
+ ```
86
+
87
+ Do not suggest installing a browser or an X server on the dev machine to fix
88
+ this. The browser belongs on the machine the user is sitting at.
89
+
90
+ Under `herdr --remote`, panes run on the remote host, so `acstack-open` looks
91
+ for a browser there and normally finds none. That is normal, not a fault. It
92
+ falls to the link route, which the client draws.
93
+
94
+ Do not add per-host browser configuration to "fix" it.
95
+
96
+ One thing to check rather than assume. We measured on herdr 0.8.2 that a pane's
97
+ OSC 52 write crosses the remote link. A copy on the dev machine then reaches the
98
+ clipboard the user attached from.
99
+
100
+ The herdr documentation never promises this, and terminals differ in whether
101
+ they act on OSC 52 at all.
102
+
103
+ So have the user run `acstack-clip test-string` after the first attach, then
104
+ paste on the client. Believe that test over the measurement.
105
+
106
+ If it does not cross, say so plainly. The link is still on screen, and herdr's
107
+ own drag-select copies it.
108
+
109
+ ### 7.1. When `o` claims it opened something nobody saw
110
+
111
+ *A successful open proves nothing. Ask what sits on the other end of the endpoint.*
112
+
113
+ `agent-browser` launches a headless Chrome on the local machine when it cannot
114
+ attach to the Chrome DevTools Protocol (CDP) endpoint the caller named. That
115
+ Chrome navigates, reports success, and shows nobody anything.
116
+
117
+ A bridge relay answering on its HTTP port does not rule this out. Ours answered
118
+ `/json/version` while refusing every CDP connection with
119
+ `Multiple extensions connected. Specify extensionId.`
120
+
121
+ Diagnose it by asking what is really on the other end, never by trusting a
122
+ successful open. Port 9555 below is the CDP port ACStack defaults to for a
123
+ headless or local browser, so a stray Chrome on this machine answers there:
124
+
125
+ ```bash
126
+ agent-browser get cdp-url # the endpoint actually attached to
127
+ curl -s 127.0.0.1:9555/json/list # the tabs a headless Chrome here holds
128
+ ```
129
+
130
+ `acstack-open` runs that check itself before taking the bridge route. If you
131
+ find a stray headless Chrome holding pages, say so. It is a leftover, and
132
+ killing it is the user's call, not yours.
133
+
134
+ Detail, and why OSC 52 rather than a clipboard daemon:
135
+ [docs/terminal-workspace.md](../../docs/terminal-workspace.md).
136
+
137
+ ### 7.2. Getting a file off the machine
138
+
139
+ *A third gap has nothing to do with gh-dash. OSC 52 carries text, and a file needs Taildrop.*
140
+
141
+ The clipboard route above carries text. A screenshot, a build artifact or a log
142
+ has no route at all. The user's own SSH client pulls one down only when they
143
+ type the path by hand.
144
+
145
+ Set `yazi.download_target` and `apply` binds one key in yazi, `D` by default. It
146
+ runs Taildrop, Tailscale's file send, on the hovered file:
147
+
148
+ ```toml
149
+ run = 'shell --block -- tailscale file cp %h <target>:'
150
+ ```
151
+
152
+ Recommend Taildrop over `scp` back to the user's machine. That route needs
153
+ three things on their machine, and Taildrop needs none of them:
154
+
155
+ - an SSH server running there
156
+ - a reverse tunnel raised on every connection
157
+ - this machine's key in their `authorized_keys`
158
+
159
+ Taildrop needs no inbound port on their machine either.
160
+
161
+ Three things break it, and `apply` names whichever one holds:
162
+
163
+ | What the user sees | What it means | What to do |
164
+ |---|---|---|
165
+ | `Access denied: file access denied` | The account does not own the local Tailscale daemon | Run `sudo tailscale set --operator=$USER` once |
166
+ | `502 Bad Gateway`, or the target reported offline | The two machines sit on different tailnets or under different accounts | Compare `tailscale status` on both ends |
167
+ | `open %*: no such file or directory` | A binding used `%*`, which yazi never expands in a keymap | Use `%h`, the hovered file |
168
+
169
+ The last row is why the key takes one file at a time. `%*` belongs to yazi's
170
+ `[opener]` table. A keybinding passes the two characters through untouched,
171
+ measured on yazi 26.8.15.
172
+
173
+ Do not offer to install an SSH server on the user's own machine to work around
174
+ a Taildrop failure. Fix the tailnet instead, or leave `yazi.download_target`
175
+ empty.