@open-product-primer/cli 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -231,7 +231,7 @@ function doctorCommand() {
231
231
  required: false,
232
232
  });
233
233
  // ── Discovery checks — warn if bet is missing discovery.md ───────────────
234
- const betsDir = path.join(primerDir, 'bets');
234
+ const betsDir = path.join(primerDir, 'bets', 'pending');
235
235
  if (fs.existsSync(betsDir)) {
236
236
  const betEntries = fs.readdirSync(betsDir, { withFileTypes: true });
237
237
  for (const entry of betEntries) {
@@ -64,7 +64,7 @@ function initCommand() {
64
64
  const specFramework = await (0, install_agent_1.promptFrameworkSelection)(projectRoot);
65
65
  const primerDir = path.join(projectRoot, 'oprim');
66
66
  (0, scaffold_1.ensureDir)(path.join(primerDir, 'decisions'));
67
- (0, scaffold_1.ensureDir)(path.join(primerDir, 'bets'));
67
+ (0, scaffold_1.ensureDir)(path.join(primerDir, 'bets', 'pending'));
68
68
  (0, scaffold_1.ensureDir)(path.join(primerDir, 'reviews'));
69
69
  (0, scaffold_1.ensureDir)(path.join(primerDir, 'notes'));
70
70
  (0, scaffold_1.ensureDir)(path.join(primerDir, 'templates'));
@@ -94,7 +94,7 @@ function initCommand() {
94
94
  (0, scaffold_1.writeFile)(path.join(primerDir, 'index.md'), (0, templates_1.indexTemplate)(projectName));
95
95
  }
96
96
  (0, scaffold_1.writeFileIfAbsent)(path.join(primerDir, 'decisions', '.gitkeep'), '');
97
- (0, scaffold_1.writeFileIfAbsent)(path.join(primerDir, 'bets', '.gitkeep'), '');
97
+ (0, scaffold_1.writeFileIfAbsent)(path.join(primerDir, 'bets', 'pending', '.gitkeep'), '');
98
98
  (0, scaffold_1.writeFileIfAbsent)(path.join(primerDir, 'reviews', '.gitkeep'), '');
99
99
  (0, scaffold_1.writeFileIfAbsent)(path.join(primerDir, 'notes', '.gitkeep'), '');
100
100
  console.log('\n' + chalk_1.default.green('✓') + ' oprim/ workspace created');
@@ -228,7 +228,7 @@ function ovwCommand() {
228
228
  .action(() => {
229
229
  const projectRoot = process.cwd();
230
230
  const sequencePath = path.join(projectRoot, 'oprim', 'sequence.yaml');
231
- const betsDir = path.join(projectRoot, 'oprim', 'bets');
231
+ const betsDir = path.join(projectRoot, 'oprim', 'bets', 'pending');
232
232
  if (!fs.existsSync(sequencePath)) {
233
233
  console.error("No oprim/sequence.yaml found — run 'oprim init' first");
234
234
  process.exit(1);
@@ -65,10 +65,10 @@ function printReport(checks) {
65
65
  console.log(`\n${passed}/${checks.length} checks passed.`);
66
66
  }
67
67
  function runDiff(projectRoot, betIdInput) {
68
- const betsDir = path.join(projectRoot, 'oprim', 'bets');
68
+ const betsDir = path.join(projectRoot, 'oprim', 'bets', 'pending');
69
69
  const resolvedDir = (0, spec_delta_1.resolveBetDirectory)(betsDir, betIdInput);
70
70
  if (!resolvedDir) {
71
- console.error(chalk_1.default.red(`Bet ${betIdInput} was not found in oprim/bets/.`));
71
+ console.error(chalk_1.default.red(`Bet ${betIdInput} was not found in oprim/bets/pending/.`));
72
72
  process.exitCode = 1;
73
73
  return;
74
74
  }
@@ -230,12 +230,10 @@ async function runBigQueryMetric(sqlPath) {
230
230
  }
231
231
  // ─── Criteria scanner (used by doctor) ───────────────────────────────────────
232
232
  function scanCriteriaForSourceType(projectRoot, sourceType) {
233
- const betsDir = path.join(projectRoot, 'oprim', 'bets');
233
+ const betsDir = path.join(projectRoot, 'oprim', 'bets', 'pending');
234
234
  if (!fs.existsSync(betsDir))
235
235
  return false;
236
236
  for (const entry of fs.readdirSync(betsDir)) {
237
- if (entry === 'archived')
238
- continue;
239
237
  const criteriaPath = path.join(betsDir, entry, 'criteria.yaml');
240
238
  if (!fs.existsSync(criteriaPath))
241
239
  continue;
@@ -73,7 +73,7 @@ function isPromoted(betDecisionContent) {
73
73
  * change) that has no criteria.yaml alongside it. Un-promoted bets are not checked.
74
74
  */
75
75
  function checkBetDefinitionOfDone(projectRoot, checks) {
76
- const betsDir = path.join(projectRoot, 'oprim', 'bets');
76
+ const betsDir = path.join(projectRoot, 'oprim', 'bets', 'pending');
77
77
  for (const entry of activeBetDirs(betsDir)) {
78
78
  const betDir = path.join(betsDir, entry.name);
79
79
  const decisionPath = path.join(betDir, 'bet-decision.md');
@@ -88,7 +88,7 @@ function checkBetDefinitionOfDone(projectRoot, checks) {
88
88
  checks.push({
89
89
  name: `bet: ${betId} promoted without criteria.yaml`,
90
90
  pass: false,
91
- note: `Add criteria.yaml to oprim/bets/${entry.name}/, or run the oprim-criteria skill`,
91
+ note: `Add criteria.yaml to oprim/bets/pending/${entry.name}/, or run the oprim-criteria skill`,
92
92
  required: false,
93
93
  });
94
94
  }
@@ -99,7 +99,7 @@ function checkBetDefinitionOfDone(projectRoot, checks) {
99
99
  * longer text-matches (whitespace-insensitive) current truth.
100
100
  */
101
101
  function checkSpecDeltaDrift(projectRoot, checks) {
102
- const betsDir = path.join(projectRoot, 'oprim', 'bets');
102
+ const betsDir = path.join(projectRoot, 'oprim', 'bets', 'pending');
103
103
  for (const entry of activeBetDirs(betsDir)) {
104
104
  const betId = extractBetId(entry.name);
105
105
  const specsDir = path.join(betsDir, entry.name, 'specs');
@@ -133,7 +133,7 @@ function checkSpecDeltaDrift(projectRoot, checks) {
133
133
  }
134
134
  /** Surfaces overlapping requirement headers across active bets' spec deltas. */
135
135
  function checkCrossBetConflicts(projectRoot, checks) {
136
- const betsDir = path.join(projectRoot, 'oprim', 'bets');
136
+ const betsDir = path.join(projectRoot, 'oprim', 'bets', 'pending');
137
137
  for (const conflict of (0, spec_delta_1.findCrossBetConflicts)(betsDir)) {
138
138
  checks.push({
139
139
  name: `spec-delta: ${extractBetId(conflict.betA)} and ${extractBetId(conflict.betB)} both touch "${conflict.header}" in ${conflict.capability}`,
@@ -2,9 +2,9 @@
2
2
  Archive a completed bet.
3
3
 
4
4
  1. Ask for bet ID (accept bet-005, 005, 5, BET-005 — normalize to BET-NNN).
5
- 2. Verify `oprim/bets/BET-NNN/` exists.
6
- 3. Check `oprim/sequence.yaml` for entries where `blocked_by` or `unlocks` reference the target bet — warn if found. Also check other active bet dirs for delta specs against the same requirement (matching `### Requirement:` headers, whitespace-insensitive) — warn if an overlap is found. Ask "Archive anyway? (y/N)" if either warning fires.
7
- 4. If `oprim/bets/BET-NNN/specs/` exists, fold each capability's `## ADDED`/`## MODIFIED`/`## REMOVED Requirements` delta into `oprim/specs/<capability>/spec.md` (matching by `### Requirement:` header; create the current-truth file if the delta is entirely ADDED) — last-write-wins on overlaps, no 3-way merge. Skip this step entirely if no `specs/` dir is present.
8
- 5. Move directory: `oprim/bets/BET-NNN → oprim/bets/archived/BET-NNN`.
5
+ 2. Verify `oprim/bets/pending/BET-NNN/` exists.
6
+ 3. Check `oprim/sequence.yaml` for entries where `blocked_by` or `unlocks` reference the target bet — warn if found. Also check other active bet dirs for delta specs against the same requirement (matching `### Requirement:` headers, whitespace-insensitive) — warn if an overlap is found. Also check the bet's `tasks.md` (if present) for unchecked `- [ ]` items — warn with the count if any remain. Ask "Archive anyway? (y/N)" if any warning fires.
7
+ 4. If `oprim/bets/pending/BET-NNN/specs/` exists, fold each capability's `## ADDED`/`## MODIFIED`/`## REMOVED Requirements` delta into `oprim/specs/<capability>/spec.md` (matching by `### Requirement:` header; create the current-truth file if the delta is entirely ADDED) — last-write-wins on overlaps, no 3-way merge. Skip this step entirely if no `specs/` dir is present.
8
+ 5. Move directory: `oprim/bets/pending/BET-NNN → oprim/bets/archived/BET-NNN`.
9
9
  6. Remove the bet entry from `oprim/sequence.yaml`.
10
10
  7. Report what was done.
@@ -19,8 +19,8 @@ Normalize the input: accept `bet-005`, `005`, `5`, or `BET-005` — always treat
19
19
 
20
20
  ### 2. Resolve the bet directory
21
21
 
22
- Look for the bet directory in `oprim/bets/` using two patterns:
23
- 1. Exact match: `oprim/bets/BET-NNN/` (legacy non-slug format)
22
+ Look for the bet directory in `oprim/bets/pending/` using two patterns:
23
+ 1. Exact match: `oprim/bets/pending/BET-NNN/` (legacy non-slug format)
24
24
  2. Slug variant: any directory starting with `BET-NNN-` (e.g., `BET-NNN-<slug>/`)
25
25
 
26
26
  Use whichever pattern matches. Call this the **resolved directory name**.
@@ -30,17 +30,19 @@ If multiple directories match (e.g., both `BET-NNN/` and `BET-NNN-slug/` exist):
30
30
  - Stop.
31
31
 
32
32
  If neither pattern matches:
33
- - Report: "Bet BET-NNN was not found in oprim/bets/. Nothing was changed."
33
+ - Report: "Bet BET-NNN was not found in oprim/bets/pending/. Nothing was changed."
34
34
  - Stop.
35
35
 
36
- ### 3. Check for active dependencies and concurrent spec-delta conflicts
36
+ ### 3. Check for active dependencies, concurrent spec-delta conflicts, and incomplete tasks.md
37
37
 
38
38
  Read `oprim/sequence.yaml`. Scan every entry across all buckets (now, next, later, backlog) for any entry whose `blocked_by` or `unlocks` list contains the target bet ID.
39
39
 
40
- Separately, if `oprim/bets/<resolved-dir>/specs/` exists: for each `<capability>/spec.md` delta file under it, extract every `### Requirement:` header from its `## ADDED`/`## MODIFIED`/`## REMOVED Requirements` sections. Then scan every other bet directory directly under `oprim/bets/` (excluding `archived/` and the bet being archived) for a `specs/<capability>/spec.md` file for the same capability; if one exists, extract its `### Requirement:` headers too. Flag any header that matches (whitespace-insensitive) between the archiving bet's delta and another still-active bet's delta as an **overlap**.
40
+ Separately, if `oprim/bets/pending/<resolved-dir>/specs/` exists: for each `<capability>/spec.md` delta file under it, extract every `### Requirement:` header from its `## ADDED`/`## MODIFIED`/`## REMOVED Requirements` sections. Then scan every other bet directory directly under `oprim/bets/pending/` (excluding the bet being archived) for a `specs/<capability>/spec.md` file for the same capability; if one exists, extract its `### Requirement:` headers too. Flag any header that matches (whitespace-insensitive) between the archiving bet's delta and another still-active bet's delta as an **overlap**.
41
41
 
42
- If either sequence.yaml dependents or delta overlaps are found:
43
- - Show a combined warning listing each dependent entry and each overlapping requirement.
42
+ Separately, if `oprim/bets/pending/<resolved-dir>/tasks.md` exists: count the number of unchecked `- [ ]` items in it. If one or more remain, flag this as an **incomplete-tasks warning**. If `tasks.md` doesn't exist, or every item is checked (`- [x]`), this contributes nothing to the warning.
43
+
44
+ If any of sequence.yaml dependents, delta overlaps, or an incomplete tasks.md are found:
45
+ - Show a combined warning listing each dependent entry, each overlapping requirement, and (if applicable) the incomplete-tasks count.
44
46
 
45
47
  Example:
46
48
  ```
@@ -48,18 +50,19 @@ If either sequence.yaml dependents or delta overlaps are found:
48
50
  - BET-007 (blocked_by: [BET-005])
49
51
  - BET-008 (unlocks: [BET-005])
50
52
  ⚠ Warning: BET-005's delta for requirement "The system SHALL ..." in capability foo overlaps with active bet BET-009's delta for the same requirement. Archiving BET-005 now applies its version to oprim/specs/foo/spec.md; if BET-009 archives later, its version will overwrite this requirement again (last-write-wins — no 3-way merge is attempted).
53
+ ⚠ Warning: BET-005's tasks.md has 3 unchecked item(s) — implementation may be incomplete.
51
54
  ```
52
55
  - Ask: "Archive BET-NNN anyway? (y/N)"
53
56
  - If "n" or Enter: stop, no changes made.
54
57
  - If "y": proceed.
55
58
 
56
- If neither is found: proceed without warning.
59
+ If none are found: proceed without warning.
57
60
 
58
61
  ### 4. Fold spec deltas into current truth
59
62
 
60
- If `oprim/bets/<resolved-dir>/specs/` does not exist: skip this step entirely and go to Step 5 — archive behavior is unchanged from before spec deltas existed.
63
+ If `oprim/bets/pending/<resolved-dir>/specs/` does not exist: skip this step entirely and go to Step 5 — archive behavior is unchanged from before spec deltas existed.
61
64
 
62
- Otherwise, for each capability subdirectory under `oprim/bets/<resolved-dir>/specs/` containing a `spec.md`:
65
+ Otherwise, for each capability subdirectory under `oprim/bets/pending/<resolved-dir>/specs/` containing a `spec.md`:
63
66
 
64
67
  1. Read the delta file's `## ADDED Requirements` / `## MODIFIED Requirements` / `## REMOVED Requirements` sections. Each `### Requirement:` block runs from its header through its body and any `#### Scenario:` sub-entries, up to the next `### Requirement:` or `## ` header.
65
68
  2. Read `oprim/specs/<capability>/spec.md` if it exists (current truth uses a single flat `## Requirements` section).
@@ -85,7 +88,7 @@ mkdir -p oprim/bets/archived
85
88
 
86
89
  Move the resolved directory:
87
90
  ```bash
88
- mv oprim/bets/<resolved-dir> oprim/bets/archived/<resolved-dir>
91
+ mv oprim/bets/pending/<resolved-dir> oprim/bets/archived/<resolved-dir>
89
92
  ```
90
93
 
91
94
  ### 6. Remove the bet entry from sequence.yaml
@@ -1 +1 @@
1
- Create a new bet in `oprim/bets/`. First explain: "A bet is a product decision you're committing to explore — a problem worth solving, a hypothesis worth testing, or a direction worth taking. You'll name it, explain why now, and set a kill criterion." Then show: "Naming tip: verb + object [for context] — Good: 'Improve bet naming for scannability' / Bad: 'Naming'". Scan `BET-(\d+)` dirs for next ID (zero-padded, default 001). Check `oprim/sequence.yaml` exists (stop if not — advise oprim init). Read `oprim/config.yaml`'s `rules.bet` — if non-empty, apply it as additional guidance and reflect it in the generated content; if empty, behavior is unchanged. After receiving the title, validate: if fewer than 4 words OR fewer than 25 characters, warn "this title may be too vague", suggest a reformulation, and ask "Proceed anyway? (y/N)" — if "n", prompt for a revised title. Gather: decision (default Build now), owner, review date, why-now, alternatives, expected outcomes, kill criteria, PDR links. Write `oprim/bets/BET-NNN/bet-decision.md` with an inline naming tip comment in the header. Append entry to sequence.yaml backlog: `{id, title, blocked_by: [], unlocks: [], requires_pdrs: []}`. Then ask: "Do you want to scaffold a discovery.md now? (y/N)" — if "y", write `oprim/bets/BET-NNN/discovery.md` from the discovery template (sections: Problem Framing, User Research Signals, Competitive Context, Open Questions); if "n" or Enter, skip silently. Report what was created.
1
+ Create a new bet in `oprim/bets/pending/`. First explain: "A bet is a product decision you're committing to explore — a problem worth solving, a hypothesis worth testing, or a direction worth taking. You'll name it, explain why now, and set a kill criterion." Then show: "Naming tip: verb + object [for context] — Good: 'Improve bet naming for scannability' / Bad: 'Naming'". Scan `oprim/bets/pending/BET-(\d+)` and `oprim/bets/archived/BET-(\d+)` dirs for next ID (zero-padded, default 001). Check `oprim/sequence.yaml` exists (stop if not — advise oprim init). Read `oprim/config.yaml`'s `rules.bet` — if non-empty, apply it as additional guidance and reflect it in the generated content; if empty, behavior is unchanged. After receiving the title, validate: if fewer than 4 words OR fewer than 25 characters, warn "this title may be too vague", suggest a reformulation, and ask "Proceed anyway? (y/N)" — if "n", prompt for a revised title. Gather: decision (default Build now), owner, review date, why-now, alternatives, expected outcomes, kill criteria, PDR links. Write `oprim/bets/pending/BET-NNN/bet-decision.md` with an inline naming tip comment in the header. Append entry to sequence.yaml backlog: `{id, title, blocked_by: [], unlocks: [], requires_pdrs: []}`. Then ask: "Do you want to scaffold a discovery.md now? (y/N)" — if "y", write `oprim/bets/pending/BET-NNN/discovery.md` from the discovery template (sections: Problem Framing, User Research Signals, Competitive Context, Open Questions); if "n" or Enter, skip silently. Report what was created.
@@ -1,13 +1,13 @@
1
1
  ### Bet authoring (oprim-bet)
2
- Create a new bet in `oprim/bets/` and register it on the sequencing board.
2
+ Create a new bet in `oprim/bets/pending/` and register it on the sequencing board.
3
3
 
4
4
  1. Show naming tip: "verb + object [for context] — e.g. 'Improve bet naming for scannability'"
5
5
  2. Ask for the bet title. Validate: fewer than 4 words OR fewer than 25 chars → warn, suggest reformulation, ask "Proceed anyway? (y/N)".
6
- 3. Assign next BET ID: scan `oprim/bets/BET-(\d+)` dirs, max+1 zero-padded to 3 digits (default 001).
6
+ 3. Assign next BET ID: scan `oprim/bets/pending/BET-(\d+)` and `oprim/bets/archived/BET-(\d+)` dirs, max+1 zero-padded to 3 digits (default 001).
7
7
  4. Check `oprim/sequence.yaml` exists — stop if not, advise `oprim init`.
8
8
  4b. Read `oprim/config.yaml`'s `rules.bet` — if non-empty, apply it as additional guidance and reflect it in the generated content; if empty, behavior is unchanged.
9
9
  5. Gather: decision (default Build now), owner, review date (YYYY-MM-DD), why now, alternatives, expected outcomes, kill criteria, PDR links.
10
- 6. Write `oprim/bets/BET-NNN/bet-decision.md` with all fields.
10
+ 6. Write `oprim/bets/pending/BET-NNN/bet-decision.md` with all fields.
11
11
  7. Append to `oprim/sequence.yaml` backlog: `{id, title, blocked_by: [], unlocks: [], requires_pdrs: []}`.
12
- 8. Ask: "Scaffold a discovery.md now? (y/N)" — if "y", write `oprim/bets/BET-NNN/discovery.md`.
12
+ 8. Ask: "Scaffold a discovery.md now? (y/N)" — if "y", write `oprim/bets/pending/BET-NNN/discovery.md`.
13
13
  9. Report what was created.
@@ -1,7 +1,7 @@
1
1
  id: bet
2
2
  skillName: oprim-bet
3
3
  title: null
4
- description: Create a new bet directory and bet-decision artifact in oprim/bets/, and add the bet to oprim/sequence.yaml backlog
4
+ description: Create a new bet directory and bet-decision artifact in oprim/bets/pending/, and add the bet to oprim/sequence.yaml backlog
5
5
  cursorDescription: Create a new bet decision and register it on the sequencing board
6
6
  claude:
7
7
  skill: true
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: oprim-bet
3
- description: Create a new bet directory and bet-decision artifact in oprim/bets/, and add the bet to oprim/sequence.yaml backlog
3
+ description: Create a new bet directory and bet-decision artifact in oprim/bets/pending/, and add the bet to oprim/sequence.yaml backlog
4
4
  ---
5
5
 
6
- Create a new bet in `oprim/bets/` and register it on the sequencing board.
6
+ Create a new bet in `oprim/bets/pending/` and register it on the sequencing board.
7
7
 
8
8
  **Interactive prompts:** Use the **AskUserQuestion tool** for every question in this skill — do not write questions as plain text.
9
9
 
@@ -30,7 +30,7 @@ After receiving the title, validate: if fewer than 4 words OR fewer than 25 char
30
30
  - If "y": proceed with the original title
31
31
 
32
32
  ### 2. Assign the next BET ID
33
- Scan both `oprim/bets/` and `oprim/bets/archived/` for directories whose names match `BET-(\d+)(-[^/]*)?` (handles both `BET-NNN/` and `BET-NNN-<slug>/`). Extract the numeric part from each match. Assign max+1, zero-padded to 3 digits. Default `001` if none found in either location.
33
+ Scan both `oprim/bets/pending/` and `oprim/bets/archived/` for directories whose names match `BET-(\d+)(-[^/]*)?` (handles both `BET-NNN/` and `BET-NNN-<slug>/`). Extract the numeric part from each match. Assign max+1, zero-padded to 3 digits. Default `001` if none found in either location.
34
34
 
35
35
  ### 2b. Derive the slug
36
36
  From the bet title: lowercase all characters, replace any character that is not a letter or digit with a hyphen, collapse consecutive hyphens to one, strip leading/trailing hyphens, truncate to 40 characters at the last hyphen boundary. This becomes `<slug>`. Example: "Add title slugs to bet directories for scannability" → `add-title-slugs-to-bet-dirs-for`.
@@ -57,7 +57,7 @@ Then ask about each of the four risk dimensions (Low / Medium / High + short rat
57
57
  Read `oprim/templates/bet-decision.md`. If it begins with a YAML frontmatter block (`---` ... `---`), this workspace has OKF frontmatter enabled. Ask for a one-line description and comma-separated tags (subject-area keywords). Prepare a frontmatter block with `type: bet-decision`, `title: <title>`, `description: <description>`, `tags: [<tags>]`, `timestamp: <today's date, ISO 8601>`, to prepend in step 5.
58
58
  If no frontmatter block is found in the template, skip this step — write the file with no frontmatter, matching current behavior.
59
59
 
60
- ### 5. Write oprim/bets/BET-NNN-<slug>/bet-decision.md
60
+ ### 5. Write oprim/bets/pending/BET-NNN-<slug>/bet-decision.md
61
61
  Prepend the frontmatter block from step 4b, if one was prepared.
62
62
  ```
63
63
  # Decision: BET-NNN <title>
@@ -108,7 +108,7 @@ Read → parse YAML → append → write back (2-space indentation):
108
108
 
109
109
  ### 7. Prompt for optional discovery scaffolding
110
110
  Ask: "Do you want to scaffold a discovery.md now? (y/N)"
111
- - If "y": write `oprim/bets/BET-NNN-<slug>/discovery.md` from the discovery template (same structure as `oprim/templates/discovery.md`).
111
+ - If "y": write `oprim/bets/pending/BET-NNN-<slug>/discovery.md` from the discovery template (same structure as `oprim/templates/discovery.md`).
112
112
  - If "n" or Enter: skip silently.
113
113
 
114
114
  ### 8. Report what was created
@@ -1 +1 @@
1
- Add metrics to `oprim/bets/BET-NNN/criteria.yaml`. Verify bet dir exists. Gather: metric ID, name, baseline, target, timeframe, launch date, segment. Ask source type (amplitude or bigquery). Amplitude: event, aggregation, denominator_event. BigQuery: table, metric_column, filter, aggregation, denominator_query. If file exists: append to metrics list (never overwrite). If not: create. Ask if adding more metrics. Report what was created.
1
+ Add metrics to `oprim/bets/pending/BET-NNN/criteria.yaml`. Verify bet dir exists. Gather: metric ID, name, baseline, target, timeframe, launch date, segment. Ask source type (amplitude or bigquery). Amplitude: event, aggregation, denominator_event. BigQuery: table, metric_column, filter, aggregation, denominator_query. If file exists: append to metrics list (never overwrite). If not: create. Ask if adding more metrics. Report what was created.
@@ -1,5 +1,5 @@
1
1
  ### Criteria authoring (oprim-criteria)
2
- Create or append to `oprim/bets/BET-NNN/criteria.yaml`.
2
+ Create or append to `oprim/bets/pending/BET-NNN/criteria.yaml`.
3
3
 
4
4
  1. Ask which bet (e.g. BET-042). Verify dir exists.
5
5
  2. Gather: metric ID (snake_case), name, baseline, target, timeframe, launch date, segment.
@@ -3,7 +3,7 @@ name: oprim-criteria
3
3
  description: Create or append to a criteria.yaml contract for a bet, with structured Amplitude and BigQuery source mapping
4
4
  ---
5
5
 
6
- Create or append to `oprim/bets/BET-NNN/criteria.yaml`.
6
+ Create or append to `oprim/bets/pending/BET-NNN/criteria.yaml`.
7
7
 
8
8
  **Interactive prompts:** Use the **AskUserQuestion tool** for every question in this skill — do not write questions as plain text.
9
9
 
@@ -13,7 +13,7 @@ Create or append to `oprim/bets/BET-NNN/criteria.yaml`.
13
13
  If not provided, ask: "Which bet are you adding criteria for? (e.g. BET-042)"
14
14
 
15
15
  ### 2. Verify bet exists
16
- If `oprim/bets/BET-NNN/` not found: report and stop — advise using the `oprim-bet` skill first.
16
+ If `oprim/bets/pending/BET-NNN/` not found: report and stop — advise using the `oprim-bet` skill first.
17
17
 
18
18
  ### 3. Gather metric details
19
19
  Ask: metric ID (snake_case), metric name, baseline (numeric), target (numeric), timeframe, launch date (YYYY-MM-DD or TBD), segment (optional).
@@ -61,6 +61,6 @@ timestamp: <today, ISO 8601>
61
61
  OKF tier: same as above, with `description: "<description>"` inserted immediately after `title`.
62
62
 
63
63
  ### 8. Link back from referenced bets
64
- For each BET-ID gathered in step 5: read `oprim/bets/BET-NNN/bet-decision.md`, and add `- Notes: NOTE-NNN` under its `## Links` section (append to an existing `Notes:` line, or add a new one).
64
+ For each BET-ID gathered in step 5: read `oprim/bets/pending/BET-NNN/bet-decision.md`, and add `- Notes: NOTE-NNN` under its `## Links` section (append to an existing `Notes:` line, or add a new one).
65
65
 
66
66
  ### 9. Report what was created
@@ -10,20 +10,20 @@ Promote an atomic note into a bet, or a prioritized bet into a capability spec.
10
10
 
11
11
  ## A. Bet → native oprim spec
12
12
 
13
- 1. **Locate the bet** — read `oprim/bets/BET-XXX/bet-decision.md`
13
+ 1. **Locate the bet** — read `oprim/bets/pending/BET-XXX/bet-decision.md`
14
14
  2. **Validate status** — decision must be "Build now"
15
15
  3. **Check authority boundary** — confirm primer artifact owns why/order/outcome only
16
- 4. **Generate the native spec delta(s)** — for each capability listed under the bet's `## Capabilities` section (or a single capability derived from the bet title if none is listed), invoke the `oprim-spec` skill with this bet as context to write `oprim/bets/BET-XXX/specs/<capability>/spec.md` — a delta using `## ADDED`/`## MODIFIED`/`## REMOVED Requirements` headers reflecting the bet's why/outcome. No OpenSpec change directory is created and OpenSpec need not be installed. Nothing is written to `oprim/specs/<capability>/spec.md` (current truth) at promote time — that only happens when this bet is archived.
17
- 5. **Link artifacts** — add `- Spec (delta): oprim/bets/BET-XXX/specs/<capability>/spec.md` (one line per capability) to the bet-decision `## Links` section
18
- 6. **Copy criteria** — if `oprim/bets/BET-XXX/criteria.yaml` exists, note it alongside the spec link
16
+ 4. **Generate the native spec delta(s)** — for each capability listed under the bet's `## Capabilities` section (or a single capability derived from the bet title if none is listed), invoke the `oprim-spec` skill with this bet as context to write `oprim/bets/pending/BET-XXX/specs/<capability>/spec.md` — a delta using `## ADDED`/`## MODIFIED`/`## REMOVED Requirements` headers reflecting the bet's why/outcome. No OpenSpec change directory is created and OpenSpec need not be installed. Nothing is written to `oprim/specs/<capability>/spec.md` (current truth) at promote time — that only happens when this bet is archived.
17
+ 5. **Link artifacts** — add `- Spec (delta): oprim/bets/pending/BET-XXX/specs/<capability>/spec.md` (one line per capability) to the bet-decision `## Links` section
18
+ 6. **Copy criteria** — if `oprim/bets/pending/BET-XXX/criteria.yaml` exists, note it alongside the spec link
19
19
  7. **Report** — show what was created and linked, and note that merge-on-archive will fold the delta into `oprim/specs/` when the bet archives
20
20
 
21
21
  ## B. Note → Bet
22
22
 
23
23
  1. **Locate the note** — read `oprim/notes/NOTE-XXX-<slug>.md`
24
- 2. **Assign the next BET ID** — scan both `oprim/bets/` and `oprim/bets/archived/` for directories matching `BET-(\d+)(-[^/]*)?`, max+1 zero-padded to 3 digits (default 001) — same convention `oprim-bet` uses
24
+ 2. **Assign the next BET ID** — scan both `oprim/bets/pending/` and `oprim/bets/archived/` for directories matching `BET-(\d+)(-[^/]*)?`, max+1 zero-padded to 3 digits (default 001) — same convention `oprim-bet` uses
25
25
  3. **Derive the slug** from the note's title (lowercase, non-alphanumeric → hyphen, collapse/trim hyphens, truncate to 40 chars at a hyphen boundary)
26
- 4. **Draft the bet** — write `oprim/bets/BET-NNN-<slug>/bet-decision.md` from the standard bet-decision structure, pre-filling only `## Why now` from the note's body. Leave `Alternatives considered`, `Expected outcomes`, and `Kill criteria / rollback trigger` as template placeholders — draft from the note, don't fabricate content it doesn't support. Ask for `Owner` and `Review date`; default `Decision: Build now` and `Date` to today.
26
+ 4. **Draft the bet** — write `oprim/bets/pending/BET-NNN-<slug>/bet-decision.md` from the standard bet-decision structure, pre-filling only `## Why now` from the note's body. Leave `Alternatives considered`, `Expected outcomes`, and `Kill criteria / rollback trigger` as template placeholders — draft from the note, don't fabricate content it doesn't support. Ask for `Owner` and `Review date`; default `Decision: Build now` and `Date` to today.
27
27
  5. **Register the new bet** — append to `oprim/sequence.yaml` backlog: `{id, title, blocked_by: [], unlocks: [], requires_pdrs: []}`
28
28
  6. **Link back** — add `Bets: BET-NNN` to the note (creating or extending its `## Bets` section)
29
29
  7. **Report** — show the new bet's path and flag that `Alternatives considered`, `Expected outcomes`, and `Kill criteria` still need authoring before this bet can itself be promoted
@@ -10,16 +10,16 @@ Promote an atomic note into a bet, or a prioritized bet into a capability spec.
10
10
 
11
11
  ## A. Bet → spec (no framework configured)
12
12
 
13
- 1. **Locate the bet** — read `oprim/bets/BET-XXX/bet-decision.md`
13
+ 1. **Locate the bet** — read `oprim/bets/pending/BET-XXX/bet-decision.md`
14
14
  2. **Validate status** — decision must be "Build now"
15
15
  3. **Report and stop** — no speccing framework is configured (`integrations.spec_framework: none`). Add `- Spec: none (no speccing framework configured)` to the bet-decision `## Links` section. No spec artifact is created.
16
16
 
17
17
  ## B. Note → Bet
18
18
 
19
19
  1. **Locate the note** — read `oprim/notes/NOTE-XXX-<slug>.md`
20
- 2. **Assign the next BET ID** — scan both `oprim/bets/` and `oprim/bets/archived/` for directories matching `BET-(\d+)(-[^/]*)?`, max+1 zero-padded to 3 digits (default 001) — same convention `oprim-bet` uses
20
+ 2. **Assign the next BET ID** — scan both `oprim/bets/pending/` and `oprim/bets/archived/` for directories matching `BET-(\d+)(-[^/]*)?`, max+1 zero-padded to 3 digits (default 001) — same convention `oprim-bet` uses
21
21
  3. **Derive the slug** from the note's title (lowercase, non-alphanumeric → hyphen, collapse/trim hyphens, truncate to 40 chars at a hyphen boundary)
22
- 4. **Draft the bet** — write `oprim/bets/BET-NNN-<slug>/bet-decision.md` from the standard bet-decision structure, pre-filling only `## Why now` from the note's body. Leave `Alternatives considered`, `Expected outcomes`, and `Kill criteria / rollback trigger` as template placeholders — draft from the note, don't fabricate content it doesn't support. Ask for `Owner` and `Review date`; default `Decision: Build now` and `Date` to today.
22
+ 4. **Draft the bet** — write `oprim/bets/pending/BET-NNN-<slug>/bet-decision.md` from the standard bet-decision structure, pre-filling only `## Why now` from the note's body. Leave `Alternatives considered`, `Expected outcomes`, and `Kill criteria / rollback trigger` as template placeholders — draft from the note, don't fabricate content it doesn't support. Ask for `Owner` and `Review date`; default `Decision: Build now` and `Date` to today.
23
23
  5. **Register the new bet** — append to `oprim/sequence.yaml` backlog: `{id, title, blocked_by: [], unlocks: [], requires_pdrs: []}`
24
24
  6. **Link back** — add `Bets: BET-NNN` to the note (creating or extending its `## Bets` section)
25
25
  7. **Report** — show the new bet's path and flag that `Alternatives considered`, `Expected outcomes`, and `Kill criteria` still need authoring before this bet can itself be promoted
@@ -10,7 +10,7 @@ Promote an atomic note into a bet, or a prioritized bet into a capability spec.
10
10
 
11
11
  ## A. Bet → OpenSpec change
12
12
 
13
- 1. **Locate the bet** — read `oprim/bets/BET-XXX/bet-decision.md`
13
+ 1. **Locate the bet** — read `oprim/bets/pending/BET-XXX/bet-decision.md`
14
14
  2. **Validate status** — decision must be "Build now"
15
15
  3. **Check authority boundary** — confirm primer artifact owns why/order/outcome only
16
16
  4. **Create OpenSpec change** — derive the change name as `bet-NNN-<slug>` where `NNN` is the zero-padded bet number (e.g. BET-004 → `bet-004`) and `<slug>` is a short kebab-case summary of the change. Then invoke the `/openspec-propose` skill (or `/opsx:propose`) with that name to create the change directory with **all required artifacts**: `proposal.md`, `design.md`, `tasks.md`, and `specs/<capability>/spec.md` for every capability listed under `## Capabilities`.
@@ -20,7 +20,7 @@ Promote an atomic note into a bet, or a prioritized bet into a capability spec.
20
20
  5. **Link artifacts**:
21
21
  - Add OpenSpec change path to bet-decision `## Links` section
22
22
  - Add bet ID to OpenSpec proposal `## Context` section
23
- 6. **Copy criteria** — if `oprim/bets/BET-XXX/criteria.yaml` exists, link it from OpenSpec proposal
23
+ 6. **Copy criteria** — if `oprim/bets/pending/BET-XXX/criteria.yaml` exists, link it from OpenSpec proposal
24
24
  7. **Verify completeness** — confirm the change directory contains:
25
25
  - `proposal.md`
26
26
  - `design.md`
@@ -32,9 +32,9 @@ Promote an atomic note into a bet, or a prioritized bet into a capability spec.
32
32
  ## B. Note → Bet
33
33
 
34
34
  1. **Locate the note** — read `oprim/notes/NOTE-XXX-<slug>.md`
35
- 2. **Assign the next BET ID** — scan both `oprim/bets/` and `oprim/bets/archived/` for directories matching `BET-(\d+)(-[^/]*)?`, max+1 zero-padded to 3 digits (default 001) — same convention `oprim-bet` uses
35
+ 2. **Assign the next BET ID** — scan both `oprim/bets/pending/` and `oprim/bets/archived/` for directories matching `BET-(\d+)(-[^/]*)?`, max+1 zero-padded to 3 digits (default 001) — same convention `oprim-bet` uses
36
36
  3. **Derive the slug** from the note's title (lowercase, non-alphanumeric → hyphen, collapse/trim hyphens, truncate to 40 chars at a hyphen boundary)
37
- 4. **Draft the bet** — write `oprim/bets/BET-NNN-<slug>/bet-decision.md` from the standard bet-decision structure, pre-filling only `## Why now` from the note's body. Leave `Alternatives considered`, `Expected outcomes`, and `Kill criteria / rollback trigger` as template placeholders — draft from the note, don't fabricate content it doesn't support. Ask for `Owner` and `Review date`; default `Decision: Build now` and `Date` to today.
37
+ 4. **Draft the bet** — write `oprim/bets/pending/BET-NNN-<slug>/bet-decision.md` from the standard bet-decision structure, pre-filling only `## Why now` from the note's body. Leave `Alternatives considered`, `Expected outcomes`, and `Kill criteria / rollback trigger` as template placeholders — draft from the note, don't fabricate content it doesn't support. Ask for `Owner` and `Review date`; default `Decision: Build now` and `Date` to today.
38
38
  5. **Register the new bet** — append to `oprim/sequence.yaml` backlog: `{id, title, blocked_by: [], unlocks: [], requires_pdrs: []}`
39
39
  6. **Link back** — add `Bets: BET-NNN` to the note (creating or extending its `## Bets` section)
40
40
  7. **Report** — show the new bet's path and flag that `Alternatives considered`, `Expected outcomes`, and `Kill criteria` still need authoring before this bet can itself be promoted
@@ -1 +1 @@
1
- Create KPI review in `oprim/reviews/YYYY-MM-DD-BET-NNN-kpi.md`. Read `oprim/config.yaml`'s `rules.review` — if non-empty, apply it as additional guidance and reflect it in the generated content; if empty, behavior is unchanged. Read `criteria.yaml` for pre-fill (baseline/target). Check `oprim/bets/BET-NNN/measurements/` for `run-*.yaml` files — if found, use the most recent to pre-populate actuals and status (include "Actuals from run: YYYY-MM-DD" note). If no run result, ask for each metric's actual value. Status: actual >= target → hit, actual < target → missed, not provided → pending. Ask reviewer name and decision quality notes. Write review with metric table and Actions checklist. Report what was created.
1
+ Create KPI review in `oprim/reviews/YYYY-MM-DD-BET-NNN-kpi.md`. Read `oprim/config.yaml`'s `rules.review` — if non-empty, apply it as additional guidance and reflect it in the generated content; if empty, behavior is unchanged. Read `criteria.yaml` for pre-fill (baseline/target). Check `oprim/bets/pending/BET-NNN/measurements/` for `run-*.yaml` files — if found, use the most recent to pre-populate actuals and status (include "Actuals from run: YYYY-MM-DD" note). If no run result, ask for each metric's actual value. Status: actual >= target → hit, actual < target → missed, not provided → pending. Ask reviewer name and decision quality notes. Write review with metric table and Actions checklist. Report what was created.
@@ -3,7 +3,7 @@ Create a KPI review artifact in `oprim/reviews/`.
3
3
 
4
4
  1. Ask which bet (e.g. BET-042).
5
5
  1b. Read `oprim/config.yaml`'s `rules.review` — if non-empty, apply it as additional guidance and reflect it in the generated content; if empty, behavior is unchanged.
6
- 2. Read `oprim/bets/BET-NNN/criteria.yaml` for pre-fill. Check `oprim/bets/BET-NNN/measurements/` for `run-*.yaml` — use most recent if present.
6
+ 2. Read `oprim/bets/pending/BET-NNN/criteria.yaml` for pre-fill. Check `oprim/bets/pending/BET-NNN/measurements/` for `run-*.yaml` — use most recent if present.
7
7
  3. If no run result, ask for each metric's actual value.
8
8
  4. Status: actual >= target → hit; actual < target → missed; not provided → pending.
9
9
  5. Ask reviewer name and decision quality notes.
@@ -17,10 +17,10 @@ Read `oprim/config.yaml`. If it has a non-empty `rules.review` value, treat it a
17
17
 
18
18
  ### 2. Load criteria and check for a run result
19
19
 
20
- Read `oprim/bets/BET-NNN/criteria.yaml` if it exists (pre-fills baseline and target).
20
+ Read `oprim/bets/pending/BET-NNN/criteria.yaml` if it exists (pre-fills baseline and target).
21
21
  If not found: inform user and continue with empty metrics list.
22
22
 
23
- **Check for measurement run result:** Scan `oprim/bets/BET-NNN/measurements/` for files matching `run-*.yaml`. If any exist, sort by filename (date-based) and read the most recent.
23
+ **Check for measurement run result:** Scan `oprim/bets/pending/BET-NNN/measurements/` for files matching `run-*.yaml`. If any exist, sort by filename (date-based) and read the most recent.
24
24
 
25
25
  **If a run result exists:** use it to pre-populate actuals and status for every metric. Skip step 3 for those metrics. Note the run date — include "Actuals from run: YYYY-MM-DD" in the review artifact.
26
26
 
@@ -1,7 +1,7 @@
1
1
  id: spec-authoring
2
2
  skillName: oprim-spec
3
3
  title: null
4
- description: Generate a native oprim capability spec delta at oprim/bets/BET-NNN-<slug>/specs/<capability>/spec.md while a bet is active, in RFC 2119 (SHALL/SHOULD/MAY) requirements and Gherkin scenarios — folded into oprim/specs/<capability>/spec.md (current truth) when the bet is archived
4
+ description: Generate a native oprim capability spec delta at oprim/bets/pending/BET-NNN-<slug>/specs/<capability>/spec.md while a bet is active, in RFC 2119 (SHALL/SHOULD/MAY) requirements and Gherkin scenarios — folded into oprim/specs/<capability>/spec.md (current truth) when the bet is archived. On the first invocation for a bet, also generates design.md and tasks.md alongside the spec delta.
5
5
  claude:
6
6
  skill: true
7
7
  command: null
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oprim-spec
3
- description: Generate a native oprim capability spec delta at oprim/bets/BET-NNN-<slug>/specs/<capability>/spec.md while a bet is active, in RFC 2119 (SHALL/SHOULD/MAY) requirements and Gherkin scenarios — folded into oprim/specs/<capability>/spec.md (current truth) when the bet is archived
3
+ description: Generate a native oprim capability spec delta at oprim/bets/pending/BET-NNN-<slug>/specs/<capability>/spec.md while a bet is active, in RFC 2119 (SHALL/SHOULD/MAY) requirements and Gherkin scenarios — folded into oprim/specs/<capability>/spec.md (current truth) when the bet is archived. On the first invocation for a bet, also generates design.md and tasks.md alongside the spec delta.
4
4
  ---
5
5
 
6
6
  Generate a capability spec delta for an active bet — RFC 2119 requirements plus Gherkin scenarios, no OpenSpec required. This skill never writes to `oprim/specs/` directly; `oprim-archive` folds the delta into current truth when the bet is archived.
@@ -12,14 +12,14 @@ Generate a capability spec delta for an active bet — RFC 2119 requirements plu
12
12
  ### 1. Get the active bet
13
13
  If a bet ID was provided as context (e.g. invoked from `/oprim:promote`), use it directly. Otherwise ask: "Which bet is this spec change for? (e.g. BET-005)"
14
14
 
15
- Resolve it to a directory in `oprim/bets/` using the same two patterns `oprim-archive` uses: exact `BET-NNN/` (legacy, no slug) or the slug variant `BET-NNN-<slug>/`. If neither matches, report "Bet BET-NNN was not found in oprim/bets/ — spec deltas can only be authored against an active bet" and stop.
15
+ Resolve it to a directory in `oprim/bets/pending/` using the same two patterns `oprim-archive` uses: exact `BET-NNN/` (legacy, no slug) or the slug variant `BET-NNN-<slug>/`. If neither matches, report "Bet BET-NNN was not found in oprim/bets/pending/ — spec deltas can only be authored against an active bet" and stop.
16
16
 
17
17
  ### 2. Get the capability name and description
18
18
  If not provided, ask: "What capability are you specifying? (a short name, e.g. 'spec-authoring')" and "What does it do? (one or two sentences)"
19
19
 
20
20
  ### 2b. Derive the slug
21
21
  From the capability name: lowercase all characters, replace any character that is not a letter or digit with a hyphen, collapse consecutive hyphens to one, strip leading/trailing hyphens. This becomes `<capability>`.
22
- Output path: `oprim/bets/<resolved-bet-dir>/specs/<capability>/spec.md` (a delta, not `oprim/specs/<capability>/spec.md` — that file is current truth and is only ever written by `oprim-archive`'s merge step).
22
+ Output path: `oprim/bets/pending/<resolved-bet-dir>/specs/<capability>/spec.md` (a delta, not `oprim/specs/<capability>/spec.md` — that file is current truth and is only ever written by `oprim-archive`'s merge step).
23
23
 
24
24
  ### 2c. Check for custom rules
25
25
  Read `oprim/config.yaml`. If it has a non-empty `rules.spec` value, treat it as additional guidance from the team — factor it into the requirements and scenarios you draft. If `rules.spec` is absent or empty, skip this step; behavior is unchanged.
@@ -33,8 +33,20 @@ For each requirement, ask whether it is new (**ADDED**), a change to an existing
33
33
  ### 4. Gather requirements and scenarios
34
34
  For ADDED and MODIFIED requirements, phrase each as an RFC 2119 statement using SHALL (mandatory), SHOULD (recommended), or MAY (optional), then ask for at least one scenario: a WHEN (trigger) and a THEN (expected outcome), with an optional GIVEN (context) and additional AND steps. REMOVED requirements only need the matching header — no new scenarios.
35
35
 
36
- ### 5. Write the delta file
37
- Append to (or create) `oprim/bets/<resolved-bet-dir>/specs/<capability>/spec.md`, grouping requirements under the matching section header — only include a section if it has at least one requirement under it:
36
+ ### 5. Check for existing design/tasks artifacts
37
+ Before writing the spec delta, check whether `design.md` and `tasks.md` already exist in `oprim/bets/pending/<resolved-bet-dir>/`.
38
+
39
+ - If neither exists, this is the first `oprim-spec` invocation for this bet — continue to Step 6 to draft both before writing the delta.
40
+ - If either already exists (from a prior `oprim-spec` invocation for this bet, e.g. for a different capability), skip Step 6 entirely and go straight to Step 7 — only the spec delta is written or appended.
41
+
42
+ ### 6. Draft design.md and tasks.md (first invocation only)
43
+ Only performed when Step 5 found neither file yet exists. Write both to `oprim/bets/pending/<resolved-bet-dir>/`:
44
+
45
+ 1. **`design.md`** — the technical approach and trade-offs for the capability being specced: key decisions, alternatives considered, risks. Scope it to this capability's implementation, not the whole bet.
46
+ 2. **`tasks.md`** — a flat implementation checklist derived from the requirements and scenarios just captured in Step 4. Group tasks under `## N. <heading>` sections (one heading per logical unit of work, e.g. per requirement or component) with `- [ ] N.M <task description>` checkbox items beneath each — the same convention OpenSpec's own `tasks.md` uses, so completion is a simple parse (count of unchecked boxes), not a new format to learn.
47
+
48
+ ### 7. Write the delta file
49
+ Append to (or create) `oprim/bets/pending/<resolved-bet-dir>/specs/<capability>/spec.md`, grouping requirements under the matching section header — only include a section if it has at least one requirement under it:
38
50
 
39
51
  ```markdown
40
52
  ## ADDED Requirements
@@ -64,5 +76,7 @@ Append to (or create) `oprim/bets/<resolved-bet-dir>/specs/<capability>/spec.md`
64
76
 
65
77
  If the delta file already exists (a prior spec-authoring pass for this bet/capability), append new requirements to the matching section, creating that section if it's not yet present.
66
78
 
67
- ### 6. Report what was created
79
+ ### 8. Report what was created
68
80
  Show the delta file path, which bet it's scoped to, and a summary of the ADDED/MODIFIED/REMOVED requirements captured. Note that it merges into `oprim/specs/<capability>/spec.md` when `BET-NNN` is archived — nothing is current truth yet.
81
+
82
+ On a first invocation (Step 6 ran), also report the `design.md` and `tasks.md` paths that were created. On a later invocation (Step 6 skipped), note that those two files already existed and were left untouched.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-product-primer/cli",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Open Product Primer CLI — product decisions, sequencing, and KPI tracking for repositories",
5
5
  "keywords": [
6
6
  "product",