projectstore-codex 0.0.1 → 0.28.2

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 (184) hide show
  1. package/.codex-plugin/plugin.json +48 -0
  2. package/README.md +15 -7
  3. package/bin/projectstore-codex.mjs +88 -0
  4. package/hooks/hooks.json +59 -0
  5. package/node_modules/projectstore/.claude-plugin/marketplace.json +40 -0
  6. package/node_modules/projectstore/.claude-plugin/plugin.json +23 -0
  7. package/node_modules/projectstore/.mcp.json +14 -0
  8. package/node_modules/projectstore/AGENTS.md +26 -0
  9. package/node_modules/projectstore/LICENSE +21 -0
  10. package/node_modules/projectstore/README.md +284 -0
  11. package/node_modules/projectstore/agents/archaeologist.md +76 -0
  12. package/node_modules/projectstore/agents/clerk.md +93 -0
  13. package/node_modules/projectstore/agents/critic.md +94 -0
  14. package/node_modules/projectstore/agents/librarian.md +81 -0
  15. package/node_modules/projectstore/agents/planner.md +80 -0
  16. package/node_modules/projectstore/agents/reviewer.md +98 -0
  17. package/node_modules/projectstore/bin/projectstore.mjs +7 -0
  18. package/node_modules/projectstore/commands/adr.md +57 -0
  19. package/node_modules/projectstore/commands/agents.md +180 -0
  20. package/node_modules/projectstore/commands/bind.md +128 -0
  21. package/node_modules/projectstore/commands/codemap.md +50 -0
  22. package/node_modules/projectstore/commands/concept.md +17 -0
  23. package/node_modules/projectstore/commands/doctor.md +166 -0
  24. package/node_modules/projectstore/commands/epic.md +40 -0
  25. package/node_modules/projectstore/commands/graph.md +56 -0
  26. package/node_modules/projectstore/commands/kanban.md +40 -0
  27. package/node_modules/projectstore/commands/meeting.md +17 -0
  28. package/node_modules/projectstore/commands/reconcile.md +73 -0
  29. package/node_modules/projectstore/commands/research.md +17 -0
  30. package/node_modules/projectstore/commands/review.md +89 -0
  31. package/node_modules/projectstore/commands/runbook.md +17 -0
  32. package/node_modules/projectstore/commands/scaffold.md +23 -0
  33. package/node_modules/projectstore/commands/search.md +22 -0
  34. package/node_modules/projectstore/commands/spec.md +91 -0
  35. package/node_modules/projectstore/commands/status.md +27 -0
  36. package/node_modules/projectstore/commands/statusline.md +46 -0
  37. package/node_modules/projectstore/commands/story.md +113 -0
  38. package/node_modules/projectstore/docs/extending.md +172 -0
  39. package/node_modules/projectstore/docs/getting-started.md +133 -0
  40. package/node_modules/projectstore/docs/harnesses.md +176 -0
  41. package/node_modules/projectstore/docs/how-it-works.md +263 -0
  42. package/node_modules/projectstore/docs/images/loop-light.svg +94 -0
  43. package/node_modules/projectstore/docs/images/loop.svg +93 -0
  44. package/node_modules/projectstore/docs/images/statusline-hud.png +0 -0
  45. package/node_modules/projectstore/docs/images/team-light.svg +79 -0
  46. package/node_modules/projectstore/docs/images/team.svg +79 -0
  47. package/node_modules/projectstore/harnesses/claude-code.json +483 -0
  48. package/node_modules/projectstore/harnesses/codex.json +332 -0
  49. package/node_modules/projectstore/hooks/hooks.json +59 -0
  50. package/node_modules/projectstore/hooks/pre-compact.mjs +121 -0
  51. package/node_modules/projectstore/hooks/session-rules.mjs +63 -0
  52. package/node_modules/projectstore/hooks/session-start.mjs +301 -0
  53. package/node_modules/projectstore/hooks/session-stop.mjs +84 -0
  54. package/node_modules/projectstore/package.json +70 -0
  55. package/node_modules/projectstore/scaffold/checklists.json +88 -0
  56. package/node_modules/projectstore/scaffold/headings.json +171 -0
  57. package/node_modules/projectstore/scaffold/layouts/engineering.json +85 -0
  58. package/node_modules/projectstore/scripts/binding.mjs +165 -0
  59. package/node_modules/projectstore/scripts/build-adapters.mjs +264 -0
  60. package/node_modules/projectstore/scripts/cli.mjs +595 -0
  61. package/node_modules/projectstore/scripts/codemap.mjs +99 -0
  62. package/node_modules/projectstore/scripts/diff-refs.mjs +127 -0
  63. package/node_modules/projectstore/scripts/doctor.mjs +2127 -0
  64. package/node_modules/projectstore/scripts/draft.mjs +261 -0
  65. package/node_modules/projectstore/scripts/graph.mjs +219 -0
  66. package/node_modules/projectstore/scripts/harness.mjs +608 -0
  67. package/node_modules/projectstore/scripts/install-harness.mjs +1387 -0
  68. package/node_modules/projectstore/scripts/kanban.mjs +174 -0
  69. package/node_modules/projectstore/scripts/lib.mjs +3085 -0
  70. package/node_modules/projectstore/scripts/mcp.mjs +391 -0
  71. package/node_modules/projectstore/scripts/portable-registration.mjs +198 -0
  72. package/node_modules/projectstore/scripts/provenance.mjs +375 -0
  73. package/node_modules/projectstore/scripts/query.mjs +490 -0
  74. package/node_modules/projectstore/scripts/reconcile.mjs +422 -0
  75. package/node_modules/projectstore/scripts/statusline-launcher.mjs +141 -0
  76. package/node_modules/projectstore/scripts/statusline.mjs +253 -0
  77. package/node_modules/projectstore/scripts/story-section.mjs +209 -0
  78. package/node_modules/projectstore/scripts/surfaces.mjs +421 -0
  79. package/node_modules/projectstore/scripts/tokens.mjs +449 -0
  80. package/node_modules/projectstore/scripts/touch-session.mjs +336 -0
  81. package/node_modules/projectstore/scripts/version-guard.mjs +261 -0
  82. package/node_modules/projectstore/scripts/worktree.mjs +109 -0
  83. package/node_modules/projectstore/skills/projectstore-decision-detector/SKILL.md +40 -0
  84. package/node_modules/projectstore/skills/projectstore-peer-reviewer/SKILL.md +38 -0
  85. package/node_modules/projectstore/skills/projectstore-story-completion/SKILL.md +50 -0
  86. package/node_modules/projectstore/skills/projectstore-vault-communication/SKILL.md +96 -0
  87. package/node_modules/projectstore/templates/claude-md-block.md.tmpl +26 -0
  88. package/node_modules/projectstore/templates/de/adr.md.tmpl +67 -0
  89. package/node_modules/projectstore/templates/de/concept.md.tmpl +43 -0
  90. package/node_modules/projectstore/templates/de/epic.md.tmpl +59 -0
  91. package/node_modules/projectstore/templates/de/folder-readme.md.tmpl +14 -0
  92. package/node_modules/projectstore/templates/de/kanban.md.tmpl +36 -0
  93. package/node_modules/projectstore/templates/de/meeting.md.tmpl +38 -0
  94. package/node_modules/projectstore/templates/de/research.md.tmpl +47 -0
  95. package/node_modules/projectstore/templates/de/runbook.md.tmpl +53 -0
  96. package/node_modules/projectstore/templates/de/spec.md.tmpl +64 -0
  97. package/node_modules/projectstore/templates/de/story.md.tmpl +76 -0
  98. package/node_modules/projectstore/templates/de/strings.json +6 -0
  99. package/node_modules/projectstore/templates/en/adr.md.tmpl +67 -0
  100. package/node_modules/projectstore/templates/en/concept.md.tmpl +43 -0
  101. package/node_modules/projectstore/templates/en/epic.md.tmpl +59 -0
  102. package/node_modules/projectstore/templates/en/folder-readme.md.tmpl +14 -0
  103. package/node_modules/projectstore/templates/en/kanban.md.tmpl +36 -0
  104. package/node_modules/projectstore/templates/en/meeting.md.tmpl +38 -0
  105. package/node_modules/projectstore/templates/en/research.md.tmpl +47 -0
  106. package/node_modules/projectstore/templates/en/runbook.md.tmpl +53 -0
  107. package/node_modules/projectstore/templates/en/spec.md.tmpl +64 -0
  108. package/node_modules/projectstore/templates/en/story.md.tmpl +76 -0
  109. package/node_modules/projectstore/templates/en/strings.json +6 -0
  110. package/node_modules/projectstore/templates/es/adr.md.tmpl +67 -0
  111. package/node_modules/projectstore/templates/es/concept.md.tmpl +43 -0
  112. package/node_modules/projectstore/templates/es/epic.md.tmpl +59 -0
  113. package/node_modules/projectstore/templates/es/folder-readme.md.tmpl +14 -0
  114. package/node_modules/projectstore/templates/es/kanban.md.tmpl +36 -0
  115. package/node_modules/projectstore/templates/es/meeting.md.tmpl +38 -0
  116. package/node_modules/projectstore/templates/es/research.md.tmpl +47 -0
  117. package/node_modules/projectstore/templates/es/runbook.md.tmpl +53 -0
  118. package/node_modules/projectstore/templates/es/spec.md.tmpl +64 -0
  119. package/node_modules/projectstore/templates/es/story.md.tmpl +76 -0
  120. package/node_modules/projectstore/templates/es/strings.json +6 -0
  121. package/node_modules/projectstore/templates/fr/adr.md.tmpl +67 -0
  122. package/node_modules/projectstore/templates/fr/concept.md.tmpl +43 -0
  123. package/node_modules/projectstore/templates/fr/epic.md.tmpl +59 -0
  124. package/node_modules/projectstore/templates/fr/folder-readme.md.tmpl +14 -0
  125. package/node_modules/projectstore/templates/fr/kanban.md.tmpl +36 -0
  126. package/node_modules/projectstore/templates/fr/meeting.md.tmpl +38 -0
  127. package/node_modules/projectstore/templates/fr/research.md.tmpl +47 -0
  128. package/node_modules/projectstore/templates/fr/runbook.md.tmpl +53 -0
  129. package/node_modules/projectstore/templates/fr/spec.md.tmpl +64 -0
  130. package/node_modules/projectstore/templates/fr/story.md.tmpl +76 -0
  131. package/node_modules/projectstore/templates/fr/strings.json +6 -0
  132. package/node_modules/projectstore/templates/ru/adr.md.tmpl +67 -0
  133. package/node_modules/projectstore/templates/ru/concept.md.tmpl +43 -0
  134. package/node_modules/projectstore/templates/ru/epic.md.tmpl +59 -0
  135. package/node_modules/projectstore/templates/ru/folder-readme.md.tmpl +14 -0
  136. package/node_modules/projectstore/templates/ru/kanban.md.tmpl +36 -0
  137. package/node_modules/projectstore/templates/ru/meeting.md.tmpl +38 -0
  138. package/node_modules/projectstore/templates/ru/research.md.tmpl +47 -0
  139. package/node_modules/projectstore/templates/ru/runbook.md.tmpl +53 -0
  140. package/node_modules/projectstore/templates/ru/spec.md.tmpl +64 -0
  141. package/node_modules/projectstore/templates/ru/story.md.tmpl +76 -0
  142. package/node_modules/projectstore/templates/ru/strings.json +6 -0
  143. package/node_modules/projectstore/templates/zh/adr.md.tmpl +67 -0
  144. package/node_modules/projectstore/templates/zh/concept.md.tmpl +43 -0
  145. package/node_modules/projectstore/templates/zh/epic.md.tmpl +59 -0
  146. package/node_modules/projectstore/templates/zh/folder-readme.md.tmpl +14 -0
  147. package/node_modules/projectstore/templates/zh/kanban.md.tmpl +36 -0
  148. package/node_modules/projectstore/templates/zh/meeting.md.tmpl +38 -0
  149. package/node_modules/projectstore/templates/zh/research.md.tmpl +47 -0
  150. package/node_modules/projectstore/templates/zh/runbook.md.tmpl +53 -0
  151. package/node_modules/projectstore/templates/zh/spec.md.tmpl +64 -0
  152. package/node_modules/projectstore/templates/zh/story.md.tmpl +76 -0
  153. package/node_modules/projectstore/templates/zh/strings.json +6 -0
  154. package/package.json +35 -14
  155. package/skills/projectstore-adr/SKILL.md +76 -0
  156. package/skills/projectstore-agents/SKILL.md +50 -0
  157. package/skills/projectstore-archaeologist/SKILL.md +109 -0
  158. package/skills/projectstore-bind/SKILL.md +44 -0
  159. package/skills/projectstore-clerk/SKILL.md +126 -0
  160. package/skills/projectstore-codemap/SKILL.md +69 -0
  161. package/skills/projectstore-concept/SKILL.md +36 -0
  162. package/skills/projectstore-critic/SKILL.md +127 -0
  163. package/skills/projectstore-decision-detector/SKILL.md +59 -0
  164. package/skills/projectstore-doctor/SKILL.md +33 -0
  165. package/skills/projectstore-epic/SKILL.md +59 -0
  166. package/skills/projectstore-graph/SKILL.md +75 -0
  167. package/skills/projectstore-kanban/SKILL.md +60 -0
  168. package/skills/projectstore-librarian/SKILL.md +114 -0
  169. package/skills/projectstore-meeting/SKILL.md +36 -0
  170. package/skills/projectstore-peer-reviewer/SKILL.md +57 -0
  171. package/skills/projectstore-planner/SKILL.md +113 -0
  172. package/skills/projectstore-reconcile/SKILL.md +92 -0
  173. package/skills/projectstore-research/SKILL.md +36 -0
  174. package/skills/projectstore-review/SKILL.md +108 -0
  175. package/skills/projectstore-reviewer/SKILL.md +131 -0
  176. package/skills/projectstore-runbook/SKILL.md +36 -0
  177. package/skills/projectstore-scaffold/SKILL.md +42 -0
  178. package/skills/projectstore-search/SKILL.md +41 -0
  179. package/skills/projectstore-spec/SKILL.md +110 -0
  180. package/skills/projectstore-status/SKILL.md +47 -0
  181. package/skills/projectstore-statusline/SKILL.md +29 -0
  182. package/skills/projectstore-story/SKILL.md +132 -0
  183. package/skills/projectstore-story-completion/SKILL.md +69 -0
  184. package/skills/projectstore-vault-communication/SKILL.md +115 -0
