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.
- 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 +163 -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 +255 -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 +36 -14
- package/plugin.json +53 -0
- 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,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.
|