projectstore-claude 0.28.0-rc.2 → 0.28.0
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/bin/projectstore-claude.mjs +4 -1
- package/node_modules/projectstore/.claude-plugin/marketplace.json +1 -1
- package/node_modules/projectstore/.claude-plugin/plugin.json +1 -1
- package/node_modules/projectstore/README.md +86 -16
- package/node_modules/projectstore/commands/agents.md +8 -2
- package/node_modules/projectstore/commands/doctor.md +26 -7
- package/node_modules/projectstore/docs/extending.md +1 -1
- package/node_modules/projectstore/docs/getting-started.md +1 -1
- package/node_modules/projectstore/docs/harnesses.md +159 -0
- package/node_modules/projectstore/harnesses/claude-code.json +17 -3
- package/node_modules/projectstore/harnesses/codex.json +331 -0
- package/node_modules/projectstore/hooks/pre-compact.mjs +7 -1
- package/node_modules/projectstore/hooks/session-rules.mjs +11 -1
- package/node_modules/projectstore/hooks/session-start.mjs +15 -5
- package/node_modules/projectstore/hooks/session-stop.mjs +7 -1
- package/node_modules/projectstore/package.json +4 -2
- package/node_modules/projectstore/scaffold/checklists.json +1 -1
- package/node_modules/projectstore/scripts/build-adapters.mjs +264 -0
- package/node_modules/projectstore/scripts/cli.mjs +36 -9
- package/node_modules/projectstore/scripts/diff-refs.mjs +12 -2
- package/node_modules/projectstore/scripts/doctor.mjs +254 -40
- package/node_modules/projectstore/scripts/harness.mjs +150 -26
- package/node_modules/projectstore/scripts/install-harness.mjs +591 -61
- package/node_modules/projectstore/scripts/lib.mjs +208 -24
- package/node_modules/projectstore/scripts/portable-registration.mjs +198 -0
- package/node_modules/projectstore/scripts/surfaces.mjs +62 -13
- package/node_modules/projectstore/scripts/touch-session.mjs +29 -18
- package/node_modules/projectstore/scripts/version-guard.mjs +18 -4
- package/node_modules/projectstore/skills/{decision-detector → projectstore-decision-detector}/SKILL.md +1 -0
- package/node_modules/projectstore/skills/{peer-reviewer → projectstore-peer-reviewer}/SKILL.md +1 -0
- package/node_modules/projectstore/skills/{story-completion → projectstore-story-completion}/SKILL.md +1 -0
- package/node_modules/projectstore/skills/{vault-communication → projectstore-vault-communication}/SKILL.md +1 -0
- package/package.json +2 -2
|
@@ -76,7 +76,10 @@ if (!core) {
|
|
|
76
76
|
// without one, so the child must see the real stdin and stdout. No
|
|
77
77
|
// timeout — the child waits on a human at the preview. exitCode, not
|
|
78
78
|
// exit(): the core's own bin says why (a pending write on a pipe).
|
|
79
|
-
const r = spawnSync(process.execPath, [core, ...fixed.argv], {
|
|
79
|
+
const r = spawnSync(process.execPath, [core, ...fixed.argv], {
|
|
80
|
+
stdio: "inherit",
|
|
81
|
+
env: { ...process.env, PROJECTSTORE_DISTRIBUTION_ROOT: root },
|
|
82
|
+
});
|
|
80
83
|
if (r.error) process.stderr.write(`${SHELL}: ${r.error.message}\n`);
|
|
81
84
|
// A signal is relayed the shell way (128 + its number): Ctrl-C at the
|
|
82
85
|
// preview is 130 here as it would be on the core itself.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"name": "projectstore",
|
|
13
13
|
"displayName": "projectstore",
|
|
14
14
|
"description": "📚 Your agent runs the project through a verified loop: task → artifact (ADR · spec · epic · story) → adversarial critic → backlog → planner → reviewer → done. Plain markdown in an Obsidian-friendly vault, every write approved by you — and any model can pick the project up tomorrow.",
|
|
15
|
-
"version": "0.28.0
|
|
15
|
+
"version": "0.28.0",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "Evgenii Konev",
|
|
18
18
|
"email": "ekonev@smartandpoint.com",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "projectstore",
|
|
3
3
|
"displayName": "projectstore",
|
|
4
|
-
"version": "0.28.0
|
|
4
|
+
"version": "0.28.0",
|
|
5
5
|
"description": "Your agent runs the project through a verified loop: task → artifact (ADR / spec / epic / story) → adversarial critic → backlog → planner → reviewer → done. Plain markdown in git — any model can pick the project up tomorrow.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Evgenii Konev @ SmartAndPoint",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/SmartAndPoint/ProjectStore/releases) [](./LICENSE) [](https://github.com/SmartAndPoint/ProjectStore/stargazers)
|
|
6
6
|
|
|
7
|
-
A [Claude Code](https://claude.com/claude-code)
|
|
7
|
+
A project workflow plugin for [Claude Code](https://claude.com/claude-code) and [OpenAI Codex](https://developers.openai.com/codex/) (experimental).
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -88,6 +88,28 @@ npx projectstore-claude install --project "$PWD"
|
|
|
88
88
|
|
|
89
89
|
The same tree is published to npm as [`projectstore`](https://www.npmjs.com/package/projectstore) — one source package carrying every harness's manifest — and `projectstore-claude` is its Claude Code shell: the core pinned at the same version and bundled inside, the harness fixed, so the one command has the same shape on every harness. It registers the plugin with Claude Code: it writes a small local marketplace of its own under your Claude home, then drives `claude plugin marketplace add` / `plugin install` **at local scope**, so the registration lands in this checkout's `.claude/settings.local.json` and nowhere else. Every host command is printed before it runs; naming the harness is the confirmation. Restart Claude Code afterwards. A git-marketplace copy already enabled for the checkout is silenced there (not globally) so the plugin does not load twice; `uninstall` turns it back on. Pin or upgrade with `npx projectstore-claude@<version> upgrade --project "$PWD"` — the version you name is the version you run. The core's low-level form, `npx projectstore <verb> --harness claude-code …`, is exactly what the shell runs. bun works the same on the packed bin.
|
|
90
90
|
|
|
91
|
+
**Codex uses its own rendered plugin root and the same one-command shape.**
|
|
92
|
+
Codex support is **experimental** (see [`docs/harnesses.md`](./docs/harnesses.md)
|
|
93
|
+
for what has been measured and what has not), and its shell is not published
|
|
94
|
+
yet. From this checkout, exercise the exact npx path against the built tarball:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
npm run shells:build -- --only projectstore-codex --dev --out dist
|
|
98
|
+
npx --package "./dist/projectstore-codex-$(node -p 'require("./package.json").version').tgz" projectstore-codex install --project "$PWD"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The Codex shell carries a canonical portable manifest, namespaced workflow and
|
|
102
|
+
role skills, lifecycle hooks, and the exact bundled core. It stages a stable
|
|
103
|
+
marketplace under `CODEX_HOME`, drives `codex plugin marketplace add` and
|
|
104
|
+
`codex plugin add`, then reads the installation back and verifies its version
|
|
105
|
+
and payload digest. Restart Codex, approve the hooks, and run
|
|
106
|
+
`$projectstore-bind <vault-path>`. After the first explicit npm publication,
|
|
107
|
+
the shorter command is
|
|
108
|
+
`npx projectstore-codex@<version> install --project "$PWD"`; use its `upgrade`
|
|
109
|
+
verb for later releases. Because Codex's
|
|
110
|
+
plugin registry is user-global, ordinary uninstall removes only the project's
|
|
111
|
+
agents block; `uninstall --global` is the explicit machine-wide removal.
|
|
112
|
+
|
|
91
113
|
The package also carries a `bin`. Without a session — in CI, or in a shell — the same core answers token-free, with a `--json` envelope on every verb:
|
|
92
114
|
|
|
93
115
|
```
|
|
@@ -119,20 +141,48 @@ npx projectstore bind ~/vaults/my-project
|
|
|
119
141
|
npx projectstore init ~/vaults/new-project --language ru
|
|
120
142
|
```
|
|
121
143
|
|
|
122
|
-
`projectstore-claude`, `projectstore-codex` and `projectstore-opencode`
|
|
144
|
+
`projectstore-claude`, `projectstore-codex` and `projectstore-opencode` are this package's per-harness shells — the core pinned and bundled, the harness fixed. Codex's shell is experimental and stays private until a live run has exercised every surface it installs, from an installed release ([`docs/harnesses.md`](./docs/harnesses.md)). The opencode shell publishes after its plugin root is rendered. The other `projectstore-*` names are reserved placeholders pointing back here. One source package, one version, N tarballs.
|
|
123
145
|
</details>
|
|
124
146
|
|
|
125
147
|
## Upgrading
|
|
126
148
|
|
|
127
|
-
`/plugin update` (or auto-update) and a restart
|
|
128
|
-
an existing project sees afterwards, and why:
|
|
129
|
-
|
|
130
|
-
- **The
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
149
|
+
`/plugin update` (or auto-update) and a restart, then one command per project
|
|
150
|
+
bound before 0.28. What an existing project sees afterwards, and why:
|
|
151
|
+
|
|
152
|
+
- **The project's files move to `.projectstore/`.** `.claude/projectstore.json`
|
|
153
|
+
and `.claude/.projectstore/` become `.projectstore/projectstore.json`,
|
|
154
|
+
`.projectstore/harness/claude-code.json` and `.projectstore/state/`. Nothing
|
|
155
|
+
breaks before you move them: every reader falls back to the old paths through
|
|
156
|
+
0.29, and the startup line names the command until the move is done. Close
|
|
157
|
+
every Claude Code session in the project, run that command from a terminal,
|
|
158
|
+
then restart. The command depends on how you installed:
|
|
159
|
+
- **From the git marketplace** (every 0.27.x install): the installed copy's
|
|
160
|
+
own `bin/projectstore.mjs`, with its path spelled out in the startup line —
|
|
161
|
+
`node "<plugin cache>/bin/projectstore.mjs" upgrade --harness claude-code --no-register --project "$PWD"`.
|
|
162
|
+
`--no-register` leaves your plugin registration as it is.
|
|
163
|
+
- **From npm**: `npx projectstore-claude@<version> upgrade --no-register --project "$PWD"`.
|
|
164
|
+
|
|
165
|
+
Both forms move only the project's files, so neither touches your plugin
|
|
166
|
+
registration. The same run re-stamps the status-line launcher at its new path
|
|
167
|
+
and re-registers the agents block, whose template is now v4. A plain
|
|
168
|
+
`npx projectstore-claude upgrade` on a git-marketplace install does more: it
|
|
169
|
+
also registers the plugin from npm for this checkout and turns the
|
|
170
|
+
git-marketplace copy off here, so `/plugin update` stops reaching the
|
|
171
|
+
checkout. The 0.28.0-rc.1 and rc.2 startup lines named that shell form
|
|
172
|
+
(`npx projectstore-claude@<version> upgrade`, without `--no-register`), so on
|
|
173
|
+
those, update first and run what the new startup line names. If it already
|
|
174
|
+
happened,
|
|
175
|
+
`npx projectstore-claude@<version> uninstall --surface plugin --project "$PWD"`
|
|
176
|
+
(0.28.0 or later) turns the git-marketplace copy back on. That copy must be 0.28 or later — an
|
|
177
|
+
older one reads a moved project as unbound — so update it first if it is not.
|
|
178
|
+
Restart, then run
|
|
179
|
+
`/projectstore:doctor --fix` in the new session, which re-stamps the status
|
|
180
|
+
line against that copy.
|
|
181
|
+
- **The status line keeps rendering.** A launcher written by an earlier version
|
|
182
|
+
still works, but it carries no file stamp and its embedded fallback root is
|
|
183
|
+
frozen at the old version; the move above re-stamps it. Nothing rewrites that
|
|
184
|
+
file behind your back any more: first wiring and refresh are `install`'s,
|
|
185
|
+
behind a preview.
|
|
136
186
|
- **`/projectstore:status` and `/projectstore:search` answer differently:**
|
|
137
187
|
facts from artifact frontmatter and the derived views' freshness instead
|
|
138
188
|
of an `mtime` walk; a literal, bounded, grouped search instead of a shell
|
|
@@ -144,9 +194,29 @@ an existing project sees afterwards, and why:
|
|
|
144
194
|
a crash.
|
|
145
195
|
- **The plugin registers an MCP server** (eight read-only tools over the
|
|
146
196
|
vault). Claude Code may ask you to approve it once.
|
|
147
|
-
- **
|
|
148
|
-
|
|
149
|
-
|
|
197
|
+
- **The agents block stays where Claude Code reads it.** In a project with an
|
|
198
|
+
`AGENTS.md`, the block goes there and `CLAUDE.md` carries a one-line
|
|
199
|
+
`@AGENTS.md` import; otherwise the block goes into `CLAUDE.md`. A project with
|
|
200
|
+
an `AGENTS.md` and no `CLAUDE.md` now gains that one-line `CLAUDE.md`.
|
|
201
|
+
- **The passive skills are published under the `projectstore-` prefix**
|
|
202
|
+
(`projectstore-decision-detector`, `projectstore-peer-reviewer`,
|
|
203
|
+
`projectstore-story-completion`, `projectstore-vault-communication`). Nothing
|
|
204
|
+
in a project names them; only a skill listing shows the new names.
|
|
205
|
+
- **Rolling back** to 0.27.x before the move: everything keeps working, since
|
|
206
|
+
0.27.x still reads the old layout. It rewrites the status-line launcher in its
|
|
207
|
+
own form, as it always did; coming forward again, the startup line names the
|
|
208
|
+
move once more, and the move re-stamps the launcher. If a session already
|
|
209
|
+
re-stamped the status line or re-registered the agents block before the move
|
|
210
|
+
(rc.2's `/projectstore:doctor --fix` did both), 0.27.x reports a foreign
|
|
211
|
+
status line and a v4 block and leaves both alone — unless you run its
|
|
212
|
+
`/projectstore:agents register`, which rewrites the block; the status line
|
|
213
|
+
still renders, and the move settles both.
|
|
214
|
+
- **Rolling back** to 0.27.x after the move: 0.27.x looks for its binding under
|
|
215
|
+
`.claude/`, finds none and offers `bind`. Do not accept. A re-bind writes
|
|
216
|
+
`.claude/projectstore.json` again, and 0.28's `install` and `upgrade` refuse
|
|
217
|
+
while two bindings exist. To come forward again, delete
|
|
218
|
+
`.claude/projectstore.json`, then run the command the startup line names
|
|
219
|
+
once more: a 0.27.x session writes its welcome marker back under `.claude/`.
|
|
150
220
|
- **Installed from npm?** Then `/plugin update` has nothing to fetch: the
|
|
151
221
|
registration is refreshed by the package itself — from a terminal outside
|
|
152
222
|
the session, `npx projectstore-claude@<version> upgrade --project "$PWD"`
|
|
@@ -193,11 +263,11 @@ The deep dive — real session files, measured payloads, how every mechanism wor
|
|
|
193
263
|
|
|
194
264
|
## Uninstalling
|
|
195
265
|
|
|
196
|
-
`/plugin uninstall projectstore@SmartAndPoint` for a git-marketplace install; `npx projectstore-claude uninstall --project "$PWD"`
|
|
266
|
+
`/plugin uninstall projectstore@SmartAndPoint` for a Claude git-marketplace install; `npx projectstore-claude uninstall --project "$PWD"` for its npm registration. For Codex, `npx projectstore-codex uninstall --project "$PWD"` removes only project-owned wiring; add `--global` only to remove the user-global Codex plugin and marketplace. Your vault is yours — plain markdown, untouched. One leftover of a host-managed plugin path can be the agents block in `CLAUDE.md`/`AGENTS.md`; remove it with the harness's agents unregister skill, or delete everything between `<!-- projectstore:agents … -->` and `<!-- /projectstore:agents -->` by hand. `uninstall` leaves a block that lives in `AGENTS.md`, because that file is read by other coding agents too, and removes the `CLAUDE.md` import when that file holds nothing else; `uninstall --surface agents_block` removes the block as well.
|
|
197
267
|
|
|
198
268
|
## Extending
|
|
199
269
|
|
|
200
|
-
See [`docs/extending.md`](./docs/extending.md) for adding layouts, templates, and skills.
|
|
270
|
+
See [`docs/extending.md`](./docs/extending.md) for adding layouts, templates, and skills, and [`docs/harnesses.md`](./docs/harnesses.md) for which coding agents projectstore runs on — what "experimental" means there, and what adding one takes.
|
|
201
271
|
|
|
202
272
|
## Contributing
|
|
203
273
|
|
|
@@ -20,7 +20,7 @@ subcommand (`.projectstore/projectstore.json`; else point to `/projectstore:bind
|
|
|
20
20
|
It renders the block from the installed plugin's template ∩ the layout's
|
|
21
21
|
roster (`scaffold/layouts/<layout>.json` — only routable agents get lines;
|
|
22
22
|
the entry-rule line, the instruction-conflict line, the
|
|
23
|
-
model-resolution line and the vault-communication line always stay), places it (`AGENTS.md` when it
|
|
23
|
+
model-resolution line and the vault-native communication line always stay), places it (`AGENTS.md` when it
|
|
24
24
|
exists, else `CLAUDE.md`; a block in the other file is migrated, never
|
|
25
25
|
duplicated; `CLAUDE.md` gets an `@AGENTS.md` import), previews every
|
|
26
26
|
write, and applies because the harness is named. A current block is
|
|
@@ -28,7 +28,13 @@ subcommand (`.projectstore/projectstore.json`; else point to `/projectstore:bind
|
|
|
28
28
|
prose byte-identical.
|
|
29
29
|
3. A non-zero exit is a refusal — a duplicated or unclosed block, a missing
|
|
30
30
|
template — relay it and stop. Never write the block with the Write or Edit
|
|
31
|
-
tool: the verb is the only writer (install spec, contract 6).
|
|
31
|
+
tool: the verb is the only writer (install spec, contract 6). One exception,
|
|
32
|
+
read from the output, not assumed: when it shows the block applied and the
|
|
33
|
+
`layout` item skipped as deferred to a terminal outside the session, the
|
|
34
|
+
exit 1 is that deferral. The block is registered — say so, and for the move
|
|
35
|
+
relay the command the startup line or `/projectstore:doctor`'s
|
|
36
|
+
`layout-legacy` finding names; never compose one. Any other non-zero exit
|
|
37
|
+
is a refusal.
|
|
32
38
|
|
|
33
39
|
## `unregister` — remove what register added
|
|
34
40
|
|
|
@@ -21,7 +21,12 @@ You are running projectstore diagnostics (ADR-005: umbrella doctor).
|
|
|
21
21
|
2. **No findings** → done. One line: "Doctor is clean — N info note(s) above."
|
|
22
22
|
|
|
23
23
|
3. **`--fix` requested** → walk the *install-side* findings only, one
|
|
24
|
-
AskUserQuestion per repair, never batched silently
|
|
24
|
+
AskUserQuestion per repair, never batched silently. **When `layout-legacy`
|
|
25
|
+
is in the report, it goes first and its command is the one repair** for a
|
|
26
|
+
stale-launcher `surface`, a v3 `agents-block` and `agents-in-binding` as
|
|
27
|
+
well: relay it and run nothing in-session for those (see its bullet below).
|
|
28
|
+
The report already shows the v3 block, and a block Claude Code cannot see,
|
|
29
|
+
as info that points at the move.
|
|
25
30
|
- `worktree-unbound` → this checkout is a git worktree of a bound one. Offer
|
|
26
31
|
`/projectstore:bind --inherit`, and say what it does: copies the parent's
|
|
27
32
|
binding, leaves the vault shared and unchanged, carries no session state.
|
|
@@ -32,7 +37,10 @@ You are running projectstore diagnostics (ADR-005: umbrella doctor).
|
|
|
32
37
|
- `agents-block` duplicate or stale → show the finding, then (after approval)
|
|
33
38
|
run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" install --harness claude-code --surface agents_block --project "${CLAUDE_PROJECT_DIR}"`
|
|
34
39
|
and print its output: it removes the copy in the non-preferred file and
|
|
35
|
-
keeps the preferred one current.
|
|
40
|
+
keeps the preferred one current. A block Claude Code cannot see — in
|
|
41
|
+
`AGENTS.md`, with no `@AGENTS.md` line in `CLAUDE.md` — is the same repair:
|
|
42
|
+
the verb adds the import. For another harness the finding names its own
|
|
43
|
+
`--harness`; relay that command. Never Edit or Write the block yourself —
|
|
36
44
|
the verb is its only writer (install spec, contract 6).
|
|
37
45
|
- `statusline` issues → offer running `/projectstore:statusline on|off`,
|
|
38
46
|
which installs or removes the entry and the launcher behind a preview
|
|
@@ -49,7 +57,8 @@ You are running projectstore diagnostics (ADR-005: umbrella doctor).
|
|
|
49
57
|
- `upgrade` (an info the SessionStart line carries, not a row of this
|
|
50
58
|
report: a launcher written before file stamps existed) → in this report
|
|
51
59
|
the same file is the `surface` issue above; the `upgrade` command re-stamps
|
|
52
|
-
it in one run.
|
|
60
|
+
it in one run. While `layout-legacy` is pending the startup line does not
|
|
61
|
+
carry it: the move re-stamps the launcher at its new path.
|
|
53
62
|
- `surface-foreign` → **never repairable.** A file under our prefix with no
|
|
54
63
|
provenance line is not ours: no `--fix` flow may edit, delete, move or
|
|
55
64
|
overwrite it. Print the finding verbatim and relay its resolution — rename
|
|
@@ -63,10 +72,20 @@ You are running projectstore diagnostics (ADR-005: umbrella doctor).
|
|
|
63
72
|
- `layout-legacy` (warn; the startup line carries it as an offer) → the project
|
|
64
73
|
still holds the pre-0.28 layout (`.claude/projectstore.json`,
|
|
65
74
|
`.claude/.projectstore/` — legacy, read through 0.29). The migration is one
|
|
66
|
-
previewed `layout` item of
|
|
67
|
-
|
|
68
|
-
inside one).
|
|
69
|
-
|
|
75
|
+
previewed `layout` item of `upgrade`, run **from a terminal outside this
|
|
76
|
+
session** (it moves files this session reads and writes; the verb defers
|
|
77
|
+
inside one). The finding names the form for the channel this plugin was
|
|
78
|
+
installed through: the installed copy's own `bin/projectstore.mjs` for a
|
|
79
|
+
git-marketplace install or a checkout, the `projectstore-claude` shell for
|
|
80
|
+
the npm registration. Relay the finding's command verbatim and never
|
|
81
|
+
substitute the other form — the shell, run for a git-marketplace install,
|
|
82
|
+
would also move this checkout to the npm channel. When the finding carries
|
|
83
|
+
advice instead of a command — the installed copy predates the move, or
|
|
84
|
+
predates `--no-register` — relay the advice and never compose a command
|
|
85
|
+
yourself. Never move the files yourself. While this finding is in the report, its command is also the one
|
|
86
|
+
repair for a stale-launcher `surface`, a v3 `agents-block` and
|
|
87
|
+
`agents-in-binding`: do not run the in-session `install` or `upgrade` for
|
|
88
|
+
those — the deferred move makes that run stop part-way.
|
|
70
89
|
- `layout-two-configs` (issue) → both `.claude/projectstore.json` (legacy) and
|
|
71
90
|
`.projectstore/projectstore.json` exist: `install` and `upgrade` refuse until
|
|
72
91
|
one is deleted. Show both, ask the user which is the binding they mean, and
|
|
@@ -47,7 +47,7 @@ vault-side layout or template override):
|
|
|
47
47
|
its index and stay there.
|
|
48
48
|
|
|
49
49
|
4. **Checklist entry** — `scaffold/checklists.json`, consumed by
|
|
50
|
-
`/projectstore:review` and the peer-reviewer skill. English-only by design.
|
|
50
|
+
`/projectstore:review` and the `projectstore-peer-reviewer` skill. English-only by design.
|
|
51
51
|
|
|
52
52
|
5. **Command prompt** — `commands/<kind>.md`, a prompt (not code) that calls
|
|
53
53
|
`node "${CLAUDE_PLUGIN_ROOT}/scripts/draft.mjs" <kind> "$ARGUMENTS"`, previews,
|
|
@@ -97,7 +97,7 @@ Every command that writes or edits a file goes through `AskUserQuestion`:
|
|
|
97
97
|
One consequence the prompt tells you about: the regeneration rewrites the
|
|
98
98
|
whole table, so a creation can also repair a stale row for another artifact.
|
|
99
99
|
|
|
100
|
-
Skills (decision-detector
|
|
100
|
+
Skills (`projectstore-decision-detector`, `projectstore-story-completion`) are passive — they suggest commands; they never write directly.
|
|
101
101
|
|
|
102
102
|
## Disabling skills
|
|
103
103
|
|
|
@@ -0,0 +1,159 @@
|
|
|
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, but its distribution shell stays
|
|
27
|
+
private until the complete built artifact passes the live gate.
|
|
28
|
+
|
|
29
|
+
The label is not prose. It is derived from the manifest, and
|
|
30
|
+
`tests/portability.test.mjs` fails if this table and `verified` disagree.
|
|
31
|
+
|
|
32
|
+
## Claude Code
|
|
33
|
+
|
|
34
|
+
The **source layout**: the repository's own `hooks/`, `commands/`, `agents/`,
|
|
35
|
+
`skills/` and `.mcp.json` are Claude Code's, written by hand and read directly.
|
|
36
|
+
Every other harness is generated from them. Exactly one manifest may say
|
|
37
|
+
`source_layout: true`, which is what keeps "the original" a single place.
|
|
38
|
+
|
|
39
|
+
Config lives in `<project>/.projectstore/`, harness-neutral, shared by every
|
|
40
|
+
harness in the project. The per-harness half — the agents block, which carries
|
|
41
|
+
model names and those are harness-specific — is
|
|
42
|
+
`<project>/.projectstore/harness/claude-code.json`.
|
|
43
|
+
|
|
44
|
+
## Codex
|
|
45
|
+
|
|
46
|
+
Experimental, measured on `codex-cli 0.153.4`. The initial spike captured 759
|
|
47
|
+
hook firings. The 2026-09-30 gate then built the npm shell from a packed core,
|
|
48
|
+
passed Codex's plugin validator, installed and upgraded it through an isolated
|
|
49
|
+
`CODEX_HOME`, verified the materialised cache by version and digest, and loaded
|
|
50
|
+
`$projectstore-status` in a fresh Codex session. The validator (the
|
|
51
|
+
plugin-creator skill's `validate_plugin.py`) reads only
|
|
52
|
+
`.codex-plugin/plugin.json`, so the canonical root `plugin.json` has not been
|
|
53
|
+
validated.
|
|
54
|
+
|
|
55
|
+
That run exercised one skill, not every installed surface, so `verified` stays
|
|
56
|
+
`null`. The hooks are the reason it matters. On 2026-10-03 the first real
|
|
57
|
+
install's cached hooks could not load the vault in any session. They were run
|
|
58
|
+
by hand through `zsh -lc`; the failure did not depend on the shell form. In the
|
|
59
|
+
first session the failure sat in the model's context under the welcome, which
|
|
60
|
+
was all the user saw. The core had taken the shell's root for its own. That is
|
|
61
|
+
fixed, and the suite now runs every rendered hook from the built shell. A live
|
|
62
|
+
Codex session firing them from an installed release is still owed.
|
|
63
|
+
|
|
64
|
+
How 0.153.4 starts a hook was read from its source, not measured: under the
|
|
65
|
+
session's shell as `<shell> -c`, with the environment the Codex process had when
|
|
66
|
+
it built the session's hooks. `$SHELL -lc` (or `/bin/sh -lc`) is the fallback
|
|
67
|
+
when the hooks are built without exactly one ready local environment. So a hook
|
|
68
|
+
finds `node` on the Codex process's own `PATH`, plus whatever `.zshenv` adds:
|
|
69
|
+
zsh reads `.zshenv` for a `-c` command, not `.zprofile` or `.zshrc`, so a Codex
|
|
70
|
+
not started from a terminal can miss a `node` that only `.zprofile` puts on
|
|
71
|
+
`PATH`.
|
|
72
|
+
|
|
73
|
+
The shell is not published. Build it and install the tarball through npx from
|
|
74
|
+
this checkout:
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
npm run shells:build -- --only projectstore-codex --dev --out dist
|
|
78
|
+
npx --package "./dist/projectstore-codex-$(node -p 'require("./package.json").version').tgz" projectstore-codex install --project "$PWD"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The shell package is release-gated until its first npm publication. From this
|
|
82
|
+
repository, the same flow is exercised against the packed tarball. Installation
|
|
83
|
+
is user-global because Codex stores marketplace registrations and plugin caches
|
|
84
|
+
in `CODEX_HOME`; the agents block in `AGENTS.md` remains project-local. After
|
|
85
|
+
the first explicit npm publication, the shorter registry form is
|
|
86
|
+
`npx projectstore-codex@<version> install --project "$PWD"` (or `upgrade`). Ordinary
|
|
87
|
+
uninstall leaves the global plugin in place; add `--global` only when you mean
|
|
88
|
+
to remove it for every project.
|
|
89
|
+
|
|
90
|
+
What is known, and how:
|
|
91
|
+
|
|
92
|
+
- **Hooks are rendered; their live firing from an installed release is not
|
|
93
|
+
yet observed.** The canonical portable `plugin.json` selects
|
|
94
|
+
`./hooks/hooks.json` through `extensions.com.openai`; the compatibility
|
|
95
|
+
`.codex-plugin/plugin.json` stays inside the current ingestion schema. Five
|
|
96
|
+
events: `SessionStart`, `PreToolUse`, `PostToolUse`, `Stop`, `PreCompact`.
|
|
97
|
+
Of the 759 captured firings, 757 came from the earlier inline form, across
|
|
98
|
+
`SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse` and `Stop`,
|
|
99
|
+
and 2 from a file-site `hooks/hooks.json` with an absolute `node` path.
|
|
100
|
+
`PreCompact` has never been observed firing on Codex, and neither has the
|
|
101
|
+
`${PLUGIN_ROOT}` form selected through `extensions.com.openai`. The hook process
|
|
102
|
+
receives `PLUGIN_ROOT` in its environment, naming the shell's root with the
|
|
103
|
+
core beneath it in `node_modules/projectstore/`, and **no project-directory
|
|
104
|
+
variable at all**. The project comes from the payload's `cwd`, which every
|
|
105
|
+
projectstore hook adopts before it resolves anything.
|
|
106
|
+
- **Trust is granted per hook, machine-wide**, and it lags: a release that
|
|
107
|
+
changes hooks may not take effect until the session after next.
|
|
108
|
+
- **Source commands are not shipped.** Codex has no registrable root slash command, and
|
|
109
|
+
shipping `commands/` is actively harmful — it rewrites them into skills itself
|
|
110
|
+
and leaves `${CLAUDE_PLUGIN_ROOT}` in the body, producing entry points that
|
|
111
|
+
exit 1. They are rendered as skills instead.
|
|
112
|
+
- **Roles are rendered as orchestration skills.** Codex spawns subagents through
|
|
113
|
+
its collaboration tool, not by loading a plugin's `agents/` directory. The
|
|
114
|
+
six ProjectStore roles therefore ship as namespaced skills that resolve their
|
|
115
|
+
configured model through the core and ask Codex to spawn the role. No effort
|
|
116
|
+
is forced: it inherits unless the user has configured a model policy.
|
|
117
|
+
- **Multi-file edits reach the activity log and entry rule when their paths
|
|
118
|
+
are absolute.** Codex's `apply_patch` carries paths inside
|
|
119
|
+
`tool_input.command`; the shared extractor reads every `Add`, `Update`,
|
|
120
|
+
`Delete` and `Move to` path from that measured envelope field. A relative
|
|
121
|
+
path is not yet resolved against the payload's `cwd`, so it is not recorded.
|
|
122
|
+
The field name remains manifest data, not a Codex branch.
|
|
123
|
+
- **MCP does not ship.** Our `.mcp.json` is in Claude Code's dialect.
|
|
124
|
+
|
|
125
|
+
Codex also sets Claude Code's `CLAUDE_PLUGIN_ROOT` for compatibility. A variable
|
|
126
|
+
two harnesses both set identifies neither, so both manifests demote it: it stops
|
|
127
|
+
being evidence for *either* harness rather than being evidence for the first file
|
|
128
|
+
in alphabetical order.
|
|
129
|
+
|
|
130
|
+
## Running both over one project
|
|
131
|
+
|
|
132
|
+
Nothing is shared that could collide. The binding
|
|
133
|
+
(`<project>/.projectstore/projectstore.json`) is harness-neutral and one file;
|
|
134
|
+
the agents block is per harness; the session state is keyed by harness id. Two
|
|
135
|
+
harnesses in one project write two overlays and neither disturbs the other.
|
|
136
|
+
|
|
137
|
+
Within one machine, run them in separate **git worktrees** over the same
|
|
138
|
+
checkout, as parallel Claude Code sessions already do. The vault itself is a git
|
|
139
|
+
repository with its own remote — that is how it syncs between people and their
|
|
140
|
+
agents.
|
|
141
|
+
|
|
142
|
+
## Adding a harness
|
|
143
|
+
|
|
144
|
+
A harness is a manifest plus measurements, not code:
|
|
145
|
+
|
|
146
|
+
1. Write `harnesses/<id>.json`. Copy the field list from an existing one; leave
|
|
147
|
+
`verified: null` and omit or null every value you have not observed. A field
|
|
148
|
+
that is `null` with a reason is a decision on the record; an absent field is
|
|
149
|
+
one someone forgot.
|
|
150
|
+
2. Measure. Install it, run a real task, capture the hook payloads. The values
|
|
151
|
+
that matter first: which environment variables the hook process receives,
|
|
152
|
+
where hooks are declared, which tool writes files and where that tool puts the
|
|
153
|
+
path.
|
|
154
|
+
3. Declare any variable the harness sets that belongs to another harness under
|
|
155
|
+
`runtime.shared_env`, or detection will answer with someone else's id.
|
|
156
|
+
4. Add a row to the table above. It stays **experimental** until the manifest
|
|
157
|
+
carries a `verified` block — the test enforces the pairing in both directions.
|
|
158
|
+
|
|
159
|
+
See [`docs/extending.md`](./extending.md) for the surfaces themselves.
|
|
@@ -222,7 +222,16 @@
|
|
|
222
222
|
"format": "skill-md",
|
|
223
223
|
"scope": "user",
|
|
224
224
|
"scope_reason": "Claude Code loads skills from the plugin installation itself, not from a per-project directory.",
|
|
225
|
-
"registered_by": "plugin"
|
|
225
|
+
"registered_by": "plugin",
|
|
226
|
+
"frontmatter_required": [
|
|
227
|
+
"name",
|
|
228
|
+
"description"
|
|
229
|
+
],
|
|
230
|
+
"frontmatter_reason": "`description` is what Claude Code matches a skill on; `name` was added 2026-09-08 because Codex's documentation requires it and this is the tree both harnesses load until the generator renders one per harness. Harmless here, required there.",
|
|
231
|
+
"invocation": null,
|
|
232
|
+
"invocation_reason": "UNMEASURED. Claude Code activates a skill from its description rather than from a form the user types; there is no explicit call syntax to record, and null says that rather than leaving the key out and reading as forgotten.",
|
|
233
|
+
"unrendered_source": false,
|
|
234
|
+
"unrendered_source_reason": "This IS the source tree (source_layout: true), so there is nothing to render and no foreign vocabulary to leak into it."
|
|
226
235
|
},
|
|
227
236
|
"hooks": {
|
|
228
237
|
"supported": true,
|
|
@@ -244,6 +253,8 @@
|
|
|
244
253
|
"AGENTS.md",
|
|
245
254
|
"CLAUDE.md"
|
|
246
255
|
],
|
|
256
|
+
"reads_natively": "CLAUDE.md",
|
|
257
|
+
"reads_natively_reason": "The file this harness reads BY ITSELF. `files` is the block's placement preference and conflates two things: AGENTS.md is first because it is the cross-tool convention, but Claude Code reaches it only through the @AGENTS.md import WE install — remove the bridge and the block is invisible. So installing for this harness must leave CLAUDE.md present: holding the block when it lands here, holding the import when it lands in AGENTS.md. Measured 2026-09-09: a project with an AGENTS.md and no CLAUDE.md took the block into AGENTS.md and created no bridge, so the harness that ran the install could not see it.",
|
|
247
258
|
"source": "templates/claude-md-block.md.tmpl",
|
|
248
259
|
"marker": {
|
|
249
260
|
"open": "<!-- projectstore:agents v",
|
|
@@ -461,9 +472,12 @@
|
|
|
461
472
|
"",
|
|
462
473
|
"Without it, you would run `/plugin marketplace update SmartAndPoint` manually. See https://github.com/SmartAndPoint/ProjectStore#upgrading for details.",
|
|
463
474
|
"",
|
|
464
|
-
"**Upgrading from 0.27.x to 0.28**: restart after the update
|
|
475
|
+
"**Upgrading from 0.27.x to 0.28**: restart after the update, then move the project's files to `.projectstore/` with the one command the first session names, run from a terminal outside the session: for a git-marketplace install, the installed copy's own `bin/projectstore.mjs upgrade --harness claude-code --no-register --project <dir>`, which leaves the registration as it is; for the npm registration, `npx projectstore-claude@<version> upgrade --no-register --project <dir>`. The same run re-stamps the status-line launcher, and until then every reader falls back to the old paths. `status` and `search` answer from artifact facts; `doctor` gains surface, version-drift and mcp lines and exits 1 on findings; the plugin registers an MCP server the host may ask you to approve once. On 0.28.0-rc.1 or rc.2, update first: their startup line named the shell form without `--no-register` (`npx projectstore-claude@<version> upgrade`), which also switches a git-marketplace install to npm for the checkout (the README's Upgrading section has the way back). Before the move, a rollback to 0.27.x keeps working and the move is the way forward again; after the move, 0.27.x reads the project as unbound."
|
|
465
476
|
],
|
|
466
477
|
"agent_translation": {
|
|
467
|
-
"carries_model": true
|
|
478
|
+
"carries_model": true,
|
|
479
|
+
"cheap_model": "sonnet",
|
|
480
|
+
"cheap_model_evidence": "measured",
|
|
481
|
+
"cheap_model_reason": "The model the clerk is pinned to when a strong default would otherwise lift it (ADR-008). A literal here, in the one file allowed to name a harness's vocabulary; it used to be a literal in scripts/cli.mjs, which made `agents configure --harness codex` write an Anthropic model name into a Codex overlay. MEASURED in the sense that matters: this is the model the clerk has been running on since ADR-008, in this repository, and tests/overlay.test.mjs asserts the pin end to end."
|
|
468
482
|
}
|
|
469
483
|
}
|