projectstore-claude 0.29.4 → 0.30.1

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.md CHANGED
@@ -1,25 +1,26 @@
1
1
  # projectstore-claude
2
2
 
3
- The Claude Code installer for [projectstore](https://www.npmjs.com/package/projectstore): the core, pinned at exactly this version and bundled inside this tarball, with the harness fixed. One command, from a terminal **outside** a Claude Code session:
3
+ > **To install ProjectStore, run `npx projectstore setup` from a terminal in your project.** This package is a release artifact; you do not need it.
4
+
5
+ The Claude Code distribution shell of [projectstore](https://www.npmjs.com/package/projectstore): the core, pinned at exactly this version and bundled inside this tarball, with the harness fixed to Claude Code.
6
+
7
+ From a terminal in your project:
4
8
 
5
9
  ```sh
6
- npx projectstore-claude install --project "$PWD"
10
+ npx projectstore setup
7
11
  ```
8
12
 
9
- It registers the plugin for that checkout at the host's local scope. It prints its plan first — every write and every host command, verbatim — and at a terminal asks `◆ Apply N changes? [Y/n]` before anything runs; then each step as it runs, and what to do next. Without a terminal (a script, CI, an agent's tool) naming the shell is the confirmation; `--json` never asks. Restart Claude Code afterwards.
10
-
11
- - See before you write: `npx projectstore-claude plan --project "$PWD"` prints the same plan and writes nothing; `--verbose` adds every row's reasoning; `npx projectstore-claude <verb> --help` lists a verb's options with examples.
13
+ Setup finds the coding agents the project uses, Claude Code among them, and installs ProjectStore for each, with a vault for the project's notes. It asks a few questions, prints one plan — every write and every host command, verbatim — and asks once before anything runs. For Claude Code it registers the plugin for that checkout at the host's local scope, through a small local marketplace under your Claude home. Restart Claude Code afterwards.
12
14
 
13
- - Upgrade, or pin: `npx projectstore-claude@<version> upgrade --project "$PWD"` — the version you name is the version you run.
14
- - Behind a registry mirror: if `npx` answers `could not determine executable to run`, the mirror's index knows only the reserved `0.0.1` placeholder — name the version, and if needed the public registry: `npx --registry https://registry.npmjs.org projectstore-claude@<version> install --project "$PWD"`.
15
- - Uninstall: `npx projectstore-claude uninstall --project "$PWD"` — forgets the registration for that checkout and nothing else; your vault is plain markdown and stays yours.
16
- - `doctor`, `status`, `search` and the other read verbs pass through unchanged: `npx projectstore-claude doctor --json`.
15
+ Upgrade, or pin, from the same place; the version you name is the version you run:
17
16
 
18
- This shell is `projectstore <verb> --harness claude-code` and nothing more. `bin/projectstore-claude.mjs` locates the bundled core under `node_modules/projectstore/` and execs it; the core's low-level form — `npx projectstore install --harness claude-code --project "$PWD"` — is exactly what runs. A different `--harness` is refused (exit 2). The shell carries no plugin of its own: the plugin Claude Code loads is the bundled core, registered through a small local marketplace under your Claude home.
17
+ ```sh
18
+ npx projectstore@<version> upgrade
19
+ ```
19
20
 
20
- Why from a terminal: the host CLI and a live session both rewrite the same settings files, so the core defers the registration inside a session and says so.
21
+ This shell's bin is `projectstore <verb> --harness claude-code` and nothing more. `bin/projectstore-claude.mjs` locates the bundled core under `node_modules/projectstore/` and execs it; a different `--harness` is refused (exit 2). The shell carries no plugin of its own: the plugin Claude Code loads is the bundled core.
21
22
 
22
- - Docs: https://github.com/SmartAndPoint/ProjectStore#install--one-message
23
+ - Docs: https://github.com/SmartAndPoint/ProjectStore#install
23
24
  - Source: https://github.com/SmartAndPoint/ProjectStore
24
25
  - Issues: https://github.com/SmartAndPoint/ProjectStore/issues
25
26
 
@@ -24,7 +24,7 @@ const HARNESS = "claude-code";
24
24
  // scripts/cli.mjs; the packaging test pins it). Any other verb — doctor,
25
25
  // status, search, --version — passes through untouched: the core refuses an
26
26
  // option a verb does not declare, so a blanket insert would break `doctor`.
27
- const HARNESS_VERBS = new Set(["setup","plan","install","uninstall","upgrade","agents"]);
27
+ const HARNESS_VERBS = new Set(["setup","configure","plan","install","uninstall","upgrade","agents"]);
28
28
 
29
29
  // The bundled core, by path — never by package resolution: a hoisted or global
30
30
  // copy at another version is exactly the pairing the pin exists to prevent,
@@ -57,7 +57,7 @@ function fixHarness(argv) {
57
57
  }
58
58
  }
59
59
  const other = given.find((g) => g !== HARNESS);
60
- if (other !== undefined) return { error: `installs for ${HARNESS} only — \`--harness ${other}\` names another harness. Run that harness's shell, or the core: npx projectstore <verb> --harness ${other} …` };
60
+ if (other !== undefined) return { error: `installs for ${HARNESS} only — \`--harness ${other}\` names another harness. Run the core: npx projectstore <verb> --harness ${other} …` };
61
61
  if (given.length) return { argv }; // named already: pass through, never twice (the core's option repeats)
62
62
  const at = scan.findIndex((a) => !a.startsWith("-"));
63
63
  if (at === -1 || !HARNESS_VERBS.has(scan[at])) return { argv };
@@ -12,7 +12,7 @@
12
12
  "name": "projectstore",
13
13
  "displayName": "projectstore",
14
14
  "description": "📚 Your agent runs the project through a verified loop: task → artifact (ADR · spec · epic · story) → adversarial critic → backlog → planner → reviewer → done. Plain markdown in an Obsidian-friendly vault, every write approved by you — and any model can pick the project up tomorrow.",
