valent-pipeline 0.5.0 → 0.5.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/bin/cli.js +43 -0
- package/package.json +1 -1
- package/pipeline/orchestrators/claude-code/plan.workflow.js +22 -0
- package/pipeline/orchestrators/claude-code/retro.workflow.js +27 -4
- package/pipeline/orchestrators/claude-code/sprint.workflow.js +32 -2
- package/skills/valent-configure/SKILL.md +16 -0
- package/skills/valent-help/SKILL.md +3 -0
- package/skills/valent-review-cost/SKILL.md +69 -0
- package/skills/valent-run-epic-workflow/SKILL.md +4 -4
- package/skills/valent-run-project-workflow/SKILL.md +4 -4
- package/skills/valent-run-story-workflow/SKILL.md +4 -3
- package/src/board/public/app.js +377 -0
- package/src/board/public/index.html +62 -0
- package/src/board/public/styles.css +542 -0
- package/src/board/server.js +209 -0
- package/src/commands/audit.js +190 -0
- package/src/commands/board.js +102 -0
- package/src/commands/init.js +11 -0
- package/src/commands/status.js +122 -0
- package/src/lib/audit.js +192 -0
- package/src/lib/board-source.js +138 -0
- package/src/lib/board.js +219 -0
- package/src/lib/config-schema.js +23 -0
package/bin/cli.js
CHANGED
|
@@ -41,6 +41,49 @@ program
|
|
|
41
41
|
await upgrade(options);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
+
// status command — board read-model (composes pipeline-state.json + backlog + artifacts)
|
|
45
|
+
program
|
|
46
|
+
.command('status')
|
|
47
|
+
.description('Show pipeline status as a board read-model (human summary, or --json for the board-state contract)')
|
|
48
|
+
.option('--json', 'Emit the board-state JSON contract to stdout (for a board/notifier/CI)')
|
|
49
|
+
.option('--out <path>', 'Write the board-state JSON to a file (e.g. board-state.json for a board to watch)')
|
|
50
|
+
.option('--root <dir>', 'Project root to inspect (defaults to the current directory)')
|
|
51
|
+
.option('--no-audit', 'Skip merging the per-agent token/wall-clock audit trail into the board')
|
|
52
|
+
.action(async (options) => {
|
|
53
|
+
const { statusCmd } = await import('../src/commands/status.js');
|
|
54
|
+
await statusCmd(options);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// board command — serves the read-only board SPA + read API (a projection, never a write path)
|
|
58
|
+
program
|
|
59
|
+
.command('board')
|
|
60
|
+
.description('Serve a read-only board UI (Backlog + Kanban) over a local HTTP server')
|
|
61
|
+
.option('--port <n>', 'Port to listen on (default 7777)', '7777')
|
|
62
|
+
.option('--host <addr>', 'Host/interface to bind (default 127.0.0.1; 0.0.0.0 warns loudly)', '127.0.0.1')
|
|
63
|
+
.option('--root <dir>', 'Project root to project the board over (defaults to the current directory)')
|
|
64
|
+
.option('--open', 'Open the board in the default browser once it is listening')
|
|
65
|
+
.option('--no-audit', 'Skip merging the per-agent token/wall-clock cost trail into the board')
|
|
66
|
+
.action(async (options) => {
|
|
67
|
+
const { boardCmd } = await import('../src/commands/board.js');
|
|
68
|
+
await boardCmd(options);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// audit command — per-agent, per-story token + wall-clock trail (reads Workflow journals)
|
|
72
|
+
program
|
|
73
|
+
.command('audit')
|
|
74
|
+
.description('Per-agent, per-story audit trail (tokens + wall-clock), read from Workflow run journals')
|
|
75
|
+
.option('--story <id>', 'Filter to a single story')
|
|
76
|
+
.option('--run <runId>', 'Filter to a single workflow run')
|
|
77
|
+
.option('--json', 'Emit the audit JSON contract to stdout')
|
|
78
|
+
.option('--out <path>', 'Write the audit JSON to a file')
|
|
79
|
+
.option('--file <path>', 'Audit a single workflow journal file (wf_*.json)')
|
|
80
|
+
.option('--session-dir <dir>', 'Scan a specific session dir\'s workflows/ folder')
|
|
81
|
+
.option('--project-dir <dir>', 'Project dir whose ~/.claude/projects session journals to read (default: cwd)')
|
|
82
|
+
.action(async (options) => {
|
|
83
|
+
const { auditCmd } = await import('../src/commands/audit.js');
|
|
84
|
+
await auditCmd(options);
|
|
85
|
+
});
|
|
86
|
+
|
|
44
87
|
// config validate command
|
|
45
88
|
const configCmd = program
|
|
46
89
|
.command('config')
|
package/package.json
CHANGED
|
@@ -166,10 +166,32 @@ const MODELS = buildModelMap(a.models)
|
|
|
166
166
|
// undefined => the agent inherits the main-loop (session) model.
|
|
167
167
|
const modelFor = (role) => MODELS[String(role).toUpperCase()]
|
|
168
168
|
|
|
169
|
+
// --- per-agent reasoning effort (thinking budget) ----------------------------
|
|
170
|
+
// Optional, config-driven, mirrors `models`. args.reasoning is a level->roles map inverted to
|
|
171
|
+
// role->trigger-phrase. EMPTY default => no trigger injected unless the config opts in, so
|
|
172
|
+
// behavior is unchanged out of the box. Static + args only => journal-replay safe.
|
|
173
|
+
const REASONING_PHRASES = { think: 'think', 'think-hard': 'think hard', 'think-harder': 'think harder', ultrathink: 'ultrathink' }
|
|
174
|
+
const DEFAULT_REASONING = {} // blank control surface — fill `reasoning` in pipeline-config.yaml to use it
|
|
175
|
+
function buildReasoningMap(cfg) {
|
|
176
|
+
const map = { ...DEFAULT_REASONING }
|
|
177
|
+
if (cfg && typeof cfg === 'object' && !Array.isArray(cfg)) {
|
|
178
|
+
for (const level of Object.keys(REASONING_PHRASES)) {
|
|
179
|
+
for (const role of cfg[level] || []) {
|
|
180
|
+
if (typeof role === 'string') map[role.toUpperCase()] = REASONING_PHRASES[level]
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return map
|
|
185
|
+
}
|
|
186
|
+
const REASONING = buildReasoningMap(a.reasoning)
|
|
187
|
+
const reasoningFor = (role) => REASONING[String(role).toUpperCase()]
|
|
188
|
+
|
|
169
189
|
function buildPrompt({ role, promptFile, storyId, taskSubject, trigger, returnContract }) {
|
|
170
190
|
const outputDir = `stories/${storyId}/output`
|
|
191
|
+
const think = reasoningFor(role) // undefined unless config opts this role into a thinking tier
|
|
171
192
|
return [
|
|
172
193
|
`You are **${role}**, for story ${storyId} in the valent-pipeline (sprint ${sprintId} planning).`,
|
|
194
|
+
...(think ? ['', `Before you act, ${think} about the hardest parts of this task.`] : []),
|
|
173
195
|
'',
|
|
174
196
|
'## Setup',
|
|
175
197
|
`1. Read your core prompt: \`.valent-pipeline/prompts/${promptFile}\` — identity, protocols, step sequence.`,
|
|
@@ -157,10 +157,33 @@ const MODELS = buildModelMap(a.models)
|
|
|
157
157
|
// undefined => the agent inherits the main-loop (session) model.
|
|
158
158
|
const modelFor = (role) => MODELS[String(role).toUpperCase()]
|
|
159
159
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
// --- reasoning effort (thinking budget) --------------------------------------
|
|
161
|
+
// Optional, config-driven, mirrors `models`. args.reasoning is a level->roles map inverted to
|
|
162
|
+
// role->trigger-phrase. EMPTY default => nothing injected unless the config opts in. Every agent
|
|
163
|
+
// here shares the RETROSPECTIVE identity, so the knob keys on that role. Static + args only.
|
|
164
|
+
const REASONING_PHRASES = { think: 'think', 'think-hard': 'think hard', 'think-harder': 'think harder', ultrathink: 'ultrathink' }
|
|
165
|
+
const DEFAULT_REASONING = {} // blank control surface — fill `reasoning` in pipeline-config.yaml to use it
|
|
166
|
+
function buildReasoningMap(cfg) {
|
|
167
|
+
const map = { ...DEFAULT_REASONING }
|
|
168
|
+
if (cfg && typeof cfg === 'object' && !Array.isArray(cfg)) {
|
|
169
|
+
for (const level of Object.keys(REASONING_PHRASES)) {
|
|
170
|
+
for (const role of cfg[level] || []) {
|
|
171
|
+
if (typeof role === 'string') map[role.toUpperCase()] = REASONING_PHRASES[level]
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return map
|
|
176
|
+
}
|
|
177
|
+
const REASONING = buildReasoningMap(a.reasoning)
|
|
178
|
+
const reasoningFor = (role) => REASONING[String(role).toUpperCase()]
|
|
179
|
+
|
|
180
|
+
const retroPrompt = (instruction, returnContract) => {
|
|
181
|
+
const think = reasoningFor('RETROSPECTIVE') // undefined unless config opts RETROSPECTIVE into a tier
|
|
182
|
+
return `You are **RETROSPECTIVE**, analyzing story batch ${batchNumber} in the valent-pipeline. ` +
|
|
183
|
+
(think ? `Before you act, ${think} about the hardest parts of this task. ` : '') +
|
|
184
|
+
`Read \`.valent-pipeline/prompts/retrospective.md\` and the step file named in the task. ${instruction} ` +
|
|
185
|
+
(returnContract || 'Return your findings as the JSON object specified.')
|
|
186
|
+
}
|
|
164
187
|
|
|
165
188
|
// A stable de-dup key so loop-until-dry converges (don't re-count the same finding).
|
|
166
189
|
const findingKey = (f) => `${(f.summary || '').toLowerCase().trim().slice(0, 80)}`
|
|
@@ -35,12 +35,17 @@
|
|
|
35
35
|
* their structured returns.
|
|
36
36
|
*
|
|
37
37
|
* args (either form):
|
|
38
|
-
* { stories: [{ storyId, projectType?, profiles? }, ...], projectType?, profiles?, maxRejectionCycles?, models? }
|
|
39
|
-
* { storyId, projectType, profiles?, maxRejectionCycles?, models? } // single-story (back-compat)
|
|
38
|
+
* { stories: [{ storyId, projectType?, profiles? }, ...], projectType?, profiles?, maxRejectionCycles?, models?, reasoning? }
|
|
39
|
+
* { storyId, projectType, profiles?, maxRejectionCycles?, models?, reasoning? } // single-story (back-compat)
|
|
40
40
|
*
|
|
41
41
|
* `models` is the pipeline-config.yaml `models` tier->roles map (e.g. { opus:[...], sonnet:[...],
|
|
42
42
|
* haiku:[...] }); the invoking skill passes it through so per-agent model tiers stay config-driven
|
|
43
43
|
* and editable via `valent configure`. Omit it to use the baked-in default assignment.
|
|
44
|
+
*
|
|
45
|
+
* `reasoning` is the pipeline-config.yaml `reasoning` level->roles map (e.g. { ultrathink:[...],
|
|
46
|
+
* 'think-harder':[...], 'think-hard':[...], think:[...] }); it injects a thinking-effort trigger
|
|
47
|
+
* into a role's prompt. BLANK by default — omit it (or leave the levels empty) and nothing is
|
|
48
|
+
* injected, behavior unchanged. It is a config-driven control surface, parallel to `models`.
|
|
44
49
|
*/
|
|
45
50
|
|
|
46
51
|
export const meta = {
|
|
@@ -206,14 +211,39 @@ const MODELS = buildModelMap(a.models)
|
|
|
206
211
|
// undefined => the agent inherits the main-loop (session) model.
|
|
207
212
|
const modelFor = (role) => MODELS[String(role).toUpperCase()]
|
|
208
213
|
|
|
214
|
+
// --- per-agent reasoning effort (thinking budget) ----------------------------
|
|
215
|
+
// Optional, config-driven, mirrors `models`. args.reasoning is a level->roles map; we invert it
|
|
216
|
+
// to role->trigger-phrase and overlay it on a baked-in default. The default is EMPTY — no role
|
|
217
|
+
// gets a thinking trigger unless the config opts it in, so behavior is unchanged out of the box.
|
|
218
|
+
// The phrase (when present) is injected into the agent prompt by buildPrompt; Claude Code
|
|
219
|
+
// escalates the thinking budget on these triggers. Static + args only => journal-replay safe.
|
|
220
|
+
const REASONING_PHRASES = { think: 'think', 'think-hard': 'think hard', 'think-harder': 'think harder', ultrathink: 'ultrathink' }
|
|
221
|
+
const DEFAULT_REASONING = {} // blank control surface — fill `reasoning` in pipeline-config.yaml to use it
|
|
222
|
+
function buildReasoningMap(cfg) {
|
|
223
|
+
const map = { ...DEFAULT_REASONING }
|
|
224
|
+
if (cfg && typeof cfg === 'object' && !Array.isArray(cfg)) {
|
|
225
|
+
for (const level of Object.keys(REASONING_PHRASES)) {
|
|
226
|
+
for (const role of cfg[level] || []) {
|
|
227
|
+
if (typeof role === 'string') map[role.toUpperCase()] = REASONING_PHRASES[level]
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return map
|
|
232
|
+
}
|
|
233
|
+
const REASONING = buildReasoningMap(a.reasoning)
|
|
234
|
+
// undefined => inject no thinking trigger for this role.
|
|
235
|
+
const reasoningFor = (role) => REASONING[String(role).toUpperCase()]
|
|
236
|
+
|
|
209
237
|
// --- prompt builder: mirrors providers/claude-code/spawn.template.md so spawned agents
|
|
210
238
|
// get full pipeline context (core prompt + shared context + step-at-execution + the
|
|
211
239
|
// handoff contract), not a terse one-liner. ------------------------------------------
|
|
212
240
|
|
|
213
241
|
function buildPrompt({ role, promptFile, storyId, taskRef, taskSubject, trigger, completion, returnContract }) {
|
|
214
242
|
const outputDir = `stories/${storyId}/output`
|
|
243
|
+
const think = reasoningFor(role) // undefined unless config opts this role into a thinking tier
|
|
215
244
|
return [
|
|
216
245
|
`You are **${role}**, for story ${storyId} in the valent-pipeline.`,
|
|
246
|
+
...(think ? ['', `Before you act, ${think} about the hardest parts of this task.`] : []),
|
|
217
247
|
'',
|
|
218
248
|
'## Setup',
|
|
219
249
|
`1. Read your core prompt: \`.valent-pipeline/prompts/${promptFile}\` — identity, protocols, step sequence.`,
|
|
@@ -141,6 +141,22 @@ Ask the user if they want to adjust any assignments. Common adjustments:
|
|
|
141
141
|
|
|
142
142
|
Note: agents that were skipped due to project type (e.g., FEND for backend-api) should still appear in the model list -- they are inactive but remain configured.
|
|
143
143
|
|
|
144
|
+
### Step 6b: Reasoning Effort (optional)
|
|
145
|
+
|
|
146
|
+
The `reasoning` section is a per-agent thinking-budget control surface that mirrors `models`. It maps an effort level to a list of agent roles; at spawn time the Workflow orchestrators inject that level's thinking trigger into the role's prompt. Levels, increasing: `think` < `think-hard` < `think-harder` < `ultrathink`.
|
|
147
|
+
|
|
148
|
+
It is **blank by default** — every level is an empty list, so nothing is injected and behavior is unchanged. Leave it blank unless the user wants to deepen specific agents' reasoning. Deeper thinking raises output quality but also token cost, so recommend the user re-check `/valent-review-cost` (or `valent audit`) after enabling it.
|
|
149
|
+
|
|
150
|
+
```yaml
|
|
151
|
+
reasoning:
|
|
152
|
+
ultrathink: []
|
|
153
|
+
think-harder: [] # e.g. ["CRITIC", "JUDGE"] to make the gates deliberate harder
|
|
154
|
+
think-hard: []
|
|
155
|
+
think: []
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Common adjustments: add the quality gates (`CRITIC`, `JUDGE`, `READINESS`) under `think-harder` when a project keeps shipping subtle defects. This currently affects the **Workflow** orchestrators only (the `reasoning` arg); the prose Lead ignores it.
|
|
159
|
+
|
|
144
160
|
---
|
|
145
161
|
|
|
146
162
|
## Writing the Config File
|
|
@@ -61,6 +61,9 @@ Read these as needed to answer questions:
|
|
|
61
61
|
**"How do I change which model an agent uses?"**
|
|
62
62
|
→ Edit the `models` section in `.valent-pipeline/pipeline-config.yaml`. Agents are assigned to opus/sonnet/haiku tiers.
|
|
63
63
|
|
|
64
|
+
**"Which agents cost the most / what's taking the most time?"**
|
|
65
|
+
→ `/valent-review-cost` analyzes per-agent token and wall-clock spend across stories (from the Workflow run journals) and recommends model-tier changes. Or get the raw numbers with `node .valent-pipeline/bin/cli.js audit --json`.
|
|
66
|
+
|
|
64
67
|
**"What happens when an agent gets rejected?"**
|
|
65
68
|
→ Peer-to-peer: READINESS rejects specs back to authors, CRITIC rejects code to devs, QA-B routes bugs to devs. Lead only handles JUDGE rejections and circuit breaker (after max_rejection_cycles). See `.valent-pipeline/docs/lead-lifecycle.md`.
|
|
66
69
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: valent-review-cost
|
|
3
|
+
description: 'Review per-agent token and wall-clock cost across stories and recommend model-tier (opus/sonnet/haiku) changes. Use when the user says "review cost", "what is taking the most time", "which agents cost the most", "tune model configs", or asks about pipeline token/time spend.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# valent-review-cost
|
|
7
|
+
|
|
8
|
+
Analyze where the pipeline spends tokens and wall-clock time, per agent and per story, then recommend concrete `models` tier changes. Read-only — you inspect run journals and config; you never modify the pipeline.
|
|
9
|
+
|
|
10
|
+
## Data Sources
|
|
11
|
+
|
|
12
|
+
1. **The audit trail** — per-agent tokens + wall-clock, read from the Workflow run journals the harness already writes (no instrumentation). Get it as JSON:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
node .valent-pipeline/bin/cli.js audit --json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or get the full board with cost merged onto each story card:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
node .valent-pipeline/bin/cli.js status --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Scope it when needed: `audit --story <id>` for one story, `audit --run <runId>` for one run.
|
|
25
|
+
|
|
26
|
+
2. **The configured model tiers** — read the `models` section of `.valent-pipeline/pipeline-config.yaml`. It maps each tier to the roles assigned to it:
|
|
27
|
+
|
|
28
|
+
```yaml
|
|
29
|
+
models:
|
|
30
|
+
opus: [READINESS, CRITIC, JUDGE, ...] # judgment-heavy
|
|
31
|
+
sonnet: [REQS, QA-A, QA-B, BEND, FEND, ...] # spec + build
|
|
32
|
+
haiku: [RESOLVE, Embed, Help, ...] # mechanical / CLI-runner
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## How to Analyze
|
|
36
|
+
|
|
37
|
+
Run `audit --json` and parse the contract:
|
|
38
|
+
- `totals` — grand `tokens`, `agent_ms` (summed agent busy-time), `elapsed_ms` (true wall clock), `invocations`, `stories`, `runs`.
|
|
39
|
+
- `stories[]` — each `{ story, tokens, agent_ms, invocations, roles[] }`, sorted by tokens.
|
|
40
|
+
- `stories[].roles[]` — each `{ role, tokens, agent_ms, toolCalls, invocations, attempts, models[] }`, sorted by tokens. `models[]` is the model the role **actually ran on**.
|
|
41
|
+
|
|
42
|
+
Then:
|
|
43
|
+
|
|
44
|
+
1. **Rank the spend.** Identify the top token consumers and top time consumers, both per role (aggregated across stories) and per story. Name the 3–5 biggest.
|
|
45
|
+
|
|
46
|
+
2. **Cross-reference actual model vs configured tier.** For each costly role, compare `roles[].models[]` (what it ran on) against the `models` map (what it's configured for). Flag mismatches loudly — a role running on a higher tier than configured usually means the per-role tiers weren't applied and everything used the session default model. That is the first and biggest lever.
|
|
47
|
+
|
|
48
|
+
3. **Separate "expensive because of tier" from "expensive because of rework."** If a role's `invocations` (or `attempts`) is > 1, its cost is inflated by rejection/rework cycles, not just model tier. CRITIC especially fans out (3 passes + triage) and re-runs on rejection. For those, note that prompt/spec quality or rejection-cap tuning may cut cost more than a tier change.
|
|
49
|
+
|
|
50
|
+
4. **Recommend tier changes** with reasoning:
|
|
51
|
+
- High-token, low-judgment roles (RESOLVE and other CLI-runners; mechanical IO) on opus/sonnet → propose dropping a tier.
|
|
52
|
+
- Spec/build roles (REQS, QA-A, QA-B, dev agents) on opus → consider sonnet unless quality data argues otherwise.
|
|
53
|
+
- Quality gates (READINESS, CRITIC, JUDGE) → judgment is the point; keep on opus unless they're cheap anyway.
|
|
54
|
+
- Always tie each recommendation to the numbers (e.g. "CRITIC = 47% of story spend, ran on opus, 8 invocations from the rejection loop").
|
|
55
|
+
|
|
56
|
+
## Output Format
|
|
57
|
+
|
|
58
|
+
Keep it short and decision-ready:
|
|
59
|
+
|
|
60
|
+
1. **Headline** — total spend (tokens, true elapsed), top 3 cost drivers.
|
|
61
|
+
2. **Per-role table** — role · tokens · agent-time · invocations · model-ran-on · configured-tier · mismatch?
|
|
62
|
+
3. **Recommendations** — a short ordered list of specific `models` edits, each with the number that justifies it. Show the exact `pipeline-config.yaml` `models` change to make.
|
|
63
|
+
4. **Caveats** — note that `agent_ms` is summed busy-time (exceeds `elapsed_ms` when agents run in parallel), and that rework-driven cost is fixed by prompt/spec quality, not tiers.
|
|
64
|
+
|
|
65
|
+
## Notes
|
|
66
|
+
|
|
67
|
+
- If `audit` finds no journals (`totals.stories == 0`), say so: cost data only exists after at least one Workflow run. Point the user at `--file` / `--session-dir` if their journals live elsewhere.
|
|
68
|
+
- Audit covers the Claude Code (Workflow) provider. The Codex provider produces no journal, so there is no cost data for Codex runs yet.
|
|
69
|
+
- Do not edit `pipeline-config.yaml` yourself — present the recommended changes and let the user (or `/valent-configure`) apply them.
|
|
@@ -29,7 +29,7 @@ Use the standard 200k context window. Workflow `agent()` calls run in their own
|
|
|
29
29
|
|
|
30
30
|
### Step 1: Load Pipeline Config
|
|
31
31
|
|
|
32
|
-
Read and follow `.valent-pipeline/steps/orchestration/load-pipeline-config.md`. Set `{epic_id}` from the argument. Also capture the entire `models` section (the `{ opus:[...], sonnet:[...], haiku:[...] }` tier→roles map) — pass it as the `models` arg to every Workflow call below so per-agent model tiers stay config-driven (editable via `/valent-configure`). If the config has no `models` section, omit the arg and the workflows use their baked-in default assignment.
|
|
32
|
+
Read and follow `.valent-pipeline/steps/orchestration/load-pipeline-config.md`. Set `{epic_id}` from the argument. Also capture the entire `models` section (the `{ opus:[...], sonnet:[...], haiku:[...] }` tier→roles map) — pass it as the `models` arg to every Workflow call below so per-agent model tiers stay config-driven (editable via `/valent-configure`). If the config has no `models` section, omit the arg and the workflows use their baked-in default assignment. Likewise capture the `reasoning` section (level→roles thinking-effort map) and pass it as the `reasoning` arg to every Workflow call; it is blank by default (injects nothing). Omit it if absent or all levels are empty.
|
|
33
33
|
|
|
34
34
|
### Step 2: Validate Epic
|
|
35
35
|
|
|
@@ -62,7 +62,7 @@ Invoke `plan.workflow.js` via the **Workflow tool**:
|
|
|
62
62
|
```js
|
|
63
63
|
Workflow({
|
|
64
64
|
scriptPath: '.valent-pipeline/orchestrators/claude-code/plan.workflow.js',
|
|
65
|
-
args: { stories: [{ storyId, projectType }, ...candidates], sprintId: '{epic_id}-sprint-{n}', velocity: {sprint.initial_velocity_points or current calibrated velocity}, models: <config.models or omit> }
|
|
65
|
+
args: { stories: [{ storyId, projectType }, ...candidates], sprintId: '{epic_id}-sprint-{n}', velocity: {sprint.initial_velocity_points or current calibrated velocity}, models: <config.models or omit>, reasoning: <config.reasoning or omit> }
|
|
66
66
|
})
|
|
67
67
|
```
|
|
68
68
|
|
|
@@ -74,7 +74,7 @@ Feed the planned batch straight into `sprint.workflow.js`:
|
|
|
74
74
|
```js
|
|
75
75
|
Workflow({
|
|
76
76
|
scriptPath: '.valent-pipeline/orchestrators/claude-code/sprint.workflow.js',
|
|
77
|
-
args: { stories: <plan output .stories>, maxRejectionCycles: {quality.max_rejection_cycles or 5}, models: <config.models or omit> }
|
|
77
|
+
args: { stories: <plan output .stories>, maxRejectionCycles: {quality.max_rejection_cycles or 5}, models: <config.models or omit>, reasoning: <config.reasoning or omit> }
|
|
78
78
|
})
|
|
79
79
|
```
|
|
80
80
|
|
|
@@ -89,7 +89,7 @@ Invoke `retro.workflow.js`:
|
|
|
89
89
|
```js
|
|
90
90
|
Workflow({
|
|
91
91
|
scriptPath: '.valent-pipeline/orchestrators/claude-code/retro.workflow.js',
|
|
92
|
-
args: { batchNumber: {n}, sprintId: '{epic_id}-sprint-{n}', models: <config.models or omit> }
|
|
92
|
+
args: { batchNumber: {n}, sprintId: '{epic_id}-sprint-{n}', models: <config.models or omit>, reasoning: <config.reasoning or omit> }
|
|
93
93
|
})
|
|
94
94
|
```
|
|
95
95
|
|
|
@@ -24,7 +24,7 @@ Use the standard 200k context window. Workflow `agent()` calls run in their own
|
|
|
24
24
|
|
|
25
25
|
### Step 1: Load Pipeline Config
|
|
26
26
|
|
|
27
|
-
Read and follow `.valent-pipeline/steps/orchestration/load-pipeline-config.md`. Also capture the entire `models` section (the `{ opus:[...], sonnet:[...], haiku:[...] }` tier→roles map) — pass it as the `models` arg to every Workflow call below so per-agent model tiers stay config-driven (editable via `/valent-configure`). If the config has no `models` section, omit the arg and the workflows use their baked-in default assignment.
|
|
27
|
+
Read and follow `.valent-pipeline/steps/orchestration/load-pipeline-config.md`. Also capture the entire `models` section (the `{ opus:[...], sonnet:[...], haiku:[...] }` tier→roles map) — pass it as the `models` arg to every Workflow call below so per-agent model tiers stay config-driven (editable via `/valent-configure`). If the config has no `models` section, omit the arg and the workflows use their baked-in default assignment. Likewise capture the `reasoning` section (level→roles thinking-effort map) and pass it as the `reasoning` arg to every Workflow call; it is blank by default (injects nothing). Omit it if absent or all levels are empty.
|
|
28
28
|
|
|
29
29
|
### Step 2: Build Cross-Epic Dependency Map
|
|
30
30
|
|
|
@@ -65,7 +65,7 @@ Invoke `plan.workflow.js` via the **Workflow tool**:
|
|
|
65
65
|
```js
|
|
66
66
|
Workflow({
|
|
67
67
|
scriptPath: '.valent-pipeline/orchestrators/claude-code/plan.workflow.js',
|
|
68
|
-
args: { stories: [{ storyId, projectType }, ...candidates], sprintId: 'project-sprint-{n}', velocity: {sprint.initial_velocity_points or current calibrated velocity}, models: <config.models or omit> }
|
|
68
|
+
args: { stories: [{ storyId, projectType }, ...candidates], sprintId: 'project-sprint-{n}', velocity: {sprint.initial_velocity_points or current calibrated velocity}, models: <config.models or omit>, reasoning: <config.reasoning or omit> }
|
|
69
69
|
})
|
|
70
70
|
```
|
|
71
71
|
|
|
@@ -77,7 +77,7 @@ Feed the planned batch straight into `sprint.workflow.js`:
|
|
|
77
77
|
```js
|
|
78
78
|
Workflow({
|
|
79
79
|
scriptPath: '.valent-pipeline/orchestrators/claude-code/sprint.workflow.js',
|
|
80
|
-
args: { stories: <plan output .stories>, maxRejectionCycles: {quality.max_rejection_cycles or 5}, models: <config.models or omit> }
|
|
80
|
+
args: { stories: <plan output .stories>, maxRejectionCycles: {quality.max_rejection_cycles or 5}, models: <config.models or omit>, reasoning: <config.reasoning or omit> }
|
|
81
81
|
})
|
|
82
82
|
```
|
|
83
83
|
|
|
@@ -92,7 +92,7 @@ Invoke `retro.workflow.js`:
|
|
|
92
92
|
```js
|
|
93
93
|
Workflow({
|
|
94
94
|
scriptPath: '.valent-pipeline/orchestrators/claude-code/retro.workflow.js',
|
|
95
|
-
args: { batchNumber: {n}, sprintId: 'project-sprint-{n}', models: <config.models or omit> }
|
|
95
|
+
args: { batchNumber: {n}, sprintId: 'project-sprint-{n}', models: <config.models or omit>, reasoning: <config.reasoning or omit> }
|
|
96
96
|
})
|
|
97
97
|
```
|
|
98
98
|
|
|
@@ -29,7 +29,7 @@ If no argument is provided, resolve the next work item from the backlog (see Ste
|
|
|
29
29
|
|
|
30
30
|
### Step 1: Load Pipeline Config
|
|
31
31
|
|
|
32
|
-
Read and follow `.valent-pipeline/steps/orchestration/load-pipeline-config.md`. Capture `project.type` and the story's `testing_profiles` — these become the Workflow's `projectType` and `profiles` args. Also capture the entire `models` section (the `{ opus:[...], sonnet:[...], haiku:[...] }` tier→roles map) — pass it as the `models` arg so per-agent model tiers stay config-driven (editable via `/valent-configure`). If the config has no `models` section, omit the arg and the workflow uses its baked-in default assignment.
|
|
32
|
+
Read and follow `.valent-pipeline/steps/orchestration/load-pipeline-config.md`. Capture `project.type` and the story's `testing_profiles` — these become the Workflow's `projectType` and `profiles` args. Also capture the entire `models` section (the `{ opus:[...], sonnet:[...], haiku:[...] }` tier→roles map) — pass it as the `models` arg so per-agent model tiers stay config-driven (editable via `/valent-configure`). If the config has no `models` section, omit the arg and the workflow uses its baked-in default assignment. Likewise capture the `reasoning` section (the `{ ultrathink:[...], 'think-harder':[...], 'think-hard':[...], think:[...] }` level→roles map) and pass it as the `reasoning` arg; it is blank by default (injects nothing). Omit the arg if the section is absent or all levels are empty.
|
|
33
33
|
|
|
34
34
|
### Step 1b: Resolve Next Work Item (when no argument provided)
|
|
35
35
|
|
|
@@ -52,7 +52,7 @@ Invoke the Workflow at `.valent-pipeline/orchestrators/claude-code/sprint.workfl
|
|
|
52
52
|
```js
|
|
53
53
|
Workflow({
|
|
54
54
|
scriptPath: '.valent-pipeline/orchestrators/claude-code/sprint.workflow.js',
|
|
55
|
-
args: { storyId: '<resolved story id>', projectType: '<project.type>', profiles: [/* testing_profiles */], maxRejectionCycles: <quality.max_rejection_cycles or 5>, models: <config.models or omit> }
|
|
55
|
+
args: { storyId: '<resolved story id>', projectType: '<project.type>', profiles: [/* testing_profiles */], maxRejectionCycles: <quality.max_rejection_cycles or 5>, models: <config.models or omit>, reasoning: <config.reasoning or omit> }
|
|
56
56
|
})
|
|
57
57
|
```
|
|
58
58
|
|
|
@@ -71,7 +71,8 @@ Every Workflow invocation returns a `runId`. If a run is interrupted — context
|
|
|
71
71
|
## Notes
|
|
72
72
|
|
|
73
73
|
- **State model.** The **journal is the state of record.** `pipeline-state.json`, `sprint-{n}-status.yaml`, and the markdown handoffs are **derived, human-readable views** that agents write for visibility — the orchestrator never reads them back to make a control-flow decision (its state lives in JS variables the journal captures). The non-atomic multi-file desync the prose Lead can hit is structurally impossible here.
|
|
74
|
-
- **Planned sprint batches.** To run a planned batch instead of one story, pass `args: { stories: [{ storyId, projectType, profiles }, ...], maxRejectionCycles, models }`. Produce that batch by running `plan.workflow.js` first (`args: { stories: [{ storyId, projectType }], sprintId, velocity, models }`), then feed its `{ sprintId, stories: [...] }` straight into `sprint.workflow.js`. After a batch ships, run `retro.workflow.js` (`args: { batchNumber, sprintId, models }`) to learn from it. Pass the same `config.models`
|
|
74
|
+
- **Planned sprint batches.** To run a planned batch instead of one story, pass `args: { stories: [{ storyId, projectType, profiles }, ...], maxRejectionCycles, models, reasoning }`. Produce that batch by running `plan.workflow.js` first (`args: { stories: [{ storyId, projectType }], sprintId, velocity, models, reasoning }`), then feed its `{ sprintId, stories: [...] }` straight into `sprint.workflow.js`. After a batch ships, run `retro.workflow.js` (`args: { batchNumber, sprintId, models, reasoning }`) to learn from it. Pass the same `config.models` and `config.reasoning` maps to all three. There is no `sprint-cycle` wrapper yet — run the three in sequence.
|
|
75
|
+
- **Per-agent reasoning effort.** The `reasoning` arg is a config-driven control surface (level→roles) that injects a thinking trigger into a role's prompt — blank by default, so it changes nothing until you fill it. Levels: `think` < `think-hard` < `think-harder` < `ultrathink`. Deeper thinking raises quality and token cost; check `valent audit` after enabling it. Edit it in `.valent-pipeline/pipeline-config.yaml` under `reasoning:`.
|
|
75
76
|
- **Per-agent models.** Each workflow assigns a model tier per agent: gates (READINESS/CRITIC/JUDGE) → opus, spec/build → sonnet, CLI-runner/IO steps → haiku. This comes from `config.models` (passed as the `models` arg); edit it with `/valent-configure` → "Model Assignments". Omitting the arg falls back to the same assignment baked into the script.
|
|
76
77
|
- **Known simplifications.** A CRITIC rejection currently re-runs ALL dev agents (not just the targeted one); there is no PMCP/visual-validation stage in the Workflow path yet. See `.valent-pipeline/orchestrators/claude-code/README.md`.
|
|
77
78
|
- Do **not** adopt the Lead persona or read `lead.md` in this skill — that is the prose-Lead path. The orchestration here is the Workflow script.
|