@@ -0,0 +1,180 @@
1
+ ---
2
+ description: Manage bundled-agent integration in this project — register/unregister the routing block in CLAUDE.md/AGENTS.md, inspect state, or configure which model its agents run on.
3
+ argument-hint: "<register | unregister | status | configure>"
4
+ ---
5
+
6
+ You are managing projectstore's agent integration (ADR-002 block lifecycle,
7
+ ADR-003 presets as revised by ADR-008 — model per invocation, no copies). Require a bound project for every
8
+ subcommand (`.projectstore/projectstore.json`; else point to `/projectstore:bind`).
9
+
10
+ ## `register` — write the managed routing block
11
+
12
+ 1. **Ask** via AskUserQuestion: "Register projectstore's agents in
13
+ CLAUDE.md/AGENTS.md so every session routes to them (critic after
14
+ authoring artifacts, planner before implementing, reviewer before commit)?
15
+ [Yes / No]". On No, stop.
16
+ 2. **Run the verb** and print its output verbatim:
17
+ ```bash
18
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" install --harness claude-code --surface agents_block --project "${CLAUDE_PROJECT_DIR}"
19
+ ```
20
+ It renders the block from the installed plugin's template ∩ the layout's
21
+ roster (`scaffold/layouts/<layout>.json` — only routable agents get lines;
22
+ the entry-rule line, the instruction-conflict line, the
23
+ model-resolution line and the vault-native communication line always stay), places it (`AGENTS.md` when it
24
+ exists, else `CLAUDE.md`; a block in the other file is migrated, never
25
+ duplicated; `CLAUDE.md` gets an `@AGENTS.md` import), previews every
26
+ write, and applies because the harness is named. A current block is
27
+ reported and left alone; a stale one is replaced in place with the user's
28
+ prose byte-identical.
29
+ 3. A non-zero exit is a refusal — a duplicated or unclosed block, a missing
30
+ template — relay it and stop. Never write the block with the Write or Edit
31
+ tool: the verb is the only writer (install spec, contract 6). One exception,
32
+ read from the output, not assumed: when it shows the block applied and the
33
+ `layout` item skipped as deferred to a terminal outside the session, the
34
+ exit 1 is that deferral. The block is registered — say so, and for the move
35
+ relay the command the startup line or `/projectstore:doctor`'s
36
+ `layout-legacy` finding names; never compose one. Any other non-zero exit
37
+ is a refusal.
38
+
39
+ ## `unregister` — remove what register added
40
+
41
+ 1. Ask via AskUserQuestion ("Remove projectstore's agents block? [Yes / No]"),
42
+ then run and print verbatim:
43
+ ```bash
44
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" uninstall --harness claude-code --surface agents_block --project "${CLAUDE_PROJECT_DIR}"
45
+ ```
46
+ It removes the marked block; deletes a `CLAUDE.md` that held nothing else,
47
+ or nothing but the `@AGENTS.md` import registration added; and leaves every
48
+ user-authored line in place. A non-zero exit is a refusal (a block whose
49
+ open marker was re-wrapped, or that appears twice in one file) — relay it
50
+ and stop; never report success over it, and never remove the block by hand.
51
+
52
+ ## `status` — read-only report
53
+
54
+ Run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" plan --json --surface agents_block --project "${CLAUDE_PROJECT_DIR}"`
55
+ and report each item's `state` from `result.items[]` — the bin wraps the plan in its envelope (`ours-current`, `ours-stale` with its reason,
56
+ `ours-absent`, or a refusal). Then:
57
+
58
+ - Block: present in which file, marker version vs the installed template, agent
59
+ names vs the layout roster.
60
+ - Model: run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" agents show --json --project "${CLAUDE_PROJECT_DIR}"`
61
+ and report `result.resolved` — per roster agent, the model the verb would
62
+ pass and its `source` (`per_agent`, `default`, or `null`: the agent's own
63
+ frontmatter), resolved by the verb over the active harness's overlay
64
+ (`result.path`) so nothing here re-derives it; `result.unknown` (configured
65
+ names no roster agent carries — nothing runs under them), `result.rejected`
66
+ (keys the overlay may not carry) and `result.agents_in_binding` (a pre-0.28
67
+ leftover; point at `upgrade`), and
68
+ whether `CLAUDE_CODE_SUBAGENT_MODEL` is set (it overrides everything) and
69
+ whether `CLAUDE_CODE_EFFORT_LEVEL` is set (ADR-008 makes it the only thing that
70
+ can move the agents off `effort: max`, and it beats frontmatter). **Warn when
71
+ `result.resolved.clerk.model` is anything but `sonnet` or `haiku`** (that
72
+ literal pair is the rule, so it is never re-derived; an unknown custom id also
73
+ warns, with "verify it is cheap"): the clerk transcribes approved
74
+ content and runs a pinned procedure — paying reasoning-model prices there is
75
+ the misallocation its ADR exists to end; point at `configure` to pin
76
+ `per_agent.clerk`.
77
+ - Leftover copies: anything in `.claude/agents/` or `~/.claude/agents/` carrying
78
+ `# source: projectstore v…`. Report these as **overriding nothing** (ADR-008)
79
+ and point at `configure` to clean them up — do not present them as the active
80
+ configuration, because they are not.
81
+
82
+ ## `configure` — model per invocation, recorded in config (ADR-008)
83
+
84
+ > **Why there are no override copies here.** ADR-003 wrote
85
+ > `<project>/.claude/agents/<name>.md` believing an equal `name:` shadows the
86
+ > bundled agent. It does not: plugin agents register as `projectstore:<name>`,
87
+ > project agents bare, so the names never collide, the scope-priority rule never
88
+ > fires, and the copy becomes a **sibling** — the registration block keeps
89
+ > invoking the bundled agent and the model pinned in the copy never runs.
90
+ > Verified by invoking both ids (ADR-003's field note). ADR-008 replaces the
91
+ > mechanism: the choice lives in config and rides the **per-invocation `model`
92
+ > parameter**, which sits above the agent file's frontmatter.
93
+
94
+ 1. **Preset question** (one choice for ALL roster agents), with this education
95
+ line in the question text: *"These agents don't write code — they are
96
+ critics, planners, and reviewers; they perform best on strong models at high
97
+ effort. The one exception is the clerk, which only transcribes approved
98
+ content — it stays cheap regardless of the preset."* Options: keep bundled default (`opus`) / `fable` / `sonnet` /
99
+ custom model ID (free-form). Offer the current session's model as a hint
100
+ option — you know what you are running on. **Do not ask about effort** — see
101
+ step 5. **`inherit` is no longer offered**: it meant "follow the session's
102
+ model", and that cannot be expressed per invocation — passing nothing falls
103
+ through to the bundled `model: opus`, not to the session. A user who wants
104
+ session-follow behaviour should pick their session's model explicitly, or set
105
+ `CLAUDE_CODE_SUBAGENT_MODEL=inherit`, which does mean exactly that.
106
+ 2. **Optional follow-up**: "configure individually?" → per-agent model for each
107
+ roster agent. Skippable.
108
+ 3. **Apply**: after the AskUserQuestion, run the verb and print its output —
109
+ `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" agents configure --harness claude-code --default <model> [--agent <name>=<model> …] --project "${CLAUDE_PROJECT_DIR}"`
110
+ (naming the harness is the confirmation; the verb writes
111
+ `.projectstore/harness/claude-code.json → agents` and nothing else — never
112
+ Edit or Write the file yourself). **Whenever `--default` is set and no
113
+ `--agent clerk=…` is, the verb pins `per_agent.clerk.model: "sonnet"`** and
114
+ says so — a strong roster preset must not silently lift the clerk with it;
115
+ an explicit clerk choice in step 2 (`--agent clerk=<model>`) wins. The same
116
+ applies as a **migration**: an overlay carrying a default with no clerk pin
117
+ gets the pin on any `configure` run. `--agent <name>=` (empty) removes a
118
+ per-agent key; `--reset` empties the block ("leave every agent to its own
119
+ frontmatter"), and a `--default`/`--agent` given with it applies on top of
120
+ the emptied block. A name outside the layout's roster is a usage error
121
+ naming the roster — a model written under a name no agent carries would
122
+ never run. That file is the whole output of this command — **never write
123
+ an agent copy into `.claude/agents/`**. The verb never writes an `effort`
124
+ key; one already inside the agents block is dropped by the next `configure`
125
+ write and named in its preview, and until then doctor reports it as a key the
126
+ overlay may not carry — it has no effect (the effort you configured is not
127
+ the effort that runs).
128
+ 4. **Migrate away from copies**: if `.claude/agents/` holds copies carrying
129
+ `# source: projectstore v…`, they are pre-ADR-008 leftovers that override
130
+ nothing. Offer to delete them **one approval per file** (matching `/projectstore:doctor --fix`), project scope only — a copy in `~/.claude/agents/` needs a manual removal, and you should say so rather than implying this command will handle it.
131
+ Copies WITHOUT the provenance marker are user-authored — never touch them,
132
+ never mention deleting them.
133
+ 5. **Effort is not configurable per project.** The bundled agents ship
134
+ `effort: max`, which is the recommended value, and there is no
135
+ per-invocation effort parameter — only frontmatter, settings, or
136
+ `CLAUDE_CODE_EFFORT_LEVEL`. If the user asks for a different effort, say
137
+ that plainly and point at the env var; do not write a copy to achieve it.
138
+ 6. **Honesty notes to print**: an org `availableModels` allowlist silently
139
+ downgrades excluded models; the `CLAUDE_CODE_SUBAGENT_MODEL` env var
140
+ overrides everything configured here, per-invocation parameter included.
141
+ `/projectstore:doctor` validates config shape and reports leftover copies —
142
+ not entitlement, and not whether a given spawn actually passed the model.
143
+ 7. **No restart is needed** — nothing about the agent list changed. The model
144
+ takes effect on the next invocation that reads the config (step "Model
145
+ resolution" below).
146
+
147
+ ## Model resolution — how the configured model is actually used
148
+
149
+ Any surface that spawns a roster agent (this plugin's own commands, and the
150
+ registration block's instructions) resolves the model with one read:
151
+
152
+ ```
153
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" agents model <name> --json --project "${CLAUDE_PROJECT_DIR}"
154
+ ```
155
+
156
+ and passes `result.model` as the spawn's model parameter — `null` means pass
157
+ nothing, the agent's own frontmatter decides. The verb applies
158
+ `agents.per_agent.<name>.model ?? agents.default.model ?? null` over
159
+ `<project>/.projectstore/harness/<harness>.json` (the active harness's
160
+ overlay); besides the agents block itself (harness-neutral prose with no bin
161
+ to call — it states the rule as a file read, deliberately), nothing else
162
+ restates that rule. Never guess a model.
163
+
164
+ `agents.default` is optional and often absent (a per-agent-only config is normal);
165
+ the resolution must tolerate that. An `effort` key, if present, is a pre-ADR-008
166
+ leftover: ignore it.
167
+
168
+ **Coverage, stated honestly.** This reaches spawns made by this plugin's commands
169
+ and spawns a session makes while following the registration block. It does *not*
170
+ reach description-based auto-delegation, where the platform picks the agent and
171
+ there is no invocation site to attach a model to — those always run the bundled
172
+ frontmatter. `CLAUDE_CODE_SUBAGENT_MODEL` is the only mechanism that covers every
173
+ path, at the cost of applying to every subagent on the machine.
174
+
175
+ ## Notes
176
+
177
+ - Uninstalling the plugin removes these commands but NOT the block — run
178
+ `unregister` first, or delete everything between the
179
+ `<!-- projectstore:agents -->` markers by hand.
180
+ - Never write any file without AskUserQuestion approval.
@@ -0,0 +1,128 @@
1
+ ---
2
+ description: Bind this project to an Obsidian vault (or any markdown directory) where projectstore will record artifacts.
3
+ argument-hint: <vault-path> | --inherit [--layout engineering] [--lang en|ru|es|de|fr|zh]
4
+ ---
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 two later stamps in steps 11–12 (`autoupdate_asked`, `statusline`), which `Edit` the file the verb wrote. The interview's `--lang` is the verb's `--language`.
7
+
8
+ Parse `$ARGUMENTS`:
9
+ - First positional arg: vault path. Expand `~` if present.
10
+ - Optional `--inherit`: adopt the binding of the checkout this worktree was forked from (step 0a). Mutually exclusive with a positional vault path.
11
+ - Optional `--layout <name>`: layout to use. Default: `engineering`.
12
+ - Optional `--lang <en|ru|es|de|fr|zh>`: template language. Default: `en`. (`zh` is Simplified Chinese.)
13
+
14
+ Steps:
15
+
16
+ 0. **Check for an existing bind** (safer rebind, v0.4.1):
17
+ - Read `<project>/.projectstore/projectstore.json` if it exists.
18
+ - `--inherit` and a positional vault path together are a contradiction: say so and stop, rather than silently picking one.
19
+ - If absent **and** no positional vault path was given (or `--inherit` was passed): run step **0a** first.
20
+ - If absent otherwise: proceed to step 1 (fresh bind).
21
+ - If present **and** `--inherit` was passed: print "Already bound to `<path>`." and stop. Do not fall through to the rebind comparison below — with `--inherit` there is no new path to compare, and the comparison would render an empty "proposed" side and offer to replace the binding. A no-op command must not reach a destructive option.
22
+ - If present, let the verb compare — run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" bind "<vault-path>" [--layout <name>] [--language <code>] --json` **without** `--rebind` (pass the user's flags, so the proposed side of the diff is what a rebind would write) (the vault is normalised on both sides: `~`, relative, trailing slash, symlinks):
23
+ - `result.state` is `"same"` (exit 0, nothing written): print "Already bound to `<path>`. Re-run `/projectstore:scaffold` if you need to (re)create the layout, or `/projectstore:status` to inspect it." and stop. If `result.ignored` names `layout` or `language`, say the flag was ignored — a change of layout or language is not a rebind.
24
+ - a refusal with code `UNREADABLE` (the config exists but is not valid JSON): relay it and stop — nothing is overwritten; the user fixes or removes the file first.
25
+ - `result.state` is `"different"` (exit 1, a `REBIND` refusal, nothing written — **the refusal is the diff**, and `result.kept_keys` lists what a rebind keeps): show the user a one-block diff built from the existing config and the refusal:
26
+ ```
27
+ Existing bind:
28
+ vault_path: <old>
29
+ layout: <old layout>
30
+ language: <old lang>
31
+ Proposed bind:
32
+ vault_path: <new>
33
+ layout: <new layout>
34
+ language: <new lang>
35
+ ```
36
+ Then ask via AskUserQuestion: "An existing projectstore bind was found. How to proceed?" with options:
37
+ - **Replace bind** (Recommended) — re-run the verb with `--rebind` in step 5 (every other key of the config is kept), leaving the old vault's `.projectstore/sessions/` to expire on its own 24h TTL.
38
+ - **Keep old bind** — make no changes, print "Kept binding to `<old>`." and stop.
39
+ - **Cancel** — make no changes, print "Cancelled." and stop.
40
+
41
+ Only on **Replace bind**, continue with the remaining steps below.
42
+
43
+ 0a. **Inherit from the checkout this worktree was forked from** (ADR "A vault worktree is an additional write path…", decision 12). `.gitignore` ignores `.claude/`, so a worktree of a bound checkout starts unbound and every `/projectstore:*` command is dead in it — including this one's usual path.
44
+
45
+ ```bash
46
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/worktree.mjs"
47
+ ```
48
+
49
+ It prints `{state, worktree, mainCheckout, vaultPath}` and writes nothing.
50
+ - `state` is **not** `inheritable` → say why in one line (not a worktree, its parent is unbound too, or git could not answer) and fall through to step 1, which needs a vault path; if none was given, ask for one.
51
+ - `state` is `inheritable` → read the parent's `<mainCheckout>/.projectstore/projectstore.json` (or, in a checkout not yet migrated, the legacy `<mainCheckout>/.claude/projectstore.json`), show it **verbatim as a code block**, and ask via AskUserQuestion: "Adopt the binding of `<mainCheckout>` (vault `<vaultPath>`)?" — Yes / No.
52
+ - On **Yes**: Write that JSON verbatim to `<project>/.projectstore/projectstore.json`, **and write `<project>/.projectstore/.gitignore` beside it** with the two lines `projectstore.json` and `state/` under a comment saying they are machine-local (the verb writes them itself on every other path; this one bypasses the verb, and without them the worktree commits an absolute vault path into the index it shares with its parent). If that file already exists, add any missing line and leave the rest — it is line-merged. Then **jump straight to step 10** (the summary). Steps 1–9 and 11–12 are decisions the parent already made and the copied config already carries — layout, language, statusline, agent models, auto-update. Do not re-ask them, and do not scaffold: the vault exists and is shared.
53
+ - Copy the **binding only** (`projectstore.json`). Never copy `.projectstore/state/` — per-session state belonging to the other checkout — and never `harness/`: the overlays are committed and arrive from git.
54
+ - Do not add a provenance key to the config. The parent is resolvable from git at any time; a key would be a second source of truth for the same fact.
55
+
56
+ 1. **Validate the vault path** read-only first: `ls -d "<path>"` (the verb has no dry run — running it on a fresh project would write the config before step 4's approval). If it does not exist, ask the user (via AskUserQuestion) whether to create it; on Yes, step 5 runs `init` instead of `bind` (it creates the directory and binds; the layout's folders remain `/projectstore:scaffold`'s). Never `mkdir` it yourself.
57
+ 2. **Detect existing layout**: list immediate subdirectories. If you see `adr/`, `epics/`, `concepts/`, `research/` — the vault already uses an engineering-like layout; suggest `engineering`. Otherwise use the user's choice or `engineering` default.
58
+ 3. **Build the config** as JSON:
59
+
60
+ ```jsonc
61
+ {
62
+ "vault_path": "<absolute-path>",
63
+ "layout": "engineering",
64
+ "auto_inject": true,
65
+ "language": "en",
66
+ "tags": [],
67
+ "default_author": "<git user.name or $USER>",
68
+ "active_skills": true,
69
+ "approval_mode": "always"
70
+ }
71
+ ```
72
+
73
+ `default_author` comes from `git config --get user.name` in the project (fallback to the login name) — the verb reads it; the block above is the preview of what the verb writes on a fresh bind (a rebind rewrites `vault_path`, `layout`, `language` and keeps every other key).
74
+
75
+ 4. **Show the user the proposed config** as a code block. Use AskUserQuestion to confirm: "Write `.projectstore/projectstore.json` with this config? [Yes / Edit a field / No]".
76
+
77
+ 5. On approval, write through the core — never with the Write tool:
78
+
79
+ ```bash
80
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" bind "<vault-path>" [--layout <name>] [--language <code>] [--rebind]
81
+ ```
82
+
83
+ `init "<vault-path>" …` instead when step 1 chose to create the vault; `--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. Steps 11 and 12 below `Edit` the file this step wrote; keep them after it.
84
+
85
+ 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.
86
+
87
+ 7. **Offer scaffold**: if the vault is empty or missing layout folders, ask: "Vault is empty/incomplete. Run `/projectstore:scaffold` to create the layout? [Yes / No]". If yes, invoke `/projectstore:scaffold` immediately (just describe; do not assume execution).
88
+
89
+ 7.5. **Vault policy** (v0.14, ADR-007 — vault-side, survives clones): check `<vault>/.projectstore.json`.
90
+ - If it already exists with a `spec_policy` key — respect it, print the current policy, do not re-ask.
91
+ - **New bind into an empty/fresh vault**: 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**.
92
+ - **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.
93
+ - On any choice, write `<vault>/.projectstore.json` (vault ROOT — deliberately not inside `<vault>/.projectstore/`, whose .gitignore would keep the policy out of git):
94
+
95
+ ```json
96
+ {
97
+ "spec_policy": "required",
98
+ "lifecycle_gates": "on",
99
+ "spec_policy_since": "<current ISO-8601 timestamp>"
100
+ }
101
+ ```
102
+
103
+ `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).
104
+
105
+ 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.
106
+
107
+ 9. **Agent model preset** (v0.13, ADR-003; mechanism per ADR-008): ask via AskUserQuestion — include this line in the question text: *"These agents don't write code — they are critics, planners, and reviewers; they perform best on strong models at high effort."* Options: **Keep bundled default — opus** (Recommended) / **fable** / **sonnet**. Do not offer `inherit` — it cannot be expressed per invocation (see `commands/agents.md`). Do not offer effort — it is not configurable per project (the bundled agents already run at `max`). Free-form model IDs and per-agent tuning live in `/projectstore:agents configure` — mention it. A non-default choice runs the `configure` apply flow from `commands/agents.md`, which writes the config only — **never an agent copy**. Skippable.
108
+
109
+ 10. **Print summary**: confirm the bind, list the layout's folders, suggest next commands (`/projectstore:status`, `/projectstore:adr "<first decision>"`, `/projectstore:epic <ID> "<title>"`).
110
+
111
+ 11. **Auto-update reminder** (v0.7+, only on first successful bind in this project): After Step 5 (config write), check whether the newly-written config has `autoupdate_asked: true`. If not, ask the user via AskUserQuestion:
112
+
113
+ > "Claude Code does not auto-update third-party marketplaces by default. Want to enable auto-update for the SmartAndPoint marketplace so you'll be notified about future projectstore releases?"
114
+
115
+ Options:
116
+ - **Yes, show me how** (Recommended) — respond with: "Open `/plugin` → **Marketplaces** tab → **SmartAndPoint** → toggle **auto-update** on. New releases (v0.7+) will be detected at Claude Code startup; you'll need to run `/reload-plugins` after the notification to activate them."
117
+ - **No, I'll handle it manually** — respond with: "OK. To pull the latest version at any time, run `/plugin marketplace update SmartAndPoint`, then `/reload-plugins`."
118
+ - **Already enabled** — respond with: "Great. New releases will be detected at the next Claude Code startup."
119
+
120
+ After the question is answered (regardless of choice), Edit `<project>/.projectstore/projectstore.json` to add `"autoupdate_asked": true` to the JSON object. This guarantees we ask only once per project.
121
+
122
+ 12. **Status line offer** (v0.13, ADR-006 — the final step, language is known by now): read `${CLAUDE_PLUGIN_ROOT}/templates/<lang>/strings.json` (fall back to `en`) and the plugin version, then show the fully rendered example:
123
+
124
+ > `[PS#<version>] 📚 <statusline_example_epic> › <statusline_example_story> (in-progress)`
125
+
126
+ (for `ru`: `[PS#<version>] 📚 Супер-фича в супер-продукте › Ручка для туалетной бумаги (in-progress)`; every bundled language ships its own example pair)
127
+
128
+ 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>`."
@@ -0,0 +1,50 @@
1
+ ---
2
+ description: Regenerate code-map.md (epic ↔ code overview) from frontmatter code_refs, or set an artifact's code_refs. The command is the write path — planner/reviewer only propose refs.
3
+ argument-hint: "[set <epic-id | story-path> <ref> [ref…]]"
4
+ ---
5
+
6
+ You are managing the epic↔code mapping (ADR-004).
7
+
8
+ ## Bare `codemap` — regenerate the view
9
+
10
+ 1. **Check config**; stop if missing.
11
+ 2. Compute (read-only, the unified reconcile path):
12
+
13
+ ```bash
14
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" reconcile --only codemap
15
+ ```
16
+
17
+ The `codemap` entry carries `{ path, changed, content?, stats }`.
18
+ 3. Show `stats` (epics, epics_with_refs, story_rows) + first ~15 lines of
19
+ `content` when changed.
20
+ 4. **Approval** via AskUserQuestion: Yes / No (disclose: content is recomputed
21
+ from frontmatter at write time; the preview is advisory). On Yes → apply
22
+ through the core, never the Write tool:
23
+
24
+ ```bash
25
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" reconcile --write --only codemap
26
+ ```
27
+
28
+ Explicit selection writes the map even on a vault with no `code_refs` yet.
29
+ Render the report's `codemap` entry; nonzero exit — surface the `error`.
30
+ 5. Suggest: "Refs are set via `codemap set`; reviewer proposes updates at story completion."
31
+
32
+ ## `codemap set <target> <ref…>` — update frontmatter (the write path)
33
+
34
+ 1. **Resolve target**: an epic id (`PS-AGENTS` → `epics/PS-AGENTS/epic.md`) or a
35
+ story path relative to the vault. Stop with a clear error if not found.
36
+ 2. **Read the file**, show current `code_refs` vs proposed (`["src/auth/", …]`).
37
+ Validate: repo-relative paths/globs; warn (don't block) on paths that don't
38
+ exist yet — planning-time refs are legitimate (doctor is status-aware).
39
+ 3. **Approval** via AskUserQuestion (diff preview). On Yes → Edit the frontmatter
40
+ `code_refs` line only; also bump `updated:` if the artifact has it.
41
+ 4. **Offer regen**: "Refresh the view? (runs bare `codemap`)" — on Yes, run the
42
+ bare flow above.
43
+
44
+ ## Notes
45
+
46
+ - Story `code_refs` = files that story touched; epic `code_refs` = the epic's
47
+ overall footprint. Doctor checks story ⊆ epic and path existence
48
+ (status-aware). `reconcile` also regenerates the view.
49
+ - Never write refs without approval; never let an agent edit them directly —
50
+ planner/reviewer *propose*, this command *writes*.
@@ -0,0 +1,17 @@
1
+ ---
2
+ description: Create a new concept note (definition, mental model, glossary entry).
3
+ argument-hint: <title>
4
+ ---
5
+
6
+ You are creating a concept note.
7
+
8
+ Steps:
9
+
10
+ 1. Check config; stop if missing.
11
+ 2. Run `node "${CLAUDE_PLUGIN_ROOT}/scripts/draft.mjs" concept "$ARGUMENTS"`.
12
+ 3. Preview path + first ~15 lines. When `index` is non-null, print `index.line` too — the exact row that will appear in the folder index, unless the index step reports a failure and no row lands at all.
13
+ 4. AskUserQuestion: Yes / Edit / No. This is the only gate: **Yes** covers the artifact and its index row. Disclose in the question that the folder's whole managed index table is regenerated from vault state at write time, so the update may also repair a stale row for another artifact.
14
+ 5. Pre-write race check (Layer 1): `test -e "<path>"`. If exists, ask: **Overwrite**, **Use new slug** (`-2`), or **Cancel**.
15
+ 6. On Yes (path free or overwrite confirmed): Write file.
16
+ 7. Index row, if `index` is non-null — apply through the core, never Write/Edit, no second gate (step 4 covers it): `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" reconcile --write --only indexes=<index.folder>`. The row is derived state: canonical order, atomic write, manual prose preserved. The file is already on disk, so a nonzero exit is a warning naming the folder (stderr with no JSON = rejected before any write, fix the header or restore the README; `error` in JSON = I/O failure, suggest `/projectstore:reconcile`), never a failed creation.
17
+ 8. Suggest: "Define `What is it` first, then `How it works`. Link from ADRs/research that reference this concept."
@@ -0,0 +1,166 @@
1
+ ---
2
+ description: Diagnose the projectstore installation (config, vault, hooks, statusline, agents wiring) and the vault's consistency (status ↔ kanban ↔ indexes, acceptance, links). Read-only by default; --fix offers approval-gated install-side repairs.
3
+ argument-hint: "[--install | --vault] [--fix]"
4
+ ---
5
+
6
+ You are running projectstore diagnostics (ADR-005: umbrella doctor).
7
+
8
+ ## Steps
9
+
10
+ 1. **Run the engine** (read-only; pass through section flags, never `--fix`):
11
+
12
+ ```bash
13
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" doctor $ARGUMENTS_WITHOUT_FIX
14
+ ```
15
+
16
+ Forward only `--install` / `--vault` from the arguments: the bin's parser is strict, and any other flag is a usage error (exit 2) rather than the shrug the bare script gave. Exit 1 means findings were reported, not that the check failed (exit 2 is usage, 3 not bound) — read the report, never the exit code, as the verdict. (The bare script always exited 0; through the bin the exit code carries the verdict, so a Bash tool that colours non-zero red is colouring findings, not a crash.)
17
+
18
+ Default (no flags) runs both sections: `--install` (wiring/config) and
19
+ `--vault` (consistency). Print the report **verbatim**.
20
+
21
+ 2. **No findings** → done. One line: "Doctor is clean — N info note(s) above."
22
+
23
+ 3. **`--fix` requested** → walk the *install-side* findings only, one
24
+ AskUserQuestion per repair, never batched silently. **When `layout-legacy`
25
+ is in the report, it goes first and its command is the one repair** for a
26
+ stale-launcher `surface`, a v3 `agents-block` and `agents-in-binding` as
27
+ well: relay it and run nothing in-session for those (see its bullet below).
28
+ The report already shows the v3 block, and a block Claude Code cannot see,
29
+ as info that points at the move.
30
+ - `worktree-unbound` → this checkout is a git worktree of a bound one. Offer
31
+ `/projectstore:bind --inherit`, and say what it does: copies the parent's
32
+ binding, leaves the vault shared and unchanged, carries no session state.
33
+ Do not offer a fresh `bind <vault-path>` here — binding a second vault by
34
+ hand is exactly what this finding exists to prevent.
35
+ - `vault-git` → offer `git init` (+ optional first commit) inside the vault.
36
+ - `gitignore` → offer appending the missing entries via Edit.
37
+ - `agents-block` duplicate or stale → show the finding, then (after approval)
38
+ run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" install --harness claude-code --surface agents_block --project "${CLAUDE_PROJECT_DIR}"`
39
+ and print its output: it removes the copy in the non-preferred file and
40
+ keeps the preferred one current. A block Claude Code cannot see — in
41
+ `AGENTS.md`, with no `@AGENTS.md` line in `CLAUDE.md` — is the same repair:
42
+ the verb adds the import. For another harness the finding names its own
43
+ `--harness`; relay that command. Never Edit or Write the block yourself —
44
+ the verb is its only writer (install spec, contract 6).
45
+ - `statusline` issues → offer running `/projectstore:statusline on|off`,
46
+ which installs or removes the entry and the launcher behind a preview
47
+ (the SessionStart hook only refreshes an entry that already exists), and
48
+ remind that a restart applies it.
49
+ - `surface` (a stale installed file or a stale shared entry) → offer running
50
+ the verb for that surface and print its output:
51
+ `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" install --harness claude-code --surface <key> --project "${CLAUDE_PROJECT_DIR}"`
52
+ (`statusline` for the launcher, `agents_block` for the block). When more
53
+ than one surface is stale — the shape of a plugin update — offer the one
54
+ command that covers them all:
55
+ `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" upgrade --harness claude-code --project "${CLAUDE_PROJECT_DIR}"`.
56
+ Repairs invoke core verbs only — never Edit, Write or delete the file yourself.
57
+ - `upgrade` (an info the SessionStart line carries, not a row of this
58
+ report: a launcher written before file stamps existed) → in this report
59
+ the same file is the `surface` issue above; the `upgrade` command re-stamps
60
+ it in one run. While `layout-legacy` is pending the startup line does not
61
+ carry it: the move re-stamps the launcher at its new path.
62
+ - `surface-foreign` → **never repairable.** A file under our prefix with no
63
+ provenance line is not ours: no `--fix` flow may edit, delete, move or
64
+ overwrite it. Print the finding verbatim and relay its resolution — rename
65
+ it if it is yours, or delete it yourself to let `install` take the name.
66
+ The verbs refuse it in code; this clause is the belt.
67
+ - `version-drift` → report only: name both versions and where each was
68
+ read; the fix is the host's update path (`/plugin update` for a git-marketplace
69
+ copy; for the npm registration, the `projectstore-claude` shell's `upgrade`
70
+ from a terminal — the `plugin-registration` finding spells the command),
71
+ not ours.
72
+ - `layout-legacy` (warn; the startup line carries it as an offer) → the project
73
+ still holds the pre-0.28 layout (`.claude/projectstore.json`,
74
+ `.claude/.projectstore/` — legacy, read through 0.29). The migration is one
75
+ previewed `layout` item of `upgrade`, run **from a terminal outside this
76
+ session** (it moves files this session reads and writes; the verb defers
77
+ inside one). The finding names the form for the channel this plugin was
78
+ installed through: the installed copy's own `bin/projectstore.mjs` for a
79
+ git-marketplace install or a checkout, the `projectstore-claude` shell for
80
+ the npm registration. Relay the finding's command verbatim and never
81
+ substitute the other form — the shell, run for a git-marketplace install,
82
+ would also move this checkout to the npm channel. When the finding carries
83
+ advice instead of a command — the installed copy predates the move, or
84
+ predates `--no-register` — relay the advice and never compose a command
85
+ yourself. Never move the files yourself. While this finding is in the report, its command is also the one
86
+ repair for a stale-launcher `surface`, a v3 `agents-block` and
87
+ `agents-in-binding`: do not run the in-session `install` or `upgrade` for
88
+ those — the deferred move makes that run stop part-way.
89
+ - `layout-two-configs` (issue) → both `.claude/projectstore.json` (legacy) and
90
+ `.projectstore/projectstore.json` exist: `install` and `upgrade` refuse until
91
+ one is deleted. Show both, ask the user which is the binding they mean, and
92
+ let them delete the other; `uninstall` and this report are not blocked.
93
+ - `gitignore-tracked` (warn) → **report only.** git already tracks a file
94
+ that is machine-local — a binding with an absolute vault path, or
95
+ `state/`. An ignore line cannot untrack what is in the index. Show the
96
+ finding's `git rm --cached` line and let the user run it: untracking is a
97
+ commit they own, and `--fix` never runs git on their behalf.
98
+ - `agents-in-binding` (warn) → the binding still carries a pre-0.28 `agents`
99
+ block that nothing reads; the `layout` item of `upgrade` moves it into the
100
+ harness overlay. Same rule as `layout-legacy`: relay the finding's command
101
+ verbatim, run from a terminal outside this session.
102
+ - `overlay-forbidden-key` / `overlay-unparseable` (issue) →
103
+ `.projectstore/harness/<id>.json` carries a key an overlay may not (only
104
+ `agents.default.model` and `agents.per_agent.<name>.model` are read) or is
105
+ not JSON. Print the finding. A key inside the agents block goes away on the
106
+ next `/projectstore:agents configure` write; a key outside it, and a parse
107
+ error, are the user's to edit — never rewrite the file yourself.
108
+ - `overlay-unknown-agent` (warn) → the overlay configures a name no roster
109
+ agent carries (a typo, or a newer package's agent): nothing runs under it.
110
+ Point at `/projectstore:agents configure` with the roster's names.
111
+ - `plugin-registration` (info) → nothing to repair; it names where the npm
112
+ registration loads from. As an **issue** — stale, or two enabled copies —
113
+ print the finding and relay its command verbatim (the package runner's
114
+ `upgrade` or `install` with `--surface plugin`): it is run **from a
115
+ terminal outside this session**. Never run `claude plugin …` from a Bash
116
+ tool here: the host CLI and this live session both rewrite the same
117
+ settings files, and the registration verb refuses inside a session for
118
+ that reason.
119
+ - `plugin-registration-foreign` → **never repairable**, like `surface-foreign`:
120
+ a marketplace directory under our name without our provenance field, or a
121
+ host registry naming our marketplace elsewhere. Print the finding verbatim;
122
+ the user moves or removes it.
123
+ - `harness` (info) → nothing to repair; it names what `install` can target.
124
+ - `mcp` → the plugin-bundled `.mcp.json` is missing or does not launch
125
+ `bin/projectstore.mjs mcp`: the install is incomplete — the fix is the
126
+ host's update path (`/plugin update`), never a hand-written file.
127
+ - `override-copies` → a copy carrying the provenance marker overrides nothing
128
+ (ADR-008): offer to **delete** it (approval-gated, one prompt per file), and
129
+ say that `/projectstore:agents configure` now records the model in
130
+ `.projectstore/harness/<harness>.json` (the active harness's overlay) instead. Never offer to delete — or edit — a
131
+ copy reported at `info`: no provenance marker means we cannot prove it is
132
+ ours, and it may be the user's own agent.
133
+ - `auto-update` off → offer adding `extraKnownMarketplaces.<marketplace>.autoUpdate: true`
134
+ to `~/.claude/settings.json` (Edit with diff preview + approval — this is the
135
+ user's global settings file), or point at `/plugin` → Marketplaces → toggle.
136
+ For "newer version available" → tell the user to run
137
+ `/plugin marketplace update <marketplace>` and `/reload-plugins` themselves.
138
+
139
+ **Boundary (ADR-005)**: `--fix` never repairs vault-side findings. For those,
140
+ point at `/projectstore:kanban` (board regen) and `/projectstore:reconcile`
141
+ (indexes + code-map + graph). Never offer a hand-written Edit of an index
142
+ row: derived views are only ever written by the core's regeneration.
143
+
144
+ `work-without-story` is not repairable by any command and must not be
145
+ presented as if it were: it reports that the project tree has uncommitted
146
+ source work while no story is `in-progress`. The response is a judgement —
147
+ open a story (`/projectstore:story <EPIC> "<title>"`), or decide the work is
148
+ a one-off and leave it. Relay the finding's own note about whether an entry
149
+ reminder fired: "fired and the work still went untracked" and "never fired"
150
+ are different problems, and the count is for this machine only.
151
+
152
+ 4. **Suggest next**: if issues remain, list the one-line repair per finding; if
153
+ only warnings remain, say they are advisory.
154
+
155
+ ## Notes
156
+
157
+ - Detection is read-only by contract — the engine never writes; only `--fix`
158
+ flows (each behind AskUserQuestion) touch files.
159
+ - The SessionStart hook runs a cheap install-only subset of this engine and
160
+ prints one line when it finds issues; the full vault lint runs only here.
161
+ - Spec gates (`spec-coverage`, `spec-status`, `spec-acceptance`) and lifecycle
162
+ gates (`evidence`, `plan-gate`, `final-summary`) key off the VAULT-side
163
+ policy file `<vault>/.projectstore.json` (`spec_policy` / `lifecycle_gates`,
164
+ ADR-007), never the machine-local config. `spec-links` integrity runs
165
+ whenever specs exist. Legacy stories (done before `spec_policy_since`, or
166
+ done with no `closed_at`) are exempt by design.
@@ -0,0 +1,40 @@
1
+ ---
2
+ description: Create a new epic (with stories subfolder) in the bound vault.
3
+ argument-hint: <epic-id> <title>
4
+ ---
5
+
6
+ You are creating a new epic.
7
+
8
+ Steps:
9
+
10
+ 1. **Check config**: if `.projectstore/projectstore.json` is missing — instruct user to `/projectstore:bind` and stop.
11
+
12
+ 2. **Validate args**: `$ARGUMENTS` must contain at least an ID and a title. ID is a short uppercase token (e.g. `AUTH-001`, `RECPLAT-269`). If only one word was given, ask user for the title via AskUserQuestion.
13
+
14
+ 3. **Render draft**:
15
+
16
+ ```bash
17
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/draft.mjs" epic "$ARGUMENTS"
18
+ ```
19
+
20
+ Capture the JSON output.
21
+
22
+ 4. **Check collision**: if `<vault>/epics/<id>/epic.md` already exists, ask user via AskUserQuestion: "Epic `<id>` exists. [Open existing / Overwrite / Cancel]".
23
+
24
+ 5. **Preview**: show path + content excerpt. When `index` is non-null, print `index.line` too — the exact row that will appear in `epics/README.md`, unless the index step reports a failure and no row lands at all.
25
+
26
+ 6. **Approval** via AskUserQuestion: Yes / Edit / No. This is the only gate: **Yes** covers the epic and its index row. Disclose in the question that the folder's whole managed index table is regenerated from vault state at write time, so the update may also repair a stale row for another epic.
27
+
28
+ 7. **Pre-write race check** (Layer 1): run `test -e "<path>"`. The earlier collision check (step 4) covers most cases, but another session could have created this epic during the approval delay. If exists now → ask the user via AskUserQuestion whether to **Overwrite** or **Cancel**. Do not silently overwrite.
29
+
30
+ 8. **On Yes** (path free or overwrite confirmed): Write the file (parent directories are created by the Write tool), then create the stories directory: `mkdir -p "<vault>/epics/<id>/stories"`. The draft script itself never touches the disk — declining at step 6 leaves the vault unchanged.
31
+
32
+ 9. **Index update**: if `index` is non-null in the draft JSON, apply the row through the core — never the Write/Edit tools, no second gate (the step-6 approval covers it). Must run **after** step 8: the regeneration scans the disk, so an epic written later would be missing from the table.
33
+
34
+ ```bash
35
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" reconcile --write --only indexes=<index.folder>
36
+ ```
37
+
38
+ The row is derived state — regenerated in canonical order, written atomically, manual prose preserved. The epic is already on disk, so a nonzero exit is a warning naming the folder (stderr with no JSON = rejected before any write, fix the header or restore the README; per-target `error` in JSON = I/O failure, suggest `/projectstore:reconcile`), never a failed creation.
39
+
40
+ 10. **Suggest next**: print "Add the first story: `/projectstore:story <epic-id> \"<first story title>\"`".