15
- "version": "0.29.4",
15
+ "version": "0.30.1",
16
16
  "author": {
17
17
  "name": "Evgenii Konev",
18
18
  "email": "ekonev@smartandpoint.com",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "projectstore",
3
3
  "displayName": "projectstore",
4
- "version": "0.29.4",
4
+ "version": "0.30.1",
5
5
  "description": "Your agent runs the project through a verified loop: task → artifact (ADR / spec / epic / story) → adversarial critic → backlog → planner → reviewer → done. Plain markdown in git — any model can pick the project up tomorrow.",
6
6
  "author": {
7
7
  "name": "Evgenii Konev @ SmartAndPoint",
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![release](https://img.shields.io/github/v/release/SmartAndPoint/ProjectStore?label=release)](https://github.com/SmartAndPoint/ProjectStore/releases) [![license](https://img.shields.io/github/license/SmartAndPoint/ProjectStore?label=license)](./LICENSE) [![Star on GitHub](https://img.shields.io/badge/%E2%AD%90-star_us-yellow?logo=github)](https://github.com/SmartAndPoint/ProjectStore/stargazers)
6
6
 
7
- A project workflow plugin for [Claude Code](https://claude.com/claude-code) and [OpenAI Codex](https://developers.openai.com/codex/) (experimental). Both are released together at one version, and each installs with one command.
7
+ A project workflow plugin for [Claude Code](https://claude.com/claude-code) and [OpenAI Codex](https://developers.openai.com/codex/) (experimental). Both are released together at one version, and one command sets a project up for either or both: see [Install](#install).
8
8
 
9
9
  ---
10
10
 
@@ -75,24 +75,64 @@ In Claude Code a band above the prompt goes further (experimental): the session'
75
75
 
76
76
  Open the vault in [Obsidian](https://obsidian.md) and you get the graph view and the board for free. Don't use Obsidian? Everything renders on GitHub and in any editor.
77
77
 
78
- ## Install — one message
78
+ ## Install
79
79
 
80
- Open Claude Code in your project and say:
80
+ From a terminal in your project:
81
81
 
82
- > Install the projectstore plugin from https://github.com/SmartAndPoint/ProjectStore and set it up for this project.
82
+ ```
83
+ npx projectstore setup
84
+ ```
83
85
 
84
- That's the whole setup. Claude adds the marketplace, installs the plugin, and walks you through binding a vault, scaffolding it and wiring the status line — every step previewed, nothing written without your Yes.
86
+ Setup finds the coding agents the project uses — Claude Code, Codex or both — and installs ProjectStore for each, with a vault for the project's notes. At a terminal it asks a few questions: which folder is the project, which agents to install for, where the vault lives (an existing folder is bound; a missing or empty one becomes a new vault, with its own git repository and the layout's folders) and whether to show ProjectStore in the status line. Then it prints one plan — every file it writes and every host command, verbatim — and asks once before it writes anything. Restart the agent afterwards; Codex asks you to approve the ProjectStore hooks once.
85
87
 
86
- **On Codex**, run one command from a terminal in your project:
88
+ **What it needs:**
89
+
90
+ - Node.js 20 or later, always. The plugin's hooks, its MCP server and the status line run as `node` inside the agent session.
91
+ - npm, for Codex only: setup fetches the Codex plugin through npm. Claude Code alone needs no npm.
92
+ - The agent's own CLI on PATH (`claude`, `codex`), and git for a new vault.
93
+ - A terminal outside every Claude Code and Codex session: inside one, the registration waits and the plan says so.
94
+ - macOS or Linux. Windows is not verified yet.
95
+
96
+ Other package runners start setup the same way. Each was observed running it with Claude Code and Codex:
87
97
 
88
98
  ```
89
- npx projectstore-codex install --project "$PWD"
99
+ bunx projectstore@latest setup
90
100
  ```
91
101
 
92
- Then restart Codex, approve the ProjectStore hooks when it asks, and run `$projectstore-bind ~/Documents/my-project-vault`. Codex support is newer and still labelled experimental: [`docs/harnesses.md`](./docs/harnesses.md#codex) says what has been verified and what has not. A project can be worked from both agents: they share the binding in `.projectstore/`, and each keeps its own overlay and session state beside it ([running both over one project](./docs/harnesses.md#running-both-over-one-project)).
102
+ ```
103
+ pnpm dlx projectstore@latest setup
104
+ ```
93
105
 
94
- <details>
95
- <summary>Prefer to type it yourself?</summary>
106
+ ```
107
+ deno run -A npm:projectstore@latest setup
108
+ ```
109
+
110
+ `pnpm dlx` needs pnpm 6.13 or later. Without npm on PATH, a runner sets up Claude Code and refuses Codex, naming npm. The runner only fetches the package: setup copies the plugin into the agents' own directories, so clearing the runner's cache later breaks nothing.
111
+
112
+ `npx projectstore setup --dry-run` shows the questions and the plan and writes nothing. Without a terminal (a script, CI, an agent's tool) nothing is asked: `--harness <id>` names an agent and is the confirmation, and `--vault <path>` names the vault. `npx projectstore setup --help` lists the rest.
113
+
114
+ If you prefer a global command:
115
+
116
+ ```
117
+ npm install -g projectstore
118
+ projectstore setup
119
+ ```
120
+
121
+ Behind a registry mirror (often a company's), `npx` runs the newest `projectstore` the mirror knows. That can be a release older than setup, which answers that `setup` is an unknown verb, or no release at all. Name the version, and if that is not enough, the public registry:
122
+
123
+ ```
124
+ npm_config_registry=https://registry.npmjs.org npx projectstore@<version> setup
125
+ ```
126
+
127
+ npm reads that variable wherever it runs, so the Codex plugin setup fetches comes from the same registry.
128
+
129
+ ### In a Claude Code session
130
+
131
+ Open Claude Code in your project and say:
132
+
133
+ > Install the projectstore plugin from https://github.com/SmartAndPoint/ProjectStore and set it up for this project.
134
+
135
+ Claude adds the git marketplace, installs the plugin, and walks you through binding a vault, scaffolding it and wiring the status line — every step previewed, nothing written without your Yes. Or type it yourself:
96
136
 
97
137
  ```
98
138
  /plugin marketplace add SmartAndPoint/ProjectStore
@@ -103,49 +143,31 @@ Then restart Codex, approve the ProjectStore hooks when it asks, and run `$proje
103
143
 
104
144
  One switch worth flipping: Claude Code does **not** auto-update third-party plugins by default — `/plugin` → **Marketplaces** → **SmartAndPoint** → toggle **auto-update** on. If you skip it, `/projectstore:doctor` will remind you later with the exact setting.
105
145
 
106
- Contributors: `git clone` this repo, then `claude --plugin-dir ./ProjectStore`.
107
-
108
- **Or from npm, in one command** — from a terminal, not inside a Claude Code session:
146
+ Contributors: `git clone` this repo, then run Claude Code from the clone's parent folder:
109
147
 
110
148
  ```
111
- npx projectstore-claude install --project "$PWD"
149
+ claude --plugin-dir ./ProjectStore
112
150
  ```
113
151
 
114
- The same tree is published to npm as [`projectstore`](https://www.npmjs.com/package/projectstore) — one source package carrying every harness's manifest — and `projectstore-claude` is its Claude Code shell: the core pinned at the same version and bundled inside, the harness fixed, so the one command has the same shape on every harness. It registers the plugin with Claude Code: it writes a small local marketplace of its own under your Claude home, then drives `claude plugin marketplace add` / `plugin install` **at local scope**, so the registration lands in this checkout's `.claude/settings.local.json` and nowhere else. It prints its plan first — every file it writes and every host command, verbatim — and at a terminal asks `◆ Apply N changes? [Y/n]`; then it shows each step as it runs and what to do next. Without a terminal (a script, CI, an agent's tool) naming the harness is the confirmation. `plan` prints the same plan and writes nothing; `--verbose` adds every row's reasoning; `npx projectstore-claude <verb> --help` lists a verb's options with examples. Restart Claude Code afterwards. A git-marketplace copy already enabled for the checkout is silenced there (not globally) so the plugin does not load twice; `uninstall` turns it back on. Pin or upgrade with `npx projectstore-claude@<version> upgrade --project "$PWD"` — the version you name is the version you run. The core's low-level form, `npx projectstore <verb> --harness claude-code …`, is exactly what the shell runs. bun works the same on the packed bin.
152
+ <details>
153
+ <summary>What setup does for each agent, the low-level verbs, the CLI and MCP</summary>
115
154
 
116
- **Codex has its own shell with the same one-command shape:**
117
- `npx projectstore-codex install --project "$PWD"`. It carries a Codex
118
- plugin manifest, namespaced workflow and role skills, lifecycle hooks, and
119
- the exact bundled core. It stages a stable marketplace under `CODEX_HOME`,
120
- drives `codex plugin marketplace add` and `codex plugin add`, then reads the
121
- installation back and verifies its version and payload digest. Before it
122
- changes anything it asks Codex for that read-back (`codex plugin list --json`),
123
- so a Codex too old to answer stops the registration before it changes anything
124
- and tells you to upgrade Codex. Restart Codex,
125
- approve the hooks, and run `$projectstore-bind <vault-path>`. For later
126
- releases, `npx projectstore-codex@<version> upgrade --project "$PWD"`. Because
127
- Codex's plugin registry is user-global, ordinary uninstall removes only the
128
- project's agents block; `uninstall --global` is the explicit machine-wide
129
- removal. If `npx` answers `could not determine executable to run`, your
130
- registry (often a company mirror) serves a stale index that knows only the
131
- reserved `0.0.1` placeholder: name the version, and if that is not enough, the
132
- public registry: `npx --registry https://registry.npmjs.org
133
- projectstore-codex@<version> install --project "$PWD"` (the same holds for
134
- `projectstore-claude`). Codex is **experimental** until a live session has exercised every
135
- surface it installs; [`docs/harnesses.md`](./docs/harnesses.md) says what has
136
- been measured and what has not. From a checkout, the same npx path runs against
137
- a built tarball:
155
+ **Claude Code.** Setup registers the plugin from the npm package [`projectstore`](https://www.npmjs.com/package/projectstore) — one source package carrying every harness's manifest. It writes a small local marketplace of its own under your Claude home, then drives `claude plugin marketplace add` / `plugin install` **at local scope**, so the registration lands in this checkout's `.claude/settings.local.json` and nowhere else. The host CLI and a live session both rewrite the same settings files, so inside a Claude Code session the registration is deferred, and the plan says so: run setup from a terminal outside the session. When the checkout already loads ProjectStore from the git marketplace, setup asks whether to switch this project to the npm install or keep the git marketplace. A switch silences the git-marketplace copy for this checkout only (not globally), so the plugin does not load twice; `uninstall` turns it back on.
156
+
157
+ **Codex.** The Codex plugin ships in a package of its own; setup fetches it at setup's own version and plans Codex in the same plan as everything else. It stages a stable marketplace under `CODEX_HOME`, drives `codex plugin marketplace add` and `codex plugin add`, then reads the installation back and verifies its version and payload digest. Before it changes anything it asks Codex for that read-back (`codex plugin list --json`), so a Codex too old to answer stops the registration before it changes anything and tells you to upgrade Codex. Codex's plugin registry is user-global; the agents block in `AGENTS.md` stays project-local. Codex is **experimental** until a live session has exercised every surface it installs: [`docs/harnesses.md`](./docs/harnesses.md#codex) says what has been verified and what has not. A project can be worked from both agents: they share the binding in `.projectstore/`, and each keeps its own overlay and session state beside it ([running both over one project](./docs/harnesses.md#running-both-over-one-project)).
158
+
159
+ **The low-level verbs.** Setup composes verbs that also run on their own. One agent's install, with no questions about the project or the vault:
138
160
 
139
- ```sh
140
- npm run shells:build -- --only projectstore-codex --dev --out dist
141
- npx --package "./dist/projectstore-codex-$(node -p 'require("./package.json").version').tgz" projectstore-codex install --project "$PWD"
142
161
  ```
162
+ npx projectstore install --harness claude-code # shows the plan, asks at a terminal, then writes; without a terminal naming the harness is the confirmation — there is no --yes
163
+ ```
164
+
165
+ `plan` prints the same plan and writes nothing; `--verbose` adds every row's reasoning; `npx projectstore <verb> --help` lists a verb's options with examples. bun works the same on the packed bin.
143
166
 
144
- The package also carries a `bin`. Without a session — in CI, or in a shell — the same core answers token-free, with a `--json` envelope on every verb:
167
+ Without a session — in CI, or in a shell — the same core answers token-free, with a `--json` envelope on every verb:
145
168
 
146
169
  ```
147
170
  npx projectstore doctor --json
148
- npx projectstore install --harness claude-code # the low-level form the shell runs: shows the plan, asks at a terminal, then writes; without a terminal naming the harness is the confirmation — there is no --yes
149
171
  npx projectstore reconcile --write --only kanban
150
172
  ```
151
173
 
@@ -175,43 +197,107 @@ npx projectstore init ~/vaults/new-project --language ru
175
197
  npx projectstore scaffold --write
176
198
  ```
177
199
 
178
- `projectstore-claude`, `projectstore-codex` and `projectstore-opencode` are this package's per-harness shells — the core pinned and bundled, the harness fixed. The Claude Code and Codex shells are published at the core's version; Codex stays labelled experimental until a live run has exercised every surface it installs ([`docs/harnesses.md`](./docs/harnesses.md)). The opencode shell publishes after its plugin root is rendered. The other `projectstore-*` names are reserved placeholders pointing back here. One source package, one version, N tarballs.
200
+ `projectstore-claude`, `projectstore-codex` and `projectstore-opencode` are release artifacts: per-harness packages that carry the core, pinned at the same version and bundled, with the harness fixed. Nobody needs to type their names. Setup fetches the Codex one, which carries the Codex plugin; the Claude Code one is published at the core's version too; the opencode one publishes after its plugin root is rendered. The other `projectstore-*` names are reserved placeholders pointing back here. One source package, one version, N tarballs. How a release builds and publishes them, and how to run a checkout's own build: [`packaging/README.md`](./packaging/README.md).
179
201
  </details>
180
202
 
203
+ ## Configure
204
+
205
+ Setup asks only what a first install needs. Everything after it is one command, from a terminal in your project:
206
+
207
+ ```
208
+ npx projectstore configure
209
+ ```
210
+
211
+ At a terminal it shows every setting with its current value and where it lives:
212
+
213
+ - each agent's model, per harness;
214
+ - the status line and the band above the prompt (Claude Code);
215
+ - the vault's template language, the default author and tags;
216
+ - the vault's spec policy and lifecycle gates.
217
+
218
+ It asks which to change, then shows one plan and asks once. Without a terminal it prints the same view and writes nothing. To change a setting there, name it with `--set`; naming it is the confirmation:
219
+
220
+ ```
221
+ npx projectstore configure --set agents.critic=fable --set statusline=on
222
+ ```
223
+
224
+ `--dry-run` shows the plan and writes nothing, and `--json` returns the settings as one envelope. In a project that uses two harnesses, an agent's model names its overlay with `--harness <id>`.
225
+
226
+ Each setting has exactly one writer, and the plan says which file it changes:
227
+
228
+ - **The agents' models** live in `.projectstore/harness/<harness>.json`. That file is committed, so a change there is a team change.
229
+ - **The status line, the band, the language and the other binding keys** live in `.projectstore/projectstore.json`, which stays on this machine.
230
+ - **The spec policy and the lifecycle gates** live in the vault's `.projectstore.json`, which commits with the vault. Setting `spec_policy=required` records when it took effect; stories closed before then are exempt.
231
+
232
+ The vault itself is changed by `bind --rebind`, which configure names when asked. In a Claude Code session, `/projectstore:statusline` and `/projectstore:agents configure` run the same writers.
233
+
181
234
  ## Upgrading
182
235
 
183
- `/plugin update` (or auto-update) and a restart, then one command per project
184
- bound before 0.28. What an existing project sees afterwards, and why:
236
+ Installed with setup or from npm: from a terminal in your project, name the version you want to run (`latest` is the newest):
237
+
238
+ ```
239
+ npx projectstore@<version> upgrade
240
+ ```
241
+
242
+ It upgrades every agent the project uses — each one whose own directory (`.claude/`, `.codex/`) or `.projectstore/state/<id>/` is there — in one plan, and fetches the Codex plugin at the same version. `npx projectstore setup` converges a project the same way and asks its questions again. Installed from the git marketplace in a Claude Code session: `/plugin update` (or auto-update) and a restart.
243
+
244
+ A bare upgrade selects agents by those directories, so on Codex name it, which upgrades Codex even in a project where no Codex session has run yet:
245
+
246
+ ```
247
+ npx projectstore@<version> upgrade --harness codex
248
+ ```
249
+
250
+ With the global command, update it first, then run it in the project:
251
+
252
+ ```
253
+ npm install -g projectstore@latest
254
+ projectstore upgrade
255
+ ```
256
+
257
+ A project bound before 0.28 needs one more command. What an existing project sees afterwards, and why:
185
258
 
186
259
  - **The project's files move to `.projectstore/`.** `.claude/projectstore.json`
187
260
  and `.claude/.projectstore/` become `.projectstore/projectstore.json`,
188
261
  `.projectstore/harness/claude-code.json` and `.projectstore/state/`. Nothing
189
262
  breaks before you move them: every reader falls back to the old paths through
190
- 0.29, and the startup line names the command until the move is done. Close
191
- every Claude Code session in the project, run that command from a terminal,
192
- then restart. The command depends on how you installed:
193
- - **From the git marketplace** (every 0.27.x install): the installed copy's
194
- own `bin/projectstore.mjs`, with its path spelled out in the startup line —
195
- `node "<plugin cache>/bin/projectstore.mjs" upgrade --harness claude-code --no-register --project "$PWD"`.
196
- `--no-register` leaves your plugin registration as it is.
197
- - **From npm**: `npx projectstore-claude@<version> upgrade --no-register --project "$PWD"`.
198
-
199
- Both forms move only the project's files, so neither touches your plugin
200
- registration. The same run re-stamps the status-line launcher at its new path
201
- and re-registers the agents block, whose template is now v4. A plain
202
- `npx projectstore-claude upgrade` on a git-marketplace install does more: it
263
+ 0.30, and the startup line names the command until the move is done. Close
264
+ every Claude Code session in the project, run that command from a terminal in
265
+ the project, then restart. The command depends on how you installed. From the
266
+ git marketplace (every 0.27.x install), it is the installed copy's own
267
+ `bin/projectstore.mjs`, with its path spelled out in the startup line:
268
+
269
+ ```
270
+ node "<plugin cache>/bin/projectstore.mjs" upgrade --harness claude-code --no-register
271
+ ```
272
+
273
+ From npm:
274
+
275
+ ```
276
+ npx projectstore@<version> upgrade --harness claude-code --no-register
277
+ ```
278
+
279
+ `--no-register` leaves your plugin registration as it is: both forms move
280
+ only the project's files. The same run re-stamps the status-line launcher at
281
+ its new path and re-registers the agents block, whose template is now v4. An
282
+ upgrade without `--no-register` on a git-marketplace install does more: it
203
283
  also registers the plugin from npm for this checkout and turns the
204
284
  git-marketplace copy off here, so `/plugin update` stops reaching the
205
- checkout. The 0.28.0-rc.1 and rc.2 startup lines named that shell form
206
- (`npx projectstore-claude@<version> upgrade`, without `--no-register`), so on
207
- those, update first and run what the new startup line names. If it already
208
- happened,
209
- `npx projectstore-claude@<version> uninstall --surface plugin --project "$PWD"`
210
- (0.28.0 or later) turns the git-marketplace copy back on. That copy must be 0.28 or later — an
211
- older one reads a moved project as unbound — so update it first if it is not.
212
- Restart, then run
213
- `/projectstore:doctor --fix` in the new session, which re-stamps the status
214
- line against that copy.
285
+ checkout. The 0.28.0-rc.1 and rc.2 startup lines named that form, without
286
+ `--no-register`, so on those, update first and run what the new startup line
287
+ names. If it already happened, this turns the git-marketplace copy back on
288
+ (0.28.0 or later), from a terminal in the project:
289
+
290
+ ```
291
+ npx projectstore@<version> uninstall --harness claude-code --surface plugin
292
+ ```
293
+
294
+ That copy must be 0.28 or later — an older one reads a moved project as
295
+ unbound — so update it first if it is not. Restart, then in the new session,
296
+ to re-stamp the status line against that copy:
297
+
298
+ ```
299
+ /projectstore:doctor --fix
300
+ ```
215
301
  - **The status line keeps rendering.** A launcher written by an earlier version
216
302
  still works, but it carries no file stamp and its embedded fallback root is
217
303
  frozen at the old version; the move above re-stamps it. Nothing rewrites that
@@ -242,9 +328,9 @@ bound before 0.28. What an existing project sees afterwards, and why:
242
328
  move once more, and the move re-stamps the launcher. If a session already
243
329
  re-stamped the status line or re-registered the agents block before the move
244
330
  (rc.2's `/projectstore:doctor --fix` did both), 0.27.x reports a foreign
245
- status line and a v4 block and leaves both alone — unless you run its
246
- `/projectstore:agents register`, which rewrites the block; the status line
247
- still renders, and the move settles both.
331
+ status line and a v4 block and leaves both alone — unless you run
332
+ `/projectstore:agents register` in it, which rewrites the block; the status
333
+ line still renders, and the move settles both.
248
334
  - **Rolling back** to 0.27.x after the move: 0.27.x looks for its binding under
249
335
  `.claude/`, finds none and offers `bind`. Do not accept. A re-bind writes
250
336
  `.claude/projectstore.json` again, and 0.28's `install` and `upgrade` refuse
@@ -252,11 +338,11 @@ bound before 0.28. What an existing project sees afterwards, and why:
252
338
  `.claude/projectstore.json`, then run the command the startup line names
253
339
  once more: a 0.27.x session writes its welcome marker back under `.claude/`.
254
340
  - **Installed from npm?** Then `/plugin update` has nothing to fetch: the
255
- registration is refreshed by the package itself — from a terminal outside
256
- the session, `npx projectstore-claude@<version> upgrade --project "$PWD"`
257
- rewrites the local marketplace and runs the host's
258
- `plugin update` for this checkout. `/projectstore:doctor` says when the
259
- registration is behind the package, and names that command.
341
+ package itself refreshes the registration. The upgrade at the top of this
342
+ section, run from a terminal outside the session, rewrites the local
343
+ marketplace and runs the host's `plugin update` for this checkout.
344
+ `/projectstore:doctor` says when the registration is behind the package, and
345
+ names the command.
260
346
 
261
347
  ## When an agent starts a task, it can find its way
262
348
 
@@ -297,7 +383,62 @@ The deep dive — real session files, measured payloads, how every mechanism wor
297
383
 
298
384
  ## Uninstalling
299
385
 
300
- `/plugin uninstall projectstore@SmartAndPoint` for a Claude git-marketplace install; `npx projectstore-claude uninstall --project "$PWD"` for its npm registration. For Codex, `npx projectstore-codex uninstall --project "$PWD"` removes only project-owned wiring; add `--global` only to remove the user-global Codex plugin and marketplace. Your vault is yours — plain markdown, untouched. One leftover of a host-managed plugin path can be the agents block in `CLAUDE.md`/`AGENTS.md`; remove it with the harness's agents unregister skill, or delete everything between `<!-- projectstore:agents … -->` and `<!-- /projectstore:agents -->` by hand. A one-harness `uninstall` leaves a block that lives in `AGENTS.md`, because that file is read by other coding agents too. Claude Code's then removes the `CLAUDE.md` import when that file holds nothing else; Codex's keeps it, so Claude Code still sees the block. `uninstall --surface agents_block` removes the block as well. A bare core `npx projectstore uninstall --project "$PWD"`, with no `--harness`, covers every harness the project uses — each one whose own directory (`.claude/`, `.codex/`) or `.projectstore/state/<id>/` is there. Once every harness that can read the block's file is among them (for `AGENTS.md`, Claude Code and Codex), the block goes too, and the `CLAUDE.md` import with it unless your own text keeps both files.
386
+ From a terminal in your project:
387
+
388
+ ```
389
+ npx projectstore uninstall
390
+ ```
391
+
392
+ With no `--harness` it covers every agent the project uses — each one whose own directory (`.claude/`, `.codex/`) or `.projectstore/state/<id>/` is there — and removes what install wrote, and only that. For Codex that is the project-owned wiring: its plugin and marketplace are user-global, and removing them for every project is explicit:
393
+
394
+ ```
395
+ npx projectstore uninstall --harness codex --global
396
+ ```
397
+
398
+ A Claude Code install from the git marketplace is removed in the session:
399
+
400
+ ```
401
+ /plugin uninstall projectstore@SmartAndPoint
402
+ ```
403
+
404
+ **What a removal keeps:**
405
+
406
+ - the vault;
407
+ - the binding `.projectstore/projectstore.json`, with the status-line choice, so a later setup wires the line again;
408
+ - the agents' models in `.projectstore/harness/`, which is committed team configuration;
409
+ - Codex's user-wide registration, until `--global` removes it.
410
+
411
+ `--global` removes the Codex plugin for every other project on this machine too. Their `AGENTS.md` blocks stay and name agents that no longer load: uninstall Codex in each of them as well, or set them up again.
412
+
413
+ Your vault is yours — plain markdown, untouched. One leftover of a host-managed plugin path can be the agents block in `CLAUDE.md`/`AGENTS.md`; remove it with the harness's agents unregister skill, or delete everything between `<!-- projectstore:agents … -->` and `<!-- /projectstore:agents -->` by hand. A one-harness `uninstall`, with `--harness <id>`, leaves a block that lives in `AGENTS.md`, because that file is read by other coding agents too. Claude Code's then removes the `CLAUDE.md` import when that file holds nothing else; Codex's keeps it, so Claude Code still sees the block. `uninstall --surface agents_block` removes the block as well. Once every harness that can read the block's file is among those uninstalled (for `AGENTS.md`, Claude Code and Codex), the block goes too, and the `CLAUDE.md` import with it unless your own text keeps both files.
414
+
415
+ ### Reinstalling clean
416
+
417
+ Keeping the vault and the binding, uninstall and set up again. The second setup finds both:
418
+
419
+ ```
420
+ npx projectstore uninstall
421
+ ```
422
+
423
+ ```
424
+ npx projectstore setup
425
+ ```
426
+
427
+ To start as if the project was never bound, remove only the machine-local half after the uninstall. `.projectstore/harness/` and `.projectstore/.gitignore` are committed; keep them. The binding also carries the template language, the default author and tags, the skills switch, the band and the status-line choice, and removing it drops them. Setup then asks for the vault again.
428
+
429
+ ```
430
+ rm -f .projectstore/projectstore.json
431
+ ```
432
+
433
+ ```
434
+ rm -rf .projectstore/state
435
+ ```
436
+
437
+ To point the project at another vault, no reinstall is needed. From a terminal in your project:
438
+
439
+ ```
440
+ npx projectstore bind ~/vaults/other --rebind
441
+ ```
301
442
 
302
443
  ## Extending
303
444
 
@@ -322,7 +463,17 @@ One formatting-only commit is listed in `.git-blame-ignore-revs`. GitHub skips i
322
463
  git config blame.ignoreRevsFile .git-blame-ignore-revs
323
464
  ```
324
465
 
325
- A branch opened before that commit rebases in two steps, so that the lint fixes before it are kept: `git rebase <the commit before it>` (real conflicts, resolved as usual), then `git rebase --onto <it> <the commit before it>`, where every conflict is formatting only: take your side, run `npx prettier --write <file>`, `git add` it and continue.
466
+ A branch opened before that commit rebases in two steps, so that the lint fixes before it are kept. First onto the commit before it, resolving real conflicts as usual:
467
+
468
+ ```sh
469
+ git rebase <the commit before it>
470
+ ```
471
+
472
+ Then onto the formatting commit itself, where every conflict is formatting only: take your side, format the file with `npx prettier --write <file>` and `git add` it, then continue.
473
+
474
+ ```sh
475
+ git rebase --onto <it> <the commit before it>
476
+ ```
326
477
 
327
478
  ## License
328
479
 
@@ -3,7 +3,7 @@ description: Bind this project to an Obsidian vault (or any markdown directory)
3
3
  argument-hint: <vault-path> | --inherit [--layout engineering] [--lang en|ru|es|de|fr|zh]
4
4
  ---
5
5
 
6
- You are binding the current project to a markdown vault for projectstore. The config is written by the core's `bind` / `init` verbs (roadmap A8); this interview decides the values, previews them, and asks — it never writes `projectstore.json` itself, except on the inherit path (step 0a), which copies the parent's file verbatim, and the one later stamp in step 11 (`statusline`), which `Edit`s the file the verb wrote. The interview's `--lang` is the verb's `--language`.
6
+ You are binding the current project to a markdown vault for projectstore. The config is written by the core's `bind` / `init` verbs (roadmap A8); this interview decides the values, previews them, and asks — it never writes `projectstore.json` itself, except on the inherit path (step 0a), which copies the parent's file verbatim. The settings later steps change — the vault policy (step 7.5) and the status line (step 11) — go through `configure --set`, each key's one writer. The interview's `--lang` is the verb's `--language`.
7
7
 
8
8
  Parse `$ARGUMENTS`:
9
9
  - First positional arg: vault path. Expand `~` if present.
@@ -81,7 +81,7 @@ Steps:
81
81
  node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" bind "<vault-path>" [--layout <name>] [--language <code>] [--rebind]
82
82
  ```
83
83
 
84
- `init "<vault-path>" …` instead when step 1 chose to create the vault — it creates the whole vault, so step 7 has nothing to offer after it; `--rebind` only when step 0 ended on **Replace bind**. Naming the vault is the verb's confirmation (there is no `--yes`); the interview's AskUserQuestion in step 4 is the in-session gate. Print the verb's output. A non-zero exit is a refusal or a usage error — relay it and stop — except an `init` whose output reports `git init failed` or `Scaffold failed`: the binding is written, so relay the remedy line it prints and continue. Step 11 below `Edit`s the file this step wrote; keep it after it.
84
+ `init "<vault-path>" …` instead when step 1 chose to create the vault — it creates the whole vault, so step 7 has nothing to offer after it; `--rebind` only when step 0 ended on **Replace bind**. Naming the vault is the verb's confirmation (there is no `--yes`); the interview's AskUserQuestion in step 4 is the in-session gate. Print the verb's output. A non-zero exit is a refusal or a usage error — relay it and stop — except an `init` whose output reports `git init failed` or `Scaffold failed`: the binding is written, so relay the remedy line it prints and continue.
85
85
 
86
86
  6. **Check `.gitignore`**: read `<project>/.gitignore` if it exists. Our own files are self-ignored inside `.projectstore/` — the verb writes that `.gitignore` itself, carrying `projectstore.json` and `state/`, with `harness/` committed on purpose (the layout ADR); on the inherit path of step 0a, which bypasses the verb, you wrote both by hand. Unless `.claude/` is ignored wholesale, the one machine-specific entry left is the host's `.claude/settings.local.json`. If it is missing, offer (AskUserQuestion) to append it. If the user declines, skip silently.
87
87
 
@@ -97,7 +97,7 @@ Steps:
97
97
  - If it already exists with a `spec_policy` key — respect it, print the current policy, do not re-ask.
98
98
  - **New bind into a vault with no artifacts** (a vault `init` just made counts: its folders and README indexes are not artifacts): ask via AskUserQuestion — "Enable spec-first policy for this vault (every story must be covered by a spec; doctor enforces it)?" with options **Yes, `spec_policy: required` (Recommended)** / **Not yet, `optional`**. Second question: "Enable lifecycle gates (plan/close sections + evidence checks on stories)?" — **Yes, `lifecycle_gates: on` (Recommended)** / **Off for now**.
99
99
  - **Bind to an existing vault with artifacts**: default to `spec_policy: optional`, `lifecycle_gates: off` and say doctor will suggest enabling once specs appear. Do not impose the gate on an existing backlog.
100
- - On any choice, write `<vault>/.projectstore.json` (vault ROOT — deliberately not inside `<vault>/.projectstore/`, whose .gitignore would keep the policy out of git):
100
+ - On any choice, run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" configure --set spec_policy=<required|optional> --set lifecycle_gates=<on|off> --dry-run --project "${CLAUDE_PROJECT_DIR}"` and show its PLAN, then ask via AskUserQuestion: "Record this policy in the vault? [Yes / No]". On **Yes**, run the same command without `--dry-run`; a non-zero exit is a refusal — relay it and go on to step 8 (the binding is already written). It writes `<vault>/.projectstore.json` — vault ROOT, deliberately not inside `<vault>/.projectstore/`, whose .gitignore would keep the policy out of git — and keeps any other key in it:
101
101
 
102
102
  ```json
103
103
  {
@@ -107,7 +107,7 @@ Steps:
107
107
  }
108
108
  ```
109
109
 
110
- `spec_policy_since` is stamped ONLY when spec_policy is set to `required` — it anchors the legacy exemption (stories done before it stay exempt; stories in progress/review at enable time are in scope).
110
+ configure stamps `spec_policy_since` whenever spec_policy becomes `required` — it anchors the legacy exemption (stories done before it stay exempt; stories in progress/review at enable time are in scope).
111
111
 
112
112
  8. **Agent registration** (v0.13, ADR-002): ask via AskUserQuestion — "Register projectstore's agents in CLAUDE.md/AGENTS.md so every session routes to them (critic after authoring artifacts, planner before implementing, reviewer before commit)? [Yes (Recommended) / No]". On Yes, run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" install --harness claude-code --surface agents_block --project "${CLAUDE_PROJECT_DIR}"` and print its output (it renders from the layout's roster, migrates rather than duplicates, previews every write, and applies because the harness is named). On a rebind where a block already exists the verb reports it current or replaces it in place — do not re-ask blindly.
113
113
 
@@ -121,4 +121,4 @@ Steps:
121
121
 
122
122
  (for `ru`: `[PS#<version>] 📚 Супер-фича в супер-продукте › Ручка для туалетной бумаги (in-progress)`; every bundled language ships its own example pair)
123
123
 
124
- Ask via AskUserQuestion: "Show your current epic/story in the status line, composed above any existing HUD? [Yes / No]". On Yes: Edit `projectstore.json` → `"statusline": { "enabled": true }` (approval-gated), then run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" install --harness claude-code --surface statusline --project "${CLAUDE_PROJECT_DIR}"` and print its output (it writes the `settings.local.json` entry and the launcher, previewed), and report: "Enabled — restart Claude Code in this project to apply. A fresh session shows: `[PS#<version>] 📚 <statusline_no_work>`."
124
+ First run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" configure --set statusline=on --dry-run --project "${CLAUDE_PROJECT_DIR}"` and show its PLAN; a non-zero exit is a refusal (a foreign status line, an unparseable settings file) — relay it and skip this step. Then ask via AskUserQuestion: "Show your current epic/story in the status line, composed above any existing HUD? [Yes / No]". On Yes, run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" configure --set statusline=on --project "${CLAUDE_PROJECT_DIR}"` and print its output — a non-zero exit is a refusal to relay (it records `statusline.enabled: true` and writes the `settings.local.json` entry and the launcher, in one plan), and report: "Enabled — restart Claude Code in this project to apply. A fresh session shows: `[PS#<version>] 📚 <statusline_no_work>`."
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Enable/disable the projectstore status line (current epic & story in the HUD). Flips a flag and runs the install verb, which wires it behind a preview; the SessionStart hook keeps an existing entry current across plugin updates.
2
+ description: Enable/disable the projectstore status line (current epic & story in the HUD). Runs `configure --set statusline=on|off`, which records the flag and wires or removes the entry behind a preview; the SessionStart hook keeps an existing entry current across plugin updates.
3
3
  argument-hint: "on | off | status"
4
4
  ---
5
5
 
@@ -7,7 +7,7 @@ You are toggling the projectstore status line for THIS project. When enabled, `i
7
7
 
8
8
  Resolution is **per-session with zero cross-session and zero vault reads** (ADR-006): the 📚 segment comes from this session's pointer (`.projectstore/state/sessions/<session_id>.json`, maintained by the tool hooks — a write's patch after the write — by `story close`, and at session start; a done, closed or parked story leaves the segment); a fresh session shows an explicit localized cold-start line ("No epic or story in this session yet" / «Эпик и стори ещё не в работе в этой сессии») — never a silent blank; a corrupt pointer shows an error-marked string. Strings localize via `templates/<lang>/strings.json` (en fallback). The version badge is controlled by `statusline.show_version` (default true).
9
9
 
10
- This command flips the flag in `.projectstore/projectstore.json` and then runs the install verb, which writes `settings.local.json` and the launcher behind a preview. The SessionStart hook only refreshes an entry that is already ours and removes it when the flag is off — it never creates one.
10
+ This command runs `configure --set statusline=on|off` (the configure spec, contracts 6 and 9): install's own items record `statusline.enabled` and write or remove the `settings.local.json` entry and the launcher, in one plan. The command never writes `projectstore.json` itself. The SessionStart hook only refreshes an entry that is already ours and removes it when the flag is off — it never creates one.
11
11
 
12
12
  ## 1. Require a bound project
13
13
 
@@ -21,15 +21,15 @@ Read `.projectstore/projectstore.json`. If missing → "No vault bound. Run `/pr
21
21
 
22
22
  ## 3. `on`
23
23
 
24
- 1. **Foreign status line check** (read-only): read `.claude/settings.local.json` if present. If it has a `statusLine` whose `command` is **not** ours (ours contains either `.projectstore/state/<harness>/statusline.mjs` — the launcher; a not-yet-migrated project's legacy launcher is `.claude/.projectstore/statusline.mjs`, also ours — or `scripts/statusline.mjs` — an older or dev wiring), warn — the hook will **not** clobber a foreign local status line, so enabling would silently do nothing (and `statusline.mjs` composes only over a base in `.claude/settings.json` or `~/.claude/settings.json`, never one in `settings.local.json`). AskUserQuestion: **Proceed anyway / Help me clear it / Cancel**. If a base HUD lives in `~/.claude/settings.json` (e.g. oh-my-claudecode), that's fine — we compose over it; no warning needed.
25
- 2. **AskUserQuestion** (Yes / No): "Wire the status line for this project?" On Yes, run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" install --harness claude-code --surface statusline --project "${CLAUDE_PROJECT_DIR}"` and print its output verbatim — it previews and writes the `statusLine` entry and the launcher (`.projectstore/state/claude-code/statusline.mjs`, provenance-stamped). A non-zero exit is a refusal (a foreign status line, an unparseable settings file) — relay it and stop, leaving the flag as it was.
26
- 3. On success, read `.projectstore/projectstore.json`, set `statusline.enabled = true`. **Preserve `statusline.position`** if present (don't drop it); keep all other keys. Preview the change, then Write.
24
+ 1. **Foreign status line check** (read-only): read `.claude/settings.local.json` if present. If it has a `statusLine` whose `command` is **not** ours (ours contains either `.projectstore/state/<harness>/statusline.mjs` — the launcher; a not-yet-migrated project's legacy launcher is `.claude/.projectstore/statusline.mjs`, also ours — or `scripts/statusline.mjs` — an older or dev wiring), warn — configure refuses to enable over a foreign local status line (and `statusline.mjs` composes only over a base in `.claude/settings.json` or `~/.claude/settings.json`, never one in `settings.local.json`). AskUserQuestion: **Help me clear it / Cancel**. If a base HUD lives in `~/.claude/settings.json` (e.g. oh-my-claudecode), that's fine — we compose over it; no warning needed.
25
+ 2. **Preview**: run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" configure --set statusline=on --dry-run --project "${CLAUDE_PROJECT_DIR}"` and print its PLAN. A non-zero exit is a refusal — relay it and stop; nothing is asked or written.
26
+ 3. **AskUserQuestion** (Yes / No): "Wire the status line for this project?" On Yes, run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" configure --set statusline=on --project "${CLAUDE_PROJECT_DIR}"` and print its output verbatim — it records `statusline.enabled: true` (keeping `statusline.position` and every other key) and writes the `statusLine` entry and the launcher (`.projectstore/state/claude-code/statusline.mjs`, provenance-stamped), in one plan. A non-zero exit is a refusal (a foreign status line, an unparseable settings file, a layout still to move) — relay it and stop; nothing was written.
27
27
  4. Report: "Enabled. `📚 <epic> › <story>` renders above your existing HUD. **Restart Claude Code in this project** to apply now (statusLine loads at session start). If `.claude/settings.local.json` is tracked in git, add it to `.gitignore` — the entry carries a machine-specific absolute path."
28
28
 
29
29
  ## 4. `off`
30
30
 
31
- 1. **AskUserQuestion** (Yes / No): "Remove the projectstore status line from this project?" On Yes, read `.projectstore/projectstore.json` and set `statusline.enabled = false` (keep `statusline.position` + other keys) — write it **even if the flag was absent**, so the hook removes any managed `statusLine` entry it previously wrote. Preview, then Write.
32
- 2. Run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" uninstall --harness claude-code --surface statusline --project "${CLAUDE_PROJECT_DIR}"` and print its output — it removes our `statusLine` entry and the launcher, previewed, and leaves a foreign entry alone.
31
+ 1. **Preview**: run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" configure --set statusline=off --dry-run --project "${CLAUDE_PROJECT_DIR}"` and print its PLAN. A non-zero exit is a refusal — relay it and stop.
32
+ 2. **AskUserQuestion** (Yes / No): "Remove the projectstore status line from this project?" On Yes, run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" configure --set statusline=off --project "${CLAUDE_PROJECT_DIR}"` and print its output — it records `statusline.enabled: false` (even if the flag was absent, so the hook keeps it off) and removes our `statusLine` entry and the launcher, and leaves a foreign entry alone.
33
33
  3. Report: "Disabled; restart to apply."
34
34
 
35
35
  ## 5. `status`
@@ -42,5 +42,5 @@ Report, read-only:
42
42
  ## Notes
43
43
 
44
44
  - Every write goes through AskUserQuestion. Never write without approval.
45
- - The command writes `.projectstore/projectstore.json` and runs the install verb for the `statusline` surface; the SessionStart hook only refreshes an entry that is already ours (and removes it when the flag is off) — it never creates one, and never touches a foreign status line.
45
+ - The command runs `configure --set statusline=on|off`, whose install items are the flag's one writer; the SessionStart hook only refreshes an entry that is already ours (and removes it when the flag is off) — it never creates one, and never touches a foreign status line.
46
46
  - Config shape: `.projectstore/projectstore.json` → `"statusline": { "enabled": true, "position": "above", "show_version": true }`. `position` is `above` (default) or `below` — the side our 📚 line sits relative to the base HUD; `show_version` toggles the `[PS#…]` badge.