@houseofwolvesllc/claude-scrum-skill 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +30 -0
- package/lib/workflows/schemas/SpecSchema.json +1 -0
- package/lib/workflows/sprint_pipeline.js +176 -68
- package/package.json +1 -1
- package/skills/design-patterns/SKILL.md +133 -0
- package/skills/domain-modeling/SKILL.md +121 -0
- package/skills/project-orchestrate/SKILL.md +8 -2
- package/skills/project-scaffold/SKILL.md +10 -0
- package/skills/project-spec/SKILL.md +38 -0
- package/skills/shared/references/ENGINEERING_BASELINE.md +154 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-scrum-skill",
|
|
3
3
|
"description": "Complete scrum pipeline — PRD to production release with Claude as scrum master. Includes project scaffolding, sprint planning, status tracking, sprint releases, and full-project emulation testing.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "2.1.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "House of Wolves LLC"
|
|
7
7
|
},
|
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ An open-source npm package of Claude Code skills that give you a complete scrum
|
|
|
4
4
|
|
|
5
5
|
Includes project scaffolding, sprint planning, status tracking, sprint releases, full-project emulation testing, autonomous orchestration, and project cleanup.
|
|
6
6
|
|
|
7
|
+
It is also an **opinionated spec-and-implementation process**: its engineering guidance is grounded in the principles of four foundational software texts — Robert C. Martin's *Clean Code*, Kent Beck's *Test-Driven Development: By Example*, Eric Evans's *Domain-Driven Design*, and the Gang of Four's *Design Patterns* — distilled into an always-on engineering baseline plus on-demand design-pattern and domain-modeling guidance. See [Acknowledgments](#acknowledgments).
|
|
8
|
+
|
|
7
9
|
```
|
|
8
10
|
Manual mode — you invoke each skill:
|
|
9
11
|
|
|
@@ -54,6 +56,7 @@ PRD (optional) --> /project-orchestrate
|
|
|
54
56
|
- [Autonomous Orchestration](#autonomous-orchestration)
|
|
55
57
|
- [Customization](#customization)
|
|
56
58
|
- [Tips](#tips)
|
|
59
|
+
- [Acknowledgments](#acknowledgments)
|
|
57
60
|
- [License](#license)
|
|
58
61
|
|
|
59
62
|
---
|
|
@@ -348,9 +351,13 @@ Create a fine-grained Personal Access Token:
|
|
|
348
351
|
| **project-emulate** | `/project-emulate` | Integration seams, layer contracts, cross-service payloads, full lifecycle walkthrough |
|
|
349
352
|
| **project-orchestrate** | `/project-orchestrate [prd] [repo]` | Autonomous lifecycle driver |
|
|
350
353
|
| **project-cleanup** | `/project-cleanup [path] [--fix]` | Build, lint, dead code, and test coverage |
|
|
354
|
+
| **design-patterns** | `/design-patterns` | Gang of Four pattern guidance, counterweight-first; composed by `spec` (design) and `project-orchestrate` (core-domain implementation) |
|
|
355
|
+
| **domain-modeling** | `/domain-modeling` | Tactical Domain-Driven Design guidance; composed by `spec` and `project-orchestrate` for core-domain epics |
|
|
351
356
|
|
|
352
357
|
The `[owner/repo]` argument is only needed in GitHub mode. Jira, Trello, and local modes read from config.
|
|
353
358
|
|
|
359
|
+
`design-patterns` and `domain-modeling` are **situational guidance** layered on top of the always-on engineering baseline (`skills/shared/references/ENGINEERING_BASELINE.md`). They are pulled in automatically by `spec` and `project-orchestrate` for `core`-classified subdomains, and are also invocable directly. See [Acknowledgments](#acknowledgments) for their sources.
|
|
360
|
+
|
|
354
361
|
---
|
|
355
362
|
|
|
356
363
|
## Branch Strategy
|
|
@@ -565,6 +572,29 @@ skills/shared/
|
|
|
565
572
|
|
|
566
573
|
---
|
|
567
574
|
|
|
575
|
+
## Acknowledgments
|
|
576
|
+
|
|
577
|
+
The engineering guidance in this package — the always-on baseline plus the
|
|
578
|
+
`design-patterns` and `domain-modeling` skills — is grounded in the principles of
|
|
579
|
+
four foundational software texts. The guidance is expressed in this project's own
|
|
580
|
+
words; these works are credited as its intellectual sources. Their authors are not
|
|
581
|
+
affiliated with and do not endorse this project.
|
|
582
|
+
|
|
583
|
+
- **Robert C. Martin**, *Clean Code: A Handbook of Agile Software Craftsmanship*
|
|
584
|
+
(Prentice Hall, 2008) — the engineering baseline's naming, function, comment, and
|
|
585
|
+
code-quality principles.
|
|
586
|
+
- **Kent Beck**, *Test-Driven Development: By Example* (Addison-Wesley, 2002) — the
|
|
587
|
+
baseline's red/green/refactor discipline and simple-design rules.
|
|
588
|
+
- **Eric Evans**, *Domain-Driven Design: Tackling Complexity in the Heart of
|
|
589
|
+
Software* (Addison-Wesley, 2003) — the `domain-modeling` skill's tactical
|
|
590
|
+
building blocks and ubiquitous-language guidance.
|
|
591
|
+
- **Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides** ("the Gang of
|
|
592
|
+
Four"), *Design Patterns: Elements of Reusable Object-Oriented Software*
|
|
593
|
+
(Addison-Wesley, 1994) — the `design-patterns` skill's pattern catalog.
|
|
594
|
+
|
|
595
|
+
If you find this guidance useful, read the originals — they go far deeper than any
|
|
596
|
+
distillation can.
|
|
597
|
+
|
|
568
598
|
## License
|
|
569
599
|
|
|
570
600
|
Apache 2.0 — See [LICENSE](LICENSE) for details.
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"name": { "type": "string" },
|
|
44
44
|
"slug": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" },
|
|
45
45
|
"description": { "type": "string" },
|
|
46
|
+
"subdomain": { "type": "string", "enum": ["core", "supporting", "generic"] },
|
|
46
47
|
"depends_on": { "type": "array", "items": { "type": "string" } },
|
|
47
48
|
"shared_design_concerns": { "type": "array", "items": { "type": "string" } },
|
|
48
49
|
"slice": {
|
|
@@ -1,8 +1,33 @@
|
|
|
1
|
-
// sprint_pipeline.js — per-story sprint execution
|
|
1
|
+
// sprint_pipeline.js — per-story sprint execution.
|
|
2
2
|
//
|
|
3
|
-
// Invoked by /project-orchestrate Phase 1 Step 3.
|
|
4
|
-
//
|
|
5
|
-
// to min(16, cpu_cores - 2) per the
|
|
3
|
+
// Invoked by /project-orchestrate Phase 1 Step 3. Each story runs its own
|
|
4
|
+
// independent chain — implement → review → verify → open PR — with no
|
|
5
|
+
// per-stage barriers and concurrency up to min(16, cpu_cores - 2) per the
|
|
6
|
+
// Workflow tool's cap.
|
|
7
|
+
//
|
|
8
|
+
// Concurrency safety. Stories run in parallel against one git repository, so
|
|
9
|
+
// the model is built around a single invariant: the main working tree is
|
|
10
|
+
// mutated only by the serialized local-mode merge step. Everything else stays
|
|
11
|
+
// off it.
|
|
12
|
+
// - Implement and verify run in isolated worktrees (`isolation: 'worktree'`).
|
|
13
|
+
// They create/build the story branch in their own tree, so concurrent
|
|
14
|
+
// `git checkout -b` and commits never race in the shared tree. Branches and
|
|
15
|
+
// commits land in the shared object store and are visible afterward.
|
|
16
|
+
// - Review only diffs two refs (object-store comparison, no checkout), so it
|
|
17
|
+
// never touches the working tree.
|
|
18
|
+
// - Local-mode finalize merges each story branch into the shared release
|
|
19
|
+
// branch in the main tree; these merges are serialized behind a lock so
|
|
20
|
+
// concurrent fan-in merges cannot race. GitHub mode opens independent PRs
|
|
21
|
+
// and needs no lock.
|
|
22
|
+
//
|
|
23
|
+
// Dependency gating. A story does not start until every blocker that is also in
|
|
24
|
+
// this batch has finished `done` (see `blocked_by`). Because a dependent only
|
|
25
|
+
// branches after its in-batch blockers have merged into the release branch, it
|
|
26
|
+
// builds on their work. Blockers outside this batch are the orchestrator's
|
|
27
|
+
// concern — it passes only stories whose external blockers are already resolved
|
|
28
|
+
// (SKILL.md "Independence check"). The in-batch graph is assumed acyclic; the
|
|
29
|
+
// orchestrate skill validates the dependency DAG (cycle + missing-edge checks)
|
|
30
|
+
// before any story reaches this workflow.
|
|
6
31
|
//
|
|
7
32
|
// args: {
|
|
8
33
|
// stories: Story[], // StorySchema-shaped
|
|
@@ -12,7 +37,9 @@
|
|
|
12
37
|
// claudeMdPath?: string, // project CLAUDE.md
|
|
13
38
|
// backendMode: "local" | "github" | "jira" | "trello",
|
|
14
39
|
// repoIdentifier?: string, // "owner/repo" — github mode only
|
|
15
|
-
// personaPreambles: Record<string, string
|
|
40
|
+
// personaPreambles: Record<string, string>, // persona name → preamble text
|
|
41
|
+
// baselinePath?: string, // shared/references/ENGINEERING_BASELINE.md — injected into every story
|
|
42
|
+
// situationalGuidance?: string[] // SKILL.md paths (design-patterns, domain-modeling) — core-domain epics only
|
|
16
43
|
// }
|
|
17
44
|
//
|
|
18
45
|
// returns: SprintStoryReturn[] (one per story; failed items filtered to null upstream)
|
|
@@ -106,6 +133,8 @@ const {
|
|
|
106
133
|
backendMode,
|
|
107
134
|
repoIdentifier,
|
|
108
135
|
personaPreambles = {},
|
|
136
|
+
baselinePath,
|
|
137
|
+
situationalGuidance = [],
|
|
109
138
|
} = args
|
|
110
139
|
|
|
111
140
|
if (!stories || stories.length === 0) {
|
|
@@ -124,6 +153,12 @@ function buildImplementPrompt(story) {
|
|
|
124
153
|
const contextLine = contextMdPath
|
|
125
154
|
? `Before writing any code, read ${contextMdPath} if it exists. Its Naming, File Layout, Shared Types, and Patterns sections are binding for this epic — they override generic CLAUDE.md conventions for this epic.`
|
|
126
155
|
: ''
|
|
156
|
+
const baselineLine = baselinePath
|
|
157
|
+
? `Before writing any code, read ${baselinePath} — the universal engineering baseline (Clean Code, Test-Driven Development, and the simple-design Arbitration Rule). Follow it for all code: write tests first (red-green-refactor), keep designs simple, and treat the Arbitration Rule as binding. On a direct conflict the project CLAUDE.md wins.`
|
|
158
|
+
: ''
|
|
159
|
+
const situationalLine = situationalGuidance.length
|
|
160
|
+
? `This is a core-domain story. Also read and apply: ${situationalGuidance.join(', ')}. These are situational guidance and remain subordinate to the baseline's Arbitration Rule — model the domain's invariants first, and reach for a design pattern or domain layer only when a demonstrated axis of variation or an essential business rule warrants it, never speculatively.`
|
|
161
|
+
: ''
|
|
127
162
|
return `${preamble}
|
|
128
163
|
|
|
129
164
|
---
|
|
@@ -131,6 +166,8 @@ function buildImplementPrompt(story) {
|
|
|
131
166
|
You are implementing story ${story.slug} on release branch ${releaseBranch}.
|
|
132
167
|
|
|
133
168
|
${claudeMdLine}
|
|
169
|
+
${baselineLine}
|
|
170
|
+
${situationalLine}
|
|
134
171
|
${contextLine}
|
|
135
172
|
|
|
136
173
|
**Story:** ${story.title}
|
|
@@ -139,7 +176,7 @@ ${(story.acceptance_criteria || []).map(c => ` - ${c}`).join('\n')}
|
|
|
139
176
|
|
|
140
177
|
**Technical context:** ${story.technical_context || '(none provided)'}
|
|
141
178
|
|
|
142
|
-
**Branch strategy:** Create branch \`story/${story.slug}\` from \`${releaseBranch}
|
|
179
|
+
**Branch strategy:** You are in an isolated git worktree — work only here; do not touch other branches. Create branch \`story/${story.slug}\` from the latest \`${releaseBranch}\` (\`git checkout -b story/${story.slug} ${releaseBranch}\`); it already contains any in-sprint dependency this story builds on. Implement. Commit with a clear message. Return the branch name, the commit SHAs, and any notes.
|
|
143
180
|
|
|
144
181
|
Do NOT open a PR yet. Do NOT merge. The next stage handles review.`
|
|
145
182
|
}
|
|
@@ -147,12 +184,12 @@ Do NOT open a PR yet. Do NOT merge. The next stage handles review.`
|
|
|
147
184
|
function buildReviewPrompt(impl, story) {
|
|
148
185
|
return `You are reviewing the implementation of story ${story.slug} on branch ${impl.branch}.
|
|
149
186
|
|
|
150
|
-
Read the diff between ${releaseBranch} and ${impl.branch}.
|
|
187
|
+
Read the diff between ${releaseBranch} and ${impl.branch} with \`git diff ${releaseBranch}...${impl.branch}\` — do NOT check out either branch (other stories run concurrently in this repository; checking out would disturb the shared working tree).
|
|
151
188
|
|
|
152
189
|
Story acceptance criteria:
|
|
153
190
|
${(story.acceptance_criteria || []).map(c => ` - ${c}`).join('\n')}
|
|
154
191
|
|
|
155
|
-
Review for: correctness against acceptance criteria, project convention compliance (per CLAUDE.md), and obvious defects. Do NOT bikeshed style the project doesn't enforce.
|
|
192
|
+
Review for: correctness against acceptance criteria, project convention compliance (per CLAUDE.md${baselinePath ? ` and the engineering baseline at ${baselinePath}` : ''}), and obvious defects. ${baselinePath ? 'Confirm the baseline was honored: tests accompany the code and the design is the simplest that satisfies the story (no unearned abstraction). ' : ''}Do NOT bikeshed style the project doesn't enforce.
|
|
156
193
|
|
|
157
194
|
Return a ReviewVerdict: recommendation (accept | accept-with-followups | block), findings grouped by severity, and a one-paragraph summary.`
|
|
158
195
|
}
|
|
@@ -160,7 +197,7 @@ Return a ReviewVerdict: recommendation (accept | accept-with-followups | block),
|
|
|
160
197
|
function buildVerifyPrompt(review, story) {
|
|
161
198
|
return `You are running a lightweight verification on story ${story.slug}.
|
|
162
199
|
|
|
163
|
-
If the project has a build/lint/test command, run it on the story branch. If not, perform a smoke read of the changed files to confirm no obvious runtime defects (broken imports, syntax errors, dangling references).
|
|
200
|
+
You are in an isolated git worktree — check out \`story/${story.slug}\` here (\`git checkout story/${story.slug}\`) so any build artifacts stay off the shared working tree. If the project has a build/lint/test command, run it on the story branch. If not, perform a smoke read of the changed files to confirm no obvious runtime defects (broken imports, syntax errors, dangling references).
|
|
164
201
|
|
|
165
202
|
Return verifyStatus (pass | warn | fail) and brief notes.`
|
|
166
203
|
}
|
|
@@ -184,69 +221,140 @@ phase('Review')
|
|
|
184
221
|
phase('Verify')
|
|
185
222
|
phase('Open PR')
|
|
186
223
|
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
224
|
+
const batchSlugs = new Set(stories.map(story => story.slug))
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Blockers of `story` that are also in this batch, by trailing slug.
|
|
228
|
+
* blocked_by entries may be bare slugs or "<epic>/<slug>" references. A story
|
|
229
|
+
* cannot block itself, and blockers outside the batch are the orchestrator's
|
|
230
|
+
* concern (it only passes stories whose external blockers are resolved).
|
|
231
|
+
*/
|
|
232
|
+
function inBatchBlockers(story) {
|
|
233
|
+
return (story.blocked_by || [])
|
|
234
|
+
.map(reference => reference.split('/').pop())
|
|
235
|
+
.filter(slug => slug !== story.slug && batchSlugs.has(slug))
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Serializes local-mode merges onto the shared release branch: each merge runs
|
|
239
|
+
// only after the previous one settles, success or failure, so a failed merge
|
|
240
|
+
// never stalls the rest. GitHub mode opens independent PRs and does not use it.
|
|
241
|
+
let mergeChain = Promise.resolve()
|
|
242
|
+
function serializeMerge(runMerge) {
|
|
243
|
+
const merged = mergeChain.then(runMerge, runMerge)
|
|
244
|
+
mergeChain = merged.then(() => {}, () => {})
|
|
245
|
+
return merged
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function reviewBlocked(story, impl, review) {
|
|
249
|
+
return makeSprintStoryReturn({
|
|
250
|
+
storySlug: story.slug,
|
|
251
|
+
status: 'blocked',
|
|
252
|
+
branch: impl.branch,
|
|
253
|
+
commits: impl.commits,
|
|
254
|
+
blockers: [
|
|
255
|
+
...review.findings.critical.map(finding => finding.title),
|
|
256
|
+
...review.findings.warning.map(finding => finding.title),
|
|
257
|
+
],
|
|
258
|
+
reason: 'Review recommended block.',
|
|
259
|
+
})
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function verifyBlocked(story, impl, verify) {
|
|
263
|
+
return makeSprintStoryReturn({
|
|
264
|
+
storySlug: story.slug,
|
|
265
|
+
status: 'blocked',
|
|
266
|
+
branch: impl.branch,
|
|
267
|
+
commits: impl.commits,
|
|
268
|
+
blockers: [verify.notes || 'verification failed'],
|
|
269
|
+
reason: 'Verification failed.',
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function dependencyBlocked(story, unmet) {
|
|
274
|
+
return makeSprintStoryReturn({
|
|
275
|
+
storySlug: story.slug,
|
|
276
|
+
status: 'blocked',
|
|
277
|
+
blockers: unmet.map(slug => `upstream story ${slug} did not complete`),
|
|
278
|
+
reason: 'Upstream in-sprint dependency did not complete.',
|
|
279
|
+
})
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Each story's terminal promise, registered before any chain runs so a
|
|
283
|
+
// dependent can always await its blocker regardless of array order.
|
|
284
|
+
const terminal = new Map()
|
|
285
|
+
|
|
286
|
+
async function runStory(story) {
|
|
287
|
+
const blockers = inBatchBlockers(story)
|
|
288
|
+
if (blockers.length) {
|
|
289
|
+
const outcomes = await Promise.all(blockers.map(slug => terminal.get(slug)))
|
|
290
|
+
const unmet = blockers.filter((_, index) => outcomes[index]?.status !== 'done')
|
|
291
|
+
if (unmet.length) {
|
|
292
|
+
log(`Skipping ${story.slug}: upstream ${unmet.join(', ')} did not complete.`)
|
|
293
|
+
return dependencyBlocked(story, unmet)
|
|
243
294
|
}
|
|
244
|
-
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const impl = await agent(buildImplementPrompt(story), {
|
|
298
|
+
label: `impl:${story.slug}`,
|
|
299
|
+
phase: 'Implement',
|
|
300
|
+
schema: IMPL_RETURN_SCHEMA,
|
|
301
|
+
isolation: 'worktree',
|
|
302
|
+
})
|
|
303
|
+
if (!impl) return null
|
|
304
|
+
|
|
305
|
+
const review = await agent(buildReviewPrompt(impl, story), {
|
|
306
|
+
label: `review:${story.slug}`,
|
|
307
|
+
phase: 'Review',
|
|
308
|
+
schema: REVIEW_VERDICT_SCHEMA,
|
|
309
|
+
})
|
|
310
|
+
if (!review) return null
|
|
311
|
+
if (review.recommendation === 'block') return reviewBlocked(story, impl, review)
|
|
312
|
+
|
|
313
|
+
const verify = await agent(buildVerifyPrompt(review, story), {
|
|
314
|
+
label: `verify:${story.slug}`,
|
|
315
|
+
phase: 'Verify',
|
|
316
|
+
schema: VERIFY_RETURN_SCHEMA,
|
|
317
|
+
isolation: 'worktree',
|
|
318
|
+
})
|
|
319
|
+
if (!verify) return null
|
|
320
|
+
if (verify.verifyStatus === 'fail') return verifyBlocked(story, impl, verify)
|
|
321
|
+
|
|
322
|
+
const finalize = () =>
|
|
323
|
+
agent(buildOpenPRPrompt(verify, story, impl), {
|
|
245
324
|
label: `pr:${story.slug}`,
|
|
246
325
|
phase: 'Open PR',
|
|
247
326
|
schema: SPRINT_STORY_RETURN_SCHEMA,
|
|
248
327
|
})
|
|
249
|
-
}
|
|
250
|
-
)
|
|
251
328
|
|
|
329
|
+
// Local mode mutates the shared release branch — serialize. GitHub mode opens
|
|
330
|
+
// an independent PR and can run concurrently.
|
|
331
|
+
return backendMode === 'github' ? finalize() : serializeMerge(finalize)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Open the gate only after every terminal promise is registered, so a
|
|
335
|
+
// dependent's blocker lookup never races an unregistered entry.
|
|
336
|
+
let openGate
|
|
337
|
+
const gate = new Promise(resolve => {
|
|
338
|
+
openGate = resolve
|
|
339
|
+
})
|
|
340
|
+
for (const story of stories) {
|
|
341
|
+
terminal.set(
|
|
342
|
+
story.slug,
|
|
343
|
+
// Isolate each chain: a thrown agent or stage becomes a 'failed' result
|
|
344
|
+
// rather than rejecting Promise.all and tearing down the whole batch. A
|
|
345
|
+
// failed (not 'done') outcome also correctly blocks any dependent.
|
|
346
|
+
gate.then(() => runStory(story)).catch(error => {
|
|
347
|
+
const detail = error?.message || String(error)
|
|
348
|
+
log(`Story ${story.slug} errored: ${detail}`)
|
|
349
|
+
return makeSprintStoryReturn({
|
|
350
|
+
storySlug: story.slug,
|
|
351
|
+
status: 'failed',
|
|
352
|
+
reason: `Unhandled error: ${detail}`,
|
|
353
|
+
})
|
|
354
|
+
})
|
|
355
|
+
)
|
|
356
|
+
}
|
|
357
|
+
openGate()
|
|
358
|
+
|
|
359
|
+
const results = await Promise.all(stories.map(story => terminal.get(story.slug)))
|
|
252
360
|
return results.filter(Boolean)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@houseofwolvesllc/claude-scrum-skill",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Claude Code skills for scrum project management — PRD to production release pipeline with project scaffolding, sprint planning, status tracking, sprint releases, full-project emulation testing, autonomous orchestration, and project cleanup.",
|
|
5
5
|
"bin": {},
|
|
6
6
|
"publishConfig": {
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: design-patterns
|
|
3
|
+
description: >-
|
|
4
|
+
Faithful Gang of Four design-pattern catalog for complex core-domain design.
|
|
5
|
+
Used by project-spec (to name candidate patterns against real axes of
|
|
6
|
+
variation) and project-orchestrate (to refactor toward a named pattern while
|
|
7
|
+
implementing core-domain epics). Surfaces on a specific, demonstrated design
|
|
8
|
+
problem — conditional/switch logic on a type spreading across call sites, a
|
|
9
|
+
need for runtime-substitutable behavior, adding variants without modifying
|
|
10
|
+
existing classes, an object that must notify dependents, or a deliberate
|
|
11
|
+
extension point — or when a pattern is named explicitly. NOT for CRUD,
|
|
12
|
+
scripts, glue code, one-off transforms, or routine feature work; for those,
|
|
13
|
+
prefer the simplest thing that works.
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Design Patterns (Gang of Four)
|
|
17
|
+
|
|
18
|
+
The classic catalog from *Design Patterns: Elements of Reusable Object-Oriented
|
|
19
|
+
Software* (Gamma, Helm, Johnson, Vlissides). This skill is the **situational
|
|
20
|
+
layer** — it composes on top of the Engineering Baseline and never overrides it.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Read this before reaching for any pattern
|
|
25
|
+
|
|
26
|
+
**You almost certainly do not need a pattern.** Patterns are a destination you
|
|
27
|
+
**refactor toward** once a smell proves you need the flexibility — not a design
|
|
28
|
+
you start from. This is the discipline of *Refactoring to Patterns* (Kerievsky),
|
|
29
|
+
and it is the only safe way to use this catalog.
|
|
30
|
+
|
|
31
|
+
Subordinate every entry below to the **Arbitration Rule** in
|
|
32
|
+
`../shared/references/ENGINEERING_BASELINE.md`:
|
|
33
|
+
|
|
34
|
+
> Simple design is the default. Abstractions and patterns are responses to
|
|
35
|
+
> demonstrated complexity — never anticipatory architecture.
|
|
36
|
+
|
|
37
|
+
Guardrails:
|
|
38
|
+
|
|
39
|
+
- **Prefer the simplest thing that works.** Three similar lines beat a premature
|
|
40
|
+
abstraction. A function, a closure, a map, or a plain conditional usually wins.
|
|
41
|
+
- **Apply the rule of three.** Don't introduce a pattern for one or two cases.
|
|
42
|
+
Wait until duplication or repeated change in the same place demands it.
|
|
43
|
+
- **Patterns are a vocabulary, not a checklist.** Naming the pattern you arrived
|
|
44
|
+
at aids communication; hunting for a pattern to apply causes over-engineering.
|
|
45
|
+
- **A named pattern can always collapse back.** If the variation it anticipated
|
|
46
|
+
never materializes, refactor it away.
|
|
47
|
+
|
|
48
|
+
### Two modes (set by the calling skill)
|
|
49
|
+
- **Design time (`project-spec`):** name a *candidate* pattern for an identified
|
|
50
|
+
axis of variation. Always in the form
|
|
51
|
+
`Pattern — because <real axis of variation>; revisit at build (may collapse to
|
|
52
|
+
a simpler form if the variation does not materialize)`. Candidate, justified,
|
|
53
|
+
revisitable — never binding.
|
|
54
|
+
- **Implementation time (`project-orchestrate`, core epics only):** refactor
|
|
55
|
+
*toward* a candidate pattern only once the variation it anticipated has
|
|
56
|
+
actually appeared in the code. Otherwise implement the simplest sufficient
|
|
57
|
+
thing and leave the pattern unbuilt.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## The 23 patterns
|
|
62
|
+
|
|
63
|
+
Each entry describes the pattern's intent in plain terms; the *reach for it* line
|
|
64
|
+
is practical guidance for when a demonstrated smell justifies it. For the canonical
|
|
65
|
+
treatment — motivation, structure, participants, and sample code — consult the book
|
|
66
|
+
itself (cited under Acknowledgments).
|
|
67
|
+
|
|
68
|
+
### Creational — how objects get made
|
|
69
|
+
|
|
70
|
+
- **Abstract Factory** — create whole families of related or dependent objects
|
|
71
|
+
through one interface, without binding code to their concrete classes. Reach for
|
|
72
|
+
it when the system must stay independent of how a product *family* is produced.
|
|
73
|
+
- **Builder** — separate the construction of a complex object from its
|
|
74
|
+
representation, so one construction process can yield different representations.
|
|
75
|
+
Reach for it for multi-step assembly or many optional parts.
|
|
76
|
+
- **Factory Method** — define a creation interface but let subclasses choose which
|
|
77
|
+
class to instantiate, deferring instantiation to them.
|
|
78
|
+
- **Prototype** — produce new objects by copying a prototypical instance rather
|
|
79
|
+
than instantiating classes directly. Reach for it when instantiation is costly or
|
|
80
|
+
types are chosen at runtime.
|
|
81
|
+
- **Singleton** — guarantee a single instance with one global access point. Use
|
|
82
|
+
sparingly — global mutable state, often an anti-pattern; prefer dependency
|
|
83
|
+
injection.
|
|
84
|
+
|
|
85
|
+
### Structural — how objects compose
|
|
86
|
+
|
|
87
|
+
- **Adapter** — convert a class's interface into the one clients expect, letting
|
|
88
|
+
otherwise-incompatible interfaces work together. Typically at a boundary.
|
|
89
|
+
- **Bridge** — decouple an abstraction from its implementation so the two can vary
|
|
90
|
+
independently. Reach for it to avoid a combinatorial subclass explosion.
|
|
91
|
+
- **Composite** — arrange objects into tree structures for part-whole hierarchies,
|
|
92
|
+
letting clients treat individual objects and compositions uniformly.
|
|
93
|
+
- **Decorator** — attach responsibilities to an object dynamically — a flexible
|
|
94
|
+
alternative to subclassing for extending behavior.
|
|
95
|
+
- **Facade** — offer a single higher-level interface to a subsystem, making it
|
|
96
|
+
easier to use and decoupling clients from its internals.
|
|
97
|
+
- **Flyweight** — share fine-grained objects to support large numbers of them
|
|
98
|
+
efficiently. Reach for it when many objects share intrinsic state.
|
|
99
|
+
- **Proxy** — stand in for another object to control access to it (lazy loading,
|
|
100
|
+
access control, remoting, caching).
|
|
101
|
+
|
|
102
|
+
### Behavioral — how objects interact and distribute responsibility
|
|
103
|
+
|
|
104
|
+
- **Chain of Responsibility** — give several objects a chance to handle a request
|
|
105
|
+
by passing it along a chain until one handles it, decoupling sender from receiver.
|
|
106
|
+
- **Command** — encapsulate a request as an object, enabling parameterization,
|
|
107
|
+
queuing, logging, and undo.
|
|
108
|
+
- **Interpreter** — represent a grammar and an interpreter that evaluates sentences
|
|
109
|
+
in that language. Reach for it only for simple, well-understood grammars.
|
|
110
|
+
- **Iterator** — traverse the elements of an aggregate sequentially without
|
|
111
|
+
exposing its underlying representation. Usually built into the language.
|
|
112
|
+
- **Mediator** — encapsulate how a set of objects interact in a mediator object,
|
|
113
|
+
promoting loose coupling by removing their direct references to each other.
|
|
114
|
+
- **Memento** — capture and externalize an object's internal state without breaking
|
|
115
|
+
encapsulation, so it can be restored later. Reach for it for undo/checkpoint.
|
|
116
|
+
- **Observer** — establish a one-to-many dependency so that when one object changes
|
|
117
|
+
state, its dependents are notified and updated automatically.
|
|
118
|
+
- **State** — let an object change its behavior when its internal state changes, as
|
|
119
|
+
if it changed class. Reach for it to replace sprawling state conditionals.
|
|
120
|
+
- **Strategy** — encapsulate a family of interchangeable algorithms behind a common
|
|
121
|
+
interface so the algorithm can vary independently of the clients that use it.
|
|
122
|
+
- **Template Method** — define the skeleton of an algorithm and defer some steps to
|
|
123
|
+
subclasses, which can redefine those steps without changing the structure.
|
|
124
|
+
- **Visitor** — represent an operation to perform on the elements of an object
|
|
125
|
+
structure, letting you add new operations without modifying those elements.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
These intents are paraphrased descriptions of the patterns from *Design Patterns:
|
|
130
|
+
Elements of Reusable Object-Oriented Software* (Gamma, Helm, Johnson, Vlissides);
|
|
131
|
+
the catalog is credited under Acknowledgments. Selecting among these patterns — and
|
|
132
|
+
resisting them when the simplest thing suffices — is governed by the counterweight
|
|
133
|
+
above and the Engineering Baseline's Arbitration Rule.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: domain-modeling
|
|
3
|
+
description: >-
|
|
4
|
+
Tactical Domain-Driven Design for modeling complex core domains — deciding
|
|
5
|
+
where a business rule belongs, designing aggregate boundaries and their
|
|
6
|
+
consistency rules, choosing between an entity and a value object, introducing
|
|
7
|
+
domain events, and keeping code aligned with the domain's ubiquitous language.
|
|
8
|
+
Used by project-spec (advisory, shaping the spec and classifying subdomains)
|
|
9
|
+
and project-orchestrate (active, while implementing core-domain epics). Fires
|
|
10
|
+
only for behavior-rich core-domain logic. STAYS DORMANT for CRUD, generic and
|
|
11
|
+
supporting subdomains, technical plumbing, data pipelines, and simple
|
|
12
|
+
persistence — per Evans's own scoping: tactical DDD is for the core domain's
|
|
13
|
+
essential complexity, not generic subdomains.
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Domain Modeling (Tactical DDD)
|
|
17
|
+
|
|
18
|
+
The tactical building blocks from *Domain-Driven Design* (Eric Evans). This skill
|
|
19
|
+
is the **situational layer** — it composes on top of the Engineering Baseline and
|
|
20
|
+
never overrides it.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Read this before modeling
|
|
25
|
+
|
|
26
|
+
**Apply this only to the complex core domain.** Evans's own thesis: tactical DDD
|
|
27
|
+
earns its structure where essential business complexity lives — not in generic or
|
|
28
|
+
supporting subdomains, and never in CRUD, plumbing, or simple persistence. For
|
|
29
|
+
those, the Engineering Baseline's Arbitration Rule governs: write the simplest
|
|
30
|
+
thing that works.
|
|
31
|
+
|
|
32
|
+
The `subdomain` classification (`core` / `supporting` / `generic`) is set once,
|
|
33
|
+
at design time, by `project-spec`. `project-orchestrate` reads it and applies
|
|
34
|
+
this guidance **only to `core` epics**. Do not re-derive the classification
|
|
35
|
+
downstream.
|
|
36
|
+
|
|
37
|
+
Subordinate every decision below to the **Arbitration Rule** in
|
|
38
|
+
`../shared/references/ENGINEERING_BASELINE.md`. Aggregates and domain services add
|
|
39
|
+
layers; pay for them only where invariants demand it.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Ubiquitous language
|
|
44
|
+
|
|
45
|
+
Evans's idea: make the domain model the backbone of a shared language, and have
|
|
46
|
+
the whole team use that language relentlessly — in speech, writing, diagrams, and
|
|
47
|
+
the code itself.
|
|
48
|
+
|
|
49
|
+
In practice: name classes, methods, and modules after the terms stakeholders
|
|
50
|
+
actually use. When the code's language drifts from the conversation, the model is
|
|
51
|
+
wrong — fix the names, and often the design follows.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Building blocks (decision-oriented)
|
|
56
|
+
|
|
57
|
+
### Entity vs. Value Object — choose deliberately
|
|
58
|
+
- **Entity** (Evans) — an object distinguished by its identity and life-cycle
|
|
59
|
+
continuity rather than its attributes; keep its definition focused on identity
|
|
60
|
+
and continuity over time. Use when the thing has a lifecycle and must be tracked
|
|
61
|
+
(an `Order`, an `Account`).
|
|
62
|
+
- **Value Object** (Evans) — an object you care about only for its attributes;
|
|
63
|
+
make it immutable, give it no identity, let it carry related behavior, and let
|
|
64
|
+
its attributes form a single conceptual whole (`Money`, `DateRange`, `Address`).
|
|
65
|
+
**Default to value objects** — they are simpler, safe to share, and push behavior
|
|
66
|
+
to where the data lives. Reach for an entity only when identity genuinely matters.
|
|
67
|
+
|
|
68
|
+
### Where does a business rule live?
|
|
69
|
+
- A rule about a single concept belongs **on that entity or value object** (rich
|
|
70
|
+
behavior, not an anemic data bag — this aligns with Clean Code's "objects
|
|
71
|
+
expose behavior").
|
|
72
|
+
- A rule that spans several objects and belongs to none belongs in a **Domain
|
|
73
|
+
Service** (Evans) — a stateless operation offered as a standalone interface in
|
|
74
|
+
the model (unlike entities and value objects, it encapsulates no state). Name it
|
|
75
|
+
in the ubiquitous language. Use sparingly; most logic belongs on the model.
|
|
76
|
+
- A rule that enforces consistency across a cluster belongs at the **aggregate
|
|
77
|
+
root** (below).
|
|
78
|
+
|
|
79
|
+
### Aggregates
|
|
80
|
+
- Evans's idea: cluster related entities and value objects into an **aggregate**
|
|
81
|
+
with a defined boundary, pick one entity as the **root**, and route all external
|
|
82
|
+
access through it — outside objects may hold a reference only to the root.
|
|
83
|
+
- Because the root controls access, it can enforce every invariant of the aggregate
|
|
84
|
+
on any state change.
|
|
85
|
+
- **Boundary heuristics:** keep aggregates small; one transaction modifies one
|
|
86
|
+
aggregate; reference other aggregates by identity, not by holding the object;
|
|
87
|
+
let cross-aggregate consistency be eventual.
|
|
88
|
+
|
|
89
|
+
### Repositories
|
|
90
|
+
- Evans's idea: for each type that needs global access, provide an object that acts
|
|
91
|
+
like an in-memory collection of all objects of that type — with methods to add,
|
|
92
|
+
remove, and select by criteria — while hiding the actual data store. One
|
|
93
|
+
repository per aggregate root.
|
|
94
|
+
- Keep persistence concerns out of the domain; map rows to domain types behind
|
|
95
|
+
the repository interface (depend on the abstraction, per the baseline).
|
|
96
|
+
|
|
97
|
+
### Factories
|
|
98
|
+
- Evans's idea: move creation of complex objects and aggregates into a dedicated
|
|
99
|
+
object whose interface encapsulates the assembly and hides the concrete classes
|
|
100
|
+
from the client. Use a factory to enforce invariants at creation; don't add one
|
|
101
|
+
for simple construction — that's anticipatory abstraction.
|
|
102
|
+
|
|
103
|
+
### Domain Events
|
|
104
|
+
- **Note on provenance:** Domain Events are **not** a building block in Evans's
|
|
105
|
+
original 2003 *Domain-Driven Design*. They were added later (Evans's 2014
|
|
106
|
+
*Domain-Driven Design Reference*; popularized by Vernon's *Implementing DDD*).
|
|
107
|
+
Treat them as a widely-adopted extension, not original Evans canon.
|
|
108
|
+
- A **Domain Event** captures something meaningful that happened in the domain,
|
|
109
|
+
named in past tense (`OrderPlaced`, `PaymentCaptured`).
|
|
110
|
+
- Use to decouple aggregates and drive eventual consistency across boundaries —
|
|
111
|
+
not as a generic message bus for every state change.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## How this composes with design-patterns
|
|
116
|
+
|
|
117
|
+
Tactical DDD answers *what the domain objects are and which invariants they hold*;
|
|
118
|
+
`design-patterns` answers *how to structure code-level variation*. They can meet
|
|
119
|
+
(a Factory appears in both vocabularies), but model the domain first — let the
|
|
120
|
+
behavior and invariants drive the shape, and reach for a GoF pattern only if a
|
|
121
|
+
demonstrated axis of variation then calls for one, per its own counterweight.
|
|
@@ -16,6 +16,8 @@ Fully autonomous project lifecycle driver. Plans sprints, executes stories via p
|
|
|
16
16
|
1a. **Multi-path mode and new flags:** when invoked with 2+ existing-file paths, `/project-orchestrate` runs in sequential multi-path mode (each spec receives its own complete orchestration end-to-end). Two new flags are accepted: `--skip-on-pause` (default off; advance the queue when a spec hits a safety gate instead of pausing) and `--merged` (default off; treat multi-path inputs as one combined legacy multi-spec project with a deprecation warning). See **Input Parsing and Mode Detection** for the full classification and **Sequential Multi-Path Mode** for execution details.
|
|
17
17
|
2. Read `../shared/config.json` to determine the scaffolding mode (`scaffolding` key: `"local"`, `"github"`, `"jira"`, or `"trello"`, default: `"local"`). If `"local"`, also read the `paths.backlog` and `paths.context` values (`paths.context` defaults to `.claude-scrum-skill/context` and is where Step 3 subagents look for per-epic CONTEXT.md files). Read `../shared/references/PROVIDERS.md` for provider-specific API commands when using a remote provider.
|
|
18
18
|
3. Read the project's `CLAUDE.md` (if it exists) for project-specific rules. **All subagents you spawn must also read and follow `CLAUDE.md`** — include this instruction explicitly in every subagent prompt.
|
|
19
|
+
3a. Read `../shared/references/ENGINEERING_BASELINE.md` — the universal engineering baseline (Clean Code, Test-Driven Development, and the simple-design Arbitration Rule). It applies to **all** work this orchestration drives, across every epic and story. Resolve its absolute path; you will pass it to the sprint pipeline as `baselinePath` so every implementation and review subagent follows it. Order of precedence: project `CLAUDE.md` > engineering baseline > situational guidance (`design-patterns`, `domain-modeling`).
|
|
20
|
+
3b. **Subdomain classification gates situational guidance.** `/project-spec` classifies each epic as `core`, `supporting`, or `generic`, and `/project-scaffold` persists that classification into epic metadata: the `subdomain` field of each `_epic.md` frontmatter (local mode) or a `subdomain:<value>` label on the epic's issues (remote modes). Read the classification from that epic metadata — the single authoritative source — and do NOT re-derive it. At implementation time, only **`core`** epics receive the situational guidance skills (`design-patterns`, `domain-modeling`); `supporting`, `generic`, and unclassified epics get the baseline only. Resolve the absolute `SKILL.md` paths for the `design-patterns` and `domain-modeling` skills so you can pass them as `situationalGuidance` for core epics.
|
|
19
21
|
4. Read `../shared/references/PERSONAS.md` for role preambles. When spawning
|
|
20
22
|
subagents, select the persona matching each story's `persona:*` label (GitHub mode)
|
|
21
23
|
or `persona` frontmatter field (local mode). If no persona exists, use `impl` (the default).
|
|
@@ -409,6 +411,8 @@ claudeMdPath: project CLAUDE.md absolute path (or omit if absent)
|
|
|
409
411
|
backendMode: local | github | jira | trello
|
|
410
412
|
repoIdentifier: <owner/repo> (github mode only)
|
|
411
413
|
personaPreambles: { impl: "...", ops: "...", research: "..." }
|
|
414
|
+
baselinePath: <absolute path to shared/references/ENGINEERING_BASELINE.md> (always set; applies to every story)
|
|
415
|
+
situationalGuidance: <array of absolute SKILL.md paths for design-patterns and domain-modeling — set ONLY when the current epic's subdomain is `core`; omit or pass [] for supporting/generic/untagged epics>
|
|
412
416
|
```
|
|
413
417
|
|
|
414
418
|
Wait for the workflow to return. The return is `SprintStoryReturn[]` — one entry per completed (or blocked / failed) story per `lib/workflows/schemas/SprintStoryReturnSchema.json`.
|
|
@@ -421,9 +425,11 @@ For each entry in the workflow's return:
|
|
|
421
425
|
- `status: "blocked"` — Record `blockers[]` and `reason` in the state file. Add the `blocked` label to the story (or mark blocked locally). Continue.
|
|
422
426
|
- `status: "failed"` — Same persistence as blocked, plus log the failure for sprint-release to roll over.
|
|
423
427
|
|
|
424
|
-
#### Concurrency and barriers
|
|
428
|
+
#### Concurrency, isolation, and barriers
|
|
425
429
|
|
|
426
|
-
The workflow runs up to `min(16, cpu_cores - 2)` stories concurrently with no per-stage barriers — each story's
|
|
430
|
+
The workflow runs up to `min(16, cpu_cores - 2)` stories concurrently with no per-stage barriers — each story's chain is independent, so one slow review doesn't gate other stories' implementations. The barrier-removal benefit is unconditional; the concurrency lift is conditional on host cores (a 4-core host gets concurrency 2, an 8-core host gets 6, a 18+-core host gets the full 16). On all hosts this still beats v1.x's hardcoded 3 + barriers model on most sprint sizes.
|
|
431
|
+
|
|
432
|
+
Concurrent stories share one git repository, so the workflow keeps them off each other's toes with a single invariant: **the main working tree is mutated only by the serialized local-mode merge step.** Implement and verify run in isolated git worktrees (each story branches, commits, and builds in its own tree); review only diffs refs without checking out; and in local mode the per-story merges into the shared release branch are serialized behind a lock. This is why the **Independence check** (above) need not be perfect: even if two file-overlapping stories run together, they cannot corrupt each other's branch or commits. The workflow also re-enforces dependencies internally — a story whose `blocked_by` names another story *in the same batch* waits for that story to finish `done` before it starts, and branches from the release branch only after the blocker has merged.
|
|
427
433
|
|
|
428
434
|
#### Progress updates
|
|
429
435
|
|
|
@@ -146,6 +146,7 @@ epics:
|
|
|
146
146
|
- name: <string>
|
|
147
147
|
slug: <kebab-case string>
|
|
148
148
|
description: <one-paragraph string>
|
|
149
|
+
subdomain: <core | supporting | generic — from the spec's .spec.json epic entry (SpecSchema)>
|
|
149
150
|
slice:
|
|
150
151
|
start_line: <int>
|
|
151
152
|
end_line: <int>
|
|
@@ -427,6 +428,7 @@ For each epic, create `<backlog-path>/<epic-slug>/`:
|
|
|
427
428
|
title: <Epic Name>
|
|
428
429
|
slug: <epic-slug>
|
|
429
430
|
status: open
|
|
431
|
+
subdomain: <core | supporting | generic>
|
|
430
432
|
created: <ISO timestamp>
|
|
431
433
|
---
|
|
432
434
|
|
|
@@ -435,6 +437,14 @@ created: <ISO timestamp>
|
|
|
435
437
|
<Epic description from PRD>
|
|
436
438
|
```
|
|
437
439
|
|
|
440
|
+
**Carry the `subdomain` classification** from the spec's `.spec.json` epic entry
|
|
441
|
+
(per `SpecSchema`) into epic metadata: the `_epic.md` frontmatter above in local
|
|
442
|
+
mode, and a `subdomain:<value>` label on the epic's issues in remote modes. This
|
|
443
|
+
is the single authoritative carrier `/project-orchestrate` reads to gate
|
|
444
|
+
situational design guidance (`design-patterns`, `domain-modeling`) to `core`
|
|
445
|
+
epics. If the spec carries no `subdomain` (e.g., not produced by the extended
|
|
446
|
+
`/project-spec`), omit the field — orchestrate then treats the epic as generic.
|
|
447
|
+
|
|
438
448
|
### Local Step 5: Create Story Files
|
|
439
449
|
|
|
440
450
|
For each story, create a numbered file in the epic directory. Use sequential
|
|
@@ -40,6 +40,43 @@ As Claude Code, your task is to transform the user's rough prompt into a compreh
|
|
|
40
40
|
- Add code examples if they help illustrate requirements
|
|
41
41
|
- Structure the document with clear headings and subheadings
|
|
42
42
|
|
|
43
|
+
## Design Passes (Baseline, Domain & Patterns)
|
|
44
|
+
|
|
45
|
+
Before finalizing, run these passes so the spec is grounded in the project's
|
|
46
|
+
engineering standards. They shape the spec at **design time**; implementation-time
|
|
47
|
+
enforcement is `/project-orchestrate`'s job.
|
|
48
|
+
|
|
49
|
+
6. **Engineering baseline.** Read `../shared/references/ENGINEERING_BASELINE.md`
|
|
50
|
+
(Clean Code, Test-Driven Development, the simple-design Arbitration Rule). The
|
|
51
|
+
spec must assume this baseline: acceptance criteria assume tests-first
|
|
52
|
+
(red-green-refactor), and every proposed design assumes the Arbitration Rule
|
|
53
|
+
— the simplest thing that works, no anticipatory abstraction.
|
|
54
|
+
|
|
55
|
+
7. **Strategic domain pass (DDD).** For each epic, capture the domain's
|
|
56
|
+
**ubiquitous language** and **classify its subdomain** as one of `core`,
|
|
57
|
+
`supporting`, or `generic`:
|
|
58
|
+
- `core` — the complex business heart with real invariants; warrants tactical
|
|
59
|
+
domain modeling.
|
|
60
|
+
- `supporting` — necessary but not differentiating.
|
|
61
|
+
- `generic` — CRUD, plumbing, off-the-shelf concerns.
|
|
62
|
+
|
|
63
|
+
Record the classification on each epic (see the JSON sibling below). It is the
|
|
64
|
+
single authoritative source `/project-orchestrate` reads to decide which epics
|
|
65
|
+
receive situational guidance — so classify carefully and do **not** expect
|
|
66
|
+
downstream skills to re-derive it. For `core` epics, sketch candidate
|
|
67
|
+
aggregates, entities vs. value objects, and where key business rules live,
|
|
68
|
+
consistent with the `domain-modeling` skill.
|
|
69
|
+
|
|
70
|
+
8. **Pattern-naming pass (GoF), candidate only.** Identify axes of *expected
|
|
71
|
+
variation* and, where one is real, name a **candidate** Gang of Four pattern.
|
|
72
|
+
Every named pattern MUST follow this form and stay non-binding:
|
|
73
|
+
|
|
74
|
+
> `Pattern — because <real axis of variation>; revisit at build (may collapse
|
|
75
|
+
> to a function or simpler form if the variation does not materialize)`.
|
|
76
|
+
|
|
77
|
+
Do not name patterns speculatively or for CRUD/generic work. A spec is not a
|
|
78
|
+
pattern shopping list — naming records a justified hypothesis, not a mandate.
|
|
79
|
+
|
|
43
80
|
## Filename Convention
|
|
44
81
|
|
|
45
82
|
Read the specs output path from `../shared/config.json` (key: `paths.specs`,
|
|
@@ -64,6 +101,7 @@ In addition to the markdown spec document, write a sibling JSON file at `<specs-
|
|
|
64
101
|
"name": "<epic name>",
|
|
65
102
|
"slug": "<kebab-case>",
|
|
66
103
|
"description": "<one-paragraph>",
|
|
104
|
+
"subdomain": "core | supporting | generic",
|
|
67
105
|
"depends_on": [],
|
|
68
106
|
"shared_design_concerns": [],
|
|
69
107
|
"slice": { "start_line": 0, "end_line": 0 }
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Engineering Baseline
|
|
2
|
+
|
|
3
|
+
> The universal engineering standard for all work this skill suite drives.
|
|
4
|
+
> `project-spec` reads it at design time; `project-orchestrate` reads it and
|
|
5
|
+
> **injects it into every subagent it spawns** at implementation time. It
|
|
6
|
+
> applies across the board, to every story and every file, regardless of domain.
|
|
7
|
+
>
|
|
8
|
+
> This is the **baseline layer**. The **situational layer** — Gang of Four
|
|
9
|
+
> design patterns (`design-patterns`) and tactical Domain-Driven Design
|
|
10
|
+
> (`domain-modeling`) — sits on top of it and is composed in only when the work
|
|
11
|
+
> warrants it (see each skill). When the situational layer fires, it remains
|
|
12
|
+
> **subordinate to the Arbitration Rule below**.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## The Arbitration Rule (read this first)
|
|
17
|
+
|
|
18
|
+
**Simple design is the default. Abstractions, design patterns, and domain layers
|
|
19
|
+
are responses to demonstrated complexity — duplication, repeated change in one
|
|
20
|
+
place, or essential domain rules — never anticipatory architecture. Arrive at
|
|
21
|
+
patterns by refactoring toward them, not by designing to them.**
|
|
22
|
+
|
|
23
|
+
Every pattern, every layer, every abstraction must justify itself against this
|
|
24
|
+
rule. Three similar lines beat a premature abstraction. When in doubt, write the
|
|
25
|
+
simplest thing that works and let duplication or change-pressure tell you when to
|
|
26
|
+
extract.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Clean Code
|
|
31
|
+
|
|
32
|
+
### Naming
|
|
33
|
+
> Martin's standard: a good name answers the big questions — why the thing exists,
|
|
34
|
+
> what it does, and how it's used. If a name needs a comment to explain it, the
|
|
35
|
+
> name has failed.
|
|
36
|
+
|
|
37
|
+
- Names reveal intent. If a name needs a comment, the name is wrong.
|
|
38
|
+
- Class names are nouns; method names are verbs.
|
|
39
|
+
- One word per concept, used consistently across the codebase.
|
|
40
|
+
- Name length matches scope. Short names for short scopes; full descriptive
|
|
41
|
+
names for wide ones.
|
|
42
|
+
- Don't encode type or scope into names (no Hungarian notation, no `m_`).
|
|
43
|
+
- Names describe side effects. A function that creates-if-absent is not a getter.
|
|
44
|
+
|
|
45
|
+
### Functions
|
|
46
|
+
> Martin's rules: functions should be small — and then smaller. Each should do one
|
|
47
|
+
> thing, do it well, and do it only.
|
|
48
|
+
|
|
49
|
+
- Small. One thing. One level of abstraction per function body.
|
|
50
|
+
- Stepdown rule: high-level functions first, helpers below — readable top to
|
|
51
|
+
bottom like a newspaper.
|
|
52
|
+
- Minimize arguments. Zero–two normal, three suspect, more → pass an object.
|
|
53
|
+
- No flag (boolean) arguments — split into two functions.
|
|
54
|
+
- No hidden side effects. Command-query separation: change state or return a
|
|
55
|
+
value, not both.
|
|
56
|
+
- Don't return null and don't pass null. Return an empty collection, an Optional,
|
|
57
|
+
or throw.
|
|
58
|
+
|
|
59
|
+
### Comments
|
|
60
|
+
> Martin's view: a comment is a way of compensating for failing to express the
|
|
61
|
+
> intent in code. Prefer rewriting the code over explaining it with a comment.
|
|
62
|
+
|
|
63
|
+
- The best comment is the one made unnecessary by clear code.
|
|
64
|
+
- Delete commented-out code; version control remembers.
|
|
65
|
+
- A necessary comment explains **why**, not **what**.
|
|
66
|
+
- TODOs carry a ticket number or removal date.
|
|
67
|
+
|
|
68
|
+
### Formatting
|
|
69
|
+
- Related code stays vertically close; declare variables near first use.
|
|
70
|
+
- Keep lines readable without horizontal scrolling (~100 chars).
|
|
71
|
+
- Blank lines separate concepts; none between tightly coupled statements.
|
|
72
|
+
- Team/project formatting rules override personal preference.
|
|
73
|
+
|
|
74
|
+
### Objects and Data
|
|
75
|
+
- Objects hide data and expose behavior; data structures expose data and have no
|
|
76
|
+
behavior. Don't make hybrids.
|
|
77
|
+
- Law of Demeter: don't reach through chains (`a.getB().getC().do()`).
|
|
78
|
+
- Prefer polymorphism over `switch`/`if-else` chains on type.
|
|
79
|
+
|
|
80
|
+
### Error Handling
|
|
81
|
+
> Martin's guidance: prefer exceptions over return codes for error signaling.
|
|
82
|
+
|
|
83
|
+
- Exceptions, not return codes. Write try-catch-finally first for fallible code.
|
|
84
|
+
- Provide context: what operation failed and what state was expected.
|
|
85
|
+
- Define exception types by how the caller handles them.
|
|
86
|
+
|
|
87
|
+
### Boundaries
|
|
88
|
+
- Wrap third-party APIs behind your own interfaces; don't let library types leak
|
|
89
|
+
across module boundaries.
|
|
90
|
+
|
|
91
|
+
### Classes
|
|
92
|
+
- Single Responsibility: one reason to change.
|
|
93
|
+
- High cohesion: most methods use most fields.
|
|
94
|
+
- Open-Closed: extend without modifying working code.
|
|
95
|
+
- Dependency Inversion: depend on abstractions, not concretions.
|
|
96
|
+
|
|
97
|
+
### Smells — fix on sight
|
|
98
|
+
Dead code; commented-out code; functions with >3 arguments; magic
|
|
99
|
+
numbers/strings; base classes referencing derivatives; feature envy; inconsistent
|
|
100
|
+
conventions; hidden temporal coupling; artificial coupling; negative conditionals
|
|
101
|
+
(`!isNotReady()` → `isReady()`).
|
|
102
|
+
|
|
103
|
+
### The Boy Scout Rule
|
|
104
|
+
> The Boy Scout Rule (Martin, adapting the scouting maxim): always leave the code
|
|
105
|
+
> a little cleaner than you found it.
|
|
106
|
+
|
|
107
|
+
Leave every file cleaner than you found it. Every commit. No exceptions.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Test-Driven Development
|
|
112
|
+
|
|
113
|
+
TDD is universal here — it governs how code comes into being, not just whether
|
|
114
|
+
tests exist.
|
|
115
|
+
|
|
116
|
+
### The discipline
|
|
117
|
+
- **Red → Green → Refactor** — Beck's rhythm. *Red:* write a small test that fails
|
|
118
|
+
(it may not even compile yet). *Green:* make it pass as quickly as possible.
|
|
119
|
+
*Refactor:* remove the duplication you created getting there. Always in that
|
|
120
|
+
order — make it work, then make it clean.
|
|
121
|
+
- **Three laws** (Robert C. Martin's formulation of the same discipline): (1)
|
|
122
|
+
write a failing test before production code; (2) write only enough test to fail;
|
|
123
|
+
(3) write only enough production code to pass.
|
|
124
|
+
- **Small steps** — Beck's techniques. When a step is hard, take a smaller one:
|
|
125
|
+
*Fake It* (return a constant) to get to green, then *Triangulate* to the real
|
|
126
|
+
implementation.
|
|
127
|
+
|
|
128
|
+
### What good tests look like
|
|
129
|
+
- Tests describe behavior, not implementation. Test names are assertions
|
|
130
|
+
("computes pace when duration is edited"), not "test case 1".
|
|
131
|
+
- One concept per test (not necessarily one assert — one idea).
|
|
132
|
+
- **F.I.R.S.T.**: Fast, Independent, Repeatable, Self-validating, Timely.
|
|
133
|
+
- Test boundary conditions and cluster tests near known bugs.
|
|
134
|
+
- Tests are first-class code: clean, readable, well-named, colocated with source.
|
|
135
|
+
|
|
136
|
+
### Emergence (simple design, in priority order)
|
|
137
|
+
1. All tests pass. Untested code is unfinished code.
|
|
138
|
+
2. No duplication. Every piece of knowledge has one authoritative representation.
|
|
139
|
+
3. Code is expressive. The reader understands intent without asking the author.
|
|
140
|
+
4. Minimal classes and methods. Don't create abstractions you don't need yet.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## How this baseline is applied
|
|
145
|
+
|
|
146
|
+
- **`project-spec` (design time):** specs are written to satisfy this baseline.
|
|
147
|
+
Acceptance criteria assume tests-first; designs assume the Arbitration Rule.
|
|
148
|
+
- **`project-orchestrate` (implementation time):** this document is injected,
|
|
149
|
+
verbatim or by reference, into every implementation, review, and hardening
|
|
150
|
+
subagent prompt. Subagents follow it in addition to the project's own
|
|
151
|
+
`CLAUDE.md` (project rules win on direct conflict).
|
|
152
|
+
- **Order of precedence:** project `CLAUDE.md` > this baseline > situational
|
|
153
|
+
guidance (`design-patterns`, `domain-modeling`). The situational layer never
|
|
154
|
+
overrides the Arbitration Rule.
|