projectstore-claude 0.30.2 โ†’ 0.30.3

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 (28) hide show
  1. package/node_modules/projectstore/.claude-plugin/marketplace.json +1 -1
  2. package/node_modules/projectstore/.claude-plugin/plugin.json +1 -1
  3. package/node_modules/projectstore/AGENTS.md +7 -5
  4. package/node_modules/projectstore/README.md +3 -3
  5. package/node_modules/projectstore/agents/clerk.md +2 -2
  6. package/node_modules/projectstore/commands/agents.md +38 -26
  7. package/node_modules/projectstore/commands/bind.md +1 -1
  8. package/node_modules/projectstore/commands/doctor.md +15 -3
  9. package/node_modules/projectstore/commands/reconcile.md +2 -2
  10. package/node_modules/projectstore/commands/review.md +1 -1
  11. package/node_modules/projectstore/commands/story.md +2 -1
  12. package/node_modules/projectstore/docs/getting-started.md +1 -1
  13. package/node_modules/projectstore/docs/harnesses.md +3 -2
  14. package/node_modules/projectstore/harnesses/claude-code.json +40 -1
  15. package/node_modules/projectstore/harnesses/codex.json +50 -14
  16. package/node_modules/projectstore/package.json +1 -1
  17. package/node_modules/projectstore/scripts/agents-change.mjs +64 -10
  18. package/node_modules/projectstore/scripts/build-adapters.mjs +28 -13
  19. package/node_modules/projectstore/scripts/cli.mjs +32 -9
  20. package/node_modules/projectstore/scripts/configure-menu.mjs +133 -6
  21. package/node_modules/projectstore/scripts/configure.mjs +156 -19
  22. package/node_modules/projectstore/scripts/doctor.mjs +95 -31
  23. package/node_modules/projectstore/scripts/install-harness.mjs +29 -0
  24. package/node_modules/projectstore/scripts/lib.mjs +32 -9
  25. package/node_modules/projectstore/scripts/menu.mjs +9 -5
  26. package/node_modules/projectstore/scripts/models.mjs +150 -6
  27. package/node_modules/projectstore/templates/claude-md-block.md.tmpl +7 -5
  28. package/package.json +2 -2
@@ -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.30.2",
15
+ "version": "0.30.3",
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.30.2",
4
+ "version": "0.30.3",
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",
@@ -1,4 +1,4 @@
1
- <!-- projectstore:agents v4 (managed by projectstore โ€” edit outside markers) -->
1
+ <!-- projectstore:agents v5 (managed by projectstore โ€” edit outside markers) -->
2
2
  ## projectstore agents
3
3
 
4
4
  - **A feature-sized request opens a vault artifact before it opens an editor.**
@@ -11,10 +11,12 @@
11
11
  harness-level instruction contradicts this block, say so and ask which wins.
12
12
  Resolving it silently is how the contradiction becomes invisible to the person
13
13
  who could have settled it.
14
- - When spawning any agent below, resolve its model from
15
- `.projectstore/harness/<harness>.json` โ†’ `agents.per_agent.<name>.model ?? agents.default.model`,
16
- where `<name>` is the **bare** agent name (`critic` for `projectstore:critic`),
17
- and pass it as the spawn's model parameter. No key โ€” pass nothing.
14
+ - When spawning any agent below, resolve its model and its effort from
15
+ `.projectstore/harness/<harness>.json` โ†’ `agents.per_agent.<name>.model ?? agents.default.model`
16
+ and `agents.per_agent.<name>.effort ?? agents.default.effort`, where `<name>` is
17
+ the **bare** agent name (`critic` for `projectstore:critic`), and pass them as
18
+ the spawn's model and effort parameters, the effort only when the spawn offers
19
+ one. No key โ€” pass nothing.
18
20
  - After authoring or revising any vault artifact (ADR/research/epic/story) or
19
21
  design proposal: run the `projectstore:critic` agent on it before treating it final.
20
22
  - Before implementing an epic/story: consult `projectstore:planner` โ€” it plans
@@ -210,7 +210,7 @@ npx projectstore configure
210
210
 
211
211
  At a terminal it opens a settings menu that works like a monitor's: โ†‘ and โ†“ move, โ†’ opens a group or a setting in a frame beside it, space chooses, โ† goes back, and Enter shows the plan. A second Enter writes it. Under the frames, a few lines say what the row under the cursor means. The settings:
212
212
 
213
- - each agent's model, per harness. Claude Code offers its aliases: `fable`, `opus`, `sonnet` and `haiku`. Codex offers its own list of models, with its descriptions. With `ANTHROPIC_API_KEY` set, each alias also names the newest model of its line. A list is kept for a day in projectstore's user cache, and "refresh the list" asks again;
213
+ - each agent's model and effort, per harness. Claude Code offers its aliases: `fable`, `opus`, `sonnet` and `haiku`. Codex offers its own list of models, with its descriptions. With `ANTHROPIC_API_KEY` set, each alias also names the newest model of its line. A list is kept for a day in projectstore's user cache, and "refresh the list" asks again. Each agent's effort sits under its model: Claude Code's levels, `low` to `max`, or the levels that Codex model lists. With none set, a Claude Code agent runs at its frontmatter's level (`max`, the clerk `low`) and a Codex one at its model's own default;
214
214
  - the status line and the band above the prompt (Claude Code);
215
215
  - the vault's template language, the default author and tags;
216
216
  - the vault's spec policy and lifecycle gates.
@@ -221,11 +221,11 @@ Without a terminal it prints every setting with its current value and where it l
221
221
  npx projectstore configure --set agents.critic=fable --set statusline=on
