murmur8 4.6.0 → 4.7.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.
@@ -0,0 +1,180 @@
1
+ # Feature Specification — Refine Feature Skill
2
+
3
+ ## 1. Feature Intent
4
+ **Why this feature exists.**
5
+
6
+ - After running `/implement-feature`, the result may not match user intent — tests pass but behaviour is wrong, scope was misunderstood, or new information changes requirements
7
+ - Users need a structured path to refine an existing feature without starting from scratch
8
+ - This supports the system purpose of iterative, AI-assisted feature development
9
+
10
+ ---
11
+
12
+ ## 2. Scope
13
+ ### In Scope
14
+ - New `/refine-feature [slug]` skill that initiates a refinement pipeline
15
+ - Alex reads existing spec, stories, and test output to build context, then converses with the user to identify changes
16
+ - Alex presents a proposed spec diff; user approves before changes are applied
17
+ - Cass updates affected story files and produces `story-changes.md`
18
+ - Nigel updates affected tests and produces `test-changes.md`
19
+ - Mandatory pause before Codey implements — user must confirm
20
+ - Codey implements changes using the same test-first approach
21
+ - Telemetry: `parentRunId` field linking this run to the run being refined; artifact diffs instead of full files
22
+ - SKILL.md written to project root; copied to `.claude/commands/refine-feature.md` on `murmur8 init`
23
+
24
+ ### Out of Scope
25
+ - Branching or forking a feature into two separate features
26
+ - Rolling back a feature (separate concern)
27
+ - Bulk-refining multiple features in one invocation
28
+ - Changing the featureId (it must be preserved across refinements)
29
+
30
+ ---
31
+
32
+ ## 3. Actors Involved
33
+
34
+ **User**
35
+ - Provides the slug of the feature to refine
36
+ - Engages in freeform conversation with Alex about what needs to change (feedback, error logs, test output)
37
+ - Reviews and approves/rejects the proposed spec diff
38
+ - Confirms before Codey implements
39
+
40
+ **Alex**
41
+ - Reads existing FEATURE_SPEC.md, story-*.md, test output, and pipeline history
42
+ - Converses with user to understand what changed or was wrong
43
+ - Identifies minimal set of spec changes needed
44
+ - Presents diff; updates FEATURE_SPEC.md only after approval
45
+
46
+ **Cass**
47
+ - Reads `story-changes.md` produced by Alex
48
+ - Updates only affected story files (not all stories)
49
+ - Produces `story-changes.md` summarising what changed and why
50
+
51
+ **Nigel**
52
+ - Reads `story-changes.md` to understand scope of change
53
+ - Updates only affected test cases
54
+ - Produces `test-changes.md` summarising what changed
55
+
56
+ **Codey**
57
+ - Receives explicit user confirmation before starting
58
+ - Implements changes to pass updated tests
59
+ - Uses the same test-first incremental approach as the main pipeline
60
+
61
+ ---
62
+
63
+ ## 4. Behaviour Overview
64
+
65
+ ### Happy Path
66
+ 1. User runs `/refine-feature [slug]`
67
+ 2. Alex reads existing artifacts and presents a brief summary of current state
68
+ 3. Alex asks: "What needs to change?"
69
+ 4. User provides feedback (freeform: description, logs, error output, screenshots)
70
+ 5. Alex identifies changes and presents a proposed diff to FEATURE_SPEC.md
71
+ 6. User approves → Alex writes updated FEATURE_SPEC.md (featureId preserved)
72
+ 7. Cass updates affected stories and writes `story-changes.md`
73
+ 8. Nigel updates affected tests and writes `test-changes.md`
74
+ 9. Pipeline pauses: user sees summary of changes across spec/stories/tests
75
+ 10. User confirms → Codey implements, runs tests, iterates until passing
76
+ 11. Pipeline commits (unless `--no-commit`) and records refinement in history
77
+
78
+ ### Key Alternatives
79
+ - User rejects Alex's proposed diff → Alex revises and re-presents
80
+ - User aborts at any stage → clean exit, no partial writes
81
+ - No stories exist (technical feature) → Cass stage skipped; Nigel works from spec diff directly
82
+ - Tests already pass after spec change → Codey stage skipped with note
83
+
84
+ ---
85
+
86
+ ## 5. State & Lifecycle Interactions
87
+
88
+ - State-transitioning: moves an existing feature from a completed/deployed state back into active refinement
89
+ - Reads but does not replace existing artifacts until user approves diff
90
+ - After refinement, artifacts reflect the refined state; originals not preserved (git history provides rollback)
91
+ - Refinement history is a chain: each run's `parentRunId` points to the previous run's `runId`
92
+
93
+ ---
94
+
95
+ ## 6. Rules & Decision Logic
96
+
97
+ **R1: featureId preservation**
98
+ - The existing `featureId` in FEATURE_SPEC.md YAML frontmatter must never be changed
99
+ - Input: existing spec; Output: updated spec with same featureId
100
+
101
+ **R2: parentRunId linkage**
102
+ - Every refinement run must include `parentRunId` = the `runId` of the run being refined
103
+ - If no prior run exists in history for this slug, `parentRunId` = null (graceful)
104
+ - Input: pipeline history for slug; Output: parentRunId in telemetry payload
105
+
106
+ **R3: Mandatory pause before Codey**
107
+ - Codey must never run without explicit user confirmation
108
+ - Applies regardless of flags (no `--yes` bypass for this gate)
109
+
110
+ **R4: Cass skipped for technical features**
111
+ - If the original feature was classified as technical (no stories exist), Cass is skipped
112
+ - Nigel works from the spec diff directly
113
+
114
+ **R5: Artifact diff in telemetry**
115
+ - Refinement telemetry sends diffs (before/after) rather than full artifact content
116
+ - Keeps payload size proportional to the change, not the total feature size
117
+
118
+ ---
119
+
120
+ ## 7. Dependencies
121
+
122
+ - `src/telemetry.js` — existing telemetry module; refinements add `parentRunId` field
123
+ - `src/history.js` — existing history module; refinements are recorded with `type: "refinement"`
124
+ - `src/classifier.js` — determines whether Cass stage runs
125
+ - `src/diff-preview.js` — used for pre-commit diff review
126
+ - `src/feedback.js` — quality gates between stages (same thresholds)
127
+ - `.blueprint/agents/AGENT_SPECIFICATION_ALEX.md` — Alex agent spec
128
+ - `.blueprint/agents/AGENT_BA_CASS.md` — Cass agent spec
129
+ - `.blueprint/agents/AGENT_TESTER_NIGEL.md` — Nigel agent spec
130
+ - `.blueprint/agents/AGENT_DEVELOPER_CODEY.md` — Codey agent spec
131
+
132
+ ---
133
+
134
+ ## 8. Non-Functional Considerations
135
+
136
+ - **Token efficiency**: Alex reads existing artifacts selectively — handoff summaries first, full spec only if needed
137
+ - **Audit**: all refinements recorded in pipeline history; parentRunId chain enables full lineage
138
+ - **Safety**: mandatory pause before Codey prevents accidental overwrites on approval
139
+
140
+ ---
141
+
142
+ ## 9. Assumptions & Open Questions
143
+
144
+ **Assumptions:**
145
+ - The feature being refined already has a FEATURE_SPEC.md
146
+ - featureId exists in YAML frontmatter (if not, it should be added before refinement proceeds)
147
+ - Git is available for diff display and commit
148
+
149
+ **Open Questions:**
150
+ - Should a `--no-pause` flag be allowed to skip the Codey confirmation? (Current decision: no, always pause)
151
+ - Should `story-changes.md` and `test-changes.md` be committed alongside the updated files, or deleted after? (Current decision: commit them as refinement audit trail)
152
+
153
+ ---
154
+
155
+ ## 10. Impact on System Specification
156
+
157
+ This feature reinforces the system's core model of iterative, agent-assisted development. It stretches the pipeline slightly by adding a conversation phase (Alex ↔ user) before spec writing, but does not contradict any existing system assumptions.
158
+
159
+ No system spec changes required.
160
+
161
+ ---
162
+
163
+ ## 11. Handover to BA (Cass)
164
+
165
+ Story themes:
166
+ - Initiating a refinement: user provides slug, Alex reads context
167
+ - Conversation and approval: user provides feedback, Alex proposes diff, user approves
168
+ - Story propagation: Cass updates affected stories, produces story-changes.md
169
+ - Test propagation: Nigel updates affected tests, produces test-changes.md
170
+ - Implementation confirmation: mandatory pause, user confirms, Codey implements
171
+ - Telemetry lineage: parentRunId chain, artifact diffs
172
+
173
+ Story boundaries: each stage transition (user→Alex, Alex→Cass, Cass→Nigel, Nigel→pause, pause→Codey) is a natural story boundary.
174
+
175
+ ---
176
+
177
+ ## 12. Change Log (Feature-Level)
178
+ | Date | Change | Reason | Raised By |
179
+ |------|--------|--------|-----------|
180
+ | 2026-05-19 | Initial spec | New feature design | Steve Newman |
@@ -0,0 +1,47 @@
1
+ # Implementation Plan — refine-feature-skill
2
+
3
+ ## Summary
4
+ Create `src/refine.js` exporting 10 pure helper functions tested by Nigel's 25-test suite. Add `src/commands/refine.js` CLI handler and wire the command into `bin/cli.js` and `src/index.js`. Write `REFINE_SKILL.md` at project root.
5
+
6
+ ## Files to Create/Modify
7
+
8
+ | Path | Action | Purpose |
9
+ |------|--------|---------|
10
+ | `src/refine.js` | Create | All 10 pure helper functions |
11
+ | `src/commands/refine.js` | Create | CLI handler for `murm refine` / `refine-feature` command |
12
+ | `src/index.js` | Modify | Export refine module functions |
13
+ | `bin/cli.js` | Modify | Register `refine-feature` command |
14
+ | `REFINE_SKILL.md` | Create | Skill definition for /refine-feature |
15
+
16
+ ## Implementation Steps
17
+
18
+ 1. **Create `src/refine.js`** — implement all 10 functions:
19
+ - `parseRefinementArgs(argv)` → `{ slug }` from argv[3] or null
20
+ - `loadRefinementContext(slug, baseDir)` → reads FEATURE_SPEC.md (throws if missing), story-*.md files, .claude/pipeline-history.json; extracts/writes featureId; returns `{ spec, stories, history, featureId, slug }`
21
+ - `applySpecDiff(specPath, newContent, featureId)` → throws on null; writes spec with YAML frontmatter containing featureId
22
+ - `buildRefinementPayload(opts)` → returns plain object with storyChangesPath, testChangesPath, specDiff, commitSkipped
23
+ - `linkParentRun(slug, history)` → finds most recent entry for slug by completedAt; returns `{ parentRunId, type: 'refinement', featureId }`
24
+ - `isTechnicalFeature(stories)` → returns `stories.length === 0`
25
+ - `filterAffectedStories(stories, changedSlugs)` → filters by slug contained in filename
26
+ - `buildStoryChanges(entries)` → returns entries array (passthrough with validation)
27
+ - `buildChangeSummary(opts)` → returns `{ specPath, affectedStories, testChangesPath }`
28
+ - `isPauseBypassable(_flags)` → always returns `false`
29
+
30
+ 2. **Run tests** after writing src/refine.js — expect 25/25 to pass
31
+
32
+ 3. **Create `src/commands/refine.js`** — CLI handler that calls loadRefinementContext and orchestrates the pipeline flow (stub-level for now; skill handles orchestration)
33
+
34
+ 4. **Modify `src/index.js`** — add require + exports for refine module
35
+
36
+ 5. **Modify `bin/cli.js`** — register `refine-feature` command routing to `src/commands/refine.js`
37
+
38
+ 6. **Create `REFINE_SKILL.md`** — skill definition with full `/refine-feature` pipeline documented
39
+
40
+ 7. **Run full test suite** — `node --test` to verify no regressions
41
+
42
+ ## Key Implementation Notes
43
+
44
+ - `loadRefinementContext`: use `fs.readdirSync` to find `story-*.md` files; parse YAML frontmatter with simple regex (no deps); if no featureId in frontmatter, generate UUID v4 and write it back (same pattern as telemetry's `ensureFeatureId`)
45
+ - `applySpecDiff`: ensure YAML frontmatter block always starts the file; preserve featureId even if newContent doesn't include it
46
+ - `linkParentRun`: sort history by `completedAt` descending, take first matching slug; if no match, parentRunId = null
47
+ - UUID generation: use `crypto.randomUUID()` (Node 18+, no deps needed)
@@ -0,0 +1,19 @@
1
+ ## Handoff Summary
2
+ **For:** Cass
3
+ **Feature:** refine-feature-skill
4
+
5
+ ### Key Decisions
6
+ - Skill is `/refine-feature [slug]` — a separate skill from `/implement-feature`, not a flag
7
+ - Alex stage is conversation-based (reads existing artifacts, chats with user, proposes diff) rather than fresh spec creation
8
+ - Hard pause before Codey is mandatory — no `--yes` bypass
9
+ - Telemetry uses `parentRunId` to form a linked chain of refinements; `featureId` is preserved
10
+ - Cass skipped if original feature had no stories (technical classification)
11
+
12
+ ### Files Created
13
+ - .blueprint/features/feature_refine-feature-skill/FEATURE_SPEC.md
14
+
15
+ ### Open Questions
16
+ - None
17
+
18
+ ### Critical Context
19
+ The six story themes map cleanly to pipeline stages: (1) initiation, (2) conversation + approval, (3) story propagation via Cass, (4) test propagation via Nigel, (5) mandatory pause + Codey confirmation, (6) telemetry lineage. Each story should have testable ACs focused on the observable behaviour at that stage boundary.
@@ -0,0 +1,26 @@
1
+ ## Handoff Summary
2
+ **For:** Nigel
3
+ **Feature:** refine-feature-skill
4
+
5
+ ### Stories Written (6)
6
+ - story-initiation.md — skill invocation, artifact loading, featureId capture/creation
7
+ - story-conversation-approval.md — freeform feedback, diff proposal loop, approval gate, clean abort
8
+ - story-story-propagation.md — Cass updates affected stories only, produces story-changes.md, skipped for technical features
9
+ - story-test-propagation.md — Nigel updates affected tests only, produces test-changes.md, uses spec diff when Cass skipped
10
+ - story-codey-confirmation.md — mandatory pre-Codey pause, no flag bypass, test-first implementation, conditional commit
11
+ - story-telemetry-lineage.md — parentRunId chain, type:"refinement", artifact diffs in telemetry, change files committed as audit trail
12
+
13
+ ### Key Constraints for Nigel
14
+ - Every AC is independently testable; prefer unit/integration tests over end-to-end
15
+ - featureId preservation (AC-6 in initiation, AC-6 in conversation-approval, AC-4 in telemetry) must be verified as a cross-cutting invariant
16
+ - The no-flag-bypass rule (AC-2 in codey-confirmation) is safety-critical — test it explicitly with `--yes` and similar flags
17
+ - Cass-skip path (technical features) is tested in both story-propagation and test-propagation stories
18
+ - parentRunId = null graceful path (AC-2 in telemetry) must be a distinct test case
19
+
20
+ ### Files Created
21
+ - story-initiation.md
22
+ - story-conversation-approval.md
23
+ - story-story-propagation.md
24
+ - story-test-propagation.md
25
+ - story-codey-confirmation.md
26
+ - story-telemetry-lineage.md
@@ -0,0 +1,30 @@
1
+ ## Handoff Summary
2
+ **For:** Codey
3
+ **Feature:** refine-feature-skill
4
+
5
+ ### Tests Written
6
+ - File: `test/feature_refine-feature-skill.test.js`
7
+ - Spec: `test/artifacts/feature_refine-feature-skill/test-spec.md`
8
+ - Total tests: 25 across 6 describe blocks (one per story)
9
+
10
+ ### Coverage
11
+ | Story | ACs covered | Test IDs |
12
+ |---|---|---|
13
+ | story-initiation.md | AC-1,2,3,4,5,6 | RF-IN-1…6 |
14
+ | story-conversation-approval.md | AC-3,5,6 | RF-CA-3,5,6 |
15
+ | story-story-propagation.md | AC-1,3,4,5,6 | RF-SP-1,3,4,5,6 |
16
+ | story-test-propagation.md | AC-1,3,5 | RF-TP-1,3,5 |
17
+ | story-codey-confirmation.md | AC-2,4,6 | RF-CC-2,4,6 |
18
+ | story-telemetry-lineage.md | AC-1,2,3,4,7 | RF-TL-1,2,3,4,7 |
19
+
20
+ ### Key Assumptions for Codey
21
+ - `src/refine.js` exports all 10 pure functions listed in test-spec.md
22
+ - `loadRefinementContext(slug, baseDir)` accepts a base directory for testability
23
+ - `applySpecDiff(specPath, newContent, featureId)` — null newContent = abort (throws)
24
+ - `linkParentRun(slug, historyArray)` is pure; no file I/O
25
+ - `isPauseBypassable` always returns `false`; no flags override it
26
+
27
+ ### Files to Create
28
+ - `src/refine.js` — all pure helper functions
29
+ - `src/commands/refine.js` — CLI handler wiring
30
+ - `REFINE_SKILL.md` and `.claude/commands/refine-feature.md`
@@ -0,0 +1,41 @@
1
+ # Story: Mandatory Pause and Codey Confirmation
2
+
3
+ **As a** developer reviewing the proposed changes to spec, stories, and tests
4
+ **I want** to see a consolidated summary of all changes before Codey begins implementation, and to give explicit confirmation before any code is touched
5
+ **So that** I retain full control and cannot accidentally trigger implementation via a flag or shortcut
6
+
7
+ ## Acceptance Criteria
8
+
9
+ ### AC-1: Pipeline pauses before Codey with a change summary
10
+ **Given** Nigel has produced `test-changes.md`
11
+ **When** the pipeline reaches the pre-Codey gate
12
+ **Then** the pipeline displays a summary showing: files changed in spec, stories affected, and tests added/modified, then waits for explicit user input before proceeding
13
+
14
+ ### AC-2: No flag or option bypasses the pre-Codey pause
15
+ **Given** the pre-Codey gate is active
16
+ **When** the user invokes `/refine-feature` with any combination of flags (including `--yes`, `--no-pause`, or any other flag)
17
+ **Then** the pipeline still pauses and requires explicit confirmation; no flag silently bypasses this gate
18
+
19
+ ### AC-3: User confirmation triggers Codey implementation
20
+ **Given** the pre-Codey change summary is displayed
21
+ **When** the user confirms (e.g., types "yes" or "proceed")
22
+ **Then** Codey begins implementation using the updated tests as its acceptance target
23
+
24
+ ### AC-4: User abort at pre-Codey gate exits cleanly
25
+ **Given** the pre-Codey change summary is displayed
26
+ **When** the user aborts (e.g., types "cancel" or "no")
27
+ **Then** the pipeline exits cleanly; all spec, story, and test file writes that have already occurred are preserved; no code changes are made
28
+
29
+ ### AC-5: Codey uses test-first incremental approach
30
+ **Given** the user has confirmed at the pre-Codey gate
31
+ **When** Codey implements changes
32
+ **Then** Codey runs the updated tests first, implements code changes incrementally to make them pass, and iterates until all updated tests pass
33
+
34
+ ### AC-6: Pipeline commits after successful implementation unless --no-commit
35
+ **Given** Codey has completed implementation and all tests pass
36
+ **When** the pipeline finishes
37
+ **Then** changes are committed to git unless the `--no-commit` flag was supplied, in which case the pipeline exits with a message indicating commit was skipped
38
+
39
+ ## Out of Scope
40
+ - Codey making spec or story changes (those are locked before this gate)
41
+ - Any automated or timed confirmation; confirmation must be an explicit user action
@@ -0,0 +1,41 @@
1
+ # Story: Conversation and Spec Diff Approval
2
+
3
+ **As a** developer providing feedback on a completed feature
4
+ **I want** to describe what is wrong or what has changed to Alex in freeform language, then review a proposed diff before anything is written
5
+ **So that** spec changes are driven by my intent and I cannot accidentally overwrite existing work
6
+
7
+ ## Acceptance Criteria
8
+
9
+ ### AC-1: Alex accepts freeform feedback input
10
+ **Given** Alex has presented the current-state summary
11
+ **When** the user provides feedback in any form (plain text, error logs, test output, screenshots)
12
+ **Then** Alex accepts the input without requiring a specific format and proceeds to analyse it
13
+
14
+ ### AC-2: Alex presents a proposed diff to FEATURE_SPEC.md
15
+ **Given** Alex has analysed the user's feedback
16
+ **When** Alex has identified the minimal set of spec changes required
17
+ **Then** Alex presents the proposed changes as a clearly labelled before/after diff and asks the user to approve or reject
18
+
19
+ ### AC-3: User approval triggers spec write
20
+ **Given** Alex has presented the proposed diff
21
+ **When** the user explicitly approves the diff
22
+ **Then** Alex writes the updated `FEATURE_SPEC.md` with the changes applied, preserving the original featureId
23
+
24
+ ### AC-4: User rejection triggers revision loop
25
+ **Given** Alex has presented the proposed diff
26
+ **When** the user rejects the diff or requests changes
27
+ **Then** Alex revises the proposed diff based on the user's clarification and presents an updated version; no files are written until approval is given
28
+
29
+ ### AC-5: User abort exits cleanly with no writes
30
+ **Given** the conversation is in progress at any point before approval
31
+ **When** the user aborts (e.g., types "cancel" or "abort")
32
+ **Then** the pipeline exits cleanly, no files are modified, and the user receives confirmation that no changes were made
33
+
34
+ ### AC-6: featureId is unchanged after spec write
35
+ **Given** the user has approved the proposed diff
36
+ **When** Alex writes the updated `FEATURE_SPEC.md`
37
+ **Then** the featureId in the YAML frontmatter is identical to the value read at initiation
38
+
39
+ ## Out of Scope
40
+ - Automated approval via a `--yes` flag for this gate
41
+ - Approving changes to story or test files at this stage (those are handled by Cass and Nigel)
@@ -0,0 +1,42 @@
1
+ # Story: Refinement Initiation
2
+
3
+ **As a** developer who has run `/implement-feature` and found the result does not fully match intent
4
+ **I want** to run `/refine-feature [slug]` and have Alex load all existing artifacts for that feature
5
+ **So that** I can start a targeted refinement without duplicating work already done
6
+
7
+ ## Acceptance Criteria
8
+
9
+ ### AC-1: Skill exists and accepts a slug argument
10
+ **Given** murmur8 has been initialised in a project
11
+ **When** the user runs `/refine-feature some-feature`
12
+ **Then** the `/refine-feature` skill is recognised as a valid command and begins execution with `some-feature` as the target slug
13
+
14
+ ### AC-2: Missing FEATURE_SPEC.md produces a clear error
15
+ **Given** no `FEATURE_SPEC.md` exists for the given slug
16
+ **When** the user runs `/refine-feature missing-slug`
17
+ **Then** the pipeline exits with a message indicating the spec was not found and no files are modified
18
+
19
+ ### AC-3: Alex reads existing artifacts before engaging the user
20
+ **Given** a feature with an existing `FEATURE_SPEC.md`, one or more `story-*.md` files, and pipeline history
21
+ **When** the refinement skill starts
22
+ **Then** Alex reads the spec, all story files, and the most recent pipeline history entry for the slug before prompting the user
23
+
24
+ ### AC-4: Alex presents a current-state summary before asking for feedback
25
+ **Given** Alex has loaded all existing artifacts
26
+ **When** the context-loading phase completes
27
+ **Then** Alex presents a brief summary (feature name, current scope, last run status) and then asks: "What needs to change?"
28
+
29
+ ### AC-5: featureId is read from YAML frontmatter
30
+ **Given** `FEATURE_SPEC.md` contains a `featureId` in its YAML frontmatter
31
+ **When** Alex initialises the refinement session
32
+ **Then** the featureId value is captured and preserved for all subsequent writes in this run
33
+
34
+ ### AC-6: Missing featureId is added before refinement proceeds
35
+ **Given** `FEATURE_SPEC.md` exists but has no `featureId` in its YAML frontmatter
36
+ **When** the refinement skill starts
37
+ **Then** Alex adds a new featureId to the frontmatter before proceeding, and logs that it was added
38
+
39
+ ## Out of Scope
40
+ - Running refinement on multiple features in a single invocation
41
+ - Forking or branching a feature into two separate features
42
+ - Rolling back a feature to a previous state
@@ -0,0 +1,42 @@
1
+ # Story: Story Propagation via Cass
2
+
3
+ **As a** developer who has approved a spec diff
4
+ **I want** Cass to update only the affected user story files and produce a `story-changes.md` summary
5
+ **So that** stories stay in sync with the refined spec without unnecessary churn to unchanged stories
6
+
7
+ ## Acceptance Criteria
8
+
9
+ ### AC-1: Cass is skipped for technical features
10
+ **Given** the original feature was classified as technical (no `story-*.md` files exist for the slug)
11
+ **When** the refinement pipeline reaches the Cass stage
12
+ **Then** the Cass stage is skipped and the pipeline proceeds directly to Nigel; a note is recorded in the run output
13
+
14
+ ### AC-2: Cass reads the spec diff not the full spec
15
+ **Given** Alex has written an updated `FEATURE_SPEC.md`
16
+ **When** Cass starts
17
+ **Then** Cass reads `story-changes.md` (produced by Alex) to understand the scope of change before reading the full spec
18
+
19
+ ### AC-3: Only affected story files are updated
20
+ **Given** a feature with multiple existing `story-*.md` files
21
+ **When** Cass has identified which stories are affected by the spec diff
22
+ **Then** Cass updates only those story files; stories not affected by the diff are left unchanged
23
+
24
+ ### AC-4: Cass produces a `story-changes.md` file
25
+ **Given** Cass has completed updating stories
26
+ **When** the Cass stage finishes
27
+ **Then** a `story-changes.md` file exists in the feature directory listing which stories were changed and a brief reason for each change
28
+
29
+ ### AC-5: Cass does not delete existing stories without cause
30
+ **Given** an existing story that is unaffected by the spec diff
31
+ **When** Cass completes
32
+ **Then** that story file is present and unmodified
33
+
34
+ ### AC-6: New stories are created if the spec diff adds new scope
35
+ **Given** the approved diff introduces new user-facing behaviour not covered by any existing story
36
+ **When** Cass processes the diff
37
+ **Then** Cass creates a new `story-[slug].md` file for the new scope and lists it in `story-changes.md`
38
+
39
+ ## Out of Scope
40
+ - Cass making changes to test files (that is Nigel's responsibility)
41
+ - Cass engaging in conversation with the user about story scope
42
+ - Bulk-updating all stories regardless of diff scope
@@ -0,0 +1,47 @@
1
+ # Story: Telemetry Lineage via parentRunId
2
+
3
+ **As a** developer or team lead reviewing a feature's evolution over multiple refinements
4
+ **I want** each refinement run to record a `parentRunId` linking it to the run it refines
5
+ **So that** I can trace the full chain of refinements for any feature from pipeline history
6
+
7
+ ## Acceptance Criteria
8
+
9
+ ### AC-1: Refinement run records parentRunId in history
10
+ **Given** a pipeline history entry exists for the slug being refined
11
+ **When** the refinement run completes
12
+ **Then** the history entry for this refinement run contains a `parentRunId` field set to the `runId` of the most recent prior run for that slug
13
+
14
+ ### AC-2: parentRunId is null when no prior history exists
15
+ **Given** no pipeline history entry exists for the slug being refined
16
+ **When** the refinement run records its history entry
17
+ **Then** the `parentRunId` field is present and set to `null`; the run is not aborted or errored because of missing history
18
+
19
+ ### AC-3: Refinement run is recorded with type "refinement"
20
+ **Given** a refinement run completes (successfully or with user abort)
21
+ **When** the history entry is written
22
+ **Then** the entry contains `"type": "refinement"` to distinguish it from original `"type": "implementation"` runs
23
+
24
+ ### AC-4: featureId is identical to the original run's featureId
25
+ **Given** an original implementation run recorded a featureId for a slug
26
+ **When** a refinement run for the same slug records its history entry
27
+ **Then** the featureId in the refinement history entry is the same value as in the original run
28
+
29
+ ### AC-5: Telemetry payload uses artifact diffs, not full files
30
+ **Given** spec, story, and test files were updated during the refinement
31
+ **When** telemetry is emitted
32
+ **Then** the payload contains before/after diffs for each changed artifact rather than the full file contents
33
+
34
+ ### AC-6: story-changes.md and test-changes.md are committed as audit trail
35
+ **Given** Cass produced `story-changes.md` and/or Nigel produced `test-changes.md`
36
+ **When** the pipeline commits at the end of a successful refinement
37
+ **Then** both change summary files are included in the commit alongside the updated spec, story, and test files
38
+
39
+ ### AC-7: parentRunId chain is traversable across multiple refinements
40
+ **Given** a feature has been refined three times, each run recording a parentRunId pointing to the previous
41
+ **When** a developer queries the history for that slug
42
+ **Then** the history entries can be ordered into a chain: run-1 ← run-2 ← run-3 ← run-4 via parentRunId links
43
+
44
+ ## Out of Scope
45
+ - Visualising the refinement chain in the CLI (a future feature)
46
+ - Preserving original artifact files alongside refined versions (git history provides rollback)
47
+ - Changing the featureId at any point in the chain
@@ -0,0 +1,42 @@
1
+ # Story: Test Propagation via Nigel
2
+
3
+ **As a** developer whose stories have been updated by Cass
4
+ **I want** Nigel to update only the affected test cases and produce a `test-changes.md` summary
5
+ **So that** the test suite reflects the refined spec without replacing tests that are still valid
6
+
7
+ ## Acceptance Criteria
8
+
9
+ ### AC-1: Nigel reads story-changes.md to scope its work
10
+ **Given** Cass has produced a `story-changes.md` (or Cass was skipped and Alex produced a spec diff)
11
+ **When** Nigel starts
12
+ **Then** Nigel reads `story-changes.md` (or the spec diff directly if Cass was skipped) before reading any test files
13
+
14
+ ### AC-2: Only affected test cases are modified
15
+ **Given** an existing test file with multiple test cases
16
+ **When** Nigel has identified which test cases correspond to changed stories or spec sections
17
+ **Then** Nigel modifies only those test cases; test cases unrelated to the diff are left unchanged
18
+
19
+ ### AC-3: Nigel produces a `test-changes.md` file
20
+ **Given** Nigel has completed updating tests
21
+ **When** the Nigel stage finishes
22
+ **Then** a `test-changes.md` file exists in the feature directory listing which test cases were added, modified, or removed and why
23
+
24
+ ### AC-4: New test cases are created for new acceptance criteria
25
+ **Given** a new acceptance criterion exists in an updated or new story
26
+ **When** Nigel processes the changes
27
+ **Then** Nigel creates a new test case covering that criterion and records it in `test-changes.md`
28
+
29
+ ### AC-5: Nigel works from spec diff when no stories exist
30
+ **Given** the original feature was technical and Cass was skipped
31
+ **When** Nigel runs
32
+ **Then** Nigel uses the before/after spec diff produced by Alex as the sole input for determining which tests to update
33
+
34
+ ### AC-6: Passing tests are not regressed
35
+ **Given** an existing test that covers behaviour not changed by the diff
36
+ **When** Nigel completes
37
+ **Then** that test case remains present and semantically equivalent to its pre-refinement version
38
+
39
+ ## Out of Scope
40
+ - Nigel running the tests (execution happens during the Codey stage)
41
+ - Nigel modifying story files
42
+ - Nigel engaging in conversation with the user about test scope
package/README.md CHANGED
@@ -1,19 +1,58 @@
1
1
  # murmur8
2
2
 
3
- A multi-agent workflow framework for automated feature development. Four specialised AI agents collaborate in sequence to take features from specification to implementation, with built-in feedback loops and self-improvement capabilities.
3
+ AI coding tools can be a black box. You describe what you want, magic happens, and code appears. If it's wrong, you describe it again and hope for better. There's no process, no trail, no shared understanding of why decisions were made.
4
4
 
5
- Like a murmuration of starlings, individual agents move together as one, each responding to its neighbours to create something greater than the sum of its parts.
5
+ murmur8 is different. Agents Alex, Cass, Nigel, and Codey run a structured, documented pipeline — the kind a good engineering team would run naturally. Each agent produces real, readable artefacts: a feature spec, user stories, a test plan, an implementation. You can read every one of them, understand the reasoning, and step in at any point. It's not magic. It's a repeatable process that happens to move very fast.
6
6
 
7
- # TLDR - Using murmur8
7
+ Like a murmuration of starlings, the agents move together — each one responding to what came before and building upon it.
8
8
 
9
- ## Using murmur8 inside Claude Code or Copilot CLI
10
- Initialize with `npx murmur8 init`, then run `/implement-feature your-feature` in Claude Code or Copilot CLI. Four AI agents collaborate to turn your idea into tested, working code — from spec to implementation. Add up to 3 feature slugs and the murmuration magic will build them in paralell in an isolated git worktree.
9
+ ## The Workflow
11
10
 
12
- ## Using murmur8 outside of Claude Code or Copilot CLI
13
- Initialize with `npx murmur8 init`, then run `npx murmur8 murm feature-a feature-b` from your terminal. Each feature gets an isolated git worktree and runs its own pipeline. Successful features auto-merge to main. Use `--dry-run` to preview the plan first.
11
+ ### Start with a conversation
12
+
13
+ Every feature starts with intent. If you're setting up a new project, murmur8 will walk you through creating a system specification interactively — Alex asks questions, you answer, and together you produce a document that grounds everything that follows. If a feature spec doesn't exist yet, the same thing happens at the feature level.
14
+
15
+ You can also trigger this explicitly with `--interactive` flag. This is useful when an idea is still fuzzy, you can have a conversation with Alex until the shape of the feature becomes clear. The spec that comes out the other side is yours to review and approve before anything else runs.
16
+
17
+ ### The pipeline runs
18
+
19
+ Once there's a spec, the pipeline takes over. Alex hands off to Cass, who writes user stories with explicit acceptance criteria. Cass hands off to Nigel, who turns those stories into a test plan and executable tests. Nigel hands off to Codey, who implements until the tests pass.
20
+
21
+ At every handoff, the agent writes a summary of what it did, what it decided, and what the next agent needs to know. These aren't logs — they're readable documents. If something goes wrong, or you want to understand why a decision was made, you can read the trail. The spec, the stories, the test plan, the implementation plan: they all live in your repository alongside the code.
22
+
23
+ ### Refine it
24
+
25
+ The first run won't always land exactly right. Requirements shift, something was misunderstood, or the implementation reveals a gap in the spec. That's normal.
26
+
27
+ `/refine-feature` reopens the conversation. You can discuss with Alex whats not right, provide error logs, or user feedback. Alex reads what was built, and describes what needs to change, and proposes an updated spec diff for your approval. From there Cass updates only the affected stories, Nigel updates only the affected tests, and Codey reimplements. The pipeline pauses before Codey runs — you always see the full picture of what's changing before any code is touched.
28
+
29
+ Every refinement is linked to the run it came from, so the history of a feature — original intent, what changed, and why — is always traceable.
30
+
31
+ ### Turning it up to 11
32
+
33
+ If you using the skill with Claude Code or Github Copilot, or via an npx command, you can run multiple of these pipelines at the same time, working independantly on features in parallel. The pipeline look at whats required and work out how multiple fetaures can be delivered at the same time withough Nigel 1, 2, and 3 treading on each others toes in the code base. The pipeline runs EXACTLY the same way... just mutiple of them at the same time!
34
+
35
+ ## Quick Start
36
+
37
+ **Inside Claude Code or Copilot CLI:**
38
+ ```bash
39
+ npx murmur8 init
40
+ /implement-feature your-feature
41
+ ```
42
+
43
+ **From the terminal (parallel execution):**
44
+ ```bash
45
+ npx murmur8 init
46
+ npx murmur8 murm feature-a feature-b feature-c
47
+ ```
48
+
49
+ Add up to three slugs and each feature runs in an isolated git worktree simultaneously. Successful features auto-merge to main. Use `--dry-run` to preview the plan before committing.
14
50
 
15
51
  ## Upgrading to v4.0
16
52
 
53
+ <details>
54
+ <summary>Breaking changes and migration notes</summary>
55
+
17
56
  v4.0 completes the murmuration theming by renaming all parallel internals. Existing users should be aware of the following breaking changes.
18
57
 
19
58
  ### Breaking changes
@@ -32,6 +71,8 @@ Legacy on-disk files (`.claude/parallel-config.json`, `.claude/parallel-queue.js
32
71
 
33
72
  The CLI commands `parallel`, `murmuration`, and `parallel-config` continue to work as aliases for `murm` and `murm-config` respectively.
34
73
 
74
+ </details>
75
+
35
76
  ## Agents
36
77
 
37
78
  | Agent | Role |
package/bin/cli.js CHANGED
@@ -10,7 +10,8 @@ const command = args[0];
10
10
  const aliases = {
11
11
  'parallel': 'murm',
12
12
  'murmuration': 'murm',
13
- 'parallel-config': 'murm-config'
13
+ 'parallel-config': 'murm-config',
14
+ 'refine-feature': 'refine'
14
15
  };
15
16
 
16
17
  const resolvedCommand = aliases[command] || command;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "murmur8",
3
- "version": "4.6.0",
3
+ "version": "4.7.1",
4
4
  "description": "Multi-agent workflow framework for automated feature development",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ const { loadRefinementContext, isPauseBypassable } = require('../refine');
4
+
5
+ const description = 'Refine an existing feature spec and propagate changes through stories, tests, and implementation';
6
+
7
+ async function run(argv) {
8
+ const { parseRefinementArgs } = require('../refine');
9
+ const { slug } = parseRefinementArgs(argv);
10
+
11
+ if (!slug) {
12
+ console.error('Usage: murmur8 refine-feature <slug>');
13
+ console.error('Example: murmur8 refine-feature user-auth');
14
+ process.exit(1);
15
+ }
16
+
17
+ console.log(`Loading refinement context for "${slug}"...`);
18
+
19
+ let ctx;
20
+ try {
21
+ ctx = await loadRefinementContext(slug, process.cwd());
22
+ } catch (err) {
23
+ console.error(`Error: ${err.message}`);
24
+ process.exit(1);
25
+ }
26
+
27
+ const storyCount = ctx.stories.length;
28
+ const lastStatus = ctx.lastRunStatus ? ` (last run: ${ctx.lastRunStatus})` : '';
29
+ console.log(`Feature: ${ctx.slug}${lastStatus}`);
30
+ console.log(`Stories: ${storyCount}`);
31
+ console.log(`Feature ID: ${ctx.featureId}`);
32
+ console.log('');
33
+ console.log('To refine this feature, use the /refine-feature skill in Claude Code:');
34
+ console.log(` /refine-feature "${slug}"`);
35
+ }
36
+
37
+ module.exports = { run, description };
package/src/index.js CHANGED
@@ -1,4 +1,16 @@
1
1
  const { init } = require('./init');
2
+ const {
3
+ parseRefinementArgs,
4
+ loadRefinementContext,
5
+ applySpecDiff,
6
+ buildRefinementPayload,
7
+ linkParentRun,
8
+ isTechnicalFeature,
9
+ filterAffectedStories,
10
+ buildStoryChanges,
11
+ buildChangeSummary,
12
+ isPauseBypassable,
13
+ } = require('./refine');
2
14
  const { update } = require('./update');
3
15
  const { validate, formatOutput, checkNodeVersion } = require('./validate');
4
16
  const { recordHistory, displayHistory, showStats, clearHistory, storeStageFeedback, updateStage } = require('./history');
@@ -209,5 +221,16 @@ module.exports = {
209
221
  SESSION_STATES,
210
222
  SECTION_ORDER,
211
223
  MIN_REQUIRED_SECTIONS,
212
- SYSTEM_SPEC_QUESTIONS
224
+ SYSTEM_SPEC_QUESTIONS,
225
+ // Refine module exports
226
+ parseRefinementArgs,
227
+ loadRefinementContext,
228
+ applySpecDiff,
229
+ buildRefinementPayload,
230
+ linkParentRun,
231
+ isTechnicalFeature,
232
+ filterAffectedStories,
233
+ buildStoryChanges,
234
+ buildChangeSummary,
235
+ isPauseBypassable,
213
236
  };
package/src/refine.js ADDED
@@ -0,0 +1,172 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const crypto = require('crypto');
6
+
7
+ function parseRefinementArgs(argv) {
8
+ const slug = argv[3] || null;
9
+ return { slug };
10
+ }
11
+
12
+ function _extractFeatureId(content) {
13
+ const match = content.match(/^---[\s\S]*?featureId:\s*([^\s\n]+)[\s\S]*?---/m);
14
+ return match ? match[1] : null;
15
+ }
16
+
17
+ function _writeFeatureId(specPath, content, featureId) {
18
+ let updated;
19
+ if (content.startsWith('---')) {
20
+ const endIdx = content.indexOf('---', 3);
21
+ if (endIdx !== -1) {
22
+ const frontmatter = content.slice(3, endIdx);
23
+ if (frontmatter.includes('featureId:')) {
24
+ updated = content.replace(/featureId:\s*[^\s\n]+/, `featureId: ${featureId}`);
25
+ } else {
26
+ updated = `---${frontmatter}featureId: ${featureId}\n${content.slice(endIdx)}`;
27
+ }
28
+ } else {
29
+ updated = `---\nfeatureId: ${featureId}\n---\n${content}`;
30
+ }
31
+ } else {
32
+ updated = `---\nfeatureId: ${featureId}\n---\n${content}`;
33
+ }
34
+ fs.writeFileSync(specPath, updated, 'utf8');
35
+ return updated;
36
+ }
37
+
38
+ async function loadRefinementContext(slug, baseDir) {
39
+ const base = baseDir || process.cwd();
40
+ const featDir = path.join(base, '.blueprint', 'features', `feature_${slug}`);
41
+ const specPath = path.join(featDir, 'FEATURE_SPEC.md');
42
+
43
+ if (!fs.existsSync(specPath)) {
44
+ throw new Error(`FEATURE_SPEC.md not found for slug "${slug}" — run /implement-feature first`);
45
+ }
46
+
47
+ let specContent = fs.readFileSync(specPath, 'utf8');
48
+ let featureId = _extractFeatureId(specContent);
49
+ if (!featureId) {
50
+ featureId = crypto.randomUUID();
51
+ specContent = _writeFeatureId(specPath, specContent, featureId);
52
+ }
53
+
54
+ const storyFiles = fs.existsSync(featDir)
55
+ ? fs.readdirSync(featDir).filter(f => f.startsWith('story-') && f.endsWith('.md'))
56
+ : [];
57
+
58
+ const stories = storyFiles.map(f => ({
59
+ file: f,
60
+ content: fs.readFileSync(path.join(featDir, f), 'utf8'),
61
+ }));
62
+
63
+ const historyPath = path.join(base, '.claude', 'pipeline-history.json');
64
+ let history = [];
65
+ if (fs.existsSync(historyPath)) {
66
+ try {
67
+ history = JSON.parse(fs.readFileSync(historyPath, 'utf8'));
68
+ } catch (_) {
69
+ history = [];
70
+ }
71
+ }
72
+
73
+ const lastRun = history.filter(e => e.slug === slug).sort((a, b) =>
74
+ (b.completedAt || '').localeCompare(a.completedAt || '')
75
+ )[0];
76
+
77
+ return {
78
+ slug,
79
+ featureId,
80
+ spec: specContent,
81
+ stories,
82
+ history: history.filter(e => e.slug === slug),
83
+ lastRunStatus: lastRun ? lastRun.status : null,
84
+ featureName: slug,
85
+ };
86
+ }
87
+
88
+ async function applySpecDiff(specPath, newContent, featureId) {
89
+ if (newContent === null || newContent === undefined) {
90
+ throw new Error('abort: null diff provided — no changes applied');
91
+ }
92
+ _writeFeatureId(specPath, newContent, featureId);
93
+ }
94
+
95
+ function buildRefinementPayload(opts) {
96
+ const {
97
+ slug,
98
+ featureId,
99
+ storyChangesPath = null,
100
+ testChangesPath = null,
101
+ specDiff = null,
102
+ noCommit = false,
103
+ } = opts || {};
104
+
105
+ return {
106
+ slug,
107
+ featureId,
108
+ storyChangesPath: storyChangesPath || null,
109
+ testChangesPath: testChangesPath || null,
110
+ specDiff: specDiff || null,
111
+ commitSkipped: Boolean(noCommit),
112
+ };
113
+ }
114
+
115
+ function linkParentRun(slug, history) {
116
+ const slugRuns = (history || [])
117
+ .filter(e => e.slug === slug)
118
+ .sort((a, b) => (b.completedAt || '').localeCompare(a.completedAt || ''));
119
+
120
+ const latest = slugRuns[0] || null;
121
+
122
+ return {
123
+ parentRunId: latest ? latest.runId : null,
124
+ type: 'refinement',
125
+ featureId: latest ? latest.featureId : null,
126
+ };
127
+ }
128
+
129
+ function isTechnicalFeature(stories) {
130
+ return stories.length === 0;
131
+ }
132
+
133
+ function filterAffectedStories(stories, changedSlugs) {
134
+ return stories.filter(f => {
135
+ const name = path.basename(f, '.md').replace(/^story-/, '');
136
+ return changedSlugs.some(s => name === s || f.includes(s));
137
+ });
138
+ }
139
+
140
+ function buildStoryChanges(entries) {
141
+ return (entries || []).map(e => ({
142
+ file: e.file,
143
+ reason: e.reason,
144
+ isNew: Boolean(e.isNew),
145
+ }));
146
+ }
147
+
148
+ function buildChangeSummary(opts) {
149
+ const { specPath, affectedStories, testChangesPath } = opts || {};
150
+ return {
151
+ specPath: specPath || null,
152
+ affectedStories: Array.isArray(affectedStories) ? affectedStories : [],
153
+ testChangesPath: testChangesPath || null,
154
+ };
155
+ }
156
+
157
+ function isPauseBypassable(_flags) {
158
+ return false;
159
+ }
160
+
161
+ module.exports = {
162
+ parseRefinementArgs,
163
+ loadRefinementContext,
164
+ applySpecDiff,
165
+ buildRefinementPayload,
166
+ linkParentRun,
167
+ isTechnicalFeature,
168
+ filterAffectedStories,
169
+ buildStoryChanges,
170
+ buildChangeSummary,
171
+ isPauseBypassable,
172
+ };