projectstore-codex 0.0.1 → 0.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) 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 +163 -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 +255 -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 +36 -14
  155. package/plugin.json +53 -0
  156. package/skills/projectstore-adr/SKILL.md +76 -0
  157. package/skills/projectstore-agents/SKILL.md +50 -0
  158. package/skills/projectstore-archaeologist/SKILL.md +109 -0
  159. package/skills/projectstore-bind/SKILL.md +44 -0
  160. package/skills/projectstore-clerk/SKILL.md +126 -0
  161. package/skills/projectstore-codemap/SKILL.md +69 -0
  162. package/skills/projectstore-concept/SKILL.md +36 -0
  163. package/skills/projectstore-critic/SKILL.md +127 -0
  164. package/skills/projectstore-decision-detector/SKILL.md +59 -0
  165. package/skills/projectstore-doctor/SKILL.md +33 -0
  166. package/skills/projectstore-epic/SKILL.md +59 -0
  167. package/skills/projectstore-graph/SKILL.md +75 -0
  168. package/skills/projectstore-kanban/SKILL.md +60 -0
  169. package/skills/projectstore-librarian/SKILL.md +114 -0
  170. package/skills/projectstore-meeting/SKILL.md +36 -0
  171. package/skills/projectstore-peer-reviewer/SKILL.md +57 -0
  172. package/skills/projectstore-planner/SKILL.md +113 -0
  173. package/skills/projectstore-reconcile/SKILL.md +92 -0
  174. package/skills/projectstore-research/SKILL.md +36 -0
  175. package/skills/projectstore-review/SKILL.md +108 -0
  176. package/skills/projectstore-reviewer/SKILL.md +131 -0
  177. package/skills/projectstore-runbook/SKILL.md +36 -0
  178. package/skills/projectstore-scaffold/SKILL.md +42 -0
  179. package/skills/projectstore-search/SKILL.md +41 -0
  180. package/skills/projectstore-spec/SKILL.md +110 -0
  181. package/skills/projectstore-status/SKILL.md +47 -0
  182. package/skills/projectstore-statusline/SKILL.md +29 -0
  183. package/skills/projectstore-story/SKILL.md +132 -0
  184. package/skills/projectstore-story-completion/SKILL.md +69 -0
  185. package/skills/projectstore-vault-communication/SKILL.md +115 -0