222
222
  ```
223
223
 
224
- `--dry-run` shows the plan and writes nothing, and `--json` returns the settings as one envelope. In a project that uses two harnesses, an agent's model names its overlay with `--harness <id>`.
224
+ An agent's effort is its own key: `--set agents.critic.effort=xhigh`. `--dry-run` shows the plan and writes nothing, and `--json` returns the settings as one envelope. In a project that uses two harnesses, an agent's model or effort names its overlay with `--harness <id>`.
225
225
 
226
226
  Each setting has exactly one writer, and the plan says which file it changes:
227
227
 
228
- - **The agents' models** live in `.projectstore/harness/<harness>.json`. That file is committed, so a change there is a team change.
228
+ - **The agents' models and efforts** live in `.projectstore/harness/<harness>.json`. That file is committed, so a change there is a team change.
229
229
  - **The status line, the band, the language and the other binding keys** live in `.projectstore/projectstore.json`, which stays on this machine.
230
230
  - **The spec policy and the lifecycle gates** live in the vault's `.projectstore.json`, which commits with the vault. Setting `spec_policy=required` records when it took effect; stories closed before then are exempt.
231
231
 
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: clerk
3
- description: Sonnet (max-effort) write ceremony executor for projectstore vaults โ€” the roster's sole write-capable agent, and its least autonomous. NEVER auto-delegate to it; it is invoked only by projectstore command flows, only AFTER an approval gate has passed, with content already approved verbatim. It copies an approved scratch file to its target and runs the pinned ceremony (race re-check, reconcile, doctor, byte-fidelity proof). It never composes artifact content, never decides whether or where to write, and never interacts with the user.
3
+ description: Sonnet (low-effort) write ceremony executor for projectstore vaults โ€” the roster's sole write-capable agent, and its least autonomous. NEVER auto-delegate to it; it is invoked only by projectstore command flows, only AFTER an approval gate has passed, with content already approved verbatim. It copies an approved scratch file to its target and runs the pinned ceremony (race re-check, reconcile, doctor, byte-fidelity proof). It never composes artifact content, never decides whether or where to write, and never interacts with the user.
4
4
  model: sonnet
5
- effort: max
5
+ effort: low
6
6
  tools: Read, Grep, Glob, Bash, Write
7
7
  ---
8
8
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Manage bundled-agent integration in this project โ€” register/unregister the routing block in CLAUDE.md/AGENTS.md, inspect state, or configure which model its agents run on.
2
+ description: Manage bundled-agent integration in this project โ€” register/unregister the routing block in CLAUDE.md/AGENTS.md, inspect state, or configure which model each of its agents runs on and at what effort.
3
3
  argument-hint: "<register | unregister | status | configure>"
4
4
  ---
5
5
 
@@ -60,14 +60,14 @@ and report each item's `state` from `result.items[]` โ€” the bin wraps the plan
60
60
  - Model: run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" agents show --json --project "${CLAUDE_PROJECT_DIR}"`
61
61
  and report `result.resolved` โ€” per roster agent, the model the verb would
62
62
  pass and its `source` (`per_agent`, `default`, or `null`: the agent's own
63
- frontmatter), resolved by the verb over the active harness's overlay
63
+ frontmatter), and the effort with its `effort_source` the same way, resolved by the verb over the active harness's overlay
64
64
  (`result.path`) so nothing here re-derives it; `result.unknown` (configured
65
65
  names no roster agent carries โ€” nothing runs under them), `result.rejected`
66
66
  (keys the overlay may not carry) and `result.agents_in_binding` (a pre-0.28
67
67
  leftover; point at `upgrade`), and
68
68
  whether `CLAUDE_CODE_SUBAGENT_MODEL` is set (it overrides everything) and
69
- whether `CLAUDE_CODE_EFFORT_LEVEL` is set (ADR-008 makes it the only thing that
70
- can move the agents off `effort: max`, and it beats frontmatter). **Warn when
69
+ whether `CLAUDE_CODE_EFFORT_LEVEL` is set (it outranks every configured effort
70
+ and the frontmatter: with it set, the spawn offers no effort parameter). **Warn when
71
71
  `result.resolved.clerk.model` is anything but `sonnet` or `haiku`** (that
72
72
  literal pair is the rule, so it is never re-derived; an unknown custom id also
73
73
  warns, with "verify it is cheap"): the clerk transcribes approved
@@ -79,7 +79,7 @@ and report each item's `state` from `result.items[]` โ€” the bin wraps the plan
79
79
  and point at `configure` to clean them up โ€” do not present them as the active
80
80
  configuration, because they are not.
81
81
 
82
- ## `configure` โ€” model per invocation, recorded in config (ADR-008)
82
+ ## `configure` โ€” model and effort per invocation, recorded in config (ADR-008; the effort ADR)
83
83
 
84
84
  > **Why there are no override copies here.** ADR-003 wrote
85
85
  > `<project>/.claude/agents/<name>.md` believing an equal `name:` shadows the
@@ -97,14 +97,15 @@ and report each item's `state` from `result.items[]` โ€” the bin wraps the plan
97
97
  effort. The one exception is the clerk, which only transcribes approved
98
98
  content โ€” it stays cheap regardless of the preset."* Options: keep bundled default (`opus`) / `fable` / `sonnet` /
99
99
  custom model ID (free-form). Offer the current session's model as a hint
100
- option โ€” you know what you are running on. **Do not ask about effort** โ€” see
101
- step 5. **`inherit` is no longer offered**: it meant "follow the session's
100
+ option โ€” you know what you are running on. Then ask the effort for the
101
+ preset โ€” `low` / `medium` / `high` / `xhigh` / `max`, or "leave it to the
102
+ frontmatter" (`max`) โ€” see step 5. **`inherit` is no longer offered**: it meant "follow the session's
102
103
  model", and that cannot be expressed per invocation โ€” passing nothing falls
103
104
  through to the bundled `model: opus`, not to the session. A user who wants
