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.
- package/.codex-plugin/plugin.json +48 -0
- package/README.md +15 -7
- package/bin/projectstore-codex.mjs +88 -0
- package/hooks/hooks.json +59 -0
- package/node_modules/projectstore/.claude-plugin/marketplace.json +40 -0
- package/node_modules/projectstore/.claude-plugin/plugin.json +23 -0
- package/node_modules/projectstore/.mcp.json +14 -0
- package/node_modules/projectstore/AGENTS.md +26 -0
- package/node_modules/projectstore/LICENSE +21 -0
- package/node_modules/projectstore/README.md +284 -0
- package/node_modules/projectstore/agents/archaeologist.md +76 -0
- package/node_modules/projectstore/agents/clerk.md +93 -0
- package/node_modules/projectstore/agents/critic.md +94 -0
- package/node_modules/projectstore/agents/librarian.md +81 -0
- package/node_modules/projectstore/agents/planner.md +80 -0
- package/node_modules/projectstore/agents/reviewer.md +98 -0
- package/node_modules/projectstore/bin/projectstore.mjs +7 -0
- package/node_modules/projectstore/commands/adr.md +57 -0
- package/node_modules/projectstore/commands/agents.md +180 -0
- package/node_modules/projectstore/commands/bind.md +128 -0
- package/node_modules/projectstore/commands/codemap.md +50 -0
- package/node_modules/projectstore/commands/concept.md +17 -0
- package/node_modules/projectstore/commands/doctor.md +166 -0
- package/node_modules/projectstore/commands/epic.md +40 -0
- package/node_modules/projectstore/commands/graph.md +56 -0
- package/node_modules/projectstore/commands/kanban.md +40 -0
- package/node_modules/projectstore/commands/meeting.md +17 -0
- package/node_modules/projectstore/commands/reconcile.md +73 -0
- package/node_modules/projectstore/commands/research.md +17 -0
- package/node_modules/projectstore/commands/review.md +89 -0
- package/node_modules/projectstore/commands/runbook.md +17 -0
- package/node_modules/projectstore/commands/scaffold.md +23 -0
- package/node_modules/projectstore/commands/search.md +22 -0
- package/node_modules/projectstore/commands/spec.md +91 -0
- package/node_modules/projectstore/commands/status.md +27 -0
- package/node_modules/projectstore/commands/statusline.md +46 -0
- package/node_modules/projectstore/commands/story.md +113 -0
- package/node_modules/projectstore/docs/extending.md +172 -0
- package/node_modules/projectstore/docs/getting-started.md +133 -0
- package/node_modules/projectstore/docs/harnesses.md +176 -0
- package/node_modules/projectstore/docs/how-it-works.md +263 -0
- package/node_modules/projectstore/docs/images/loop-light.svg +94 -0
- package/node_modules/projectstore/docs/images/loop.svg +93 -0
- package/node_modules/projectstore/docs/images/statusline-hud.png +0 -0
- package/node_modules/projectstore/docs/images/team-light.svg +79 -0
- package/node_modules/projectstore/docs/images/team.svg +79 -0
- package/node_modules/projectstore/harnesses/claude-code.json +483 -0
- package/node_modules/projectstore/harnesses/codex.json +332 -0
- package/node_modules/projectstore/hooks/hooks.json +59 -0
- package/node_modules/projectstore/hooks/pre-compact.mjs +121 -0
- package/node_modules/projectstore/hooks/session-rules.mjs +63 -0
- package/node_modules/projectstore/hooks/session-start.mjs +301 -0
- package/node_modules/projectstore/hooks/session-stop.mjs +84 -0
- package/node_modules/projectstore/package.json +70 -0
- package/node_modules/projectstore/scaffold/checklists.json +88 -0
- package/node_modules/projectstore/scaffold/headings.json +171 -0
- package/node_modules/projectstore/scaffold/layouts/engineering.json +85 -0
- package/node_modules/projectstore/scripts/binding.mjs +165 -0
- package/node_modules/projectstore/scripts/build-adapters.mjs +264 -0
- package/node_modules/projectstore/scripts/cli.mjs +595 -0
- package/node_modules/projectstore/scripts/codemap.mjs +99 -0
- package/node_modules/projectstore/scripts/diff-refs.mjs +127 -0
- package/node_modules/projectstore/scripts/doctor.mjs +2127 -0
- package/node_modules/projectstore/scripts/draft.mjs +261 -0
- package/node_modules/projectstore/scripts/graph.mjs +219 -0
- package/node_modules/projectstore/scripts/harness.mjs +608 -0
- package/node_modules/projectstore/scripts/install-harness.mjs +1387 -0
- package/node_modules/projectstore/scripts/kanban.mjs +174 -0
- package/node_modules/projectstore/scripts/lib.mjs +3085 -0
- package/node_modules/projectstore/scripts/mcp.mjs +391 -0
- package/node_modules/projectstore/scripts/portable-registration.mjs +198 -0
- package/node_modules/projectstore/scripts/provenance.mjs +375 -0
- package/node_modules/projectstore/scripts/query.mjs +490 -0
- package/node_modules/projectstore/scripts/reconcile.mjs +422 -0
- package/node_modules/projectstore/scripts/statusline-launcher.mjs +141 -0
- package/node_modules/projectstore/scripts/statusline.mjs +253 -0
- package/node_modules/projectstore/scripts/story-section.mjs +209 -0
- package/node_modules/projectstore/scripts/surfaces.mjs +421 -0
- package/node_modules/projectstore/scripts/tokens.mjs +449 -0
- package/node_modules/projectstore/scripts/touch-session.mjs +336 -0
- package/node_modules/projectstore/scripts/version-guard.mjs +261 -0
- package/node_modules/projectstore/scripts/worktree.mjs +109 -0
- package/node_modules/projectstore/skills/projectstore-decision-detector/SKILL.md +40 -0
- package/node_modules/projectstore/skills/projectstore-peer-reviewer/SKILL.md +38 -0
- package/node_modules/projectstore/skills/projectstore-story-completion/SKILL.md +50 -0
- package/node_modules/projectstore/skills/projectstore-vault-communication/SKILL.md +96 -0
- package/node_modules/projectstore/templates/claude-md-block.md.tmpl +26 -0
- package/node_modules/projectstore/templates/de/adr.md.tmpl +67 -0
- package/node_modules/projectstore/templates/de/concept.md.tmpl +43 -0
- package/node_modules/projectstore/templates/de/epic.md.tmpl +59 -0
- package/node_modules/projectstore/templates/de/folder-readme.md.tmpl +14 -0
- package/node_modules/projectstore/templates/de/kanban.md.tmpl +36 -0
- package/node_modules/projectstore/templates/de/meeting.md.tmpl +38 -0
- package/node_modules/projectstore/templates/de/research.md.tmpl +47 -0
- package/node_modules/projectstore/templates/de/runbook.md.tmpl +53 -0
- package/node_modules/projectstore/templates/de/spec.md.tmpl +64 -0
- package/node_modules/projectstore/templates/de/story.md.tmpl +76 -0
- package/node_modules/projectstore/templates/de/strings.json +6 -0
- package/node_modules/projectstore/templates/en/adr.md.tmpl +67 -0
- package/node_modules/projectstore/templates/en/concept.md.tmpl +43 -0
- package/node_modules/projectstore/templates/en/epic.md.tmpl +59 -0
- package/node_modules/projectstore/templates/en/folder-readme.md.tmpl +14 -0
- package/node_modules/projectstore/templates/en/kanban.md.tmpl +36 -0
- package/node_modules/projectstore/templates/en/meeting.md.tmpl +38 -0
- package/node_modules/projectstore/templates/en/research.md.tmpl +47 -0
- package/node_modules/projectstore/templates/en/runbook.md.tmpl +53 -0
- package/node_modules/projectstore/templates/en/spec.md.tmpl +64 -0
- package/node_modules/projectstore/templates/en/story.md.tmpl +76 -0
- package/node_modules/projectstore/templates/en/strings.json +6 -0
- package/node_modules/projectstore/templates/es/adr.md.tmpl +67 -0
- package/node_modules/projectstore/templates/es/concept.md.tmpl +43 -0
- package/node_modules/projectstore/templates/es/epic.md.tmpl +59 -0
- package/node_modules/projectstore/templates/es/folder-readme.md.tmpl +14 -0
- package/node_modules/projectstore/templates/es/kanban.md.tmpl +36 -0
- package/node_modules/projectstore/templates/es/meeting.md.tmpl +38 -0
- package/node_modules/projectstore/templates/es/research.md.tmpl +47 -0
- package/node_modules/projectstore/templates/es/runbook.md.tmpl +53 -0
- package/node_modules/projectstore/templates/es/spec.md.tmpl +64 -0
- package/node_modules/projectstore/templates/es/story.md.tmpl +76 -0
- package/node_modules/projectstore/templates/es/strings.json +6 -0
- package/node_modules/projectstore/templates/fr/adr.md.tmpl +67 -0
- package/node_modules/projectstore/templates/fr/concept.md.tmpl +43 -0
- package/node_modules/projectstore/templates/fr/epic.md.tmpl +59 -0
- package/node_modules/projectstore/templates/fr/folder-readme.md.tmpl +14 -0
- package/node_modules/projectstore/templates/fr/kanban.md.tmpl +36 -0
- package/node_modules/projectstore/templates/fr/meeting.md.tmpl +38 -0
- package/node_modules/projectstore/templates/fr/research.md.tmpl +47 -0
- package/node_modules/projectstore/templates/fr/runbook.md.tmpl +53 -0
- package/node_modules/projectstore/templates/fr/spec.md.tmpl +64 -0
- package/node_modules/projectstore/templates/fr/story.md.tmpl +76 -0
- package/node_modules/projectstore/templates/fr/strings.json +6 -0
- package/node_modules/projectstore/templates/ru/adr.md.tmpl +67 -0
- package/node_modules/projectstore/templates/ru/concept.md.tmpl +43 -0
- package/node_modules/projectstore/templates/ru/epic.md.tmpl +59 -0
- package/node_modules/projectstore/templates/ru/folder-readme.md.tmpl +14 -0
- package/node_modules/projectstore/templates/ru/kanban.md.tmpl +36 -0
- package/node_modules/projectstore/templates/ru/meeting.md.tmpl +38 -0
- package/node_modules/projectstore/templates/ru/research.md.tmpl +47 -0
- package/node_modules/projectstore/templates/ru/runbook.md.tmpl +53 -0
- package/node_modules/projectstore/templates/ru/spec.md.tmpl +64 -0
- package/node_modules/projectstore/templates/ru/story.md.tmpl +76 -0
- package/node_modules/projectstore/templates/ru/strings.json +6 -0
- package/node_modules/projectstore/templates/zh/adr.md.tmpl +67 -0
- package/node_modules/projectstore/templates/zh/concept.md.tmpl +43 -0
- package/node_modules/projectstore/templates/zh/epic.md.tmpl +59 -0
- package/node_modules/projectstore/templates/zh/folder-readme.md.tmpl +14 -0
- package/node_modules/projectstore/templates/zh/kanban.md.tmpl +36 -0
- package/node_modules/projectstore/templates/zh/meeting.md.tmpl +38 -0
- package/node_modules/projectstore/templates/zh/research.md.tmpl +47 -0
- package/node_modules/projectstore/templates/zh/runbook.md.tmpl +53 -0
- package/node_modules/projectstore/templates/zh/spec.md.tmpl +64 -0
- package/node_modules/projectstore/templates/zh/story.md.tmpl +76 -0
- package/node_modules/projectstore/templates/zh/strings.json +6 -0
- package/package.json +35 -14
- package/skills/projectstore-adr/SKILL.md +76 -0
- package/skills/projectstore-agents/SKILL.md +50 -0
- package/skills/projectstore-archaeologist/SKILL.md +109 -0
- package/skills/projectstore-bind/SKILL.md +44 -0
- package/skills/projectstore-clerk/SKILL.md +126 -0
- package/skills/projectstore-codemap/SKILL.md +69 -0
- package/skills/projectstore-concept/SKILL.md +36 -0
- package/skills/projectstore-critic/SKILL.md +127 -0
- package/skills/projectstore-decision-detector/SKILL.md +59 -0
- package/skills/projectstore-doctor/SKILL.md +33 -0
- package/skills/projectstore-epic/SKILL.md +59 -0
- package/skills/projectstore-graph/SKILL.md +75 -0
- package/skills/projectstore-kanban/SKILL.md +60 -0
- package/skills/projectstore-librarian/SKILL.md +114 -0
- package/skills/projectstore-meeting/SKILL.md +36 -0
- package/skills/projectstore-peer-reviewer/SKILL.md +57 -0
- package/skills/projectstore-planner/SKILL.md +113 -0
- package/skills/projectstore-reconcile/SKILL.md +92 -0
- package/skills/projectstore-research/SKILL.md +36 -0
- package/skills/projectstore-review/SKILL.md +108 -0
- package/skills/projectstore-reviewer/SKILL.md +131 -0
- package/skills/projectstore-runbook/SKILL.md +36 -0
- package/skills/projectstore-scaffold/SKILL.md +42 -0
- package/skills/projectstore-search/SKILL.md +41 -0
- package/skills/projectstore-spec/SKILL.md +110 -0
- package/skills/projectstore-status/SKILL.md +47 -0
- package/skills/projectstore-statusline/SKILL.md +29 -0
- package/skills/projectstore-story/SKILL.md +132 -0
- package/skills/projectstore-story-completion/SKILL.md +69 -0
- 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>\"`".
|