valent-pipeline 0.2.3 → 0.2.5
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/package.json +1 -1
- package/pipeline/prompts/lead.md +12 -0
- package/pipeline/steps/orchestration/adopt-lead-and-create-team.md +7 -3
- package/skills/valent-configure/SKILL.md +15 -0
- package/src/commands/init.js +36 -0
- package/src/commands/upgrade.js +18 -0
- package/src/commands/validate.js +9 -1
package/package.json
CHANGED
package/pipeline/prompts/lead.md
CHANGED
|
@@ -8,6 +8,18 @@ The story is your unit of work. The cycle is: **kick off story team -> monitor -
|
|
|
8
8
|
|
|
9
9
|
You operate like a good manager: always able to answer "what is happening right now," accountable for the story shipping, but not micromanaging the work. Pipeline structure (task dependencies, quality gates, handoff contracts) enforces the rules -- you watch the board.
|
|
10
10
|
|
|
11
|
+
## Agent Teams (CRITICAL)
|
|
12
|
+
|
|
13
|
+
**You MUST use Claude Code's Agent Teams to spawn teammates.** Do NOT use subagents. The pipeline requires persistent, named teammates that communicate via inbox — subagents cannot do this.
|
|
14
|
+
|
|
15
|
+
The correct pattern:
|
|
16
|
+
1. `TeamCreate` to create the team (once per story or epic)
|
|
17
|
+
2. **Agent tool** with `name` parameter to spawn each teammate onto the team. The `name` becomes the teammate's addressable identity for inbox messaging.
|
|
18
|
+
3. `SendMessage` to communicate with living teammates by name
|
|
19
|
+
4. `shutdown_request` via SendMessage to tear down individual teammates
|
|
20
|
+
|
|
21
|
+
**NEVER** spawn pipeline agents as anonymous subagents. Every agent must be a named teammate on the team so it can send and receive inbox messages with other teammates.
|
|
22
|
+
|
|
11
23
|
## Core Operating Principles
|
|
12
24
|
|
|
13
25
|
These override all other instructions when in conflict:
|
|
@@ -73,13 +73,17 @@ This file is appended to incrementally during monitoring as agents complete phas
|
|
|
73
73
|
|
|
74
74
|
## 7. Spawn Agents
|
|
75
75
|
|
|
76
|
+
**IMPORTANT: Use the Agent tool to spawn teammates onto the team — NOT subagents.** Every pipeline agent must be a named teammate so it can send and receive inbox messages with other teammates. Use the `name` parameter on the Agent tool to set the teammate's addressable name (e.g., `name: "REQS"`).
|
|
77
|
+
|
|
76
78
|
Read the spawn templates:
|
|
77
79
|
- `.valent-pipeline/spawn-templates/knowledge-spawn.template.md` -- for the Knowledge Agent
|
|
78
80
|
- `.valent-pipeline/spawn-templates/agent-spawn.template.md` -- for all other agents
|
|
79
81
|
|
|
80
|
-
|
|
82
|
+
Substitute all `{{variables}}` in the template with resolved values, then pass the filled template as the `prompt` parameter to the Agent tool. Set `name` to the agent's name from the manifest (e.g., `"REQS"`, `"UXA"`, `"Knowledge"`). Set `run_in_background: true` so agents work autonomously.
|
|
83
|
+
|
|
84
|
+
**Wave 1: Knowledge Agent first.** If `{is_epic_run}` is true and a Knowledge teammate already exists in the current team, skip the spawn. Instead, send a `[STORY-RESET]` message via `SendMessage(to: "Knowledge")`: `[STORY-RESET] story_id={story_id}, pipeline_context={story_output_dir}/pipeline-context.md`. Wait for `[KNOWLEDGE-READY]` response before proceeding.
|
|
81
85
|
|
|
82
|
-
Otherwise, substitute variables in the knowledge spawn template (`{{story_id}}`, `{{story_output_dir}}`, knowledge config). Spawn with `run_in_background: true`. Wait for ready notification.
|
|
86
|
+
Otherwise, substitute variables in the knowledge spawn template (`{{story_id}}`, `{{story_output_dir}}`, knowledge config). Spawn as a named teammate with `run_in_background: true`. Wait for ready notification.
|
|
83
87
|
|
|
84
88
|
**Wave 1 timestamp capture:** Before spawning each Wave 1 agent (except Knowledge), capture the start timestamp via `date -u +%Y-%m-%dT%H:%M:%SZ`. Record it as that agent's phase start time for `phase-timing.md`. Knowledge is excluded from phase timing (reactive service).
|
|
85
89
|
|
|
@@ -99,7 +103,7 @@ When spawning a later-wave agent:
|
|
|
99
103
|
- Substitute all variables as for wave 1 agents
|
|
100
104
|
- For agents with two task refs: populate `{{additional_task_ids}}` with the second task
|
|
101
105
|
- Use the `model` from `pipeline-config.yaml` `models` section (match agent name to tier)
|
|
102
|
-
- Spawn with `run_in_background: true
|
|
106
|
+
- **Spawn as a named teammate** using the Agent tool with `name` set to the agent's name (e.g., `name: "BEND"`). Set `run_in_background: true`. Do NOT use subagents.
|
|
103
107
|
|
|
104
108
|
## 8. Enter Monitoring Mode
|
|
105
109
|
|
|
@@ -78,6 +78,21 @@ Present defaults and let the user adjust:
|
|
|
78
78
|
| `retrospective_every_n_stories` | `5` | How often the Retrospective Agent runs (range: 3-10) |
|
|
79
79
|
| `stall_threshold_minutes` | `15` | Minutes before a stalled agent gets a check-in (range: 5-30) |
|
|
80
80
|
|
|
81
|
+
### Step 4b: Sprint Planning
|
|
82
|
+
|
|
83
|
+
Present defaults and let the user adjust. These settings control sprint-based planning in epic and project runs:
|
|
84
|
+
|
|
85
|
+
| Setting | Default | Description |
|
|
86
|
+
|---------|---------|-------------|
|
|
87
|
+
| `duration_minutes` | `480` | Sprint time budget in minutes (480 = 8 hours, "overnight") |
|
|
88
|
+
| `initial_velocity_points` | `60` | Bootstrap velocity until first sprint completes (range: 20-120) |
|
|
89
|
+
| `estimation_model` | `calibrated` | `calibrated` uses retro history for estimates; `baseline` estimates from specs only |
|
|
90
|
+
| `auto_plan` | `true` | Enable sprint planning in epic/project runs |
|
|
91
|
+
| `fibonacci_scale` | `[1, 2, 3, 5, 8, 13, 21]` | Point scale for story sizing (standard Fibonacci) |
|
|
92
|
+
| `max_groom_batch_size` | `10` | Kill and respawn Phase 1 agents after this many stories to manage context |
|
|
93
|
+
|
|
94
|
+
Note: Sprint config only affects `valent-run-epic` and `valent-run-project`. Standalone `valent-run-story` ignores it.
|
|
95
|
+
|
|
81
96
|
### Step 5: Knowledge Store Mode
|
|
82
97
|
|
|
83
98
|
Ask the user to pick one:
|
package/src/commands/init.js
CHANGED
|
@@ -205,6 +205,34 @@ async function runWizard() {
|
|
|
205
205
|
config.knowledge.chromadb_host = chromadbHost;
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
// Sprint planning
|
|
209
|
+
const { sprintDuration } = await inquirer.prompt([{
|
|
210
|
+
type: 'input', name: 'sprintDuration',
|
|
211
|
+
message: 'Sprint duration (minutes, for epic/project runs):',
|
|
212
|
+
default: '480',
|
|
213
|
+
validate: v => !isNaN(parseInt(v)) || 'Must be a number',
|
|
214
|
+
}]);
|
|
215
|
+
config.sprint.duration_minutes = parseInt(sprintDuration);
|
|
216
|
+
|
|
217
|
+
const { initialVelocity } = await inquirer.prompt([{
|
|
218
|
+
type: 'input', name: 'initialVelocity',
|
|
219
|
+
message: 'Initial velocity (story points per sprint):',
|
|
220
|
+
default: '60',
|
|
221
|
+
validate: v => !isNaN(parseInt(v)) || 'Must be a number',
|
|
222
|
+
}]);
|
|
223
|
+
config.sprint.initial_velocity_points = parseInt(initialVelocity);
|
|
224
|
+
|
|
225
|
+
const { estimationModel } = await inquirer.prompt([{
|
|
226
|
+
type: 'list', name: 'estimationModel',
|
|
227
|
+
message: 'Estimation model:',
|
|
228
|
+
choices: [
|
|
229
|
+
{ name: 'Calibrated (uses historical data from retros)', value: 'calibrated' },
|
|
230
|
+
{ name: 'Baseline (estimates from specs only, no history)', value: 'baseline' },
|
|
231
|
+
],
|
|
232
|
+
default: 'calibrated',
|
|
233
|
+
}]);
|
|
234
|
+
config.sprint.estimation_model = estimationModel;
|
|
235
|
+
|
|
208
236
|
return config;
|
|
209
237
|
}
|
|
210
238
|
|
|
@@ -256,6 +284,14 @@ ${config.knowledge.mode === 'sqlite' ? ` sqlite_db_path: "${config.knowledge.sq
|
|
|
256
284
|
curated_files_path: "${config.knowledge.curated_files_path}"
|
|
257
285
|
correction_directives_path: "${config.knowledge.correction_directives_path}"
|
|
258
286
|
|
|
287
|
+
sprint:
|
|
288
|
+
duration_minutes: ${config.sprint?.duration_minutes ?? 480}
|
|
289
|
+
initial_velocity_points: ${config.sprint?.initial_velocity_points ?? 60}
|
|
290
|
+
estimation_model: "${config.sprint?.estimation_model ?? 'calibrated'}"
|
|
291
|
+
auto_plan: ${config.sprint?.auto_plan ?? true}
|
|
292
|
+
fibonacci_scale: [${(config.sprint?.fibonacci_scale ?? [1, 2, 3, 5, 8, 13, 21]).join(', ')}]
|
|
293
|
+
max_groom_batch_size: ${config.sprint?.max_groom_batch_size ?? 10}
|
|
294
|
+
|
|
259
295
|
orchestration:
|
|
260
296
|
recommended_context_window: "${config.orchestration?.recommended_context_window || '200k'}"
|
|
261
297
|
epic_progress_path: "${config.orchestration?.epic_progress_path || './epic-progress.md'}"
|
package/src/commands/upgrade.js
CHANGED
|
@@ -73,6 +73,24 @@ export async function upgrade(options = {}) {
|
|
|
73
73
|
console.log('Updated skills in .claude/skills/');
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
// Migrate config: add sprint section if missing
|
|
77
|
+
const configPath = join(projectRoot, '.valent-pipeline', 'pipeline-config.yaml');
|
|
78
|
+
if (fileExists(configPath)) {
|
|
79
|
+
let configContent = readFile(configPath);
|
|
80
|
+
if (!configContent.includes('sprint:')) {
|
|
81
|
+
// Insert sprint section before orchestration (or at end if orchestration not found)
|
|
82
|
+
const sprintBlock = `\nsprint:\n duration_minutes: 480\n initial_velocity_points: 60\n estimation_model: "calibrated"\n auto_plan: true\n fibonacci_scale: [1, 2, 3, 5, 8, 13, 21]\n max_groom_batch_size: 10\n`;
|
|
83
|
+
const insertPoint = configContent.indexOf('\norchestration:');
|
|
84
|
+
if (insertPoint !== -1) {
|
|
85
|
+
configContent = configContent.slice(0, insertPoint) + sprintBlock + configContent.slice(insertPoint);
|
|
86
|
+
} else {
|
|
87
|
+
configContent += sprintBlock;
|
|
88
|
+
}
|
|
89
|
+
writeFileSafe(configPath, configContent);
|
|
90
|
+
console.log('Migrated pipeline-config.yaml: added sprint section');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
76
94
|
// Update version file
|
|
77
95
|
writeFileSafe(versionFile, packageVersion);
|
|
78
96
|
console.log(`Updated .valent-pipeline/.valent-version to ${packageVersion}`);
|
package/src/commands/validate.js
CHANGED
|
@@ -75,10 +75,18 @@ function parseSimpleYaml(content) {
|
|
|
75
75
|
if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
|
|
76
76
|
s = s.slice(1, -1);
|
|
77
77
|
}
|
|
78
|
+
// Parse numeric array elements
|
|
79
|
+
if (/^\d+(\.\d+)?$/.test(s)) {
|
|
80
|
+
return parseFloat(s);
|
|
81
|
+
}
|
|
78
82
|
return s;
|
|
79
|
-
}).filter(s => s
|
|
83
|
+
}).filter(s => s !== '');
|
|
80
84
|
}
|
|
81
85
|
|
|
86
|
+
// Parse booleans
|
|
87
|
+
if (typeof value === 'string' && value === 'true') value = true;
|
|
88
|
+
if (typeof value === 'string' && value === 'false') value = false;
|
|
89
|
+
|
|
82
90
|
// Parse numbers
|
|
83
91
|
if (typeof value === 'string' && /^\d+$/.test(value)) {
|
|
84
92
|
value = parseInt(value, 10);
|