104
105
  session-follow behaviour should pick their session's model explicitly, or set
105
106
  `CLAUDE_CODE_SUBAGENT_MODEL=inherit`, which does mean exactly that.
106
- 2. **Optional follow-up**: "configure individually?" โ†’ per-agent model for each
107
- roster agent. Skippable.
107
+ 2. **Optional follow-up**: "configure individually?" โ†’ per-agent model and
108
+ effort for each roster agent. Skippable.
108
109
  3. **Apply**: after the AskUserQuestion, run the verb and print its output โ€”
109
110
  `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" agents configure --harness claude-code --default <model> [--agent <name>=<model> โ€ฆ] --project "${CLAUDE_PROJECT_DIR}"`
110
111
  (naming the harness is the confirmation; the verb writes
@@ -120,24 +121,31 @@ and report each item's `state` from `result.items[]` โ€” the bin wraps the plan
120
121
  the emptied block. A name outside the layout's roster is a usage error
121
122
  naming the roster โ€” a model written under a name no agent carries would
122
123
  never run. That file is the whole output of this command โ€” **never write
123
- an agent copy into `.claude/agents/`**. The verb never writes an `effort`
124
- key; one already inside the agents block is dropped by the next `configure`
125
- write and named in its preview, and until then doctor reports it as a key the
126
- overlay may not carry โ€” it has no effect (the effort you configured is not
127
- the effort that runs).
124
+ an agent copy into `.claude/agents/`**. `agents configure` keeps every
125
+ effort the overlay holds; `--reset` drops them with the models.
126
+ **Efforts** chosen in steps 1โ€“2 are written by `configure`, the one verb
127
+ with effort keys โ€” preview first, then apply after the same approval:
128
+ `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" configure --set agents.default.effort=<level> [--set agents.<name>.effort=<level> โ€ฆ] --harness claude-code --dry-run --project "${CLAUDE_PROJECT_DIR}"`,
129
+ then the same command without `--dry-run`. `-` as the level clears one. A
130
+ default effort with no clerk effort named pins the clerk's effort to `low`
131
+ and says so, as a default model pins its model: the clerk transcribes.
128
132
  4. **Migrate away from copies**: if `.claude/agents/` holds copies carrying
129
133
  `# source: projectstore vโ€ฆ`, they are pre-ADR-008 leftovers that override
130
134
  nothing. Offer to delete them **one approval per file** (matching `/projectstore:doctor --fix`), project scope only โ€” a copy in `~/.claude/agents/` needs a manual removal, and you should say so rather than implying this command will handle it.
131
135
  Copies WITHOUT the provenance marker are user-authored โ€” never touch them,
132
136
  never mention deleting them.
133
- 5. **Effort is not configurable per project.** The bundled agents ship
134
- `effort: max`, which is the recommended value, and there is no
135
- per-invocation effort parameter โ€” only frontmatter, settings, or
136
- `CLAUDE_CODE_EFFORT_LEVEL`. If the user asks for a different effort, say
137
- that plainly and point at the env var; do not write a copy to achieve it.
137
+ 5. **Effort rides the spawn, like the model.** The overlay's
138
+ `agents.per_agent.<name>.effort ?? agents.default.effort` is passed as the
139
+ spawn's effort parameter; with none, the bundled agents run at their
140
+ frontmatter's `effort: max`, and the clerk at its `effort: low`. A level outside `low`, `medium`, `high`,
141
+ `xhigh`, `max` is written with a warning and refused by the spawn. Do not
142
+ write a copy to achieve an effort.
138
143
  6. **Honesty notes to print**: an org `availableModels` allowlist silently
139
144
  downgrades excluded models; the `CLAUDE_CODE_SUBAGENT_MODEL` env var
140
- overrides everything configured here, per-invocation parameter included.
145
+ overrides everything configured here, per-invocation parameter included;
146
+ `CLAUDE_CODE_EFFORT_LEVEL` overrides every configured effort, and a
147
+ `maxEffortLevel` setting or an organization's effort cap still limits the
148
+ level an agent runs at.
141
149
  `/projectstore:doctor` validates config shape and reports leftover copies โ€”
142
150
  not entitlement, and not whether a given spawn actually passed the model.
143
151
  7. **No restart is needed** โ€” nothing about the agent list changed. The model
@@ -154,16 +162,17 @@ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" agents model <name> --json --p
154
162
  ```
155
163
 
156
164
  and passes `result.model` as the spawn's model parameter โ€” `null` means pass
157
- nothing, the agent's own frontmatter decides. The verb applies
158
- `agents.per_agent.<name>.model ?? agents.default.model ?? null` over
165
+ nothing, the agent's own frontmatter decides โ€” and `result.effort` as its
166
+ effort parameter when it is not `null` and the spawn offers one. The verb applies
167
+ `agents.per_agent.<name>.model ?? agents.default.model ?? null` (and the same
168
+ two terms for `effort`) over
159
169
  `<project>/.projectstore/harness/<harness>.json` (the active harness's
160
170
  overlay); besides the agents block itself (harness-neutral prose with no bin
161
171
  to call โ€” it states the rule as a file read, deliberately), nothing else
162
172
  restates that rule. Never guess a model.
163
173
 
164
174
  `agents.default` is optional and often absent (a per-agent-only config is normal);
165
- the resolution must tolerate that. An `effort` key, if present, is a pre-ADR-008
166
- leftover: ignore it.
175
+ the resolution must tolerate that, and so must an effort set without a model.
167
176
 
168
177
  **Coverage, stated honestly.** This reaches spawns made by this plugin's commands
169
178
  and spawns a session makes while following the registration block. It does *not*
@@ -174,7 +183,10 @@ path, at the cost of applying to every subagent on the machine.
174
183
 
175
184
  ## Notes
176
185
 
177
- - Uninstalling the plugin removes these commands but NOT the block โ€” run
186
+ - `/plugin uninstall` removes these commands but NOT the block โ€” run
178
187
  `unregister` first, or delete everything between the
179
- `<!-- projectstore:agents -->` markers by hand.
188
+ `<!-- projectstore:agents -->` markers by hand. From a terminal in the
189
+ project, the package's bare `uninstall` removes the block too. A one-harness
190
+ `--harness` run keeps a block in `AGENTS.md` that another harness still
191
+ reads; `uninstall --surface agents_block` removes it outright.
180
192
  - Never write any file without AskUserQuestion approval.
@@ -111,7 +111,7 @@ Steps:
111
111
 
112
112
  8. **Agent registration** (v0.13, ADR-002): ask via AskUserQuestion โ€” "Register projectstore's agents in CLAUDE.md/AGENTS.md so every session routes to them (critic after authoring artifacts, planner before implementing, reviewer before commit)? [Yes (Recommended) / No]". On Yes, run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" install --harness claude-code --surface agents_block --project "${CLAUDE_PROJECT_DIR}"` and print its output (it renders from the layout's roster, migrates rather than duplicates, previews every write, and applies because the harness is named). On a rebind where a block already exists the verb reports it current or replaces it in place โ€” do not re-ask blindly.
113
113
 
114
- 9. **Agent model preset** (v0.13, ADR-003; mechanism per ADR-008): ask via AskUserQuestion โ€” include this line in the question text: *"These agents don't write code โ€” they are critics, planners, and reviewers; they perform best on strong models at high effort."* Options: **Keep bundled default โ€” opus** (Recommended) / **fable** / **sonnet**. Do not offer `inherit` โ€” it cannot be expressed per invocation (see `commands/agents.md`). Do not offer effort โ€” it is not configurable per project (the bundled agents already run at `max`). Free-form model IDs and per-agent tuning live in `/projectstore:agents configure` โ€” mention it. A non-default choice runs the `configure` apply flow from `commands/agents.md`, which writes the config only โ€” **never an agent copy**. Skippable.
114
+ 9. **Agent model preset** (v0.13, ADR-003; mechanism per ADR-008): ask via AskUserQuestion โ€” include this line in the question text: *"These agents don't write code โ€” they are critics, planners, and reviewers; they perform best on strong models at high effort."* Options: **Keep bundled default โ€” opus** (Recommended) / **fable** / **sonnet**. Do not offer `inherit` โ€” it cannot be expressed per invocation (see `commands/agents.md`). Do not ask effort here โ€” until one is set, the bundled agents run at their frontmatter's `max`, and the clerk at `low`. Free-form model IDs, per-agent tuning and each agent's effort live in `/projectstore:agents configure` โ€” mention it. A non-default choice runs the `configure` apply flow from `commands/agents.md`, which writes the config only โ€” **never an agent copy**. Skippable.
115
115
 
116
116
  10. **Print summary**: confirm the bind, list the layout's folders, suggest next commands (`/projectstore:status`, `/projectstore:adr "<first decision>"`, `/projectstore:epic <ID> "<title>"`).
117
117
 
@@ -106,13 +106,21 @@ You are running projectstore diagnostics (ADR-005: umbrella doctor).
106
106
  verbatim, run from a terminal outside this session.
107
107
  - `overlay-forbidden-key` / `overlay-unparseable` (issue) โ†’
108
108
  `.projectstore/harness/<id>.json` carries a key an overlay may not (only
109
- `agents.default.model` and `agents.per_agent.<name>.model` are read) or is
109
+ `agents.default.model`, `agents.default.effort`,
110
+ `agents.per_agent.<name>.model` and `agents.per_agent.<name>.effort` are
111
+ read) or is
110
112
  not JSON. Print the finding. A key inside the agents block goes away on the
111
113
  next `/projectstore:agents configure` write; a key outside it, and a parse
112
114
  error, are the user's to edit โ€” never rewrite the file yourself.
113
115
  - `overlay-unknown-agent` (warn) โ†’ the overlay configures a name no roster
114
116
  agent carries (a typo, or a newer package's agent): nothing runs under it.
115
- Point at `/projectstore:agents configure` with the roster's names.
117
+ Point at `/projectstore:agents configure` with the roster's names; a name
118
+ outside the roster is refused by both writers, so removing one is
119
+ `agents configure --reset` or the user's own edit of the file.
120
+ - `overlay-unknown-effort` (warn) โ†’ the overlay sets an effort the harness's
121
+ levels lack (a typo, or a leftover such as `Max`): a spawn may refuse it.
122
+ Point at `/projectstore:agents configure`, which writes efforts through
123
+ `configure --set agents.<name>.effort=<level>`; `-` clears one.
116
124
  - `plugin-registration` (info) โ†’ nothing to repair; it names where the npm
117
125
  registration loads from. As an **issue** โ€” stale, or two enabled copies โ€”
118
126
  print the finding and relay its command verbatim (the package runner's
@@ -128,7 +136,11 @@ You are running projectstore diagnostics (ADR-005: umbrella doctor).
128
136
  - `harness` (info) โ†’ nothing to repair; it names what `install` can target.
129
137
  - `mcp` โ†’ the plugin-bundled `.mcp.json` is missing or does not launch
130
138
  `bin/projectstore.mjs mcp`: the install is incomplete โ€” the fix is the
131
- host's update path (`/plugin update`), never a hand-written file.
139
+ update for the channel this copy was installed through (`/plugin update`
140
+ for a git-marketplace copy; for the npm registration, the package's
141
+ `upgrade` from a terminal in the project, outside this session โ€” the
142
+ `plugin-registration` finding spells the command), never a hand-written
143
+ file.
132
144
  - `override-copies` โ†’ a copy carrying the provenance marker overrides nothing
133
145
  (ADR-008): offer to **delete** it (approval-gated, one prompt per file), and
134
146
  say that `/projectstore:agents configure` now records the model in
@@ -38,8 +38,8 @@ You are reconciling the vault's derived views with their source of truth (frontm
38
38
  content is authored by the context-holder, the write ceremony by a clerk").
39
39
  When the approved set contains two or more targets, hand steps 6-7 to
40
40
  `projectstore:clerk`: pass the exact selector list from step 4's preview and
41
- the expectation that doctor ends clean. **Model (ADR-008)**: resolve
42
- the model 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);
41
+ the expectation that doctor ends clean. **Model and effort (ADR-008)**: resolve
42
+ them 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), and `result.effort` as its effort parameter when it is not `null` and the spawn offers one;
43
43
  missing key, `inherit`, or unreadable config โ†’ pass nothing and let the
44
44
  agent's own frontmatter decide; never guess a model. The clerk applies
45
45
  through the core exactly as step 6 specifies and reports per target. A single
@@ -64,7 +64,7 @@ You are running a peer review on a projectstore artifact.
64
64
 
65
65
  Set the agent description to: `Peer-review of {{kind}} artifact at {{path}}`. Pass it as a foreground task (you need the result to continue).
66
66
 
67
- **Model (ADR-008)**: resolve it with `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" agents model critic --json --project "${CLAUDE_PROJECT_DIR}"` and pass `result.model` as the spawn's model parameter (`null` โ†’ pass nothing). Missing key, `inherit`, or unreadable config โ†’ pass nothing and let the agent's own frontmatter decide; never guess a model. This is the only way the configured model reaches the agent โ€” there are no override copies (`/projectstore:agents configure`). When falling back to `oh-my-claudecode:critic` or `general-purpose`, pass the same model.
67
+ **Model and effort (ADR-008)**: resolve them with `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" agents model critic --json --project "${CLAUDE_PROJECT_DIR}"` and pass `result.model` as the spawn's model parameter (`null` โ†’ pass nothing), and `result.effort` as its effort parameter when it is not `null` and the spawn offers one. Missing key, `inherit`, or unreadable config โ†’ pass nothing and let the agent's own frontmatter decide; never guess a model. This is the only way the configured model and effort reach the agent โ€” there are no override copies (`/projectstore:agents configure`). When falling back to `oh-my-claudecode:critic` or `general-purpose`, pass the same model and effort.
68
68
 
69
69
  7. **Show findings**: print the agent's report verbatim. Number is its number.
70
70
 
@@ -80,7 +80,8 @@ the two cannot collide).
80
80
  files with different jobs: the scratch is what gets copied to the target;