@@ -0,0 +1,113 @@
1
+ ---
2
+ description: Create a new story inside an existing epic, or run its lifecycle gates (plan / close).
3
+ argument-hint: <epic-id> <title> [--spec SPEC-ID] | plan <story> | close <story>
4
+ ---
5
+
6
+ You are managing a story: creating one, or running its lifecycle gates.
7
+
8
+ **Dispatch rule** (positional-1 contract, PS-SPEC story-007): if the first
9
+ argument is `plan` or `close` AND the second argument resolves to an existing
10
+ story file (path, or `<epic-id>/<story-id>` searched under
11
+ `<vault>/epics/*/stories/`), run the **Lifecycle gate flow** below. Otherwise
12
+ this is a **create** (first argument = epic id — uppercase by convention, so
13
+ the two cannot collide).
14
+
15
+ # Create flow
16
+
17
+ 1. **Check config**: stop if `.projectstore/projectstore.json` missing.
18
+
19
+ 2. **Validate args**: epic-id (positional 1) + title (rest). If only one word, ask for the title. An optional `--spec SPEC-ID` names the covering spec — put it into the rendered draft's `specs:` list (inline flow: `specs: ["SPEC-001"]`). Under `spec_policy: required` (vault's `.projectstore.json`), remind that every story needs a covering spec before implementation starts.
20
+
21
+ 3. **Render draft**:
22
+
23
+ ```bash
24
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/draft.mjs" story "$ARGUMENTS"
25
+ ```
26
+
27
+ The script fails if the epic folder does not exist. Surface the error and suggest `/projectstore:epic <id> "<title>"` first.
28
+
29
+ 4. **Preview**: path + first ~25 lines.
30
+
31
+ 5. **Approval** via AskUserQuestion: Yes / Edit / No.
32
+
33
+ When prompting "Edit", note that the story template has a `Decomposition` checklist — if the user wants to seed it with concrete tasks from the current conversation, regenerate with those tasks pre-filled in place of the empty checkboxes.
34
+
35
+ 6. **Post-approval race re-check** (Layer 1): re-run `draft.mjs story "$ARGUMENTS"` and re-read its `collision` field — an exact-name `test -e` cannot see normalized cross-era collisions (`story-006-foo.md` vs `story-foo.md`). If `collision` is non-null, surface it as a topic collision (`"<identity>" already exists as <with>`), and ask: extend the existing story, pick a different slug (`-2` is a deliberate distinct identity), or cancel. Render `warnings` entries as `⚠️` lines in the preview too.
36
+
37
+ 7. **On Yes** (path free): Write file.
38
+
39
+ 8. **Suggest next**: "Now decompose the work in the `Decomposition` section, or run `/projectstore:kanban` to refresh the board. Before implementation: `/projectstore:story plan <story>`."
40
+
41
+ # Lifecycle gate flow (plan / close)
42
+
43
+ 1. **Resolve the story file** (second argument). Ambiguous → list candidates and ask.
44
+
45
+ 2. **Run the compute script** (pure — writes nothing):
46
+
47
+ ```bash
48
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/story-section.mjs" <plan|close> "<story-path>"
49
+ ```
50
+
51
+ It returns `{ path, changed, notes, content }`: section inserted when
52
+ absent, status transition, lifecycle timestamps (`started_at` /
53
+ `plan_updated_at` / `closed_at` — stamped unconditionally; the
54
+ `lifecycle_gates` key gates checks, never data).
55
+
56
+ 3. **Fill the section content** in the returned `content` before preview:
57
+ - `plan` — write the Implementation Plan. When the story's `specs:` names a
58
+ covering spec, the plan is a THIN ROUTE through that spec's behavioral
59
+ contracts: which contracts, in what order, which files. Consult the
60
+ planner agent's output if one ran. Do not restate the spec.
61
+ - `close` — write the Final Summary (what changed / why / tests executed /
62
+ risks & follow-ups), and update the Acceptance Criteria checkboxes with
63
+ evidence suffixes: `- [x] <criterion> — evidence: <test | command | file:line>`.
64
+ Check a box ONLY with real evidence (reviewer output, test run, command).
65
+
66
+ 4. **Preview** path + notes + the changed sections. **Approval** via
67
+ AskUserQuestion: Yes / Edit / No.
68
+
69
+ 5. **Immediately before writing**, re-run the script and verify its `content`
70
+ (before your section edits) still matches what you previewed against — a
71
+ human may have edited the file in Obsidian meanwhile. On divergence:
72
+ re-preview, re-ask.
73
+
74
+ 5a. **Delegate the ceremony — enumerated case: story close** (ADR "Artifact
75
+ content is authored by the context-holder, the write ceremony by a clerk").
76
+ After the approval in step 4 and the re-check in step 5, on a `close`:
77
+ - Write TWO files to the session scratchpad: the **scratch** (the full final
78
+ content you previewed — sections filled) and the **baseline** (the script's
79
+ raw `content` from step 2, BEFORE your section edits). They are different
80
+ files with different jobs: the scratch is what gets copied to the target;
81
+ the baseline is what `--check` compares against. Handing `--check` the
82
+ scratch makes it report drift on every run.
83
+ - **Model (ADR-008)**: resolve it with `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" agents model clerk --json --project "${CLAUDE_PROJECT_DIR}"` and pass `result.model` as the spawn's model parameter (`null` → pass nothing).
84
+ Missing key, `inherit`, or unreadable config → pass nothing and let the
85
+ agent's own frontmatter decide; never guess a model.
86
+ - Capture doctor's summary line (`node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" doctor
87
+ --vault`, last line) — the clerk needs it as the **pre-state**: it must not
88
+ stop on findings that were already there and are not its own.
89
+ - Spawn `projectstore:clerk` **as a foreground task** (you need its report to
90
+ continue) with: the scratch path, the target path, the exact re-check
91
+ invocation (`story-section.mjs close "<story-path>" --check
92
+ <baseline-path>`), the derived targets (`kanban`, plus `indexes=<epic
93
+ folder>` when status changed), and the doctor pre-state line. On a clean
94
+ report (`verbatim: true`, `stopped_at: null`, doctor no worse than the
95
+ pre-state) skip steps 6-6b — the clerk's report is the write evidence. On a
96
+ stopped report: fix what diverged, then re-delegate (the resume rule: after
97
+ the copy, the ceremony restarts at reconcile, not at the race gate) or
98
+ finish the remaining steps yourself (the copy is idempotent).
99
+ - No clerk available → perform steps 6-6b yourself. There is no fallback
100
+ agent: a general-purpose writer is an unpinned procedure.
101
+
102
+ 6. **On Yes** (undelegated path): Write the full file. On a `plan`, finish by
103
+ suggesting `/projectstore:kanban` (the status changed) — 6a/6b below are the
104
+ close's ceremony, not the plan's.
105
+
106
+ 6a. **(close only) Reconcile** the touched derived targets through the core:
107
+ `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" reconcile --write --only kanban` (add
108
+ `indexes=<epic folder>` when the status changed).
109
+
110
+ 6b. **(close only) Verify**: `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" doctor --vault` (exit 1 = findings, not failure)
111
+ — a close is not done while doctor got worse. Then suggest the reviewer's
112
+ proposed `code_refs` via `/projectstore:codemap set` (the reviewer computes it
113
+ from `scripts/diff-refs.mjs --since <started_at>`).
@@ -0,0 +1,172 @@
1
+ # Extending projectstore
2
+
3
+ ## Adding a new artifact kind — the honest checklist
4
+
5
+ Since v0.14 the kind machinery is layout-driven: `draft.mjs` builds ANY kind
6
+ declared in the layout, and doctor's template check follows the layout instead
7
+ of a hardcoded list. A new kind needs **five touch points** — note that **all
8
+ five live inside the plugin installation**, not in your vault (there is no
9
+ vault-side layout or template override):
10
+
11
+ 1. **Layout folder entry** — `scaffold/layouts/<name>.json` → `folders`:
12
+
13
+ ```jsonc
14
+ { "path": "specs", "kind": "spec", "readme": true, "numbered": true, "prefix": "SPEC-", "pad": 3 }
15
+ ```
16
+
17
+ Since v0.18 every kind creates **slug-only filenames** (`<slug>.md`;
18
+ stories keep the `story-` marker: `story-<slug>.md`) — identity lives in
19
+ the slug, sequence numbers are no longer allocated (ADR-010), which makes
20
+ concurrent creation collision-free by construction. `numbered` + `prefix`
21
+ + `pad` stay declared for **grandfathered** vaults: the prefix drives
22
+ legacy-number stripping in identity matching and the index label badge
23
+ (`SPEC-002` rows keep their labels; slug rows are labelled by slug).
24
+ `date_prefix: true` gives `YYYY-MM-DD-slug.md`. The epic folder
25
+ additionally accepts `story_prefix` (default `story-`) for its stories'
26
+ kind marker; `story_pad` remains recognized but only describes legacy
27
+ files.
28
+
29
+ 2. **Layout command entry** — the same file's `commands` array. A command
30
+ needs a template only if it maps to a declared folder kind (`story` maps
31
+ through the `epic` folder; `kanban` through the `kanban` block). Folders
32
+ without a command (e.g. `diagrams`) need no template.
33
+
34
+ 3. **Template** — `templates/en/<kind>.md.tmpl` (and `templates/ru/…`).
35
+ Variables filled by `scripts/draft.mjs`: `{{date}}`, `{{author}}`,
36
+ `{{tags}}`, `{{title}}`, `{{slug}}`, `{{id}}` (the exact machine id: the
37
+ slug itself; `story-<slug>` for stories), `{{epic_id}}` (stories). Use
38
+ `{{x_json}}` for any frontmatter scalar — it renders as a valid YAML
39
+ double-quoted string. Frontmatter should carry `id:` and an inline-flow
40
+ `external_refs: {}` (the designed home for Jira/YouTrack-style keys —
41
+ ADR-010); `number:` is optional display metadata, never identity. The
42
+ template's own frontmatter `status:` is what the index row shows at
43
+ creation (derived, never hardcoded), and its `date:` (or `created:`) is
44
+ the index row's date. Carry one of them: with neither, the date cell
45
+ renders empty — consistently, in both the preview and the written row —
46
+ but an empty date sorts first, so the kind's rows pile up at the top of
47
+ its index and stay there.
48
+
49
+ 4. **Checklist entry** — `scaffold/checklists.json`, consumed by
50
+ `/projectstore:review` and the `projectstore-peer-reviewer` skill. English-only by design.
51
+
52
+ 5. **Command prompt** — `commands/<kind>.md`, a prompt (not code) that calls
53
+ `node "${CLAUDE_PLUGIN_ROOT}/scripts/draft.mjs" <kind> "$ARGUMENTS"`, previews,
54
+ and gates every write behind AskUserQuestion. Copy `commands/research.md`
55
+ for a plain kind, `commands/adr.md` for one that renders the draft's
56
+ `collision`/`warnings` fields and updates an index, `commands/spec.md`
57
+ for one with status transitions.
58
+
59
+ If the kind introduces **new section headings or inline keywords** that
60
+ deterministic checks must recognize (doctor, reconcile, story-section),
61
+ register a form per bundled language (en, ru, es, de, fr, zh) in
62
+ `scaffold/headings.json` — matchers accept every registered language, so a
63
+ ru-headed file lints in an en-bound vault.
64
+
65
+ ## Adding a new layout
66
+
67
+ A layout is a JSON file at `scaffold/layouts/<name>.json` declaring folders,
68
+ kinds, commands, agents and (optionally) a kanban block — see
69
+ `engineering.json` for the full shape. Every command that maps to a folder
70
+ kind needs its template per the checklist above.
71
+
72
+ ## Adding a new command
73
+
74
+ Create `commands/<name>.md` with frontmatter:
75
+
76
+ ```yaml
77
+ ---
78
+ description: One-line summary shown in `/help`.
79
+ argument-hint: <expected args>
80
+ ---
81
+ ```
82
+
83
+ Body is a **prompt** for Claude — instructions, not code. To do real work, call
84
+ the plugin's scripts via Bash. Always gate writes through `AskUserQuestion`
85
+ after showing a preview. Scripts are pure compute (they never write); the
86
+ command writes after approval — keep that split.
87
+
88
+ ## Adding a new skill
89
+
90
+ Skills passively watch the conversation and suggest commands. Create
91
+ `skills/<name>/SKILL.md`:
92
+
93
+ ```yaml
94
+ ---
95
+ description: When [trigger condition], suggest [the relevant /projectstore:* command]. Never write to disk directly.
96
+ ---
97
+ ```
98
+
99
+ The `description` field is what Claude uses to decide activation. Be specific
100
+ about triggers, and include an Anti-patterns section.
101
+
102
+ ## Adding a new language
103
+
104
+ Bundled: `en`, `ru`, `es`, `de`, `fr`, `zh`. To add another:
105
+
106
+ Mirror `templates/en/` to `templates/<lang>/` and translate the bodies.
107
+ Frontmatter keys **and their values** stay English (`status: planned` is
108
+ machine-read; only prose and table labels get translated). Then register the
109
+ language's heading/keyword/index-column forms in `scaffold/headings.json`, and
110
+ add the locale to `LOCALES` in `tests/locales.test.mjs` so the suite actually
111
+ runs over it. `templates/<lang>/strings.json` localizes the statusline only.
112
+
113
+ Skipping the registry does not produce one clean error — it degrades *unevenly*,
114
+ which is why the spec exists: an unregistered index header raises a doctor
115
+ `index-header` warn while reconcile drops the same index silently; an
116
+ unregistered `acceptance` heading is silent everywhere; an unregistered
117
+ `implementation_plan` is misdiagnosed as "this done story has no Implementation
118
+ Plan"; and `heading(id, lang)` falls back to English, so the lifecycle gates
119
+ write English headings into an otherwise translated story.
120
+
121
+ Constraints the deterministic scripts impose on the translation:
122
+
123
+ - **Every heading must match *some* registered form.** `insertSection` guards on
124
+ `headingLineRe`, which accepts every registered form of every language — so a
125
+ heading in another locale's form is filled, not duplicated. Only a spelling
126
+ registered nowhere makes the gate append a second section beside it.
127
+ - **Use the FIRST form of your language** — that is what `story-section` writes
128
+ when it has to insert, so agreeing with it keeps written and rendered
129
+ documents identical. This is a convention; the gate does not enforce it.
130
+ - **No form may match two ids.** Keep the `acceptance` ("Acceptance Criteria")
131
+ and `spec_acceptance` ("Acceptance") headings distinct in your language;
132
+ matching is whole-line, so a prefix relationship is fine but equality is not.
133
+ - **The folder-README index header must use the registered column names —
134
+ exactly those four, and no more** — and the separator row under it must stay
135
+ a plain `|---|---|---|---|`. Matching is end-anchored: adding a fifth column
136
+ of your own does not extend the managed table, it stops being one. That is
137
+ deliberate — an unanchored match let the regeneration rewrite your extra
138
+ column away. An unrecognized header is now loud in both directions: doctor
139
+ warns, and a creation into that folder fails its index step on stderr
140
+ (the artifact still lands — see the failure prose in the create commands).
141
+ - **Inline grammars carry a keyword and a colon**: the evidence suffix on a
142
+ checked criterion and the `stories:` attribution on a spec acceptance item.
143
+ Both accept the CJK-width colon (`evidenceSuffixRe` / `storiesAttributionRe`
144
+ in `lib.mjs`); if your language punctuates differently, widen them there
145
+ rather than working around it in the template.
146
+
147
+ Where two spellings are realistic (Russian `ё`/`е`, a French typographic vs
148
+ ASCII apostrophe), register both: the first is written, all are accepted. No
149
+ test can decide "realistic" — have someone who reads the language check it.
150
+
151
+ Domain terms follow the language's practitioners, not the dictionary. `epic`
152
+ and `story` are localized where the field localizes them (`ru` "Эпик", `es`
153
+ "Épica") and left in English where teams say the English word (`de`, `fr`,
154
+ `zh`). Nothing reads these table labels, so the only cost of getting it wrong
155
+ is that the document reads like a translation.
156
+
157
+ The bundled set is currently spelled out by hand in four places (the test's
158
+ `LOCALES`, the registry's `_description`, this page, `commands/bind.md`) with
159
+ nothing checking that they agree — see the PS-I18N epic's backlog.
160
+
161
+ ## Vault-side policy
162
+
163
+ `<vault>/.projectstore.json` (vault root — committed with the vault, survives
164
+ clones) carries `spec_policy: required|optional`, `lifecycle_gates: on|off`,
165
+ and `spec_policy_since` (ISO-8601). See ADR-007 in the project vault and
166
+ `commands/doctor.md` for which checks each key activates.
167
+
168
+ ## Contributing back
169
+
170
+ PRs welcome at https://github.com/SmartAndPoint/ProjectStore. Prefer one
171
+ focused PR per layout / template / skill. Include a sample output in your PR
172
+ description.
@@ -0,0 +1,133 @@
1
+ # Getting started with projectstore
2
+
3
+ ## Install (local dev)
4
+
5
+ Until projectstore is published to a public marketplace, install it from a local clone.
6
+
7
+ ```bash
8
+ git clone https://github.com/SmartAndPoint/ProjectStore.git ~/Projects/SmartAndPoint/ProjectStore
9
+ ```
10
+
11
+ In Claude Code, register the local plugin directory:
12
+
13
+ ```
14
+ claude --plugin-dir ~/Projects/SmartAndPoint/ProjectStore
15
+ ```
16
+
17
+ Inside a Claude Code session, reload the plugin without restart:
18
+
19
+ ```
20
+ /reload-plugins
21
+ ```
22
+
23
+ Verify the plugin appears:
24
+
25
+ ```
26
+ /plugin list
27
+ ```
28
+
29
+ You should see `projectstore` (displayName) with prefix `projectstore`.
30
+
31
+ ## Install (via marketplace)
32
+
33
+ ```
34
+ /plugin marketplace add SmartAndPoint/ProjectStore
35
+ /plugin install projectstore@SmartAndPoint
36
+ ```
37
+
38
+ ## First-time setup
39
+
40
+ 1. **Pick a vault directory** — any folder where you want your project artifacts to live. Obsidian opens it natively. Git tracks it cleanly.
41
+
42
+ ```bash
43
+ mkdir -p ~/Documents/projects/my-project-vault
44
+ ```
45
+
46
+ 2. **Bind your current project to that vault**:
47
+
48
+ ```
49
+ /projectstore:bind ~/Documents/projects/my-project-vault
50
+ ```
51
+
52
+ This creates `.projectstore/projectstore.json` in your project root (machine-local, gitignored) — and then walks you through a short interview: gitignore entries → scaffold offer → agent registration in `CLAUDE.md` (recommended: Yes) → model preset for the review agents (the default `opus` is fine) → status line offer (you'll see a preview of the exact line). Every step shows what it wants to write and waits for your approval.
53
+
54
+ **Working in a git worktree?** That config is gitignored, so a worktree of a bound checkout starts unbound and `/projectstore:*` will not run there. Session start says so and names the fix:
55
+
56
+ ```
57
+ /projectstore:bind --inherit
58
+ ```
59
+
60
+ It copies the binding of the checkout the worktree was forked from — same vault, shared and unchanged, no session state carried over — and skips the interview, since the parent already answered it.
61
+
62
+ 3. **Scaffold the layout** if the vault is empty (bind offers this automatically):
63
+
64
+ ```
65
+ /projectstore:scaffold engineering
66
+ ```
67
+
68
+ Creates `adr/`, `specs/`, `epics/`, `research/`, `concepts/`, `meetings/`, `ops/`, `diagrams/` and a top-level `README.md`.
69
+
70
+ ## Daily flow
71
+
72
+ ```
73
+ /projectstore:status # what's bound, what's in progress, view freshness
74
+ /projectstore:adr "Use Postgres for primary storage" # capture a decision
75
+ /projectstore:epic AUTH-001 "Authentication system" # plan a major piece of work
76
+ /projectstore:story AUTH-001 "OIDC discovery" # decompose into stories
77
+ /projectstore:kanban # regenerate the board
78
+ /projectstore:search "data detective" # search the vault
79
+ /projectstore:doctor # install + vault diagnostics (no LLM)
80
+ /projectstore:reconcile # re-derive board/indexes/code-map from frontmatter
81
+ /projectstore:codemap # epic ↔ code mapping view
82
+ /projectstore:graph # vault link graph: nodes + typed edges
83
+ /projectstore:agents status # routing block + model config state
84
+ ```
85
+
86
+ ## How approval works
87
+
88
+ Every command that writes or edits a file goes through `AskUserQuestion`:
89
+
90
+ 1. The command renders a draft (via a plugin script, no disk write).
91
+ 2. You see the target path + content preview.
92
+ 3. You pick `Yes` / `Edit before saving` / `No`.
93
+ 4. Only on `Yes` does the file land.
94
+ 5. That same `Yes` covers the folder's index README — the row is not appended,
95
+ the folder's managed index table is regenerated through the core, so it
96
+ arrives in canonical order and your prose around the table is preserved.
97
+ One consequence the prompt tells you about: the regeneration rewrites the
98
+ whole table, so a creation can also repair a stale row for another artifact.
99
+
100
+ Skills (`projectstore-decision-detector`, `projectstore-story-completion`) are passive — they suggest commands; they never write directly.
101
+
102
+ ## Disabling skills
103
+
104
+ Edit `.projectstore/projectstore.json`:
105
+
106
+ ```jsonc
107
+ {
108
+ "active_skills": false
109
+ }
110
+ ```
111
+
112
+ ## Multi-language templates
113
+
114
+ Default is English (`en`). Also bundled: Russian (`ru`), Spanish (`es`), German (`de`), French (`fr`), Simplified Chinese (`zh`):
115
+
116
+ ```
117
+ /projectstore:bind <path> --lang de
118
+ ```
119
+
120
+ Or edit `language: "de"` in `.projectstore/projectstore.json` (templates must exist at `templates/de/`). The language also localizes the status line strings (e.g. the "no epic or story in this session yet" line).
121
+
122
+ What the language does and does not change: section headings, table labels and prose are translated; frontmatter keys and their values (`status: planned`, `priority: p2`) stay English, because they are machine-read. Section headings are registered in `scaffold/headings.json`, so doctor, reconcile and the story lifecycle gates recognize every bundled language — a Russian-headed file lints in a French-bound vault, and mixed-language vaults reconcile.
123
+
124
+ ## Updating to a new version
125
+
126
+ ```
127
+ /plugin marketplace update SmartAndPoint
128
+ /reload-plugins
129
+ ```
130
+
131
+ Or enable auto-update once (`/plugin` → **Marketplaces** → **SmartAndPoint** → toggle **auto-update**) and Claude Code will detect new releases at startup.
132
+
133
+ **After any update, run `/projectstore:doctor`.** It compares your project's wiring against what the new version expects and names each fix with the command to run — stale agents block in `CLAUDE.md` (`/projectstore:agents register`), leftover agent copies that override nothing (`/projectstore:agents configure`), auto-update still off (the exact setting and file), a newer release than the one running. `doctor --fix` applies the install-side repairs interactively; `/projectstore:reconcile` rebuilds the board/indexes/code-map if content drifted. Silence at session start means healthy — the cheap checks run automatically and only speak up when something is wrong.
@@ -0,0 +1,163 @@
1
+ # Harnesses
2
+
3
+ projectstore's engine is one package. What differs between coding agents —
4
+ where a hook is declared, whether a subagent can be shipped, which environment
5
+ variable names the project — lives in `harnesses/<id>.json`, one **capability
6
+ manifest** per harness, and nowhere else. No script branches on a harness name;
7
+ the portability suite greps for it.
8
+
9
+ This page says which harnesses exist, how far each one is trusted, and what
10
+ "experimental" means when you read it below.
11
+
12
+ ## Status
13
+
14
+ | Harness | id | Status | Verified | Surfaces installed |
15
+ |---|---|---|---|---|
16
+ | Claude Code | `claude-code` | **supported** | 2026-08-30 | hooks, commands, agents, skills, MCP, status line, agents block |
17
+ | Codex | `codex` | **experimental** | — | portable plugin, hooks, rendered workflow skills, agents block |
18
+
19
+ **supported** means the manifest carries a `verified` block: a session id and a
20
+ date on which this harness's surfaces were installed and exercised end to end,
21
+ and the measurements in the manifest came from that run.
22
+
23
+ **experimental** means `verified` is `null`. Every field that was not measured
24
+ is absent or `null` rather than guessed. It is enough to run on; it is not enough
25
+ to promise. An experimental harness is never the source layout. A generated
26
+ adapter may exist while it is experimental. Its distribution shell may
27
+ publish before the live run that sets `verified`, but only by the maintainer's
28
+ decision (Codex's does, from 0.28.1); the label stays experimental until that
29
+ run.
30
+
31
+ The label is not prose. It is derived from the manifest, and
32
+ `tests/portability.test.mjs` fails if this table and `verified` disagree.
33
+
34
+ ## Claude Code
35
+
36
+ The **source layout**: the repository's own `hooks/`, `commands/`, `agents/`,
37
+ `skills/` and `.mcp.json` are Claude Code's, written by hand and read directly.
38
+ Every other harness is generated from them. Exactly one manifest may say
39
+ `source_layout: true`, which is what keeps "the original" a single place.
40
+
41
+ Config lives in `<project>/.projectstore/`, harness-neutral, shared by every
42
+ harness in the project. The per-harness half — the agents block, which carries
43
+ model names and those are harness-specific — is
44
+ `<project>/.projectstore/harness/claude-code.json`.
45
+
46
+ ## Codex
47
+
48
+ Experimental, measured on `codex-cli 0.153.4`. The initial spike captured 759
49
+ hook firings. The 2026-09-30 gate then built the npm shell from a packed core,
50
+ passed Codex's plugin validator, installed and upgraded it through an isolated
51
+ `CODEX_HOME`, verified the materialised cache by version and digest, and loaded
52
+ the `projectstore-status` skill in a fresh Codex session. The validator (the
53
+ plugin-creator skill's `validate_plugin.py`) reads only
54
+ `.codex-plugin/plugin.json`. The canonical root `plugin.json` was validated
55
+ separately on 2026-10-04, against the schema it declares (Agent Plugins 1.0.0).
56
+
57
+ That run exercised one skill, not every installed surface, so `verified` stays
58
+ `null`. The hooks are the reason it matters. On 2026-10-03 the first real
59
+ install's cached hooks could not load the vault in any session. They were run
60
+ by hand through `zsh -lc`; the failure did not depend on the shell form. In the
61
+ first session the failure sat in the model's context under the welcome, which
62
+ was all the user saw. The core had taken the shell's root for its own. That is
63
+ fixed, and the suite now runs every rendered hook from the built shell. A live
64
+ Codex session firing them from an installed release is still owed.
65
+
66
+ How 0.153.4 starts a hook was read from its source, not measured: under the
67
+ session's shell as `<shell> -c`, with the environment the Codex process had when
68
+ it built the session's hooks. `$SHELL -lc` (or `/bin/sh -lc`) is the fallback
69
+ when the hooks are built without exactly one ready local environment. So a hook
70
+ finds `node` on the Codex process's own `PATH`, plus whatever `.zshenv` adds:
71
+ zsh reads `.zshenv` for a `-c` command, not `.zprofile` or `.zshrc`, so a Codex
72
+ not started from a terminal can miss a `node` that only `.zprofile` puts on
73
+ `PATH`.
74
+
75
+ The shell is published as `projectstore-codex` from 0.28.1, ahead of that live
76
+ run, by the maintainer's decision:
77
+
78
+ ```sh
79
+ npx projectstore-codex install --project "$PWD"
80
+ ```
81
+
82
+ For later releases, `npx projectstore-codex@<version> upgrade --project "$PWD"`.
83
+ Installation is user-global because Codex stores marketplace registrations and
84
+ plugin caches in `CODEX_HOME`; the agents block in `AGENTS.md` remains
85
+ project-local. Ordinary uninstall leaves the global plugin in place; add
86
+ `--global` only when you mean to remove it for every project. From this
87
+ checkout, the same flow runs against a built tarball:
88
+
89
+ ```sh
90
+ npm run shells:build -- --only projectstore-codex --dev --out dist
91
+ npx --package "./dist/projectstore-codex-$(node -p 'require("./package.json").version').tgz" projectstore-codex install --project "$PWD"
92
+ ```
93
+
94
+ What is known, and how:
95
+
96
+ - **Hooks are rendered; their live firing from an installed release is not
97
+ yet observed.** The canonical portable `plugin.json` selects
98
+ `./hooks/hooks.json` through `extensions.com.openai`; the compatibility
99
+ `.codex-plugin/plugin.json` stays inside the current ingestion schema. Five
100
+ events: `SessionStart`, `PreToolUse`, `PostToolUse`, `Stop`, `PreCompact`.
101
+ Of the 759 captured firings, 757 came from the earlier inline form, across
102
+ `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse` and `Stop`,
103
+ and 2 from a file-site `hooks/hooks.json` with an absolute `node` path.
104
+ `PreCompact` has never been observed firing on Codex, and neither has the
105
+ `${PLUGIN_ROOT}` form selected through `extensions.com.openai`. The hook process
106
+ receives `PLUGIN_ROOT` in its environment, naming the shell's root with the
107
+ core beneath it in `node_modules/projectstore/`, and **no project-directory
108
+ variable at all**. The project comes from the payload's `cwd`, which every
109
+ projectstore hook adopts before it resolves anything.
110
+ - **Trust is granted per hook, machine-wide**, and it lags: a release that
111
+ changes hooks may not take effect until the session after next.
112
+ - **Source commands are not shipped.** Codex has no registrable root slash command, and
113
+ shipping `commands/` is actively harmful — it rewrites them into skills itself
114
+ and leaves `${CLAUDE_PLUGIN_ROOT}` in the body, producing entry points that
115
+ exit 1. They are rendered as skills instead.
116
+ - **Roles are rendered as orchestration skills.** Codex spawns subagents through
117
+ its collaboration tool, not by loading a plugin's `agents/` directory. The
118
+ six ProjectStore roles therefore ship as namespaced skills that resolve their
119
+ configured model through the core and ask Codex to spawn the role. No effort
120
+ is forced: it inherits unless the user has configured a model policy.
121
+ - **Multi-file edits reach the activity log and entry rule when their paths
122
+ are absolute.** Codex's `apply_patch` carries paths inside
123
+ `tool_input.command`; the shared extractor reads every `Add`, `Update`,
124
+ `Delete` and `Move to` path from that measured envelope field. A relative
125
+ path is not yet resolved against the payload's `cwd`, so it is not recorded.
126
+ The field name remains manifest data, not a Codex branch.
127
+ - **MCP does not ship.** Our `.mcp.json` is in Claude Code's dialect.
128
+
129
+ Codex also sets Claude Code's `CLAUDE_PLUGIN_ROOT` for compatibility. A variable
130
+ two harnesses both set identifies neither, so both manifests demote it: it stops
131
+ being evidence for *either* harness rather than being evidence for the first file
132
+ in alphabetical order.
133
+
134
+ ## Running both over one project
135
+
136
+ Nothing is shared that could collide. The binding
137
+ (`<project>/.projectstore/projectstore.json`) is harness-neutral and one file;
138
+ the agents block is per harness; the session state is keyed by harness id. Two
139
+ harnesses in one project write two overlays and neither disturbs the other.
140
+
141
+ Within one machine, run them in separate **git worktrees** over the same
142
+ checkout, as parallel Claude Code sessions already do. The vault itself is a git
143
+ repository with its own remote — that is how it syncs between people and their
144
+ agents.
145
+
146
+ ## Adding a harness
147
+
148
+ A harness is a manifest plus measurements, not code:
149
+
150
+ 1. Write `harnesses/<id>.json`. Copy the field list from an existing one; leave
151
+ `verified: null` and omit or null every value you have not observed. A field
152
+ that is `null` with a reason is a decision on the record; an absent field is
153
+ one someone forgot.
154
+ 2. Measure. Install it, run a real task, capture the hook payloads. The values
155
+ that matter first: which environment variables the hook process receives,
156
+ where hooks are declared, which tool writes files and where that tool puts the
157
+ path.
158
+ 3. Declare any variable the harness sets that belongs to another harness under
159
+ `runtime.shared_env`, or detection will answer with someone else's id.
160
+ 4. Add a row to the table above. It stays **experimental** until the manifest
161
+ carries a `verified` block — the test enforces the pairing in both directions.
162
+
163
+ See [`docs/extending.md`](./extending.md) for the surfaces themselves.