81
81
  the baseline is what `--check` compares against. Handing `--check` the
82
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).
83
+ - **Model and effort (ADR-008)**: resolve them 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
+ and `result.effort` as its effort parameter when it is not `null` and the spawn offers one.
84
85
  Missing key, `inherit`, or unreadable config โ†’ pass nothing and let the
85
86
  agent's own frontmatter decide; never guess a model.
86
87
  - Capture doctor's summary line (`node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" doctor
@@ -97,7 +97,7 @@ After setup, every setting is one command away, from a terminal in your project:
97
97
  npx projectstore configure
98
98
  ```
99
99
 
100
- At a terminal it opens a settings menu: each agent's model, the status line and the band, the template language, and the vault's spec policy and lifecycle gates. โ†‘ and โ†“ move, โ†’ opens, space chooses, โ† goes back, and Enter shows one plan; a second Enter writes it. A model is chosen from its harness's list: Claude Code's aliases, or Codex's own models. Without a terminal it prints the settings with their values and the file each one lives in. From a script or an agent, name the change; naming it is the confirmation:
100
+ At a terminal it opens a settings menu: each agent's model and effort, the status line and the band, the template language, and the vault's spec policy and lifecycle gates. โ†‘ and โ†“ move, โ†’ opens, space chooses, โ† goes back, and Enter shows one plan; a second Enter writes it. A model is chosen from its harness's list: Claude Code's aliases, or Codex's own models. Without a terminal it prints the settings with their values and the file each one lives in. From a script or an agent, name the change; naming it is the confirmation:
101
101
 
102
102
  ```
103
103
  npx projectstore configure --set language=de --set lifecycle_gates=on
@@ -138,8 +138,9 @@ What is known, and how:
138
138
  - **Roles are rendered as orchestration skills.** Codex spawns subagents through
139
139
  its collaboration tool, not by loading a plugin's `agents/` directory. The
140
140
  six ProjectStore roles therefore ship as namespaced skills that resolve their
141
- configured model through the core and ask Codex to spawn the role. No effort
142
- is forced: it inherits unless the user has configured a model policy.
141
+ configured model and effort through the core and ask Codex to spawn the role
142
+ with them. With no effort configured, a role spawned on a configured model
143
+ runs at that model's own default level.
143
144
  - **Multi-file edits reach the activity log and entry rule when their paths
144
145
  are absolute.** Codex's `apply_patch` carries paths inside
145
146
  `tool_input.command`; the shared extractor reads every `Add`, `Update`,
@@ -49,7 +49,7 @@
49
49
  {
50
50
  "env": "CLAUDE_CODE_EFFORT_LEVEL",
51
51
  "kind": "effort",
52
- "beats": "agent frontmatter"
52
+ "beats": "the spawn's effort parameter and agent frontmatter: with it set, the Agent tool offers no effort parameter at all (measured 2026-10-14, 2.1.296)"
53
53
  },
54
54
  {
55
55
  "env": "CLAUDE_CODE_SUBAGENT_MODEL",
@@ -534,6 +534,45 @@
534
534
  "cheap_model": "sonnet",
535
535
  "cheap_model_evidence": "measured",
536
536
  "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.",
537
+ "effort": {
538
+ "spawn_param": "effort",
539
+ "spawn_param_evidence": "measured",
540
+ "spawn_param_reason": "The Agent tool's `effort` parameter, an enum of the five levels below, in the tool schema Claude Code 2.1.296 gave a session on 2026-10-14 (documented from 2.1.292). A plugin agent with `effort: max` in its frontmatter, spawned with `effort: \"xhigh\"`, ran every request at xhigh; spawned with none, at max (subagent transcripts). An off-enum level fails the tool's schema and no subagent starts. So the overlay's effort is passed here, as the model is (the ADR \"Agent effort is passed at spawn beside the model, from the overlay, in each harness's own levels\", decision 2).",
541
+ "levels": [
542
+ {
543
+ "id": "low",
544
+ "description": "The fastest and cheapest: little thinking before an answer."
545
+ },
546
+ {
547
+ "id": "medium",
548
+ "description": "Balances speed and depth: thinks where the task needs it."
549
+ },
550
+ {
551
+ "id": "high",
552
+ "description": "Thinks longer before answering, for harder work."
553
+ },
554
+ {
555
+ "id": "xhigh",
556
+ "description": "Extended thinking for hard reviews, plans and designs."
557
+ },
558
+ {
559
+ "id": "max",
560
+ "description": "The most thinking Claude Code allows: the level the bundled agents' frontmatter names, the clerk's excepted."
561
+ }
562
+ ],
563
+ "levels_reason": "The Agent tool's enum, measured. Claude Code lowers a level a model does not support to the highest one it does (documented), so one list serves every alias and no catalog is read.",
564
+ "strict": true,
565
+ "strict_reason": "The spawn takes these levels and nothing else: an off-enum level (ultra) failed the Agent tool's schema and no subagent started (measured 2026-10-14, 2.1.296). So a level off this list is written with a note that the spawn refuses it.",
566
+ "unset": {
567
+ "value": "frontmatter",
568
+ "row": "use frontmatter",
569
+ "model_default": false,
570
+ "reason": "With no effort passed, the agent runs at its frontmatter's effort โ€” max for every bundled agent but the clerk, which runs at low โ€” whatever model is passed (transcripts of 2026-10-11/12)."
571
+ },
572
+ "cheap": "low",
573
+ "cheap_evidence": "chosen",
574
+ "cheap_reason": "The clerk's level, in its frontmatter and as its pin under a default effort (the effort ADR, decision 6): it copies an approved file and runs a pinned ceremony. Chosen by the maintainer on 2026-10-14 (\"ะบะปะตั€ะบะฐ ะดะฐ ะฝะฐ ะปะพัƒ\"), as on Codex."
575
+ },
537
576
  "models": {
538
577
  "spawn_takes": "alias",
539
578
  "spawn_takes_evidence": "measured",
@@ -339,25 +339,61 @@
339
339
  "update_instructions": "From a terminal in the project, run `npx projectstore@<version> upgrade --harness codex` and restart Codex afterwards, so the new skills and hooks are loaded. The run fetches the shell at that version, atomically replaces its stable source, and `codex plugin add projectstore@projectstore-npx` materialises the new version; this was measured across two dev builds on codex-cli 0.153.4.",
340
340
  "agent_translation": {
341
341
  "carries_model": false,
342
- "carries_model_reason": "The surface projectstore ships โ€” a plugin's agents/ entry โ€” carries no model on Codex: surfaces.agents is supported:false because no route from a plugin's agents/ directory to collaborationspawn_agent has been found (measured). Codex DOES have a definition file that carries model and effort, recorded below, but it is project- or user-scoped and not plugin-shippable, so contract 12 holds as written: what we ship cannot carry a model. Was true here until 2026-09-08, which contradicted both contract 12 and this file's own agents row.",
342
+ "carries_model_reason": "The surface projectstore ships โ€” a plugin's agents/ entry โ€” carries no model on Codex: surfaces.agents is supported:false because no route from a plugin's agents/ directory to collaborationspawn_agent has been found (measured). Codex DOES have a definition file that carries model and effort, recorded below, but it is project- or user-scoped and not plugin-shippable, so contract 12 holds as written: what we ship cannot carry a model. Was true here until 2026-09-08, which contradicted both contract 12 and this file's own agents row. What the plugin's role skills pass instead is a value at spawn: `spawn_agent` takes `model` and `reasoning_effort` (measured 2026-10-14, effort block below).",
343
343
  "definition_file": ".codex/agents/<name>.toml",
344
344
  "definition_file_evidence": "documented",
345
- "definition_file_reason": "Codex agent definitions are TOML under .codex/agents/ (project) or ~/.codex/agents/ (personal) and accept `model`, `model_reasoning_effort`, `sandbox_mode` and `mcp_servers`. Documented at learn.chatgpt.com/docs/agent-configuration/subagents, read 2026-09-08; NOT measured, and not reachable from a plugin today. This is the route the rendering story (Per-agent effort returns, PS-AGENTS) has to decide on, and B4 has to measure.",
345
+ "definition_file_reason": "Codex agent definitions are TOML under .codex/agents/ (project) or ~/.codex/agents/ (personal) and accept `model`, `model_reasoning_effort`, `sandbox_mode` and `mcp_servers`. Documented at learn.chatgpt.com/docs/agent-configuration/subagents, read 2026-09-08; NOT measured, and not reachable from a plugin. Not used: the spawn carries model and effort, so no definition is rendered (the ADR \"Agent effort is passed at spawn beside the model, from the overlay, in each harness's own levels\", alternative A).",
346
346
  "cheap_model": "gpt-5.6-luna",
347
347
  "cheap_model_evidence": "chosen",
348
348
  "cheap_model_reason": "CHOSEN, not measured: the verified plugin session exercised the rendered skill surface, not this optional model pin. It reaches a user's overlay โ€” `agents configure --harness codex` writes it as the clerk's pin โ€” so if the id is wrong the failure is at spawn time, on the harness, not here. The transcriber's model. gpt-5.6-luna at $0.20/$1.20 per Mtok is the cost tier gpt-5.6-sol ($4/$20) is twenty times above, and the clerk composes nothing: it copies an approved file and runs a pinned ceremony (ADR-008). Chosen 2026-09-08 from the published model list, by the same reasoning that pins the clerk to the cheap tier on Claude Code.",
349
- "effort_levels": [
350
- "low",
351
- "medium",
352
- "high",
353
- "xhigh",
354
- "max",
355
- "ultra"
356
- ],
357
- "effort_key": "model_reasoning_effort",
358
- "effort_evidence": "documented",
359
- "effort_precedence": "explicit spawn value, then the [agents] default from config, then the parent agent's value. A model chosen without an effort uses that model's default effort.",
360
- "effort_reason": "Recorded, not yet consumed: the overlay's allowlist rejects an effort key and rewrites it out, deliberately, until the story Per-agent effort returns decides whether a role's effort travels in a rendered definition or at spawn. Documented 2026-09-08; the `ultra` level is Codex's and is not a level Claude Code accepts.",
349
+ "effort": {
350
+ "spawn_param": "reasoning_effort",
351
+ "spawn_param_evidence": "measured",
352
+ "spawn_param_reason": "`collaboration.spawn_agent` takes `reasoning_effort` beside `model`. Measured on codex-cli 0.162.1, 2026-10-14: a parent on gpt-5.6-sol at xhigh spawned gpt-5.6-luna at low, and the child's first turn_context reads gpt-5.6-luna, low. An effort with no model ran the parent's model at that effort.",
353
+ "levels": [
354
+ {
355
+ "id": "low",
356
+ "description": "Fast responses with lighter reasoning."
357
+ },
358
+ {
359
+ "id": "medium",
360
+ "description": "Balances speed and reasoning depth for everyday tasks."
361
+ },
362
+ {
363
+ "id": "high",
364
+ "description": "Greater reasoning depth for complex problems."
365
+ },
366
+ {
367
+ "id": "xhigh",
368
+ "description": "Extra high reasoning depth for complex problems."
369
+ },
370
+ {
371
+ "id": "max",
372
+ "description": "Maximum reasoning depth for the hardest problems."
373
+ },
374
+ {
375
+ "id": "ultra",
376
+ "description": "Maximum reasoning with automatic task delegation; not every model takes it."
377
+ }
378
+ ],
379
+ "levels_reason": "The floor, offered when the agent's model is not in a list that names its own levels: every level Codex's catalog listed on 2026-10-14, in its own words. Not every model takes every level (gpt-5.6-luna stops at max), which is why a listed model's own levels win.",
380
+ "catalog": {
381
+ "list": "supported_reasoning_levels",
382
+ "id": "effort",
383
+ "description": "description",
384
+ "default": "default_reasoning_level",
385
+ "reason": "Fields of a model entry in Codex's own catalog (models_cache.json, `codex debug models`), measured 2026-10-14 on codex-cli 0.162.1: each model lists the levels it takes as { effort, description } and names its default."
386
+ },
387
+ "unset": {
388
+ "value": "Codex decides",
389
+ "row": "let Codex decide",
390
+ "model_default": true,
391
+ "reason": "With no effort passed and a model passed, the child runs at that model's own default level, not the parent's: gpt-5.6-sol ran at low under an xhigh parent (measured 2026-10-14; Codex's subagents documentation says the same). With no model passed either, Codex's [agents] default, then the parent's effort (documented)."
392
+ },
393
+ "cheap": "low",
394
+ "cheap_evidence": "chosen",
395
+ "cheap_reason": "The clerk's level under a default effort (the ADR \"Agent effort is passed at spawn beside the model, from the overlay, in each harness's own levels\", decision 6): it copies an approved file and runs a pinned ceremony. Chosen by the maintainer on 2026-09-08 with its model: gpt-5.6-luna at the lowest level."
396
+ },
361
397
  "models": {
362
398
  "spawn_takes": "id",
363
399
  "spawn_takes_evidence": "documented",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projectstore",
3
- "version": "0.30.2",
3
+ "version": "0.30.3",
4
4
  "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.",
5
5
  "keywords": [
6
6
  "project-management",
@@ -7,9 +7,20 @@ import { harnessForOverlay } from "./harness.mjs";
7
7
 
8
8
  // What a change would write. `before` is readOverlayAt's read; `roster` the
9
9
  // layout's agent names (null when no layout loads); `agents` the
10
- // `<name>=<model>` specs. A malformed spec or a name outside the roster comes
11
- // back as `usage`, with nothing planned.
12
- export function planAgentsChange({ before, harness, layout, roster, defaultModel, agents = [], reset = false }) {
10
+ // `<name>=<model>` specs; `defaultEffort` and `efforts` (`<name>=<level>`)
11
+ // the same for effort (the effort ADR, decision 8). A malformed spec or a name
12
+ // outside the roster comes back as `usage`, with nothing planned.
13
+ export function planAgentsChange({
14
+ before,
15
+ harness,
16
+ layout,
17
+ roster,
18
+ defaultModel,
19
+ agents = [],
20
+ defaultEffort,
21
+ efforts = [],
22
+ reset = false,
23
+ }) {
13
24
  // --reset empties the block first; --default and --agent then apply on top of
14
25
  // the emptied block โ€” "reset, then set" is one call, and nothing given is
15
26
  // silently dropped.
@@ -27,6 +38,22 @@ export function planAgentsChange({ before, harness, layout, roster, defaultModel
27
38
  if (m[2]) next.per_agent[m[1]] = m[2];
28
39
  else delete next.per_agent[m[1]];
29
40
  }
41
+ // Efforts, field by field beside the models: a run that names none keeps
42
+ // every effort the overlay holds, and --reset empties them with the models.
43
+ const beforeEfforts = before.efforts || { default: null, per_agent: {} };
44
+ const baseEfforts = reset ? { default: null, per_agent: {} } : beforeEfforts;
45
+ const nextEfforts = {
46
+ default: defaultEffort !== undefined ? defaultEffort || null : baseEfforts.default,
47
+ per_agent: { ...baseEfforts.per_agent },
48
+ };
49
+ for (const spec of efforts) {
50
+ const m = /^([a-z][a-z0-9-]*)=(.*)$/.exec(spec);
51
+ if (!m) return { usage: `an effort takes <name>=<level>, got ${spec}` };
52
+ if (roster && !roster.includes(m[1]))
53
+ return { usage: `no agent named ${m[1]} in the ${layout} roster โ€” known: ${roster.join(", ")}` };
54
+ if (m[2]) nextEfforts.per_agent[m[1]] = m[2];
55
+ else delete nextEfforts.per_agent[m[1]];
56
+ }
30
57
  // The clerk transcribes; a strong default must not lift it (commands/agents.md,
31
58
  // ADR-008). WHICH model it is pinned to is the harness's vocabulary, so the
32
59
  // manifest names it and this file does not: pinning every harness to
@@ -49,12 +76,29 @@ export function planAgentsChange({ before, harness, layout, roster, defaultModel
49
76
  pinnedClerk = true;
50
77
  } else clerkPinUnavailable = true;
51
78
  }
52
- // Keys inside the agents block that the allowlist rejected (an `effort`, a
53
- // stray shape) are rewritten out by the write and announced here; keys
54
- // outside the block are kept, and stay doctor's to name.
79
+ // The clerk's effort, pinned the same way while a default effort stands
80
+ // (the effort ADR, decision 6), where the harness names a cheap level; a
81
+ // harness that names none pins nothing and says nothing, because its clerk
82
+ // already runs at its frontmatter's level.
83
+ let pinnedClerkEffort = false;
84
+ const clerkEffortAsked = efforts.some((s) => s.startsWith("clerk="));
85
+ if (nextEfforts.default && !nextEfforts.per_agent.clerk && !clerkEffortAsked) {
86
+ const cheap = harnessForOverlay(harness)?.agent_translation?.effort?.cheap || null;
87
+ if (cheap) {
88
+ nextEfforts.per_agent.clerk = cheap;
89
+ pinnedClerkEffort = true;
90
+ }
91
+ }
92
+ // Keys inside the agents block that the allowlist rejected (a stray shape)
93
+ // are rewritten out by the write and announced here; keys outside the block
94
+ // are kept, and stay doctor's to name.
55
95
  const dropped = before.rejected.filter((k) => k.startsWith("agents."));
96
+ const sameEfforts =
97
+ JSON.stringify({ d: beforeEfforts.default, p: beforeEfforts.per_agent }) ===
98
+ JSON.stringify({ d: nextEfforts.default, p: nextEfforts.per_agent });
56
99
  const same =
57
100
  !dropped.length &&
101
+ sameEfforts &&
58
102
  JSON.stringify({ d: before.agents.default, p: before.agents.per_agent }) ===
59
103
  JSON.stringify({ d: next.default, p: next.per_agent });
60
104
  const preview = [
@@ -72,13 +116,23 @@ export function planAgentsChange({ before, harness, layout, roster, defaultModel
72
116
  preview.push(
73
117
  ` clerk: takes the default โ€” ${harness} declares no cheap model to pin it to, so name one with --agent clerk=<model>`,
74
118
  );
119
+ // Effort lines only where an effort is held or asked for, so a run over an
120
+ // overlay of models alone previews exactly as it did before efforts.
121
+ if (beforeEfforts.default || nextEfforts.default)
122
+ preview.push(` default effort: ${beforeEfforts.default || "โ€”"} โ†’ ${nextEfforts.default || "โ€”"}`);
123
+ const effortNames = new Set([...Object.keys(beforeEfforts.per_agent), ...Object.keys(nextEfforts.per_agent)]);
124
+ for (const n of [...effortNames].sort())
125
+ preview.push(
126
+ ` ${n} effort: ${beforeEfforts.per_agent[n] || "โ€”"} โ†’ ${nextEfforts.per_agent[n] || "โ€”"}${pinnedClerkEffort && n === "clerk" ? " (pinned: the clerk stays cheap under a strong default)" : ""}`,
127
+ );
75
128
  if (dropped.length)
76
- preview.push(` drops from the agents block (an overlay carries only models): ${dropped.join(", ")}`);
77
- return { next, pinnedClerk, clerkPinUnavailable, dropped, same, preview };
129
+ preview.push(` drops from the agents block (an overlay carries only models and efforts): ${dropped.join(", ")}`);
130
+ return { next, nextEfforts, pinnedClerk, pinnedClerkEffort, clerkPinUnavailable, dropped, same, preview };
78
131
  }
79
132
 
80
133
  // Writes a planned change through the overlay's one writer and reads it back.
81
- export function applyAgentsChange(projectDir, harness, next) {
82
- const path = writeOverlayAt(projectDir, harness, next);
134
+ // `nextEfforts` left out keeps the efforts the file holds.
135
+ export function applyAgentsChange(projectDir, harness, next, nextEfforts) {
136
+ const path = writeOverlayAt(projectDir, harness, next, nextEfforts);
83
137
  return { path, after: readOverlayAt(projectDir, harness) };
84
138
  }