joycraft 0.5.15 → 0.5.16

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.
@@ -1,4592 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/bundled-files.ts
4
- var SKILLS = {
5
- "joycraft-add-fact.md": `---
6
- name: joycraft-add-fact
7
- description: Capture a project fact and route it to the correct context document -- production map, dangerous assumptions, decision log, institutional knowledge, or troubleshooting
8
- instructions: 38
9
- ---
10
-
11
- # Add Fact
12
-
13
- The user has a fact to capture. Your job is to classify it, route it to the correct context document, append it in the right format, and optionally add a CLAUDE.md boundary rule.
14
-
15
- ## Step 1: Get the Fact
16
-
17
- If the user already provided the fact (e.g., \`/joycraft-add-fact the staging DB resets every Sunday\`), use it directly.
18
-
19
- If not, ask: "What fact do you want to capture?" -- then wait for their response.
20
-
21
- If the user provides multiple facts at once, process each one separately through all the steps below, then give a combined confirmation at the end.
22
-
23
- ## Step 2: Classify the Fact
24
-
25
- Route the fact to one of these 5 context documents based on its content:
26
-
27
- ### \`docs/context/production-map.md\`
28
- The fact is about **infrastructure, services, environments, URLs, endpoints, credentials, or what is safe/unsafe to touch**.
29
- - Signal words: "production", "staging", "endpoint", "URL", "database", "service", "deployed", "hosted", "credentials", "secret", "environment"
30
- - Examples: "The staging DB is at postgres://staging.example.com", "We use Vercel for the frontend and Railway for the API"
31
-
32
- ### \`docs/context/dangerous-assumptions.md\`
33
- The fact is about **something an AI agent might get wrong -- a false assumption that leads to bad outcomes**.
34
- - Signal words: "assumes", "might think", "but actually", "looks like X but is Y", "not what it seems", "trap", "gotcha"
35
- - Examples: "The \`users\` table looks like a test table but it's production", "Deleting a workspace doesn't delete the billing subscription"
36
-
37
- ### \`docs/context/decision-log.md\`
38
- The fact is about **an architectural or tooling choice and why it was made**.
39
- - Signal words: "decided", "chose", "because", "instead of", "we went with", "the reason we use", "trade-off"
40
- - Examples: "We chose SQLite over Postgres because this runs on embedded devices", "We use pnpm instead of npm for workspace support"
41
-
42
- ### \`docs/context/institutional-knowledge.md\`
43
- The fact is about **team conventions, unwritten rules, organizational context, or who owns what**.
44
- - Signal words: "convention", "rule", "always", "never", "team", "process", "review", "approval", "owns", "responsible"
45
- - Examples: "The design team reviews all color changes", "We never deploy on Fridays", "PR titles must start with the ticket number"
46
-
47
- ### \`docs/context/troubleshooting.md\`
48
- The fact is about **diagnostic knowledge -- when X happens, do Y (or don't do Z)**.
49
- - Signal words: "when", "fails", "error", "if you see", "stuck", "broken", "fix", "workaround", "before trying", "reboot", "restart", "reset"
50
- - Examples: "If Wi-Fi disconnects during flash, wait and retry -- don't switch networks", "When tests fail with ECONNREFUSED, check if Docker is running"
51
-
52
- ### Ambiguous Facts
53
-
54
- If the fact fits multiple categories, pick the **best fit** based on the primary intent. You will mention the alternative in your confirmation message so the user can correct you.
55
-
56
- ## Step 3: Ensure the Target Document Exists
57
-
58
- 1. If \`docs/context/\` does not exist, create the directory.
59
- 2. If the target document does not exist, create it from the template structure. Check \`docs/templates/\` for the matching template. If no template exists, use this minimal structure:
60
-
61
- For **production-map.md**:
62
- \`\`\`markdown
63
- # Production Map
64
-
65
- > What's real, what's staging, what's safe to touch.
66
-
67
- ## Services
68
-
69
- | Service | Environment | URL/Endpoint | Impact if Corrupted |
70
- |---------|-------------|-------------|-------------------|
71
- \`\`\`
72
-
73
- For **dangerous-assumptions.md**:
74
- \`\`\`markdown
75
- # Dangerous Assumptions
76
-
77
- > Things the AI agent might assume that are wrong in this project.
78
-
79
- ## Assumptions
80
-
81
- | Agent Might Assume | But Actually | Impact If Wrong |
82
- |-------------------|-------------|----------------|
83
- \`\`\`
84
-
85
- For **decision-log.md**:
86
- \`\`\`markdown
87
- # Decision Log
88
-
89
- > Why choices were made, not just what was chosen.
90
-
91
- ## Decisions
92
-
93
- | Date | Decision | Why | Alternatives Rejected | Revisit When |
94
- |------|----------|-----|----------------------|-------------|
95
- \`\`\`
96
-
97
- For **institutional-knowledge.md**:
98
- \`\`\`markdown
99
- # Institutional Knowledge
100
-
101
- > Unwritten rules, team conventions, and organizational context.
102
-
103
- ## Team Conventions
104
-
105
- - (none yet)
106
- \`\`\`
107
-
108
- For **troubleshooting.md**:
109
- \`\`\`markdown
110
- # Troubleshooting
111
-
112
- > What to do when things go wrong for non-code reasons.
113
-
114
- ## Common Failures
115
-
116
- | When This Happens | Do This | Don't Do This |
117
- |-------------------|---------|---------------|
118
- \`\`\`
119
-
120
- ## Step 4: Read the Target Document
121
-
122
- Read the target document to understand its current structure. Note:
123
- - Which section to append to
124
- - Whether it uses tables or lists
125
- - The column format if it's a table
126
-
127
- ## Step 5: Append the Fact
128
-
129
- Add the fact to the appropriate section of the target document. Match the existing format exactly:
130
-
131
- - **Table-based documents** (production-map, dangerous-assumptions, decision-log, troubleshooting): Add a new table row in the correct columns. Use today's date where a date column exists.
132
- - **List-based documents** (institutional-knowledge): Add a new list item (\`- \`) to the most appropriate section.
133
-
134
- Remove any italic example rows (rows where all cells start with \`_\`) before appending, so the document transitions from template to real content. Only remove examples from the specific table you are appending to.
135
-
136
- **Append only. Never modify or remove existing real content.**
137
-
138
- ## Step 6: Evaluate CLAUDE.md Boundary Rule
139
-
140
- Decide whether the fact also warrants a rule in CLAUDE.md's behavioral boundaries:
141
-
142
- **Add a CLAUDE.md rule if the fact:**
143
- - Describes something that should ALWAYS or NEVER be done
144
- - Could cause real damage if violated (data loss, broken deployments, security issues)
145
- - Is a hard constraint that applies across all work, not just a one-time note
146
-
147
- **Do NOT add a CLAUDE.md rule if the fact is:**
148
- - Purely informational (e.g., "staging DB is at this URL")
149
- - A one-time decision that's already captured
150
- - A diagnostic tip rather than a prohibition
151
-
152
- If a rule is warranted, read CLAUDE.md, find the appropriate section (ALWAYS, ASK FIRST, or NEVER under Behavioral Boundaries), and append the rule. If no Behavioral Boundaries section exists, append one.
153
-
154
- ## Step 7: Confirm
155
-
156
- Report what you did in this format:
157
-
158
- \`\`\`
159
- Added to [document name]:
160
- [summary of what was added]
161
-
162
- [If CLAUDE.md was also updated:]
163
- Added CLAUDE.md rule:
164
- [ALWAYS/ASK FIRST/NEVER]: [rule text]
165
-
166
- [If the fact was ambiguous:]
167
- Routed to [chosen doc] -- move to [alternative doc] if this is more about [alternative category description].
168
- \`\`\`
169
- `,
170
- "joycraft-bugfix.md": `---
171
- name: joycraft-bugfix
172
- description: Structured bug fix workflow \u2014 triage, diagnose, discuss with user, write a focused spec, hand off for implementation
173
- instructions: 32
174
- ---
175
-
176
- # Bug Fix Workflow
177
-
178
- You are fixing a bug. Follow this process in order. Do not skip steps.
179
-
180
- **Guard clause:** If this is clearly a new feature, redirect to \`/joycraft-new-feature\` and stop.
181
-
182
- ---
183
-
184
- ## Phase 1: Triage
185
-
186
- Establish what's broken. Gather: symptom, steps to reproduce, expected vs actual behavior, when it started, relevant logs/errors. If an error message or stack trace is provided, read the referenced files immediately. Try to reproduce if steps are given.
187
-
188
- **Done when:** You can describe the symptom in one sentence.
189
-
190
- ---
191
-
192
- ## Phase 2: Diagnose
193
-
194
- Find the root cause. Start from the error site and trace backward. Read source files \u2014 don't guess. Identify the specific line(s) and logic error. Check git blame if it's a recent regression.
195
-
196
- **Done when:** You can explain what's wrong, why, and where in 2-3 sentences.
197
-
198
- ---
199
-
200
- ## Phase 3: Discuss
201
-
202
- Present findings to the user BEFORE writing any code or spec:
203
- 1. **Symptom** \u2014 confirm it matches what they see
204
- 2. **Root cause** \u2014 specific file(s) and line(s)
205
- 3. **Proposed fix** \u2014 what changes, where
206
- 4. **Risk** \u2014 side effects? scope?
207
-
208
- Ask: "Does this match? Comfortable with this approach?" If large/risky, suggest decomposing into multiple specs.
209
-
210
- **Done when:** User agrees with the diagnosis and fix direction.
211
-
212
- ---
213
-
214
- ## Phase 4: Spec the Fix
215
-
216
- Write a bug fix spec to \`docs/specs/<feature-or-area>/bugfix-name.md\`. Use the relevant feature name or area as the subdirectory (e.g., \`auth\`, \`cli\`, \`parser\`). Create the \`docs/specs/<feature-or-area>/\` directory if it doesn't exist.
217
-
218
- **Why:** Even bug fixes deserve a spec. It forces clarity on what "fixed" means, ensures test-first discipline, and creates a traceable record of the fix.
219
-
220
- Use this template:
221
-
222
- \`\`\`markdown
223
- # Fix [Bug Description] \u2014 Bug Fix Spec
224
-
225
- > **Parent Brief:** none (bug fix)
226
- > **Issue/Error:** [error message, issue link, or symptom description]
227
- > **Status:** Ready
228
- > **Date:** YYYY-MM-DD
229
- > **Estimated scope:** [1 session / N files / ~N lines]
230
-
231
- ---
232
-
233
- ## Bug
234
-
235
- What is broken? Describe the symptom the user experiences.
236
-
237
- ## Root Cause
238
-
239
- What is wrong in the code and why? Name the specific file(s) and line(s).
240
-
241
- ## Fix
242
-
243
- What changes will fix this? Be specific \u2014 describe the code change, not just "fix the bug."
244
-
245
- ## Acceptance Criteria
246
-
247
- - [ ] [The bug no longer occurs \u2014 describe the correct behavior]
248
- - [ ] [No regressions in related functionality]
249
- - [ ] Build passes
250
- - [ ] Tests pass
251
-
252
- ## Test Plan
253
-
254
- | Acceptance Criterion | Test | Type |
255
- |---------------------|------|------|
256
- | [Bug no longer occurs] | [Test that reproduces the bug, then verifies the fix] | [unit/integration/e2e] |
257
- | [No regressions] | [Existing tests still pass, or new regression test] | [unit/integration] |
258
-
259
- **Execution order:**
260
- 1. Write a test that reproduces the bug \u2014 it should FAIL (red)
261
- 2. Run the test to confirm it fails
262
- 3. Apply the fix
263
- 4. Run the test to confirm it passes (green)
264
- 5. Run the full test suite to check for regressions
265
-
266
- **Smoke test:** [The bug reproduction test \u2014 fastest way to verify the fix works]
267
-
268
- **Before implementing, verify your test harness:**
269
- 1. Run the reproduction test \u2014 it must FAIL (if it passes, you're not testing the actual bug)
270
- 2. The test must exercise your actual code \u2014 not a reimplementation or mock
271
- 3. Identify your smoke test \u2014 it must run in seconds, not minutes
272
-
273
- ## Constraints
274
-
275
- - MUST: [any hard requirements for the fix]
276
- - MUST NOT: [any prohibitions \u2014 e.g., don't change the public API]
277
-
278
- ## Affected Files
279
-
280
- | Action | File | What Changes |
281
- |--------|------|-------------|
282
-
283
- ## Edge Cases
284
-
285
- | Scenario | Expected Behavior |
286
- |----------|------------------|
287
- \`\`\`
288
-
289
- **For trivial bugs:** The spec will be short. That's fine \u2014 the structure is the point, not the length.
290
-
291
- **For large bugs that span multiple files/systems:** Consider whether this should be decomposed into multiple specs. If so, create a brief first using \`/joycraft-new-feature\`, then decompose. A bug fix spec should be implementable in a single session.
292
-
293
- ---
294
-
295
- ## Phase 5: Hand Off
296
-
297
- Tell the user:
298
-
299
- \`\`\`
300
- Bug fix spec is ready: docs/specs/<feature-or-area>/bugfix-name.md
301
-
302
- Summary:
303
- - Bug: [one sentence]
304
- - Root cause: [one sentence]
305
- - Fix: [one sentence]
306
- - Estimated: 1 session
307
-
308
- To execute: Start a fresh session and:
309
- 1. Read the spec
310
- 2. Write the reproduction test (must fail)
311
- 3. Apply the fix (test must pass)
312
- 4. Run full test suite
313
- 5. Run /joycraft-session-end to capture discoveries
314
- 6. Commit and PR
315
-
316
- Ready to start?
317
- \`\`\`
318
-
319
- **Why:** A fresh session for implementation produces better results. This diagnostic session has context noise from exploration \u2014 a clean session with just the spec is more focused.
320
- `,
321
- "joycraft-decompose.md": `---
322
- name: joycraft-decompose
323
- description: Break a feature brief into atomic specs \u2014 small, testable, independently executable units
324
- instructions: 32
325
- ---
326
-
327
- # Decompose Feature into Atomic Specs
328
-
329
- You have a Feature Brief (or the user has described a feature). Your job is to decompose it into atomic specs that can be executed independently \u2014 one spec per session.
330
-
331
- ## Step 1: Verify the Brief Exists
332
-
333
- Look for a Feature Brief in \`docs/briefs/\`. If one doesn't exist yet, tell the user:
334
-
335
- > No feature brief found. Run \`/joycraft-new-feature\` first to interview and create one, or describe the feature now and I'll work from your description.
336
-
337
- If the user describes the feature inline, work from that description directly. You don't need a formal brief to decompose \u2014 but recommend creating one for complex features.
338
-
339
- ## Step 2: Identify Natural Boundaries
340
-
341
- **Why:** Good boundaries make specs independently testable and committable. Bad boundaries create specs that can't be verified without other specs also being done.
342
-
343
- Read the brief (or description) and identify natural split points:
344
-
345
- - **Data layer changes** (schemas, types, migrations) \u2014 always a separate spec
346
- - **Pure functions / business logic** \u2014 separate from I/O
347
- - **UI components** \u2014 separate from data fetching
348
- - **API endpoints / route handlers** \u2014 separate from business logic
349
- - **Test infrastructure** (mocks, fixtures, helpers) \u2014 can be its own spec if substantial
350
- - **Configuration / environment** \u2014 separate from code changes
351
-
352
- Ask yourself: "Can this piece be committed and tested without the other pieces existing?" If yes, it's a good boundary.
353
-
354
- ## Step 3: Build the Decomposition Table
355
-
356
- For each atomic spec, define:
357
-
358
- | # | Spec Name | Description | Dependencies | Size |
359
- |---|-----------|-------------|--------------|------|
360
-
361
- **Rules:**
362
- - Each spec name is \`verb-object\` format (e.g., \`add-terminal-detection\`, \`extract-prompt-module\`)
363
- - Each description is ONE sentence \u2014 if you need two, the spec is too big
364
- - Dependencies reference other spec numbers \u2014 keep the dependency graph shallow
365
- - More than 2 dependencies on a single spec = it's too big, split further
366
- - Aim for 3-7 specs per feature. Fewer than 3 = probably not decomposed enough. More than 10 = the feature brief is too big
367
-
368
- ## Step 4: Present and Iterate
369
-
370
- Show the decomposition table to the user. Ask:
371
- 1. "Does this breakdown match how you think about this feature?"
372
- 2. "Are there any specs that feel too big or too small?"
373
- 3. "Should any of these run in parallel (separate worktrees)?"
374
-
375
- Iterate until the user approves.
376
-
377
- ## Step 5: Generate Atomic Specs
378
-
379
- For each approved row, create \`docs/specs/<feature-name>/spec-name.md\`. Derive the feature-name from the brief filename (strip the date prefix and \`.md\` \u2014 e.g., \`2026-04-06-token-discipline.md\` \u2192 \`token-discipline\`). If no brief exists, use a user-provided or inferred feature name (slugified to kebab-case). Create the \`docs/specs/<feature-name>/\` directory if it doesn't exist.
380
-
381
- **Why:** Each spec must be self-contained \u2014 a fresh Claude session should be able to execute it without reading the Feature Brief. Copy relevant constraints and context into each spec.
382
-
383
- Use this structure:
384
-
385
- \`\`\`markdown
386
- # [Verb + Object] \u2014 Atomic Spec
387
-
388
- > **Parent Brief:** \`docs/briefs/YYYY-MM-DD-feature-name.md\` (or "standalone")
389
- > **Status:** Ready
390
- > **Date:** YYYY-MM-DD
391
- > **Estimated scope:** [1 session / N files / ~N lines]
392
-
393
- ---
394
-
395
- ## What
396
- One paragraph \u2014 what changes when this spec is done?
397
-
398
- ## Why
399
- One sentence \u2014 what breaks or is missing without this?
400
-
401
- ## Acceptance Criteria
402
- - [ ] [Observable behavior]
403
- - [ ] Build passes
404
- - [ ] Tests pass
405
-
406
- ## Test Plan
407
-
408
- | Acceptance Criterion | Test | Type |
409
- |---------------------|------|------|
410
- | [Each AC above] | [What to call/assert] | [unit/integration/e2e] |
411
-
412
- **Execution order:**
413
- 1. Write all tests above \u2014 they should fail against current/stubbed code
414
- 2. Run tests to confirm they fail (red)
415
- 3. Implement until all tests pass (green)
416
-
417
- **Smoke test:** [Identify the fastest test for iteration feedback]
418
-
419
- **Before implementing, verify your test harness:**
420
- 1. Run all tests \u2014 they must FAIL (if they pass, you're testing the wrong thing)
421
- 2. Each test calls your actual function/endpoint \u2014 not a reimplementation or the underlying library
422
- 3. Identify your smoke test \u2014 it must run in seconds, not minutes, so you get fast feedback on each change
423
-
424
- ## Constraints
425
- - MUST: [hard requirement]
426
- - MUST NOT: [hard prohibition]
427
-
428
- ## Affected Files
429
- | Action | File | What Changes |
430
- |--------|------|-------------|
431
-
432
- ## Approach
433
- Strategy, data flow, key decisions. Name one rejected alternative.
434
-
435
- ## Edge Cases
436
- | Scenario | Expected Behavior |
437
- |----------|------------------|
438
- \`\`\`
439
-
440
- If \`docs/templates/ATOMIC_SPEC_TEMPLATE.md\` exists, reference it for the full template with additional guidance.
441
-
442
- Fill in all sections \u2014 each spec must be self-contained (no "see the brief for context"). Copy relevant constraints from the Feature Brief into each spec. Write acceptance criteria specific to THIS spec, not the whole feature. Every acceptance criterion must have at least one corresponding test in the Test Plan. If the user provided test strategy info from the interview, use it to choose test types and frameworks. Include the test harness verification rules in every Test Plan.
443
-
444
- ## Step 6: Recommend Execution Strategy
445
-
446
- Based on the dependency graph:
447
- - **Independent specs** \u2014 "These can run in parallel worktrees"
448
- - **Sequential specs** \u2014 "Execute these in order: 1 -> 2 -> 4"
449
- - **Mixed** \u2014 "Start specs 1 and 3 in parallel. After 1 completes, start 2."
450
-
451
- Update the Feature Brief's Execution Strategy section with the plan (if a brief exists).
452
-
453
- ## Step 7: Hand Off
454
-
455
- Tell the user:
456
- \`\`\`
457
- Decomposition complete:
458
- - [N] atomic specs created in docs/specs/
459
- - [N] can run in parallel, [N] are sequential
460
- - Estimated total: [N] sessions
461
-
462
- To execute:
463
- - Sequential: Open a session, point Claude at each spec in order
464
- - Parallel: Use worktrees \u2014 one spec per worktree, merge when done
465
- - Each session should end with /joycraft-session-end to capture discoveries
466
-
467
- Ready to start execution?
468
- \`\`\`
469
-
470
- **Tip:** Run \`/clear\` before starting the next step. Your artifacts are saved to files \u2014 this conversation context is disposable.
471
- `,
472
- "joycraft-design.md": `---
473
- name: joycraft-design
474
- description: Design discussion before decomposition \u2014 produce a ~200-line design artifact for human review, catching wrong assumptions before they propagate into specs
475
- ---
476
-
477
- # Design Discussion
478
-
479
- You are producing a design discussion document for a feature. This sits between research and decomposition \u2014 it captures your understanding so the human can catch wrong assumptions before specs are written.
480
-
481
- **Guard clause:** If no brief path is provided and no brief exists in \`docs/briefs/\`, say:
482
- "No feature brief found. Run \`/joycraft-new-feature\` first to create one, or provide the path to your brief."
483
- Then stop.
484
-
485
- ---
486
-
487
- ## Step 1: Read Inputs
488
-
489
- Read the feature brief at the path the user provides. If the user also provides a research document path, read that too. Research is optional \u2014 if none exists, note that you'll explore the codebase directly.
490
-
491
- ## Step 2: Explore the Codebase
492
-
493
- Spawn subagents to explore the codebase for patterns relevant to the brief. Focus on:
494
-
495
- - Files and functions that will be touched or extended
496
- - Existing patterns this feature should follow (naming, data flow, error handling)
497
- - Similar features already implemented that serve as models
498
- - Boundaries and interfaces the feature must integrate with
499
-
500
- Gather file paths, function signatures, and code snippets. You need concrete evidence, not guesses.
501
-
502
- ## Step 3: Write the Design Document
503
-
504
- Create \`docs/designs/\` directory if it doesn't exist. Write the design document to \`docs/designs/YYYY-MM-DD-feature-name.md\`.
505
-
506
- The document has exactly five sections:
507
-
508
- ### Section 1: Current State
509
-
510
- What exists today in the codebase that is relevant to this feature. Include file paths, function signatures, and data flows. Be specific \u2014 reference actual code, not abstractions. If no research doc was provided, note that and describe what you found through direct exploration.
511
-
512
- ### Section 2: Desired End State
513
-
514
- What the codebase should look like when this feature is complete. Describe the change at a high level \u2014 new files, modified interfaces, new data flows. Do NOT include implementation steps. This is the "what," not the "how."
515
-
516
- ### Section 3: Patterns to Follow
517
-
518
- Existing patterns in the codebase that this feature should match. Include short code snippets and \`file:line\` references. Show the pattern, don't just name it.
519
-
520
- If this is a greenfield project with no existing patterns, propose conventions and note that no precedent exists.
521
-
522
- ### Section 4: Resolved Design Decisions
523
-
524
- Decisions you have already made, with brief rationale. Format each as:
525
-
526
- > **Decision:** [what you decided]
527
- > **Rationale:** [why, referencing existing code or constraints]
528
- > **Alternative rejected:** [what you considered and why you rejected it]
529
-
530
- ### Section 5: Open Questions
531
-
532
- Things you don't know or where multiple valid approaches exist. Each question MUST present 2-3 concrete options with pros and cons. Format:
533
-
534
- > **Q: [question]**
535
- > - **Option A:** [description] \u2014 Pro: [benefit]. Con: [cost].
536
- > - **Option B:** [description] \u2014 Pro: [benefit]. Con: [cost].
537
- > - **Option C (if applicable):** [description] \u2014 Pro: [benefit]. Con: [cost].
538
-
539
- Do NOT ask vague questions like "what do you think?" Every question must have actionable options the human can choose from.
540
-
541
- ## Step 4: Present and STOP
542
-
543
- Present the design document to the user. Say:
544
-
545
- \`\`\`
546
- Design discussion written to docs/designs/YYYY-MM-DD-feature-name.md
547
-
548
- Please review the document above. Specifically:
549
- 1. Are the patterns in Section 3 the right ones to follow, or should I use different ones?
550
- 2. Do you agree with the resolved decisions in Section 4?
551
- 3. Pick an option for each open question in Section 5 (or propose your own).
552
-
553
- Reply with your feedback. I will NOT proceed to decomposition until you have reviewed and approved this design.
554
- \`\`\`
555
-
556
- **CRITICAL: Do NOT proceed to \`/joycraft-decompose\` or generate specs.** Wait for the human to review, answer open questions, and correct any wrong assumptions. The entire value of this skill is the pause \u2014 it forces a human checkpoint before mistakes propagate.
557
-
558
- ## After Human Review
559
-
560
- Once the human responds:
561
- - Update the design document with their corrections and chosen options
562
- - Move answered questions from "Open Questions" to "Resolved Design Decisions"
563
- - Present the updated document for final confirmation
564
- - Only after explicit approval, tell the user: "Design approved. Run \`/joycraft-decompose\` with this brief to generate atomic specs."
565
- `,
566
- "joycraft-implement-level5.md": `---
567
- name: joycraft-implement-level5
568
- description: Set up Level 5 autonomous development \u2014 autofix loop, holdout scenario testing, and scenario evolution from specs
569
- instructions: 35
570
- ---
571
-
572
- # Implement Level 5 \u2014 Autonomous Development Loop
573
-
574
- You are guiding the user through setting up Level 5: the autonomous feedback loop where specs go in, validated software comes out. This is a one-time setup that installs workflows, creates a scenarios repo, and configures the autofix loop.
575
-
576
- ## Before You Begin
577
-
578
- Check prerequisites:
579
-
580
- 1. **Project must be initialized.** Look for \`.joycraft-version\`. If missing, tell the user to run \`npx joycraft init\` first.
581
- 2. **Project should be at Level 4.** Check \`docs/joycraft-assessment.md\` if it exists. If the project hasn't been assessed yet, suggest running \`/joycraft-tune\` first. But don't block \u2014 the user may know they're ready.
582
- 3. **Git repo with GitHub remote.** This setup requires GitHub Actions. Check for \`.git/\` and a GitHub remote.
583
-
584
- If prerequisites aren't met, explain what's needed and stop.
585
-
586
- ## Step 1: Explain What Level 5 Means
587
-
588
- Tell the user:
589
-
590
- > Level 5 is the autonomous loop. When you push specs, three things happen automatically:
591
- >
592
- > 1. **Scenario evolution** \u2014 A separate AI agent reads your specs and writes holdout tests in a private scenarios repo. These tests are invisible to your coding agent.
593
- > 2. **Autofix** \u2014 When CI fails on a PR, Claude Code automatically attempts a fix (up to 3 times).
594
- > 3. **Holdout validation** \u2014 When CI passes, your scenarios repo runs behavioral tests against the PR. Results post as PR comments.
595
- >
596
- > The key insight: your coding agent never sees the scenario tests. This prevents it from gaming the test suite \u2014 like a validation set in machine learning.
597
-
598
- ## Step 2: Gather Configuration
599
-
600
- Ask these questions **one at a time**:
601
-
602
- ### Question 1: Scenarios repo name
603
-
604
- > What should we call your scenarios repo? It'll be a private repo that holds your holdout tests.
605
- >
606
- > Default: \`{current-repo-name}-scenarios\`
607
-
608
- Accept the default or the user's choice.
609
-
610
- ### Question 2: GitHub App
611
-
612
- > Level 5 needs a GitHub App to provide a separate identity for autofix pushes (this avoids GitHub's anti-recursion protection). Creating one takes about 2 minutes:
613
- >
614
- > 1. Go to https://github.com/settings/apps/new
615
- > 2. Give it a name (e.g., "My Project Autofix")
616
- > 3. Uncheck "Webhook > Active" (not needed)
617
- > 4. Under **Repository permissions**, set:
618
- > - **Contents**: Read & Write
619
- > - **Pull requests**: Read & Write
620
- > - **Actions**: Read & Write
621
- > 5. Click **Create GitHub App**
622
- > 6. Note the **App ID** from the settings page
623
- > 7. Scroll to **Private keys** > click **Generate a private key** > save the \`.pem\` file
624
- > 8. Click **Install App** in the left sidebar > install it on your repo
625
- >
626
- > What's your App ID?
627
-
628
- ## Step 3: Run init-autofix
629
-
630
- Run the CLI command with the gathered configuration:
631
-
632
- \`\`\`bash
633
- npx joycraft init-autofix --scenarios-repo {name} --app-id {id}
634
- \`\`\`
635
-
636
- Review the output with the user. Confirm files were created.
637
-
638
- ## Step 4: Walk Through Secret Configuration
639
-
640
- Guide the user step by step:
641
-
642
- ### 4a: Add Secrets to Main Repo
643
-
644
- > You should already have the \`.pem\` file from when you created the app in Step 2.
645
-
646
- > Go to your repo's Settings > Secrets and variables > Actions, and add:
647
- > - \`JOYCRAFT_APP_PRIVATE_KEY\` \u2014 paste the contents of your \`.pem\` file
648
- > - \`ANTHROPIC_API_KEY\` \u2014 your Anthropic API key
649
-
650
- ### 4b: Create the Scenarios Repo
651
-
652
- > Create the private scenarios repo:
653
- > \`\`\`bash
654
- > gh repo create {scenarios-repo-name} --private
655
- > \`\`\`
656
- >
657
- > Then copy the scenario templates into it:
658
- > \`\`\`bash
659
- > cp -r docs/templates/scenarios/* ../{scenarios-repo-name}/
660
- > cd ../{scenarios-repo-name}
661
- > git add -A && git commit -m "init: scaffold scenarios repo from Joycraft"
662
- > git push
663
- > \`\`\`
664
-
665
- ### 4c: Add Secrets to Scenarios Repo
666
-
667
- > The scenarios repo also needs the App private key:
668
- > - \`JOYCRAFT_APP_PRIVATE_KEY\` \u2014 same \`.pem\` file as the main repo
669
- > - \`ANTHROPIC_API_KEY\` \u2014 same key (needed for scenario generation)
670
-
671
- ## Step 5: Verify Setup
672
-
673
- Help the user verify everything is wired correctly:
674
-
675
- 1. **Check workflow files exist:** \`ls .github/workflows/autofix.yml .github/workflows/scenarios-dispatch.yml .github/workflows/spec-dispatch.yml .github/workflows/scenarios-rerun.yml\`
676
- 2. **Check scenario templates were copied:** Verify the scenarios repo has \`example-scenario.test.ts\`, \`workflows/run.yml\`, \`workflows/generate.yml\`, \`prompts/scenario-agent.md\`
677
- 3. **Check the App ID is correct** in the workflow files (not still a placeholder)
678
-
679
- ## Step 6: Update CLAUDE.md
680
-
681
- If the project's CLAUDE.md doesn't already have an "External Validation" section, add one:
682
-
683
- > ## External Validation
684
- >
685
- > This project uses holdout scenario tests in a separate private repo.
686
- >
687
- > ### NEVER
688
- > - Access, read, or reference the scenarios repo
689
- > - Mention scenario test names or contents
690
- > - Modify the scenarios dispatch workflow to leak test information
691
- >
692
- > The scenarios repo is deliberately invisible to you. This is the holdout guarantee.
693
-
694
- ## Step 7: First Test (Optional)
695
-
696
- If the user wants to test the loop:
697
-
698
- > Want to do a quick test? Here's how:
699
- >
700
- > 1. Write a simple spec in \`docs/specs/\` and push to main \u2014 this triggers scenario generation
701
- > 2. Create a PR with a small change \u2014 when CI passes, scenarios will run
702
- > 3. Watch for the scenario test results as a PR comment
703
- >
704
- > Or deliberately break something in a PR to test the autofix loop.
705
-
706
- ## Step 8: Summary
707
-
708
- Print a summary of what was set up:
709
-
710
- > **Level 5 is live.** Here's what's running:
711
- >
712
- > | Trigger | What Happens |
713
- > |---------|-------------|
714
- > | Push specs to \`docs/specs/\` | Scenario agent writes holdout tests |
715
- > | PR fails CI | Claude autofix attempts (up to 3x) |
716
- > | PR passes CI | Holdout scenarios run against PR |
717
- > | Scenarios update | Open PRs re-tested with latest scenarios |
718
- >
719
- > Your scenarios repo: \`{name}\`
720
- > Your coding agent cannot see those tests. The holdout wall is intact.
721
-
722
- Update \`docs/joycraft-assessment.md\` if it exists \u2014 set the Level 5 score to reflect the new setup.
723
- `,
724
- "joycraft-interview.md": `---
725
- name: joycraft-interview
726
- description: Brainstorm freely about what you want to build \u2014 yap, explore ideas, and get a structured summary you can use later
727
- instructions: 18
728
- ---
729
-
730
- # Interview \u2014 Idea Exploration
731
-
732
- You are helping the user brainstorm and explore what they want to build. This is a lightweight, low-pressure conversation \u2014 not a formal spec process. Let them yap.
733
-
734
- ## How to Run the Interview
735
-
736
- ### 1. Open the Floor
737
-
738
- Start with something like:
739
- "What are you thinking about building? Just talk \u2014 I'll listen and ask questions as we go."
740
-
741
- Let the user talk freely. Do not interrupt their flow. Do not push toward structure yet.
742
-
743
- ### 2. Ask Clarifying Questions
744
-
745
- As they talk, weave in questions naturally \u2014 don't fire them all at once:
746
-
747
- - **What problem does this solve?** Who feels the pain today?
748
- - **What does "done" look like?** If this worked perfectly, what would a user see?
749
- - **What are the constraints?** Time, tech, team, budget \u2014 what boxes are we in?
750
- - **What's NOT in scope?** What's tempting but should be deferred?
751
- - **What are the edge cases?** What could go wrong? What's the weird input?
752
- - **What exists already?** Are we building on something or starting fresh?
753
-
754
- ### 3. Play Back Understanding
755
-
756
- After the user has gotten their ideas out, reflect back:
757
- "So if I'm hearing you right, you want to [summary]. The core problem is [X], and done looks like [Y]. Is that right?"
758
-
759
- Let them correct and refine. Iterate until they say "yes, that's it."
760
-
761
- ### 4. Write a Draft Brief
762
-
763
- Create a draft file at \`docs/briefs/YYYY-MM-DD-topic-draft.md\`. Create the \`docs/briefs/\` directory if it doesn't exist.
764
-
765
- Use this format:
766
-
767
- \`\`\`markdown
768
- # [Topic] \u2014 Draft Brief
769
-
770
- > **Date:** YYYY-MM-DD
771
- > **Status:** DRAFT
772
- > **Origin:** /joycraft-interview session
773
-
774
- ---
775
-
776
- ## The Idea
777
- [2-3 paragraphs capturing what the user described \u2014 their words, their framing]
778
-
779
- ## Problem
780
- [What pain or gap this addresses]
781
-
782
- ## What "Done" Looks Like
783
- [The user's description of success \u2014 observable outcomes]
784
-
785
- ## Constraints
786
- - [constraint 1]
787
- - [constraint 2]
788
-
789
- ## Open Questions
790
- - [things that came up but weren't resolved]
791
- - [decisions that need more thought]
792
-
793
- ## Out of Scope (for now)
794
- - [things explicitly deferred]
795
-
796
- ## Raw Notes
797
- [Any additional context, quotes, or tangents worth preserving]
798
- \`\`\`
799
-
800
- ### 5. Hand Off
801
-
802
- After writing the draft, tell the user:
803
-
804
- \`\`\`
805
- Draft brief saved to docs/briefs/YYYY-MM-DD-topic-draft.md
806
-
807
- When you're ready to move forward:
808
- - /joycraft-new-feature \u2014 formalize this into a full Feature Brief with specs
809
- - /joycraft-decompose \u2014 break it directly into atomic specs if scope is clear
810
- - Or just keep brainstorming \u2014 run /joycraft-interview again anytime
811
- \`\`\`
812
-
813
- ## Guidelines
814
-
815
- - **This is NOT /joycraft-new-feature.** Do not push toward formal briefs, decomposition tables, or atomic specs. The point is exploration.
816
- - **Let the user lead.** Your job is to listen, clarify, and capture \u2014 not to structure or direct.
817
- - **Mark everything as DRAFT.** The output is a starting point, not a commitment.
818
- - **Keep it short.** The draft brief should be 1-2 pages max. Capture the essence, not every detail.
819
- - **Multiple interviews are fine.** The user might run this several times as their thinking evolves. Each creates a new dated draft.
820
-
821
- **Tip:** Run \`/clear\` before starting the next step. Your artifacts are saved to files \u2014 this conversation context is disposable.
822
- `,
823
- "joycraft-lockdown.md": `---
824
- name: joycraft-lockdown
825
- description: Generate constrained execution boundaries for an implementation session -- NEVER rules and deny patterns to prevent agent overreach
826
- instructions: 28
827
- ---
828
-
829
- # Lockdown Mode
830
-
831
- The user wants to constrain agent behavior for an implementation session. Your job is to interview them about what should be off-limits, then generate CLAUDE.md NEVER rules and \`.claude/settings.json\` deny patterns they can review and apply.
832
-
833
- ## When Is Lockdown Useful?
834
-
835
- Lockdown is most valuable for:
836
- - **Complex tech stacks** (hardware, firmware, multi-device) where agents can cause real damage
837
- - **Long-running autonomous sessions** where you won't be monitoring every action
838
- - **Production-adjacent work** where accidental network calls or package installs are risky
839
-
840
- For simple feature work on a well-tested codebase, lockdown is usually overkill. Mention this context to the user so they can decide.
841
-
842
- ## Step 1: Check for Tests
843
-
844
- Before starting the interview, check if the project has test files or directories (look for \`tests/\`, \`test/\`, \`__tests__/\`, \`spec/\`, or files matching \`*.test.*\`, \`*.spec.*\`).
845
-
846
- If no tests are found, tell the user:
847
-
848
- > Lockdown mode is most useful when you already have tests in place -- it prevents the agent from modifying them while constraining behavior to writing code and running tests. Consider running \`/joycraft-new-feature\` first to set up a test-driven workflow, then come back to lock it down.
849
-
850
- If the user wants to proceed anyway, continue with the interview.
851
-
852
- ## Step 2: Interview -- What to Lock Down
853
-
854
- Ask these three questions, one at a time. Wait for the user's response before proceeding to the next question.
855
-
856
- ### Question 1: Read-Only Files
857
-
858
- > What test files or directories should be off-limits for editing? (e.g., \`tests/\`, \`__tests__/\`, \`spec/\`, specific test files)
859
- >
860
- > I'll generate NEVER rules to prevent editing these.
861
-
862
- If the user isn't sure, suggest the test directories you found in Step 1.
863
-
864
- ### Question 2: Allowed Commands
865
-
866
- > What commands should the agent be allowed to run? Defaults:
867
- > - Write and edit source code files
868
- > - Run the project's smoke test command
869
- > - Run the full test suite
870
- >
871
- > Any other commands to explicitly allow? Or should I restrict to just these?
872
-
873
- ### Question 3: Denied Commands
874
-
875
- > What commands should be denied? Defaults:
876
- > - Package installs (\`npm install\`, \`pip install\`, \`cargo add\`, \`go get\`, etc.)
877
- > - Network tools (\`curl\`, \`wget\`, \`ping\`, \`ssh\`)
878
- > - Direct log file reading
879
- >
880
- > Any specific commands to add or remove from this list?
881
-
882
- **Edge case -- user wants to allow some network access:** If the user mentions API tests or specific endpoints that need network access, exclude those from the deny list and note the exception in the output.
883
-
884
- **Edge case -- user wants to lock down file writes:** If the user wants to prevent ALL file writes, warn them:
885
-
886
- > Denying all file writes would prevent the agent from doing any work. I recommend keeping source code writes allowed and only locking down test files, config files, or other sensitive directories.
887
-
888
- ## Step 3: Generate Boundaries
889
-
890
- Based on the interview responses, generate output in this exact format:
891
-
892
- \`\`\`
893
- ## Lockdown boundaries generated
894
-
895
- Review these suggestions and add them to your project:
896
-
897
- ### CLAUDE.md -- add to NEVER section:
898
-
899
- - Edit any file in \`[user's test directories]\`
900
- - Run \`[denied package manager commands]\`
901
- - Use \`[denied network tools]\`
902
- - Read log files directly -- interact with logs only through test assertions
903
- - [Any additional NEVER rules based on user responses]
904
-
905
- ### .claude/settings.json -- suggested deny patterns:
906
-
907
- Add these to the \`permissions.deny\` array:
908
-
909
- ["[command1]", "[command2]", "[command3]"]
910
-
911
- ---
912
-
913
- Copy these into your project manually, or tell me to apply them now (I'll show you the exact changes for approval first).
914
- \`\`\`
915
-
916
- Adjust the content based on the actual interview responses:
917
- - Only include deny patterns for commands the user confirmed should be denied
918
- - Only include NEVER rules for directories/files the user specified
919
- - If the user allowed certain network tools or package managers, exclude those
920
-
921
- ## Recommended Permission Mode
922
-
923
- After generating the boundaries above, also recommend a Claude Code permission mode. Include this section in your output:
924
-
925
- \`\`\`
926
- ### Recommended Permission Mode
927
-
928
- You don't need \`--dangerously-skip-permissions\`. Safer alternatives exist:
929
-
930
- | Your situation | Use | Why |
931
- |---|---|---|
932
- | Autonomous spec execution | \`--permission-mode dontAsk\` + allowlist above | Only pre-approved commands run |
933
- | Long session with some trust | \`--permission-mode auto\` | Safety classifier reviews each action |
934
- | Interactive development | \`--permission-mode acceptEdits\` | Auto-approves file edits, prompts for commands |
935
-
936
- **For lockdown mode, we recommend \`--permission-mode dontAsk\`** combined with the deny patterns above. This gives you full autonomy for allowed operations while blocking everything else -- no classifier overhead, no prompts, and no safety bypass.
937
-
938
- \`--dangerously-skip-permissions\` disables ALL safety checks. The modes above give you autonomy without removing the guardrails.
939
- \`\`\`
940
-
941
- ## Step 4: Offer to Apply
942
-
943
- If the user asks you to apply the changes:
944
-
945
- 1. **For CLAUDE.md:** Read the existing CLAUDE.md, find the Behavioral Boundaries section, and show the user the exact diff for the NEVER section. Ask for confirmation before writing.
946
- 2. **For settings.json:** Read the existing \`.claude/settings.json\`, show the user what the \`permissions.deny\` array will look like after adding the new patterns. Ask for confirmation before writing.
947
-
948
- **Never auto-apply. Always show the exact changes and wait for explicit approval.**
949
- `,
950
- "joycraft-new-feature.md": `---
951
- name: joycraft-new-feature
952
- description: Guided feature development \u2014 interview the user, produce a Feature Brief, then decompose into atomic specs
953
- instructions: 35
954
- ---
955
-
956
- # New Feature Workflow
957
-
958
- You are starting a new feature. Follow this process in order. Do not skip steps.
959
-
960
- ## Phase 1: Interview
961
-
962
- Interview the user about what they want to build. Let them talk \u2014 your job is to listen, then sharpen.
963
-
964
- **Ask about:**
965
- - What problem does this solve? Who is affected?
966
- - What does "done" look like?
967
- - Hard constraints? (business rules, tech limitations, deadlines)
968
- - What is explicitly NOT in scope? (push hard on this)
969
- - Edge cases or error conditions?
970
- - What existing code/patterns should this follow?
971
- - Testing: existing setup? framework? smoke test budget? lockdown mode desired?
972
-
973
- **Interview technique:**
974
- - Let the user "yap" \u2014 don't interrupt their flow
975
- - Play back your understanding: "So if I'm hearing you right..."
976
- - Push toward testable statements: "How would we verify that works?"
977
-
978
- Keep asking until you can fill out a Feature Brief.
979
-
980
- ## Phase 2: Feature Brief
981
-
982
- Write a Feature Brief to \`docs/briefs/YYYY-MM-DD-feature-name.md\`. Create the \`docs/briefs/\` directory if it doesn't exist.
983
-
984
- **Why:** The brief is the single source of truth for what we're building. It prevents scope creep and gives every spec a shared reference point.
985
-
986
- Use this structure:
987
-
988
- \`\`\`markdown
989
- # [Feature Name] \u2014 Feature Brief
990
-
991
- > **Date:** YYYY-MM-DD
992
- > **Project:** [project name]
993
- > **Status:** Interview | Decomposing | Specs Ready | In Progress | Complete
994
-
995
- ---
996
-
997
- ## Vision
998
- What are we building and why? The full picture in 2-4 paragraphs.
999
-
1000
- ## User Stories
1001
- - As a [role], I want [capability] so that [benefit]
1002
-
1003
- ## Hard Constraints
1004
- - MUST: [constraint that every spec must respect]
1005
- - MUST NOT: [prohibition that every spec must respect]
1006
-
1007
- ## Out of Scope
1008
- - NOT: [tempting but deferred]
1009
-
1010
- ## Test Strategy
1011
- - **Existing setup:** [framework and tools, or "none yet"]
1012
- - **User expertise:** [comfortable / learning / needs guidance]
1013
- - **Test types:** [smoke, unit, integration, e2e, etc.]
1014
- - **Smoke test budget:** [target time for fast-feedback tests]
1015
- - **Lockdown mode:** [yes/no \u2014 constrain agent to code + tests only]
1016
-
1017
- ## Decomposition
1018
- | # | Spec Name | Description | Dependencies | Est. Size |
1019
- |---|-----------|-------------|--------------|-----------|
1020
- | 1 | [verb-object] | [one sentence] | None | [S/M/L] |
1021
-
1022
- ## Execution Strategy
1023
- - [ ] Sequential (specs have chain dependencies)
1024
- - [ ] Parallel worktrees (specs are independent)
1025
- - [ ] Mixed
1026
-
1027
- ## Success Criteria
1028
- - [ ] [End-to-end behavior 1]
1029
- - [ ] [No regressions in existing features]
1030
- \`\`\`
1031
-
1032
- If \`docs/templates/FEATURE_BRIEF_TEMPLATE.md\` exists, reference it for the full template with additional guidance.
1033
-
1034
- Present the brief to the user. Focus review on:
1035
- - "Does the decomposition match how you think about this?"
1036
- - "Is anything in scope that shouldn't be?"
1037
- - "Are the specs small enough? Can each be described in one sentence?"
1038
-
1039
- Iterate until approved.
1040
-
1041
- ## Phase 3: Generate Atomic Specs
1042
-
1043
- For each row in the decomposition table, create a self-contained spec file at \`docs/specs/<feature-name>/spec-name.md\`. Derive the feature-name from the brief filename (strip the date prefix and \`.md\` \u2014 e.g., \`2026-04-06-token-discipline.md\` \u2192 \`token-discipline\`). Create the \`docs/specs/<feature-name>/\` directory if it doesn't exist.
1044
-
1045
- **Why:** Each spec must be understandable WITHOUT reading the Feature Brief. This prevents the "Curse of Instructions" \u2014 no spec should require holding the entire feature in context. Copy relevant context into each spec.
1046
-
1047
- Use this structure for each spec:
1048
-
1049
- \`\`\`markdown
1050
- # [Verb + Object] \u2014 Atomic Spec
1051
-
1052
- > **Parent Brief:** \`docs/briefs/YYYY-MM-DD-feature-name.md\`
1053
- > **Status:** Ready
1054
- > **Date:** YYYY-MM-DD
1055
- > **Estimated scope:** [1 session / N files / ~N lines]
1056
-
1057
- ---
1058
-
1059
- ## What
1060
- One paragraph \u2014 what changes when this spec is done?
1061
-
1062
- ## Why
1063
- One sentence \u2014 what breaks or is missing without this?
1064
-
1065
- ## Acceptance Criteria
1066
- - [ ] [Observable behavior]
1067
- - [ ] Build passes
1068
- - [ ] Tests pass
1069
-
1070
- ## Test Plan
1071
-
1072
- | Acceptance Criterion | Test | Type |
1073
- |---------------------|------|------|
1074
- | [Each AC above] | [What to call/assert] | [unit/integration/e2e] |
1075
-
1076
- **Execution order:**
1077
- 1. Write all tests above \u2014 they should fail against current/stubbed code
1078
- 2. Run tests to confirm they fail (red)
1079
- 3. Implement until all tests pass (green)
1080
-
1081
- **Smoke test:** [Identify the fastest test for iteration feedback]
1082
-
1083
- **Before implementing, verify your test harness:**
1084
- 1. Run all tests \u2014 they must FAIL (if they pass, you're testing the wrong thing)
1085
- 2. Each test calls your actual function/endpoint \u2014 not a reimplementation or the underlying library
1086
- 3. Identify your smoke test \u2014 it must run in seconds, not minutes, so you get fast feedback on each change
1087
-
1088
- ## Constraints
1089
- - MUST: [hard requirement]
1090
- - MUST NOT: [hard prohibition]
1091
-
1092
- ## Affected Files
1093
- | Action | File | What Changes |
1094
- |--------|------|-------------|
1095
-
1096
- ## Approach
1097
- Strategy, data flow, key decisions. Name one rejected alternative.
1098
-
1099
- ## Edge Cases
1100
- | Scenario | Expected Behavior |
1101
- |----------|------------------|
1102
- \`\`\`
1103
-
1104
- If \`docs/templates/ATOMIC_SPEC_TEMPLATE.md\` exists, reference it for the full template with additional guidance.
1105
-
1106
- ## Phase 4: Hand Off for Execution
1107
-
1108
- Tell the user:
1109
- \`\`\`
1110
- Feature Brief and [N] atomic specs are ready.
1111
-
1112
- Specs:
1113
- 1. [spec-name] \u2014 [one sentence] [S/M/L]
1114
- 2. [spec-name] \u2014 [one sentence] [S/M/L]
1115
- ...
1116
-
1117
- Recommended execution:
1118
- - [Parallel/Sequential/Mixed strategy]
1119
- - Estimated: [N] sessions total
1120
-
1121
- To execute: Start a fresh session per spec. Each session should:
1122
- 1. Read the spec
1123
- 2. Implement
1124
- 3. Run /joycraft-session-end to capture discoveries
1125
- 4. Commit and PR
1126
-
1127
- Ready to start?
1128
- \`\`\`
1129
-
1130
- **Why:** A fresh session for execution produces better results. The interview session has too much context noise \u2014 a clean session with just the spec is more focused.
1131
-
1132
- You can also use \`/joycraft-decompose\` to re-decompose a brief if the breakdown needs adjustment, or run \`/joycraft-interview\` first for a lighter brainstorm before committing to the full workflow.
1133
-
1134
- **Tip:** Run \`/clear\` before starting the next step. Your artifacts are saved to files \u2014 this conversation context is disposable.
1135
- `,
1136
- "joycraft-optimize.md": `---
1137
- name: joycraft-optimize
1138
- description: Audit your Claude Code or Codex session overhead \u2014 harness file sizes, plugins, MCP servers, hooks \u2014 and report actionable recommendations
1139
- instructions: 20
1140
- ---
1141
-
1142
- # Optimize \u2014 Session Overhead Audit
1143
-
1144
- You are auditing the user's AI development session for token overhead. Produce a conversational diagnostic report \u2014 no files created.
1145
-
1146
- ## Step 1: Detect Platform
1147
-
1148
- Check which platform is active:
1149
- - **Claude Code:** Look for \`.claude/\` directory, \`CLAUDE.md\`
1150
- - **Codex:** Look for \`.agents/\` directory, \`AGENTS.md\`
1151
-
1152
- If both exist, run both checks. If neither, default to Claude Code checks and note the uncertainty.
1153
-
1154
- ## Step 2: Audit Harness Files
1155
-
1156
- ### Claude Code Path
1157
-
1158
- 1. **CLAUDE.md** \u2014 count lines. Threshold: \u2264200 lines.
1159
- 2. **Skill files** \u2014 glob \`.claude/skills/**/*.md\`. Count lines per file. Threshold: \u2264200 lines each.
1160
-
1161
- ### Codex Path
1162
-
1163
- 1. **AGENTS.md** \u2014 count lines. Threshold: \u2264200 lines.
1164
- 2. **Skill files** \u2014 glob \`.agents/skills/**/*.md\`. Count lines per file. Threshold: \u2264200 lines each.
1165
-
1166
- ## Step 3: Audit Plugins & MCP Servers
1167
-
1168
- ### Claude Code Path
1169
-
1170
- 1. **Installed plugins** \u2014 read \`~/.claude/plugins/installed_plugins.json\`. List plugin names and versions. If not found, report "no plugins file found."
1171
- 2. **Enabled plugins** \u2014 read \`~/.claude/settings.json\`, check \`enabledPlugins\` array. Show enabled vs installed count.
1172
- 3. **MCP servers** \u2014 read \`~/.claude/settings.json\`, count entries under \`mcpServers\`. List server names.
1173
-
1174
- ### Codex Path
1175
-
1176
- 1. **Plugin config** \u2014 read \`~/.codex/config.toml\`. List any plugin toggles. Note: Codex syncs its curated plugin marketplace at startup \u2014 this is a boot cost even if you don't use them.
1177
- 2. **MCP servers** \u2014 check \`~/.codex/config.toml\` for MCP server entries. List server names.
1178
-
1179
- ## Step 4: Audit Hooks (Claude Code Only)
1180
-
1181
- Read \`.claude/settings.json\` in the project directory. List all hook definitions under the \`hooks\` key \u2014 show the event name and command for each.
1182
-
1183
- For Codex: note "hook auditing not yet supported on Codex."
1184
-
1185
- ## Step 5: Report
1186
-
1187
- Organize findings by category. Use pass/warn indicators:
1188
-
1189
- \`\`\`
1190
- ## Session Overhead Report
1191
-
1192
- ### Harness Files
1193
- - CLAUDE.md: [N] lines [PASS \u2264200 / WARN >200]
1194
- - Skills: [N] files, [list any over 200 lines]
1195
-
1196
- ### Plugins
1197
- - Installed: [N] ([list names])
1198
- - Enabled: [N] of [M] installed
1199
- - [If 0: "No plugins \u2014 zero boot cost from plugins."]
1200
-
1201
- ### MCP Servers
1202
- - Count: [N] ([list names])
1203
- - [If 0: "No MCP servers \u2014 zero boot cost from servers."]
1204
-
1205
- ### Hooks
1206
- - [N] hook definitions ([list event names])
1207
-
1208
- ### Recommendations
1209
- - [Specific, actionable items for anything over threshold]
1210
- - [e.g., "CLAUDE.md is 312 lines \u2014 consider splitting reference sections into docs/"]
1211
- - [e.g., "3 MCP servers load at boot \u2014 disable unused ones in settings.json"]
1212
- \`\`\`
1213
-
1214
- ## Step 6: Further Resources
1215
-
1216
- End with:
1217
-
1218
- > For deeper token optimization, see:
1219
- > - [Nate B Jones's token optimization techniques](https://www.youtube.com/watch?v=bDcgHzCBgmQ)
1220
- > - [OB1 repo](https://github.com/nate-b-j/OB1) \u2014 Heavy File Ingestion skill and stupid button prompt kit
1221
- > - [Joycraft's token discipline guide](docs/guides/token-discipline.md)
1222
-
1223
- ## Edge Cases
1224
-
1225
- | Scenario | Behavior |
1226
- |----------|----------|
1227
- | Config files don't exist | Report "not found" for that check, don't error |
1228
- | No plugins installed | Report 0 plugins \u2014 this is good, say so |
1229
- | CLAUDE.md/AGENTS.md exactly 200 lines | PASS \u2014 threshold is \u2264200 |
1230
- | \`~/.claude/\` or \`~/.codex/\` not accessible | Skip user-level checks, note limitation |
1231
- | Both platforms detected | Run both audits, report separately |
1232
- `,
1233
- "joycraft-research.md": `---
1234
- name: joycraft-research
1235
- description: Produce objective codebase research by isolating question generation from fact-gathering \u2014 subagent sees only questions, never the brief
1236
- ---
1237
-
1238
- # Research Codebase for a Feature
1239
-
1240
- You are producing objective codebase research to inform a future spec or implementation. The key insight: the researching agent must never see the brief or ticket \u2014 only research questions. This prevents opinions from contaminating the facts.
1241
-
1242
- **Guard clause:** If the user doesn't provide a brief path or inline description, ask:
1243
- "What feature or change are you researching? Provide a brief path (e.g., \`docs/briefs/2026-03-30-my-feature.md\`) or describe it in a few sentences."
1244
-
1245
- ---
1246
-
1247
- ## Phase 1: Generate Research Questions
1248
-
1249
- Read the brief file (if a path was provided) or use the user's inline description.
1250
-
1251
- Identify which zones of the codebase are relevant to this feature. Then generate 5-10 research questions that are:
1252
-
1253
- - **Objective and fact-seeking** \u2014 "How does X work?" not "How should we build X?"
1254
- - **Specific to the codebase** \u2014 reference concrete systems, files, or flows
1255
- - **Answerable by reading code** \u2014 no questions about business strategy or user preferences
1256
-
1257
- Good examples:
1258
- - "How does endpoint registration work in the current router?"
1259
- - "What patterns exist for input validation across existing handlers?"
1260
- - "Trace the data flow from API request to database write for entity X."
1261
- - "What test infrastructure exists? Where are fixtures, mocks, and helpers?"
1262
- - "What dependencies does module Y import, and what does its public API look like?"
1263
-
1264
- Bad examples (do NOT generate these):
1265
- - "What's the best way to implement this feature?" (opinion)
1266
- - "Should we use library X or Y?" (recommendation)
1267
- - "What would a good architecture look like?" (design, not research)
1268
-
1269
- Write the questions to a temporary file at \`docs/research/.questions-tmp.md\`. Create the \`docs/research/\` directory if it doesn't exist.
1270
-
1271
- **Do NOT include any content from the brief in this file \u2014 only the questions.**
1272
-
1273
- ---
1274
-
1275
- ## Phase 2: Spawn Research Subagent
1276
-
1277
- Use Claude Code's Agent tool to spawn a subagent. Pass ONLY the research questions \u2014 never the brief path, brief content, or feature description.
1278
-
1279
- Build the subagent prompt by reading the questions file you just wrote, then use this template:
1280
-
1281
- \`\`\`
1282
- You are researching a codebase to answer specific questions. You have NO context about why these questions are being asked \u2014 you are simply gathering facts.
1283
-
1284
- RULES \u2014 these are hard constraints:
1285
- - Answer each question with FACTS ONLY: file paths, function signatures, data flows, patterns, dependencies
1286
- - Do NOT recommend, suggest, or opine on anything
1287
- - Do NOT speculate about what should be built or how
1288
- - If a question cannot be answered (no relevant code exists), say "No existing code found for this"
1289
- - Use the Read tool and Grep tool to explore the codebase thoroughly
1290
- - Include code snippets only when they are essential evidence (e.g., a function signature, a config block)
1291
-
1292
- QUESTIONS:
1293
- [INSERT_QUESTIONS_HERE]
1294
-
1295
- OUTPUT FORMAT \u2014 write your findings as a single markdown document using this structure:
1296
-
1297
- # Codebase Research
1298
-
1299
- **Date:** [today's date]
1300
- **Questions answered:** [N/total]
1301
-
1302
- ---
1303
-
1304
- ## Q1: [question text]
1305
-
1306
- [Facts, file paths, function signatures, data flows. No opinions.]
1307
-
1308
- ## Q2: [question text]
1309
-
1310
- [Facts, file paths, function signatures, data flows. No opinions.]
1311
-
1312
- [Continue for all questions]
1313
- \`\`\`
1314
-
1315
- ## Phase 3: Write the Research Document
1316
-
1317
- Take the subagent's response and write it to \`docs/research/YYYY-MM-DD-feature-name.md\`. Derive the feature name from the brief filename or the user's description (lowercase, hyphenated).
1318
-
1319
- Delete the temporary questions file (\`docs/research/.questions-tmp.md\`).
1320
-
1321
- Present the research document path to the user:
1322
-
1323
- \`\`\`
1324
- Research complete: docs/research/YYYY-MM-DD-feature-name.md
1325
-
1326
- This document contains objective facts about your codebase \u2014 no opinions or recommendations.
1327
-
1328
- Next steps:
1329
- - /joycraft-decompose \u2014 break the feature into atomic specs (research will inform the specs)
1330
- - /joycraft-new-feature \u2014 formalize into a full Feature Brief first
1331
- - Read the research and add any corrections or missing context manually
1332
- \`\`\`
1333
-
1334
- ## Edge Cases
1335
-
1336
- | Scenario | Behavior |
1337
- |----------|----------|
1338
- | No brief provided | Accept inline description, generate questions from that |
1339
- | Codebase is empty or new | Research doc reports "no existing patterns found" per question |
1340
- | User runs research twice for same feature | Overwrites previous research doc (same filename) |
1341
- | Brief is very short (1-2 sentences) | Still generate questions \u2014 even simple features benefit from understanding existing patterns |
1342
- | \`docs/research/\` doesn't exist | Create it |
1343
- `,
1344
- "joycraft-session-end.md": `---
1345
- name: joycraft-session-end
1346
- description: Wrap up a session \u2014 capture discoveries, verify, prepare for PR or next session
1347
- instructions: 22
1348
- ---
1349
-
1350
- # Session Wrap-Up
1351
-
1352
- Before ending this session, complete these steps in order.
1353
-
1354
- ## 1. Capture Discoveries
1355
-
1356
- **Why:** Discoveries are the surprises \u2014 things that weren't in the spec or that contradicted expectations. They prevent future sessions from hitting the same walls.
1357
-
1358
- Check: did anything surprising happen during this session? If yes, create or update a discovery file at \`docs/discoveries/YYYY-MM-DD-topic.md\`. Create the \`docs/discoveries/\` directory if it doesn't exist.
1359
-
1360
- Only capture what's NOT obvious from the code or git diff:
1361
- - "We thought X but found Y" \u2014 assumptions that were wrong
1362
- - "This API/library behaves differently than documented" \u2014 external gotchas
1363
- - "This edge case needs handling in a future spec" \u2014 deferred work with context
1364
- - "The approach in the spec didn't work because..." \u2014 spec-vs-reality gaps
1365
- - Key decisions made during implementation that aren't in the spec
1366
-
1367
- **Do NOT capture:**
1368
- - Files changed (that's the diff)
1369
- - What you set out to do (that's the spec)
1370
- - Step-by-step narrative of the session (nobody re-reads these)
1371
-
1372
- Use this format:
1373
-
1374
- \`\`\`markdown
1375
- # Discoveries \u2014 [topic]
1376
-
1377
- **Date:** YYYY-MM-DD
1378
- **Spec:** [link to spec if applicable]
1379
-
1380
- ## [Discovery title]
1381
- **Expected:** [what we thought would happen]
1382
- **Actual:** [what actually happened]
1383
- **Impact:** [what this means for future work]
1384
- \`\`\`
1385
-
1386
- If nothing surprising happened, skip the discovery file entirely. No discovery is a good sign \u2014 the spec was accurate.
1387
-
1388
- ## 1b. Update Context Documents
1389
-
1390
- If \`docs/context/\` exists, quickly check whether this session revealed anything about:
1391
-
1392
- - **Production risks** \u2014 did you interact with or learn about production vs staging systems? \u2192 Update \`docs/context/production-map.md\`
1393
- - **Wrong assumptions** \u2014 did the agent (or you) assume something that turned out to be false? \u2192 Update \`docs/context/dangerous-assumptions.md\`
1394
- - **Key decisions** \u2014 did you make an architectural or tooling choice? \u2192 Add a row to \`docs/context/decision-log.md\`
1395
- - **Unwritten rules** \u2014 did you discover a convention or constraint not documented anywhere? \u2192 Update \`docs/context/institutional-knowledge.md\`
1396
-
1397
- Skip this if nothing applies. Don't force it \u2014 only update when there's genuine new context.
1398
-
1399
- ## 2. Run Validation
1400
-
1401
- Run the project's validation commands. Check CLAUDE.md for project-specific commands. Common checks:
1402
-
1403
- - Type-check (e.g., \`tsc --noEmit\`, \`mypy\`, \`cargo check\`)
1404
- - Tests (e.g., \`npm test\`, \`pytest\`, \`cargo test\`)
1405
- - Lint (e.g., \`eslint\`, \`ruff\`, \`clippy\`)
1406
-
1407
- Fix any failures before proceeding.
1408
-
1409
- ## 3. Update Spec Status
1410
-
1411
- If working from an atomic spec in \`docs/specs/\` (scan recursively \u2014 specs may be in subdirectories like \`docs/specs/<feature-name>/\`):
1412
- - All acceptance criteria met \u2014 update status to \`Complete\`
1413
- - Partially done \u2014 update status to \`In Progress\`, note what's left
1414
-
1415
- If working from a Feature Brief in \`docs/briefs/\`, check off completed specs in the decomposition table.
1416
-
1417
- ## 4. Commit
1418
-
1419
- Commit all changes including the discovery file (if created) and spec status updates. The commit message should reference the spec if applicable.
1420
-
1421
- ## 5. Push and PR (if autonomous git is enabled)
1422
-
1423
- **Check CLAUDE.md for "Git Autonomy" in the Behavioral Boundaries section.** If it says "STRICTLY ENFORCED" or the ALWAYS section includes "Push to feature branches immediately after every commit":
1424
-
1425
- 1. **Push immediately.** Run \`git push origin <branch>\` \u2014 do not ask, do not hesitate.
1426
- 2. **Open a PR if the feature is complete.** Check the parent Feature Brief's decomposition table \u2014 if all specs are done, run \`gh pr create\` with a summary of all completed specs. Do not ask first.
1427
- 3. **If not all specs are done,** still push. The PR comes when the last spec is complete.
1428
-
1429
- If CLAUDE.md does NOT have autonomous git rules (or has "ASK FIRST" for pushing), ask the user before pushing.
1430
-
1431
- ## 6. Report
1432
-
1433
- \`\`\`
1434
- Session complete.
1435
- - Spec: [spec name] \u2014 [Complete / In Progress]
1436
- - Build: [passing / failing]
1437
- - Discoveries: [N items / none]
1438
- - Pushed: [yes / no \u2014 and why not]
1439
- - PR: [opened #N / not yet \u2014 N specs remaining]
1440
- - Next: [what the next session should tackle]
1441
- \`\`\`
1442
-
1443
- **Tip:** Run \`/clear\` before starting the next step. Your artifacts are saved to files \u2014 this conversation context is disposable.
1444
- `,
1445
- "joycraft-tune.md": `---
1446
- name: joycraft-tune
1447
- description: Assess and upgrade your project's AI development harness \u2014 score 7 dimensions, apply fixes, show path to Level 5
1448
- instructions: 15
1449
- ---
1450
-
1451
- # Tune \u2014 Project Harness Assessment & Upgrade
1452
-
1453
- You are evaluating and upgrading this project's AI development harness.
1454
-
1455
- ## Step 1: Detect Harness State
1456
-
1457
- Check for: CLAUDE.md (with meaningful content), \`docs/specs/\`, \`docs/briefs/\`, \`docs/discoveries/\`, \`.claude/skills/\`, and test configuration.
1458
-
1459
- ## Step 2: Route
1460
-
1461
- - **No harness** (no CLAUDE.md or just a README): Recommend \`npx joycraft init\` and stop.
1462
- - **Harness exists**: Continue to assessment.
1463
-
1464
- ## Step 3: Assess \u2014 Score 7 Dimensions (1-5 scale)
1465
-
1466
- Read CLAUDE.md and explore the project. Score each with specific evidence:
1467
-
1468
- | Dimension | What to Check |
1469
- |-----------|--------------|
1470
- | Spec Quality | \`docs/specs/\` (scan recursively) \u2014 structured? acceptance criteria? self-contained? |
1471
- | Spec Granularity | Can each spec be done in one session? |
1472
- | Behavioral Boundaries | ALWAYS/ASK FIRST/NEVER sections (or equivalent rules under any heading) |
1473
- | Skills & Hooks | \`.claude/skills/\` files, hooks config |
1474
- | Documentation | \`docs/\` structure, templates, referenced from CLAUDE.md |
1475
- | Knowledge Capture | \`docs/discoveries/\`, \`docs/context/*.md\` \u2014 existence AND real content |
1476
- | Testing & Validation | Test framework, CI pipeline, validation commands in CLAUDE.md |
1477
-
1478
- Score 1 = absent, 3 = partially there, 5 = comprehensive. Give credit for substance over format.
1479
-
1480
- ## Step 4: Write Assessment
1481
-
1482
- Write to \`docs/joycraft-assessment.md\` AND display it. Include: scores table, detailed findings (evidence + gap + recommendation per dimension), and an upgrade plan (up to 5 actions ordered by impact).
1483
-
1484
- ## Step 5: Apply Upgrades
1485
-
1486
- Apply using three tiers \u2014 do NOT ask per-item permission:
1487
-
1488
- **Tier 1 (silent):** Create missing dirs, install missing skills, copy missing templates, create AGENTS.md.
1489
-
1490
- **Before Tier 2, ask TWO things:**
1491
-
1492
- 1. **Git autonomy:** Cautious (ask before push/PR) or Autonomous (push + PR without asking)?
1493
- 2. **Risk interview (3-5 questions, one at a time):** What could break? What services connect to prod? Unwritten rules? Off-limits files/commands? Skip if \`docs/context/\` already has content.
1494
-
1495
- From answers, generate: CLAUDE.md boundary rules, \`.claude/settings.json\` deny patterns, \`docs/context/\` documents. Also recommend a permission mode (\`auto\` for most; \`dontAsk\` + allowlist for high-risk).
1496
-
1497
- **Tier 2 (show diff):** Add missing CLAUDE.md sections (Boundaries, Workflow, Key Files). Draft from real codebase content. Append only \u2014 never reformat existing content.
1498
-
1499
- **Tier 3 (confirm first):** Rewriting existing sections, overwriting customized files, suggesting test framework installs.
1500
-
1501
- After applying, append to \`docs/joycraft-history.md\` and show a consolidated upgrade results table.
1502
-
1503
- ## Step 6: Show Path to Level 5
1504
-
1505
- Show a tailored roadmap: Level 2-5 table, specific next steps based on actual gaps, and the Level 5 north star (spec queue, autofix, holdout scenarios, self-improving harness).
1506
-
1507
- ## Edge Cases
1508
-
1509
- - **CLAUDE.md is just a README:** Treat as no harness.
1510
- - **Non-Joycraft skills:** Acknowledge, don't replace.
1511
- - **Rules under non-standard headings:** Give credit for substance.
1512
- - **Previous assessment exists:** Read it first. If nothing to upgrade, say so.
1513
- - **Non-Joycraft content in CLAUDE.md:** Preserve as-is. Only append.
1514
-
1515
- **Tip:** Run \`/joycraft-optimize\` to audit your session's token overhead \u2014 plugins, MCP servers, and harness file sizes.
1516
- `,
1517
- "joycraft-verify.md": `---
1518
- name: joycraft-verify
1519
- description: Spawn an independent verifier subagent to check an implementation against its spec -- read-only, no code edits, structured pass/fail verdict
1520
- instructions: 30
1521
- ---
1522
-
1523
- # Verify Implementation Against Spec
1524
-
1525
- The user wants independent verification of an implementation. Your job is to find the relevant spec, extract its acceptance criteria and test plan, then spawn a separate verifier subagent that checks each criterion and produces a structured verdict.
1526
-
1527
- **Why a separate subagent?** Anthropic's research found that agents reliably skew positive when grading their own work. Separating the agent doing the work from the agent judging it consistently outperforms self-evaluation. The verifier gets a clean context window with no implementation bias.
1528
-
1529
- ## Step 1: Find the Spec
1530
-
1531
- If the user provided a spec path (e.g., \`/joycraft-verify docs/specs/my-feature/add-widget.md\`), use that path directly.
1532
-
1533
- If no path was provided, scan \`docs/specs/\` recursively for spec files (they may be in subdirectories like \`docs/specs/<feature-name>/\`). Pick the most recently modified \`.md\` file. If \`docs/specs/\` doesn't exist or is empty, tell the user:
1534
-
1535
- > No specs found in \`docs/specs/\`. Please provide a spec path: \`/joycraft-verify path/to/spec.md\`
1536
-
1537
- ## Step 2: Read and Parse the Spec
1538
-
1539
- Read the spec file and extract:
1540
-
1541
- 1. **Spec name** -- from the H1 title
1542
- 2. **Acceptance Criteria** -- the checklist under the \`## Acceptance Criteria\` section
1543
- 3. **Test Plan** -- the table under the \`## Test Plan\` section, including any test commands
1544
- 4. **Constraints** -- the \`## Constraints\` section if present
1545
-
1546
- If the spec has no Acceptance Criteria section, tell the user:
1547
-
1548
- > This spec doesn't have an Acceptance Criteria section. Verification needs criteria to check against. Add acceptance criteria to the spec and try again.
1549
-
1550
- If the spec has no Test Plan section, note this but proceed -- the verifier can still check criteria by reading code and running any available project tests.
1551
-
1552
- ## Step 3: Identify Test Commands
1553
-
1554
- Look for test commands in these locations (in priority order):
1555
-
1556
- 1. The spec's Test Plan section (look for commands in backticks or "Type" column entries like "unit", "integration", "e2e", "build")
1557
- 2. The project's CLAUDE.md (look for test/build commands in the Development Workflow section)
1558
- 3. Common defaults based on the project type:
1559
- - Node.js: \`npm test\` or \`pnpm test --run\`
1560
- - Python: \`pytest\`
1561
- - Rust: \`cargo test\`
1562
- - Go: \`go test ./...\`
1563
-
1564
- Build a list of specific commands the verifier should run.
1565
-
1566
- ## Step 4: Spawn the Verifier Subagent
1567
-
1568
- Use Claude Code's Agent tool to spawn a subagent with the following prompt. Replace the placeholders with the actual content extracted in Steps 2-3.
1569
-
1570
- \`\`\`
1571
- You are a QA verifier. Your job is to independently verify an implementation against its spec. You have NO context about how the implementation was done -- you are checking it fresh.
1572
-
1573
- RULES -- these are hard constraints, not suggestions:
1574
- - You may READ any file using the Read tool or cat
1575
- - You may RUN these specific test/build commands: [TEST_COMMANDS]
1576
- - You may NOT edit, create, or delete any files
1577
- - You may NOT run commands that modify state (no git commit, no npm install, no file writes)
1578
- - You may NOT install packages or access the network
1579
- - Report what you OBSERVE, not what you expect or hope
1580
-
1581
- SPEC NAME: [SPEC_NAME]
1582
-
1583
- ACCEPTANCE CRITERIA:
1584
- [ACCEPTANCE_CRITERIA]
1585
-
1586
- TEST PLAN:
1587
- [TEST_PLAN]
1588
-
1589
- CONSTRAINTS:
1590
- [CONSTRAINTS_OR_NONE]
1591
-
1592
- YOUR TASK:
1593
- For each acceptance criterion, determine if it PASSES or FAILS based on evidence:
1594
-
1595
- 1. Run the test commands listed above. Record the output.
1596
- 2. For each acceptance criterion:
1597
- a. Check if there is a corresponding test and whether it passes
1598
- b. If no test exists, read the relevant source files to verify the criterion is met
1599
- c. If the criterion cannot be verified by reading code or running tests, mark it MANUAL CHECK NEEDED
1600
- 3. For criteria about build/test passing, actually run the commands and report results.
1601
-
1602
- OUTPUT FORMAT -- you MUST use this exact format:
1603
-
1604
- VERIFICATION REPORT
1605
-
1606
- | # | Criterion | Verdict | Evidence |
1607
- |---|-----------|---------|----------|
1608
- | 1 | [criterion text] | PASS/FAIL/MANUAL CHECK NEEDED | [what you observed] |
1609
- | 2 | [criterion text] | PASS/FAIL/MANUAL CHECK NEEDED | [what you observed] |
1610
- [continue for all criteria]
1611
-
1612
- SUMMARY: X/Y criteria passed. [Z failures need attention. / All criteria verified.]
1613
-
1614
- If any test commands fail to run (missing dependencies, wrong command, etc.), report the error as evidence for a FAIL verdict on the relevant criterion.
1615
- \`\`\`
1616
-
1617
- ## Step 5: Format and Present the Verdict
1618
-
1619
- Take the subagent's response and present it to the user in this format:
1620
-
1621
- \`\`\`
1622
- ## Verification Report -- [Spec Name]
1623
-
1624
- | # | Criterion | Verdict | Evidence |
1625
- |---|-----------|---------|----------|
1626
- | 1 | ... | PASS | ... |
1627
- | 2 | ... | FAIL | ... |
1628
-
1629
- **Overall: X/Y criteria passed.**
1630
-
1631
- [If all passed:]
1632
- All criteria verified. Ready to commit and open a PR.
1633
-
1634
- [If any failed:]
1635
- N failures need attention. Review the evidence above and fix before proceeding.
1636
-
1637
- [If any MANUAL CHECK NEEDED:]
1638
- N criteria need manual verification -- they can't be checked by reading code or running tests alone.
1639
- \`\`\`
1640
-
1641
- ## Step 6: Suggest Next Steps
1642
-
1643
- Based on the verdict:
1644
-
1645
- - **All PASS:** Suggest committing and opening a PR, or running \`/joycraft-session-end\` to capture discoveries.
1646
- - **Some FAIL:** List the failed criteria and suggest the user fix them, then run \`/joycraft-verify\` again.
1647
- - **MANUAL CHECK NEEDED items:** Explain what needs human eyes and why automation couldn't verify it.
1648
-
1649
- **Do NOT offer to fix failures yourself.** The verifier reports; the human (or implementation agent in a separate turn) decides what to do. This separation is the whole point.
1650
-
1651
- ## Edge Cases
1652
-
1653
- | Scenario | Behavior |
1654
- |----------|----------|
1655
- | Spec has no Test Plan | Warn that verification is weaker without a test plan, but proceed by checking criteria through code reading and any available project-level tests |
1656
- | All tests pass but a criterion is not testable | Mark as MANUAL CHECK NEEDED with explanation |
1657
- | Subagent can't run tests (missing deps) | Report the error as FAIL evidence |
1658
- | No specs found and no path given | Tell user to provide a spec path or create a spec first |
1659
- | Spec status is "Complete" | Still run verification -- "Complete" means the implementer thinks it's done, verification confirms |
1660
- `
1661
- };
1662
- var TEMPLATES = {
1663
- "context/dangerous-assumptions.md": `# Dangerous Assumptions
1664
-
1665
- > Things the AI agent might assume that are wrong in this project.
1666
- > Generated by Joycraft risk interview. Update when you discover new gotchas.
1667
-
1668
- ## Assumptions
1669
-
1670
- | Agent Might Assume | But Actually | Impact If Wrong |
1671
- |-------------------|-------------|----------------|
1672
- | _Example: All databases are dev/test_ | _The default connection is production_ | _Data loss_ |
1673
- | _Example: Deleting and recreating is safe_ | _Some resources have manual config not in code_ | _Hours of manual recovery_ |
1674
-
1675
- ## Historical Incidents
1676
-
1677
- | Date | What Happened | Lesson | Rule Added |
1678
- |------|-------------|--------|------------|
1679
- | _Example: 2026-03-15_ | _Agent deleted staging infra thinking it was temp_ | _Always verify environment before destructive ops_ | _NEVER: Delete cloud resources without listing them first_ |
1680
- `,
1681
- "context/decision-log.md": `# Decision Log
1682
-
1683
- > Why choices were made, not just what was chosen.
1684
- > Update this when making architectural, tooling, or process decisions.
1685
- > This is the institutional memory that prevents re-litigating settled questions.
1686
-
1687
- ## Decisions
1688
-
1689
- | Date | Decision | Why | Alternatives Rejected | Revisit When |
1690
- |------|----------|-----|----------------------|-------------|
1691
- | _Example: 2026-03-15_ | _Use Supabase over Firebase_ | _Postgres flexibility, row-level security, self-hostable_ | _Firebase (vendor lock-in), PlanetScale (no RLS)_ | _If we need real-time sync beyond Supabase's capabilities_ |
1692
-
1693
- ## Principles
1694
-
1695
- _Capture recurring decision patterns here \u2014 they save time on future choices._
1696
-
1697
- - _Example: "Prefer tools we can self-host over pure SaaS \u2014 reduces vendor risk"_
1698
- - _Example: "Choose boring technology for infrastructure, cutting-edge only for core differentiators"_
1699
- `,
1700
- "context/institutional-knowledge.md": `# Institutional Knowledge
1701
-
1702
- > Unwritten rules, team conventions, and organizational context that AI agents can't derive from code.
1703
- > This is the knowledge that takes a new developer months to absorb.
1704
- > Update when you catch yourself saying "oh, you didn't know about that?"
1705
-
1706
- ## Team Conventions
1707
-
1708
- _Things everyone on the team knows but nobody wrote down._
1709
-
1710
- - _Example: "We never deploy on Fridays"_
1711
- - _Example: "The CEO reviews all UI changes before they ship"_
1712
- - _Example: "PR titles must reference the Jira ticket number"_
1713
-
1714
- ## Organizational Constraints
1715
-
1716
- _Business rules, compliance requirements, or political realities that affect technical decisions._
1717
-
1718
- - _Example: "Legal requires all user data to be stored in EU regions"_
1719
- - _Example: "The payments team owns the billing schema \u2014 never modify without their approval"_
1720
- - _Example: "We have an informal agreement with Vendor X about API rate limits"_
1721
-
1722
- ## Historical Context
1723
-
1724
- _Why things are the way they are \u2014 especially when it looks wrong._
1725
-
1726
- - _Example: "The auth module uses an old pattern because it predates our TypeScript migration \u2014 don't refactor without a spec"_
1727
- - _Example: "The caching layer has a 5-second TTL because we had a consistency bug in 2025 \u2014 increasing it requires careful testing"_
1728
-
1729
- ## People & Ownership
1730
-
1731
- _Who owns what, who to ask, who cares about what._
1732
-
1733
- - _Example: "Alice owns the payment pipeline \u2014 all changes need her review"_
1734
- - _Example: "The data team is sensitive about query performance on the analytics tables"_
1735
- `,
1736
- "context/production-map.md": `# Production Map
1737
-
1738
- > What's real, what's staging, what's safe to touch.
1739
- > Generated by Joycraft risk interview. Update as your infrastructure evolves.
1740
-
1741
- ## Services
1742
-
1743
- | Service | Environment | URL/Endpoint | Impact if Corrupted |
1744
- |---------|-------------|-------------|-------------------|
1745
- | _Example: Main DB_ | _Production_ | _postgres://prod.example.com_ | _1.9M user records lost_ |
1746
- | _Example: Staging DB_ | _Staging_ | _postgres://staging.example.com_ | _Test data only, safe to reset_ |
1747
-
1748
- ## Secrets & Credentials
1749
-
1750
- | Secret | Location | Notes |
1751
- |--------|----------|-------|
1752
- | _Example: DATABASE_URL_ | _.env.local_ | _Production connection \u2014 NEVER commit_ |
1753
-
1754
- ## Safe to Touch
1755
-
1756
- - [ ] Staging environment at [URL]
1757
- - [ ] Test/fixture data in [location]
1758
- - [ ] Development API keys
1759
-
1760
- ## NEVER Touch Without Explicit Approval
1761
-
1762
- - [ ] Production database
1763
- - [ ] Live API endpoints
1764
- - [ ] User-facing infrastructure
1765
- `,
1766
- "context/troubleshooting.md": `# Troubleshooting
1767
-
1768
- > What to do when things go wrong for non-code reasons.
1769
- > Environment issues, flaky dependencies, hardware quirks, and diagnostic steps.
1770
- > Update when you discover new failure modes and their fixes.
1771
-
1772
- ## Common Failures
1773
-
1774
- | When This Happens | Do This | Don't Do This |
1775
- |-------------------|---------|---------------|
1776
- | _Example: Tests fail with ECONNREFUSED_ | _Check if the dev database is running_ | _Don't rewrite the test or mock the connection_ |
1777
- | _Example: Build fails with out-of-memory_ | _Increase Node heap size or close other processes_ | _Don't simplify the code to reduce bundle size_ |
1778
- | _Example: Lint passes locally but fails in CI_ | _Check Node/tool version mismatch between local and CI_ | _Don't disable the lint rule_ |
1779
-
1780
- ## Environment Issues
1781
-
1782
- | Symptom | Likely Cause | Fix |
1783
- |---------|-------------|-----|
1784
- | _Example: "Module not found" after branch switch_ | _Dependencies changed on the new branch_ | _Run the package manager install command_ |
1785
- | _Example: Port already in use_ | _Previous dev server didn't shut down cleanly_ | _Kill the process on that port or use a different one_ |
1786
- | _Example: Permission denied on file/directory_ | _File ownership or permission mismatch_ | _Check and fix file permissions, don't run as root_ |
1787
-
1788
- ## Diagnostic Steps
1789
-
1790
- _When something fails unexpectedly, follow this sequence before trying to fix the code:_
1791
-
1792
- 1. **Check the error message literally** -- don't assume what it means, read it
1793
- 2. **Check environment prerequisites** -- are all services running? Correct versions?
1794
- 3. **Check recent changes** -- did a config file, dependency, or environment variable change?
1795
- 4. **Check network/connectivity** -- is the internet up? Are external services reachable?
1796
- 5. **Search project docs first** -- check this file and \`docs/discoveries/\` before web searching
1797
-
1798
- ## "Stop and Ask" Scenarios
1799
-
1800
- _Situations where the AI agent should stop and ask the human instead of trying to fix things._
1801
-
1802
- - _Example: Hardware device not responding -- the human may need to physically reconnect it_
1803
- - _Example: Authentication token expired -- the human needs to re-authenticate manually_
1804
- - _Example: CI pipeline blocked by a required approval -- a human needs to approve it_
1805
- - _Example: Error messages referencing infrastructure the agent doesn't have access to_
1806
- `,
1807
- "examples/example-brief.md": `# Add User Notifications \u2014 Feature Brief
1808
-
1809
- > **Date:** 2026-03-15
1810
- > **Project:** acme-web
1811
- > **Status:** Specs Ready
1812
-
1813
- ---
1814
-
1815
- ## Vision
1816
-
1817
- Our users have no idea when things happen in their account. A teammate comments on their pull request, a deployment finishes, a billing threshold is hit \u2014 they find out by accident, minutes or hours later. This is the #1 complaint in our last user survey.
1818
-
1819
- We are building a notification system that delivers real-time and batched notifications across in-app, email, and (later) Slack channels. Users will have fine-grained control over what they receive and how. When this ships, no important event goes unnoticed, and no user gets buried in noise they didn't ask for.
1820
-
1821
- The system is designed to be extensible \u2014 new event types plug in without touching the notification infrastructure. We start with three event types (PR comments, deploy status, billing alerts) and prove the pattern works before expanding.
1822
-
1823
- ## User Stories
1824
-
1825
- - As a developer, I want to see a notification badge in the app when someone comments on my PR so that I can respond quickly
1826
- - As a team lead, I want to receive an email when a production deployment fails so that I can coordinate the response
1827
- - As a billing admin, I want to get alerted when usage exceeds 80% of our plan limit so that I can upgrade before service is disrupted
1828
- - As any user, I want to control which notifications I receive and through which channels so that I am not overwhelmed
1829
-
1830
- ## Hard Constraints
1831
-
1832
- - MUST: All notifications go through a single event bus \u2014 no direct coupling between event producers and delivery channels
1833
- - MUST: Email delivery uses the existing SendGrid integration (do not add a new email provider)
1834
- - MUST: Respect user preferences before delivering \u2014 never send a notification the user has opted out of
1835
- - MUST NOT: Store notification content in plaintext in the database \u2014 use the existing encryption-at-rest pattern
1836
- - MUST NOT: Send more than 50 emails per user per day (batch if necessary)
1837
-
1838
- ## Out of Scope
1839
-
1840
- - NOT: Slack/Discord integration (Phase 2)
1841
- - NOT: Push notifications / mobile (Phase 2)
1842
- - NOT: Notification templates with rich HTML \u2014 plain text and simple markdown only for now
1843
- - NOT: Admin dashboard for monitoring notification delivery rates
1844
- - NOT: Retroactive notifications for events that happened before the feature ships
1845
-
1846
- ## Decomposition
1847
-
1848
- | # | Spec Name | Description | Dependencies | Est. Size |
1849
- |---|-----------|-------------|--------------|-----------|
1850
- | 1 | add-notification-preferences-api | Create REST endpoints for users to read and update their notification preferences | None | M |
1851
- | 2 | add-event-bus-infrastructure | Set up the internal event bus that decouples event producers from notification delivery | None | M |
1852
- | 3 | add-notification-delivery-service | Build the service that consumes events, checks preferences, and dispatches to channels (in-app, email) | Spec 1, Spec 2 | L |
1853
- | 4 | add-in-app-notification-ui | Add notification bell, dropdown, and badge count to the app header | Spec 3 | M |
1854
- | 5 | add-email-batching | Implement daily digest batching for email notifications that exceed the per-user threshold | Spec 3 | S |
1855
-
1856
- ## Execution Strategy
1857
-
1858
- - [x] Agent teams (parallel teammates within phases, sequential between phases)
1859
-
1860
- \`\`\`
1861
- Phase 1: Teammate A -> Spec 1 (preferences API), Teammate B -> Spec 2 (event bus)
1862
- Phase 2: Teammate A -> Spec 3 (delivery service) \u2014 depends on Phase 1
1863
- Phase 3: Teammate A -> Spec 4 (UI), Teammate B -> Spec 5 (batching) \u2014 both depend on Spec 3
1864
- \`\`\`
1865
-
1866
- ## Success Criteria
1867
-
1868
- - [ ] User updates notification preferences via API, and subsequent events respect those preferences
1869
- - [ ] A PR comment event triggers an in-app notification visible in the UI within 2 seconds
1870
- - [ ] A deploy failure event sends an email to subscribed users via SendGrid
1871
- - [ ] When email threshold (50/day) is exceeded, remaining notifications are batched into a daily digest
1872
- - [ ] No regressions in existing PR, deployment, or billing features
1873
-
1874
- ## External Scenarios
1875
-
1876
- | Scenario | What It Tests | Pass Criteria |
1877
- |----------|--------------|---------------|
1878
- | opt-out-respected | User disables email for deploy events, deploy fails | No email sent, in-app notification still appears |
1879
- | batch-threshold | Send 51 email-eligible events for one user in a day | 50 individual emails + 1 digest containing the overflow |
1880
- | preference-persistence | User sets preferences, logs out, logs back in | Preferences are unchanged |
1881
- `,
1882
- "examples/example-spec.md": `# Add Notification Preferences API \u2014 Atomic Spec
1883
-
1884
- > **Parent Brief:** \`docs/briefs/2026-03-15-add-user-notifications.md\`
1885
- > **Status:** Ready
1886
- > **Date:** 2026-03-15
1887
- > **Estimated scope:** 1 session / 4 files / ~250 lines
1888
-
1889
- ---
1890
-
1891
- ## What
1892
-
1893
- Add REST API endpoints that let users read and update their notification preferences. Each user gets a preferences record with per-event-type, per-channel toggles (e.g., "PR comments: in-app=on, email=off"). Preferences default to all-on for new users and are stored encrypted alongside the user profile.
1894
-
1895
- ## Why
1896
-
1897
- The notification delivery service (Spec 3) needs to check preferences before dispatching. Without this API, there is no way for users to control what they receive, and we cannot build the delivery pipeline.
1898
-
1899
- ## Acceptance Criteria
1900
-
1901
- - [ ] \`GET /api/v1/notifications/preferences\` returns the current user's preferences as JSON
1902
- - [ ] \`PATCH /api/v1/notifications/preferences\` updates one or more preference fields and returns the updated record
1903
- - [ ] New users get default preferences (all channels enabled for all event types) on first read
1904
- - [ ] Preferences are validated \u2014 unknown event types or channels return 400
1905
- - [ ] Preferences are stored using the existing encryption-at-rest pattern (\`EncryptedJsonColumn\`)
1906
- - [ ] Endpoint requires authentication (returns 401 for unauthenticated requests)
1907
- - [ ] Build passes
1908
- - [ ] Tests pass (unit + integration)
1909
-
1910
- ## Test Plan
1911
-
1912
- | Acceptance Criterion | Test | Type |
1913
- |---------------------|------|------|
1914
- | GET returns preferences as JSON | Call GET with authenticated user, assert 200 + JSON shape matches preferences schema | integration |
1915
- | PATCH updates preferences | Call PATCH with valid partial update, assert 200 + returned record reflects changes | integration |
1916
- | New users get defaults | Call GET for user with no existing record, assert default preferences (all channels enabled) | unit |
1917
- | Unknown event types return 400 | Call PATCH with \`{"foo": {"email": true}}\`, assert 400 + validation error | unit |
1918
- | Stored with EncryptedJsonColumn | Verify model uses EncryptedJsonColumn for preferences field | unit |
1919
- | Auth required | Call GET/PATCH without auth token, assert 401 | integration |
1920
- | Build passes | Verified by build step \u2014 no separate test needed | build |
1921
- | Tests pass | Verified by test runner \u2014 no separate test needed | meta |
1922
-
1923
- **Execution order:**
1924
- 1. Write all tests above \u2014 they should fail against current/stubbed code
1925
- 2. Run tests to confirm they fail (red)
1926
- 3. Implement until all tests pass (green)
1927
-
1928
- **Smoke test:** The "New users get defaults" unit test \u2014 no database or HTTP needed, fastest feedback loop.
1929
-
1930
- **Before implementing, verify your test harness:**
1931
- 1. Run all tests \u2014 they must FAIL (if they pass, you're testing the wrong thing)
1932
- 2. Each test calls your actual function/endpoint \u2014 not a reimplementation or the underlying library
1933
- 3. Identify your smoke test \u2014 it must run in seconds, not minutes, so you get fast feedback on each change
1934
-
1935
- ## Constraints
1936
-
1937
- - MUST: Use the existing \`EncryptedJsonColumn\` utility for storage \u2014 do not roll a new encryption pattern
1938
- - MUST: Follow the existing REST controller pattern in \`src/controllers/\`
1939
- - MUST NOT: Expose other users' preferences (scope queries to authenticated user only)
1940
- - SHOULD: Return the full preferences object on PATCH (not just the changed fields), so the frontend can replace state without merging
1941
-
1942
- ## Affected Files
1943
-
1944
- | Action | File | What Changes |
1945
- |--------|------|-------------|
1946
- | Create | \`src/controllers/notification-preferences.controller.ts\` | New controller with GET and PATCH handlers |
1947
- | Create | \`src/models/notification-preferences.model.ts\` | Sequelize model with EncryptedJsonColumn for preferences blob |
1948
- | Create | \`src/migrations/20260315-add-notification-preferences.ts\` | Database migration to create notification_preferences table |
1949
- | Create | \`tests/controllers/notification-preferences.test.ts\` | Unit and integration tests for both endpoints |
1950
- | Modify | \`src/routes/index.ts\` | Register the new controller routes |
1951
-
1952
- ## Approach
1953
-
1954
- Create a \`NotificationPreferences\` model backed by a single \`notification_preferences\` table with columns: \`id\`, \`user_id\` (unique FK), \`preferences\` (EncryptedJsonColumn), \`created_at\`, \`updated_at\`. The \`preferences\` column stores a JSON blob shaped like \`{ "pr_comment": { "in_app": true, "email": true }, "deploy_status": { ... } }\`.
1955
-
1956
- The GET endpoint does a find-or-create: if no record exists for the user, create one with defaults and return it. The PATCH endpoint deep-merges the request body into the existing preferences, validates the result against a known schema of event types and channels, and saves.
1957
-
1958
- **Rejected alternative:** Storing preferences as individual rows (one per event-type-channel pair). This would make queries more complex and would require N rows per user instead of 1. The JSON blob approach is simpler and matches how the frontend will consume the data.
1959
-
1960
- ## Edge Cases
1961
-
1962
- | Scenario | Expected Behavior |
1963
- |----------|------------------|
1964
- | PATCH with empty body \`{}\` | Return 200 with unchanged preferences (no-op) |
1965
- | PATCH with unknown event type \`{"foo": {"email": true}}\` | Return 400 with validation error listing valid event types |
1966
- | GET for user with no existing record | Create default preferences, return 200 |
1967
- | Concurrent PATCH requests | Last-write-wins (optimistic, no locking) \u2014 acceptable for user preferences |
1968
- `,
1969
- "scenarios/README.md": `# $SCENARIOS_REPO
1970
-
1971
- Holdout scenario tests for the main project. These tests run in CI against the
1972
- built artifact of each PR \u2014 but they live here, in a separate repository, so
1973
- the coding agent working on the main project cannot see them.
1974
-
1975
- ---
1976
-
1977
- ## What is the holdout pattern?
1978
-
1979
- Think of it like a validation set in machine learning. When you train a model,
1980
- you keep a slice of your data hidden from the training process. If the model
1981
- scores well on data it has never seen, you can trust that it has actually
1982
- learned something \u2014 not just memorized the training examples.
1983
-
1984
- Scenario tests work the same way. The coding agent writes code and passes
1985
- internal tests in the main repo. These scenario tests then check whether the
1986
- result behaves correctly from a real user's perspective, using only the public
1987
- interface of the built artifact.
1988
-
1989
- Because the agent cannot read this repository, it cannot game the tests. A
1990
- passing scenario run means the feature genuinely works.
1991
-
1992
- ---
1993
-
1994
- ## Why a separate repository?
1995
-
1996
- A single repository would expose the tests to the agent. Claude Code reads
1997
- files in the working directory; if scenario tests lived in the main repo, the
1998
- agent could (and would) read them when fixing failures, which defeats the
1999
- purpose.
2000
-
2001
- A separate repo also means:
2002
-
2003
- - The test suite can be updated by humans without triggering the autofix loop
2004
- - Scenarios can reference multiple projects over time
2005
- - Access controls are independent \u2014 the scenarios repo can be more restricted
2006
-
2007
- ---
2008
-
2009
- ## How the CI pipeline works
2010
-
2011
- \`\`\`
2012
- Main repo PR opened
2013
- |
2014
- v
2015
- Main repo CI runs (unit + integration tests)
2016
- |
2017
- | passes
2018
- v
2019
- scenarios-dispatch.yml fires a repository_dispatch event
2020
- |
2021
- v
2022
- This repo: run.yml receives the event
2023
- |
2024
- +-- clones main-repo PR branch to ../main-repo
2025
- |
2026
- +-- builds the artifact (npm ci && npm run build)
2027
- |
2028
- +-- runs: NO_COLOR=1 npx vitest run
2029
- |
2030
- +-- captures exit code + output
2031
- |
2032
- v
2033
- Posts PASS / FAIL comment on the originating PR
2034
- \`\`\`
2035
-
2036
- The PR author sees the scenario result as a comment. No separate status check
2037
- is required, though you can add one via the GitHub Checks API if you prefer.
2038
-
2039
- ---
2040
-
2041
- ## Adding scenarios
2042
-
2043
- ### Rules
2044
-
2045
- 1. **Behavioral, not structural.** Test what the tool does, not how it is
2046
- built internally. Invoke the binary; assert on stdout, exit codes, and
2047
- filesystem state. Never import from \`../main-repo/src\`.
2048
-
2049
- 2. **End-to-end.** Each test should represent something a real user would
2050
- actually do. If you would not put it in a demo or docs example, reconsider
2051
- whether it belongs here.
2052
-
2053
- 3. **No source imports.** The entire point of the holdout is that tests cannot
2054
- see source code. Any \`import\` that reaches into \`../main-repo/src\` breaks
2055
- the pattern.
2056
-
2057
- 4. **Independent.** Each test must be able to run in isolation. Use \`beforeEach\`
2058
- / \`afterEach\` to set up and tear down temp directories. Do not share mutable
2059
- state between tests.
2060
-
2061
- 5. **Deterministic.** Avoid network calls, timestamps, or random values in
2062
- assertions unless the feature under test genuinely involves them.
2063
-
2064
- ### File layout
2065
-
2066
- \`\`\`
2067
- $SCENARIOS_REPO/
2068
- \u251C\u2500\u2500 example-scenario.test.ts # Starter file \u2014 replace with real scenarios
2069
- \u251C\u2500\u2500 workflows/
2070
- \u2502 \u2514\u2500\u2500 run.yml # CI workflow (do not rename)
2071
- \u251C\u2500\u2500 package.json
2072
- \u2514\u2500\u2500 README.md
2073
- \`\`\`
2074
-
2075
- Add new \`.test.ts\` files at the top level or in subdirectories. Vitest will
2076
- discover them automatically.
2077
-
2078
- ### Example structure
2079
-
2080
- \`\`\`ts
2081
- import { spawnSync } from "node:child_process";
2082
- import { join } from "node:path";
2083
-
2084
- const CLI = join(__dirname, "..", "main-repo", "dist", "cli.js");
2085
-
2086
- it("init creates a CLAUDE.md file", () => {
2087
- const tmp = mkdtempSync(join(tmpdir(), "scenario-"));
2088
- const { status } = spawnSync("node", [CLI, "init", tmp], { encoding: "utf8" });
2089
- expect(status).toBe(0);
2090
- expect(existsSync(join(tmp, "CLAUDE.md"))).toBe(true);
2091
- });
2092
- \`\`\`
2093
-
2094
- ---
2095
-
2096
- ## Internal tests vs scenario tests
2097
-
2098
- | | Internal tests (main repo) | Scenario tests (this repo) |
2099
- |---|---|---|
2100
- | Location | \`tests/\` in main repo | This repo |
2101
- | Visible to agent | Yes | No |
2102
- | What they test | Units, modules, logic | End-to-end behavior |
2103
- | Import source code | Yes | Never |
2104
- | Run on every push | Yes | Yes (via dispatch) |
2105
- | Purpose | Catch regressions fast | Validate real behavior |
2106
-
2107
- ---
2108
-
2109
- ## Relationship to Joycraft
2110
-
2111
- This repository was bootstrapped by \`npx joycraft init --autofix\`. Joycraft
2112
- manages the \`run.yml\` workflow and keeps it in sync when you run
2113
- \`npx joycraft upgrade\`. The test files are yours \u2014 Joycraft will never
2114
- overwrite them.
2115
-
2116
- If the \`run.yml\` workflow needs updating (e.g., a new version of
2117
- \`actions/create-github-app-token\`), run \`npx joycraft upgrade\` in this repo
2118
- and review the diff before applying.
2119
- `,
2120
- "scenarios/example-scenario.test.ts": `/**
2121
- * Example Scenario Test
2122
- *
2123
- * This file is a template for scenario tests in your holdout repository.
2124
- * Scenarios are behavioral, end-to-end tests that run against the BUILT
2125
- * artifact of your main project \u2014 not its source code.
2126
- *
2127
- * The Holdout Pattern
2128
- * -------------------
2129
- * These tests live in a SEPARATE repository that your coding agent cannot
2130
- * see. This is intentional: if the agent could read these tests, it could
2131
- * write code that passes them without actually solving the problem correctly
2132
- * (the same way a student who sees the exam beforehand can score well without
2133
- * understanding the material).
2134
- *
2135
- * In CI, the main repo is cloned to ../main-repo (relative to this repo's
2136
- * checkout). The run.yml workflow builds the artifact there before running
2137
- * these tests, so \`../main-repo\` is always available and already built.
2138
- *
2139
- * How to Write Scenarios
2140
- * ----------------------
2141
- * DO:
2142
- * - Invoke the built binary / entry point via child_process (execSync, spawnSync)
2143
- * - Test observable behavior: exit codes, stdout/stderr content, file system state
2144
- * - Write scenarios around things a real user would actually do
2145
- * - Keep each test fully independent \u2014 no shared state between tests
2146
- *
2147
- * DON'T:
2148
- * - Import from ../main-repo/src \u2014 that defeats the holdout
2149
- * - Test internal implementation details (function names, module structure)
2150
- * - Rely on network access unless your tool genuinely requires it
2151
- * - Share mutable fixtures across tests
2152
- */
2153
-
2154
- import { execSync, spawnSync } from "node:child_process";
2155
- import { existsSync, mkdtempSync, rmSync } from "node:fs";
2156
- import { tmpdir } from "node:os";
2157
- import { join } from "node:path";
2158
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
2159
-
2160
- // Path to the built CLI entry point in the main repo.
2161
- // The run.yml workflow clones the main repo to ../main-repo and builds it
2162
- // before this test file runs, so this path is always valid in CI.
2163
- const CLI = join(__dirname, "..", "main-repo", "dist", "cli.js");
2164
-
2165
- // ---------------------------------------------------------------------------
2166
- // Helpers
2167
- // ---------------------------------------------------------------------------
2168
-
2169
- /** Run the CLI and return { stdout, stderr, status }. Never throws. */
2170
- function runCLI(args: string[], cwd?: string) {
2171
- const result = spawnSync("node", [CLI, ...args], {
2172
- encoding: "utf8",
2173
- cwd: cwd ?? process.cwd(),
2174
- env: { ...process.env, NO_COLOR: "1" },
2175
- });
2176
- return {
2177
- stdout: result.stdout ?? "",
2178
- stderr: result.stderr ?? "",
2179
- status: result.status ?? 1,
2180
- };
2181
- }
2182
-
2183
- // ---------------------------------------------------------------------------
2184
- // Basic invocation scenarios
2185
- // ---------------------------------------------------------------------------
2186
-
2187
- describe("CLI: basic invocation", () => {
2188
- it("--help prints usage information", () => {
2189
- const { stdout, status } = runCLI(["--help"]);
2190
- expect(status).toBe(0);
2191
- expect(stdout).toContain("Usage:");
2192
- });
2193
-
2194
- it("--version returns a semver string", () => {
2195
- const { stdout, status } = runCLI(["--version"]);
2196
- expect(status).toBe(0);
2197
- // Matches x.y.z, x.y.z-alpha.1, etc.
2198
- expect(stdout.trim()).toMatch(/^\\d+\\.\\d+\\.\\d+/);
2199
- });
2200
-
2201
- it("unknown command exits non-zero", () => {
2202
- const { status } = runCLI(["not-a-real-command"]);
2203
- expect(status).not.toBe(0);
2204
- });
2205
- });
2206
-
2207
- // ---------------------------------------------------------------------------
2208
- // Example: filesystem interaction scenario
2209
- //
2210
- // This pattern is useful when your CLI creates or modifies files.
2211
- // Each test gets a fresh temp directory so they can't interfere.
2212
- // ---------------------------------------------------------------------------
2213
-
2214
- describe("CLI: init command (example \u2014 replace with your real scenarios)", () => {
2215
- let tmpDir: string;
2216
-
2217
- beforeEach(() => {
2218
- tmpDir = mkdtempSync(join(tmpdir(), "scenarios-"));
2219
- });
2220
-
2221
- afterEach(() => {
2222
- rmSync(tmpDir, { recursive: true, force: true });
2223
- });
2224
-
2225
- it("init creates expected output in an empty directory", () => {
2226
- // This is a placeholder. Replace with whatever your CLI actually does.
2227
- // The point is: invoke the binary, observe side effects, assert on them.
2228
- const { status } = runCLI(["init", tmpDir]);
2229
-
2230
- // Example assertions \u2014 adjust to your tool's actual behavior:
2231
- // expect(status).toBe(0);
2232
- // expect(existsSync(join(tmpDir, "CLAUDE.md"))).toBe(true);
2233
-
2234
- // Remove this line once you've written a real assertion above:
2235
- expect(typeof status).toBe("number"); // placeholder
2236
- });
2237
- });
2238
- `,
2239
- "scenarios/package.json": `{
2240
- "name": "$SCENARIOS_REPO",
2241
- "version": "0.0.1",
2242
- "private": true,
2243
- "type": "module",
2244
- "scripts": {
2245
- "test": "vitest run"
2246
- },
2247
- "devDependencies": {
2248
- "vitest": "^3.0.0"
2249
- }
2250
- }
2251
- `,
2252
- "scenarios/prompts/scenario-agent.md": `You are a QA engineer working in a holdout test repository. You CANNOT access the main repository's source code. Your job is to write or update behavioral scenario tests based on specs that are pushed from the main repo.
2253
-
2254
- ## What You Have Access To
2255
-
2256
- - This scenarios repository (test files, \`specs/\` mirror, \`package.json\`)
2257
- - The incoming spec (provided below)
2258
- - A list of existing test files and spec mirrors (provided below)
2259
- - The main repo is available at \`../main-repo\` and is already built \u2014 you can invoke its CLI or entry point via \`execSync\`/\`spawnSync\`, but you MUST NOT import from \`../main-repo/src\`
2260
-
2261
- ## Triage Decision Tree
2262
-
2263
- Read the incoming spec carefully. Decide which of these three actions to take:
2264
-
2265
- ### SKIP \u2014 Do nothing if the spec is:
2266
- - An internal refactor with no user-facing behavior change (e.g., "extract module", "rename internal type")
2267
- - CI or dev tooling changes (e.g., "add lint rule", "update GitHub Actions workflow")
2268
- - Documentation-only changes
2269
- - Performance improvements with identical observable behavior
2270
-
2271
- If you SKIP, write a brief comment in the relevant test file (or a new one) explaining why, then stop.
2272
-
2273
- ### NEW \u2014 Create a new test file if the spec describes:
2274
- - A new command, flag, or subcommand
2275
- - A new output format or file that gets generated
2276
- - A new user-facing behavior that doesn't map to any existing test file
2277
-
2278
- Name the file after the feature area: \`[feature-area].test.ts\`. One feature area per test file.
2279
-
2280
- ### UPDATE \u2014 Modify an existing test file if the spec:
2281
- - Changes behavior that is already tested
2282
- - Adds a flag or option to an existing command
2283
- - Modifies output format for an existing feature
2284
-
2285
- Match to the most relevant existing test file by feature area.
2286
-
2287
- **If you are unsure whether a spec is user-facing, err on the side of writing a test.**
2288
-
2289
- ## Test Writing Rules
2290
-
2291
- 1. **Behavioral only.** Test observable output \u2014 stdout, stderr, exit codes, files created/modified on disk. Never test internal implementation details or import source modules.
2292
-
2293
- 2. **Use \`execSync\` or \`spawnSync\`.** Invoke the built binary at \`../main-repo/dist/cli.js\` (or whatever the main repo's entry point is). Check \`../main-repo/package.json\` to find the correct entry point if unsure.
2294
-
2295
- 3. **Use vitest.** Import \`describe\`, \`it\`, \`expect\` from \`vitest\`. Use \`beforeEach\`/\`afterEach\` for temp directory setup/teardown.
2296
-
2297
- 4. **Each test is fully independent.** No shared mutable state between tests. Each test that touches the filesystem gets its own temp directory via \`mkdtempSync\`.
2298
-
2299
- 5. **Assert on realistic user actions.** Write tests that reflect what a real user would do \u2014 not what the implementation happens to do.
2300
-
2301
- 6. **Never import from the parent repo's source.** If you find yourself writing \`import { ... } from '../main-repo/src/...'\`, stop \u2014 that defeats the holdout.
2302
-
2303
- ## Test File Template
2304
-
2305
- \`\`\`typescript
2306
- import { execSync, spawnSync } from 'node:child_process';
2307
- import { existsSync, mkdtempSync, rmSync, readFileSync } from 'node:fs';
2308
- import { tmpdir } from 'node:os';
2309
- import { join } from 'node:path';
2310
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2311
-
2312
- const CLI = join(__dirname, '..', 'main-repo', 'dist', 'cli.js');
2313
-
2314
- function runCLI(args: string[], cwd?: string) {
2315
- const result = spawnSync('node', [CLI, ...args], {
2316
- encoding: 'utf8',
2317
- cwd: cwd ?? process.cwd(),
2318
- env: { ...process.env, NO_COLOR: '1' },
2319
- });
2320
- return {
2321
- stdout: result.stdout ?? '',
2322
- stderr: result.stderr ?? '',
2323
- status: result.status ?? 1,
2324
- };
2325
- }
2326
-
2327
- describe('[feature area]: [behavior being tested]', () => {
2328
- let tmpDir: string;
2329
-
2330
- beforeEach(() => {
2331
- tmpDir = mkdtempSync(join(tmpdir(), 'scenarios-'));
2332
- });
2333
-
2334
- afterEach(() => {
2335
- rmSync(tmpDir, { recursive: true, force: true });
2336
- });
2337
-
2338
- it('[specific observable behavior]', () => {
2339
- const { stdout, status } = runCLI(['command', 'args'], tmpDir);
2340
- expect(status).toBe(0);
2341
- expect(stdout).toContain('expected output');
2342
- });
2343
- });
2344
- \`\`\`
2345
-
2346
- ## Checklist Before Committing
2347
-
2348
- - [ ] Decision: SKIP / NEW / UPDATE (and why)
2349
- - [ ] Tests assert on observable behavior, not implementation
2350
- - [ ] No imports from \`../main-repo/src\`
2351
- - [ ] Each test has its own temp directory if it touches the filesystem
2352
- - [ ] File is named after the feature area, not the spec
2353
- `,
2354
- "scenarios/workflows/generate.yml": `# Scenario Generation Workflow
2355
- #
2356
- # Triggered by a \`spec-pushed\` repository_dispatch event sent from the main
2357
- # project when a spec is added or modified on main. A scenario agent triages
2358
- # the spec and writes or updates holdout tests in this repo.
2359
- #
2360
- # After the agent commits changes, fires \`scenarios-updated\` back to the main
2361
- # repo so that any open PRs are re-tested with the new/updated scenarios.
2362
- #
2363
- # Prerequisites:
2364
- # - ANTHROPIC_API_KEY secret: Anthropic API key for Claude Code
2365
- # - JOYCRAFT_APP_PRIVATE_KEY secret: GitHub App private key (.pem)
2366
- # - $JOYCRAFT_APP_ID is replaced with the actual App ID number at install time
2367
-
2368
- name: Generate Scenarios
2369
-
2370
- on:
2371
- repository_dispatch:
2372
- types: [spec-pushed]
2373
-
2374
- jobs:
2375
- generate:
2376
- name: Run scenario agent
2377
- runs-on: ubuntu-latest
2378
-
2379
- steps:
2380
- # \u2500\u2500 1. Check out the scenarios repo \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2381
- - name: Checkout scenarios repo
2382
- uses: actions/checkout@v4
2383
-
2384
- # \u2500\u2500 2. Save incoming spec to local mirror \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2385
- # The agent reads this file to understand what changed.
2386
- - name: Save spec to mirror
2387
- run: |
2388
- mkdir -p specs
2389
- cat > "specs/\${{ github.event.client_payload.spec_filename }}" << 'SPEC_EOF'
2390
- \${{ github.event.client_payload.spec_content }}
2391
- SPEC_EOF
2392
- echo "Saved \${{ github.event.client_payload.spec_filename }} to specs/"
2393
-
2394
- # \u2500\u2500 3. Gather context for the agent \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2395
- # Bounded context: filenames only (not file contents) to stay within
2396
- # token limits. The agent uses these lists to decide whether to create
2397
- # a new test file or update an existing one.
2398
- - name: Gather context
2399
- id: context
2400
- run: |
2401
- EXISTING_TESTS=$(find . -name "*.test.ts" -not -path "./.git/*" \\
2402
- | sed 's|^\\./||' | sort | tr '\\n' ',' | sed 's/,$//')
2403
- EXISTING_SPECS=$(find specs/ -name "*.md" 2>/dev/null \\
2404
- | sed 's|^specs/||' | sort | tr '\\n' ',' | sed 's/,$//')
2405
-
2406
- echo "existing_tests=$EXISTING_TESTS" >> "$GITHUB_OUTPUT"
2407
- echo "existing_specs=$EXISTING_SPECS" >> "$GITHUB_OUTPUT"
2408
- echo "Existing test files: $EXISTING_TESTS"
2409
- echo "Existing spec mirrors: $EXISTING_SPECS"
2410
-
2411
- # \u2500\u2500 4. Set up Node.js \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2412
- - name: Set up Node.js
2413
- uses: actions/setup-node@v4
2414
- with:
2415
- node-version: "20"
2416
-
2417
- # \u2500\u2500 5. Install Claude Code CLI \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2418
- - name: Install Claude Code
2419
- run: npm install -g @anthropic-ai/claude-code
2420
-
2421
- # \u2500\u2500 6. Run scenario agent \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2422
- # - Uses \`claude -p\` (prompt mode) for non-interactive execution.
2423
- # - No --model flag: the environment's default model is used.
2424
- # - --dangerously-skip-permissions lets Claude write files without prompts.
2425
- # - --max-turns 20 caps the agentic loop so it can't run indefinitely.
2426
- - name: Run scenario agent
2427
- id: agent
2428
- env:
2429
- ANTHROPIC_API_KEY: \${{ secrets.ANTHROPIC_API_KEY }}
2430
- run: |
2431
- PROMPT=$(cat .claude/prompts/scenario-agent.md 2>/dev/null || cat prompts/scenario-agent.md)
2432
-
2433
- claude -p \\
2434
- --dangerously-skip-permissions \\
2435
- --max-turns 20 \\
2436
- "\${PROMPT}
2437
-
2438
- ---
2439
-
2440
- ## Incoming Spec
2441
-
2442
- Filename: \${{ github.event.client_payload.spec_filename }}
2443
-
2444
- Content:
2445
- $(cat 'specs/\${{ github.event.client_payload.spec_filename }}')
2446
-
2447
- ---
2448
-
2449
- ## Context
2450
-
2451
- Existing test files in this repo: \${{ steps.context.outputs.existing_tests }}
2452
- Existing spec mirrors: \${{ steps.context.outputs.existing_specs }}"
2453
-
2454
- # \u2500\u2500 7. Commit any changes the agent made \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2455
- - name: Commit scenario changes
2456
- id: commit
2457
- run: |
2458
- git config user.name "Joycraft Scenario Agent"
2459
- git config user.email "joycraft-scenarios@users.noreply.github.com"
2460
-
2461
- git add -A
2462
-
2463
- if git diff --cached --quiet; then
2464
- echo "No changes to commit \u2014 spec triaged as no-op."
2465
- echo "committed=false" >> "$GITHUB_OUTPUT"
2466
- exit 0
2467
- fi
2468
-
2469
- git commit -m "scenarios: update tests for \${{ github.event.client_payload.spec_filename }}"
2470
- git push
2471
- echo "committed=true" >> "$GITHUB_OUTPUT"
2472
-
2473
- # \u2500\u2500 8. Generate GitHub App token for cross-repo dispatch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2474
- # Only needed if the agent committed changes (otherwise nothing to re-run).
2475
- - name: Generate GitHub App token
2476
- id: app-token
2477
- if: steps.commit.outputs.committed == 'true'
2478
- uses: actions/create-github-app-token@v1
2479
- with:
2480
- app-id: $JOYCRAFT_APP_ID
2481
- private-key: \${{ secrets.JOYCRAFT_APP_PRIVATE_KEY }}
2482
- repositories: \${{ github.event.client_payload.repo }}
2483
-
2484
- # \u2500\u2500 9. Notify main repo that scenarios were updated \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2485
- # Fires \`scenarios-updated\` so the main repo's re-run workflow can
2486
- # trigger scenario runs against any open PRs that may now be affected.
2487
- - name: Dispatch scenarios-updated to main repo
2488
- if: steps.commit.outputs.committed == 'true'
2489
- env:
2490
- GH_TOKEN: \${{ steps.app-token.outputs.token }}
2491
- run: |
2492
- REPO="\${{ github.event.client_payload.repo }}"
2493
- REPO_OWNER="\${REPO%%/*}"
2494
- REPO_NAME="\${REPO##*/}"
2495
-
2496
- gh api "repos/\${REPO_OWNER}/\${REPO_NAME}/dispatches" \\
2497
- -f event_type=scenarios-updated \\
2498
- -f "client_payload[spec_filename]=\${{ github.event.client_payload.spec_filename }}" \\
2499
- -f "client_payload[scenarios_repo]=\${{ github.repository }}"
2500
-
2501
- echo "Dispatched scenarios-updated to \${REPO}"
2502
- `,
2503
- "scenarios/workflows/run.yml": `# Scenarios Run Workflow
2504
- #
2505
- # Triggered by a \`repository_dispatch\` event (type: run-scenarios) sent from
2506
- # the main project's CI pipeline after a PR passes its internal tests.
2507
- #
2508
- # This workflow:
2509
- # 1. Clones the main repo's PR branch to ../main-repo
2510
- # 2. Builds the artifact
2511
- # 3. Runs the scenario tests in this repo
2512
- # 4. Posts a PASS or FAIL comment on the originating PR
2513
- #
2514
- # Prerequisites:
2515
- # - A GitHub App ("Joycraft Autofix" or equivalent) installed on BOTH repos.
2516
- # $JOYCRAFT_APP_ID is replaced with the actual App ID number at install time.
2517
- # JOYCRAFT_APP_PRIVATE_KEY must be stored as a repository secret in this repo.
2518
- # - This scenarios repo must be added to the App's repository access list.
2519
-
2520
- name: Run Scenarios
2521
-
2522
- on:
2523
- repository_dispatch:
2524
- types: [run-scenarios]
2525
-
2526
- jobs:
2527
- run-scenarios:
2528
- name: Run holdout scenario tests
2529
- runs-on: ubuntu-latest
2530
-
2531
- steps:
2532
- # \u2500\u2500 1. Check out the scenarios repo \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2533
- - name: Checkout scenarios repo
2534
- uses: actions/checkout@v4
2535
- with:
2536
- path: scenarios
2537
-
2538
- # \u2500\u2500 2. Mint a GitHub App token \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2539
- # $JOYCRAFT_APP_ID is replaced with the numeric App ID at install time
2540
- # (e.g., app-id: 3180156). It is NOT a secret \u2014 App IDs are public.
2541
- - name: Generate GitHub App token
2542
- id: app-token
2543
- uses: actions/create-github-app-token@v1
2544
- with:
2545
- app-id: $JOYCRAFT_APP_ID
2546
- private-key: \${{ secrets.JOYCRAFT_APP_PRIVATE_KEY }}
2547
- repositories: \${{ github.event.client_payload.repo }}
2548
-
2549
- # \u2500\u2500 3. Clone the main repo's PR branch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2550
- # Cloned to ./main-repo so scenario tests can reference ../main-repo
2551
- # relative to the scenarios/ checkout.
2552
- - name: Clone main repo PR branch
2553
- env:
2554
- GH_TOKEN: \${{ steps.app-token.outputs.token }}
2555
- run: |
2556
- git clone \\
2557
- --branch \${{ github.event.client_payload.branch }} \\
2558
- --depth 1 \\
2559
- https://x-access-token:\${GH_TOKEN}@github.com/\${{ github.event.client_payload.repo }}.git \\
2560
- main-repo
2561
-
2562
- # \u2500\u2500 4. Set up Node.js \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2563
- - name: Set up Node.js
2564
- uses: actions/setup-node@v4
2565
- with:
2566
- node-version: "20"
2567
- cache: "npm"
2568
- cache-dependency-path: main-repo/package-lock.json
2569
-
2570
- # \u2500\u2500 5. Build the main repo artifact \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2571
- - name: Build main repo
2572
- working-directory: main-repo
2573
- run: npm ci && npm run build
2574
-
2575
- # \u2500\u2500 6. Install scenario test dependencies \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2576
- - name: Install scenario dependencies
2577
- working-directory: scenarios
2578
- run: npm ci
2579
-
2580
- # \u2500\u2500 7. Run scenario tests \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2581
- # set +e \u2014 don't abort on non-zero exit; we capture it manually
2582
- # set -o pipefail \u2014 propagate failures through pipes (for tee)
2583
- # NO_COLOR=1 \u2014 strip color codes before they reach tee
2584
- # ANSI codes are also stripped via sed as a belt-and-suspenders measure
2585
- - name: Run scenario tests
2586
- id: scenarios
2587
- working-directory: scenarios
2588
- run: |
2589
- set +e
2590
- set -o pipefail
2591
- NO_COLOR=1 npx vitest run 2>&1 \\
2592
- | sed 's/\\x1b\\[[0-9;]*m//g' \\
2593
- | tee test-output.txt
2594
- VITEST_EXIT=$?
2595
- echo "exit_code=$VITEST_EXIT" >> "$GITHUB_OUTPUT"
2596
- exit $VITEST_EXIT
2597
-
2598
- # \u2500\u2500 8. Post PASS or FAIL comment on the originating PR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2599
- # Always runs so the PR author always gets feedback.
2600
- - name: Post result comment on PR
2601
- if: always()
2602
- env:
2603
- GH_TOKEN: \${{ steps.app-token.outputs.token }}
2604
- PR_NUMBER: \${{ github.event.client_payload.pr_number }}
2605
- MAIN_REPO: \${{ github.event.client_payload.repo }}
2606
- VITEST_EXIT: \${{ steps.scenarios.outputs.exit_code }}
2607
- run: |
2608
- # Read test output (cap at 100 lines to keep the comment manageable)
2609
- OUTPUT=$(head -100 scenarios/test-output.txt 2>/dev/null || echo "(no output captured)")
2610
-
2611
- if [ "$VITEST_EXIT" = "0" ]; then
2612
- STATUS_LINE="**Scenario tests: PASS**"
2613
- else
2614
- STATUS_LINE="**Scenario tests: FAIL** (exit code: $VITEST_EXIT)"
2615
- fi
2616
-
2617
- BODY="\${STATUS_LINE}
2618
-
2619
- <details>
2620
- <summary>Test output</summary>
2621
-
2622
- \\\`\\\`\\\`
2623
- \${OUTPUT}
2624
- \\\`\\\`\\\`
2625
-
2626
- </details>
2627
-
2628
- Run triggered by commit \\\`\${{ github.event.client_payload.sha }}\\\`."
2629
-
2630
- gh api "repos/\${MAIN_REPO}/issues/\${PR_NUMBER}/comments" \\
2631
- -f body="$BODY"
2632
- `,
2633
- "workflows/autofix.yml": `# Autofix Workflow
2634
- #
2635
- # Triggered when CI fails on a PR. Uses Claude Code to attempt an automated fix,
2636
- # then pushes a commit and re-triggers CI. Limits to 3 autofix attempts per PR
2637
- # before escalating to human review.
2638
- #
2639
- # Prerequisites:
2640
- # - A GitHub App called "Joycraft Autofix" (or equivalent) installed on the repo.
2641
- # Its credentials must be stored as repository secrets:
2642
- # JOYCRAFT_APP_ID \u2014 the App's numeric ID
2643
- # JOYCRAFT_APP_PRIVATE_KEY \u2014 the App's PEM private key
2644
- # - ANTHROPIC_API_KEY secret for Claude Code
2645
-
2646
- name: Autofix
2647
-
2648
- on:
2649
- workflow_run:
2650
- # Replace with the exact name of your CI workflow
2651
- workflows: ["CI"]
2652
- types: [completed]
2653
-
2654
- # One autofix run per PR at a time \u2014 cancel in-flight runs for the same PR
2655
- concurrency:
2656
- group: autofix-pr-\${{ github.event.workflow_run.pull_requests[0].number }}
2657
- cancel-in-progress: true
2658
-
2659
- jobs:
2660
- autofix:
2661
- name: Attempt automated fix
2662
- runs-on: ubuntu-latest
2663
-
2664
- # Only run when CI failed and the triggering workflow was on a PR
2665
- if: |
2666
- github.event.workflow_run.conclusion == 'failure' &&
2667
- github.event.workflow_run.pull_requests[0] != null
2668
-
2669
- steps:
2670
- # \u2500\u2500 1. Mint a short-lived GitHub App token \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2671
- # Using a dedicated App identity lets this workflow push commits without
2672
- # triggering GitHub's anti-recursion protection on the GITHUB_TOKEN.
2673
- - name: Generate GitHub App token
2674
- id: app-token
2675
- uses: actions/create-github-app-token@v1
2676
- with:
2677
- # $JOYCRAFT_APP_ID is replaced with the actual App ID number at install time
2678
- app-id: $JOYCRAFT_APP_ID
2679
- private-key: \${{ secrets.JOYCRAFT_APP_PRIVATE_KEY }}
2680
-
2681
- # \u2500\u2500 2. Check out the PR branch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2682
- # We check out the exact branch (not a merge ref) so that any commit we
2683
- # push lands directly on the PR branch.
2684
- - name: Checkout PR branch
2685
- uses: actions/checkout@v4
2686
- with:
2687
- token: \${{ steps.app-token.outputs.token }}
2688
- ref: \${{ github.event.workflow_run.pull_requests[0].head.ref }}
2689
- fetch-depth: 0
2690
-
2691
- # \u2500\u2500 3. Count previous autofix attempts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2692
- # Count "autofix:" commits in the log. If we have already made 3 attempts
2693
- # on this PR, stop and ask a human to review instead.
2694
- - name: Check autofix iteration count
2695
- id: iteration
2696
- run: |
2697
- COUNT=$(git log --oneline | grep "autofix:" | wc -l | tr -d ' ')
2698
- echo "count=$COUNT" >> "$GITHUB_OUTPUT"
2699
- echo "Autofix attempts so far: $COUNT"
2700
-
2701
- # \u2500\u2500 4. Post "human review needed" and exit if limit reached \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2702
- - name: Post human-review comment and exit
2703
- if: steps.iteration.outputs.count >= 3
2704
- env:
2705
- GH_TOKEN: \${{ steps.app-token.outputs.token }}
2706
- PR_NUMBER: \${{ github.event.workflow_run.pull_requests[0].number }}
2707
- run: |
2708
- gh pr comment "$PR_NUMBER" \\
2709
- --body "**Autofix limit reached (3 attempts).** Please review manually \u2014 Claude was unable to resolve the CI failures automatically."
2710
- echo "Max iterations reached. Exiting without further autofix."
2711
- exit 0
2712
-
2713
- # \u2500\u2500 5. Fetch the CI failure logs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2714
- # Download logs from the failed workflow run so Claude has concrete
2715
- # failure context to work from. ANSI escape codes are stripped so the
2716
- # logs are readable as plain text.
2717
- - name: Fetch CI failure logs
2718
- id: logs
2719
- env:
2720
- GH_TOKEN: \${{ github.token }}
2721
- RUN_ID: \${{ github.event.workflow_run.id }}
2722
- run: |
2723
- gh run view "$RUN_ID" --log-failed 2>&1 \\
2724
- | sed 's/\\x1b\\[[0-9;]*m//g' \\
2725
- > /tmp/ci-failure.log
2726
- echo "=== CI failure log (first 200 lines) ==="
2727
- head -200 /tmp/ci-failure.log
2728
-
2729
- # \u2500\u2500 6. Set up Node.js (adjust version to match your project) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2730
- - name: Set up Node.js
2731
- uses: actions/setup-node@v4
2732
- with:
2733
- node-version: "20"
2734
- cache: "npm"
2735
-
2736
- # \u2500\u2500 7. Install project dependencies \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2737
- - name: Install dependencies
2738
- run: npm ci
2739
-
2740
- # \u2500\u2500 8. Install Claude Code CLI \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2741
- - name: Install Claude Code
2742
- run: npm install -g @anthropic-ai/claude-code
2743
-
2744
- # \u2500\u2500 9. Run Claude Code to fix the failure \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2745
- # - Uses \`claude -p\` (prompt mode) so it runs non-interactively.
2746
- # - No --model flag: the environment's default model is used.
2747
- # - --dangerously-skip-permissions lets Claude edit files without prompts.
2748
- # - --max-turns 20 caps the agentic loop so it can't run indefinitely.
2749
- # - set +e captures the exit code without aborting the step immediately.
2750
- # - set -o pipefail ensures piped commands propagate failures correctly.
2751
- - name: Run Claude Code autofix
2752
- id: claude
2753
- env:
2754
- ANTHROPIC_API_KEY: \${{ secrets.ANTHROPIC_API_KEY }}
2755
- GH_TOKEN: \${{ steps.app-token.outputs.token }}
2756
- run: |
2757
- set +e
2758
- set -o pipefail
2759
-
2760
- FAILURE_LOG=$(cat /tmp/ci-failure.log)
2761
-
2762
- claude -p \\
2763
- --dangerously-skip-permissions \\
2764
- --max-turns 20 \\
2765
- "CI is failing on this PR. Here are the failure logs:
2766
-
2767
- \${FAILURE_LOG}
2768
-
2769
- Please investigate the root cause, fix the code, and make sure the tests pass.
2770
- Do not modify workflow files. Focus only on source code and test files.
2771
- After making changes, run the test suite to verify the fix works." \\
2772
- 2>&1 | sed 's/\\x1b\\[[0-9;]*m//g' | tee /tmp/claude-output.log
2773
-
2774
- CLAUDE_EXIT=$?
2775
- echo "exit_code=$CLAUDE_EXIT" >> "$GITHUB_OUTPUT"
2776
- exit $CLAUDE_EXIT
2777
-
2778
- # \u2500\u2500 10. Commit and push any changes Claude made \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2779
- # If Claude modified files, commit them with an "autofix:" prefix so the
2780
- # iteration counter in step 3 can find them on future runs.
2781
- - name: Commit and push autofix changes
2782
- if: steps.claude.outputs.exit_code == '0'
2783
- env:
2784
- GH_TOKEN: \${{ steps.app-token.outputs.token }}
2785
- run: |
2786
- git config user.name "Joycraft Autofix"
2787
- git config user.email "autofix@joycraft.dev"
2788
-
2789
- git add -A
2790
-
2791
- if git diff --cached --quiet; then
2792
- echo "No changes to commit \u2014 Claude made no file modifications."
2793
- exit 0
2794
- fi
2795
-
2796
- ITERATION=\${{ steps.iteration.outputs.count }}
2797
- NEXT=$(( ITERATION + 1 ))
2798
-
2799
- git commit -m "autofix: attempt $NEXT \u2014 fix CI failures [skip autofix]"
2800
- git push
2801
-
2802
- # \u2500\u2500 11. Post a summary comment on the PR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2803
- # Always post a comment so the PR author knows what happened.
2804
- - name: Post result comment
2805
- if: always()
2806
- env:
2807
- GH_TOKEN: \${{ steps.app-token.outputs.token }}
2808
- PR_NUMBER: \${{ github.event.workflow_run.pull_requests[0].number }}
2809
- CLAUDE_EXIT: \${{ steps.claude.outputs.exit_code }}
2810
- run: |
2811
- if [ "$CLAUDE_EXIT" = "0" ]; then
2812
- BODY="**Autofix pushed a fix.** CI has been re-triggered. If it still fails, another autofix attempt will run (up to 3 total)."
2813
- else
2814
- BODY="**Autofix ran but could not produce a clean fix** (exit code: $CLAUDE_EXIT). Please review the logs and fix manually."
2815
- fi
2816
-
2817
- gh pr comment "$PR_NUMBER" --body "$BODY"
2818
- `,
2819
- "workflows/scenarios-dispatch.yml": `# Scenarios Dispatch Workflow
2820
- #
2821
- # Triggered when CI passes on a PR. Fires a \`repository_dispatch\` event to a
2822
- # separate scenarios repository so that integration / end-to-end scenario tests
2823
- # can run against the PR's code without living in this repo.
2824
- #
2825
- # Prerequisites:
2826
- # - JOYCRAFT_APP_PRIVATE_KEY secret: GitHub App private key (.pem)
2827
- # - $SCENARIOS_REPO is replaced with the actual repo name at install time
2828
-
2829
- name: Scenarios Dispatch
2830
-
2831
- on:
2832
- workflow_run:
2833
- # Replace with the exact name of your CI workflow
2834
- workflows: ["CI"]
2835
- types: [completed]
2836
-
2837
- jobs:
2838
- dispatch:
2839
- name: Fire scenarios dispatch
2840
- runs-on: ubuntu-latest
2841
-
2842
- # Only run when CI succeeded and the triggering workflow was on a PR
2843
- if: |
2844
- github.event.workflow_run.conclusion == 'success' &&
2845
- github.event.workflow_run.pull_requests[0] != null
2846
-
2847
- steps:
2848
- # \u2500\u2500 1. Generate GitHub App token for cross-repo dispatch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2849
- - name: Generate GitHub App token
2850
- id: app-token
2851
- uses: actions/create-github-app-token@v1
2852
- with:
2853
- app-id: $JOYCRAFT_APP_ID
2854
- private-key: \${{ secrets.JOYCRAFT_APP_PRIVATE_KEY }}
2855
- repositories: $SCENARIOS_REPO
2856
-
2857
- # \u2500\u2500 2. Fire repository_dispatch to the scenarios repo \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2858
- # Sends a \`run-scenarios\` event carrying enough context for the scenarios
2859
- # repo to check out the correct branch/SHA and know which PR triggered it.
2860
- # $SCENARIOS_REPO is replaced with the actual repo name at install time.
2861
- - name: Dispatch run-scenarios event
2862
- env:
2863
- GH_TOKEN: \${{ steps.app-token.outputs.token }}
2864
- run: |
2865
- PR_NUMBER=\${{ github.event.workflow_run.pull_requests[0].number }}
2866
- BRANCH=\${{ github.event.workflow_run.pull_requests[0].head.ref }}
2867
- SHA=\${{ github.event.workflow_run.head_sha }}
2868
-
2869
- gh api repos/\${{ github.repository_owner }}/$SCENARIOS_REPO/dispatches \\
2870
- -f event_type=run-scenarios \\
2871
- -f "client_payload[pr_number]=$PR_NUMBER" \\
2872
- -f "client_payload[branch]=$BRANCH" \\
2873
- -f "client_payload[sha]=$SHA" \\
2874
- -f "client_payload[repo]=\${{ github.repository }}"
2875
-
2876
- echo "Dispatched run-scenarios to $SCENARIOS_REPO for PR #$PR_NUMBER"
2877
- `,
2878
- "workflows/scenarios-rerun.yml": `# Scenarios Re-run Workflow
2879
- #
2880
- # Triggered when the scenarios repo reports that it has updated its tests
2881
- # (type: scenarios-updated). Finds all open PRs and fires a \`run-scenarios\`
2882
- # dispatch to the scenarios repo for each one, so that newly generated or
2883
- # updated tests are exercised against in-flight PR branches.
2884
- #
2885
- # This handles the race condition where a PR's implementation completes before
2886
- # the scenario agent has finished writing its holdout tests.
2887
- #
2888
- # Prerequisites:
2889
- # - JOYCRAFT_APP_PRIVATE_KEY secret: GitHub App private key (.pem)
2890
- # - $JOYCRAFT_APP_ID is replaced with the actual App ID number at install time
2891
- # - $SCENARIOS_REPO is replaced with the actual scenarios repo name at install time
2892
-
2893
- name: Scenarios Re-run
2894
-
2895
- on:
2896
- repository_dispatch:
2897
- types: [scenarios-updated]
2898
-
2899
- jobs:
2900
- rerun:
2901
- name: Re-run scenarios against open PRs
2902
- runs-on: ubuntu-latest
2903
-
2904
- steps:
2905
- # \u2500\u2500 1. Generate GitHub App token for cross-repo dispatch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2906
- - name: Generate GitHub App token
2907
- id: app-token
2908
- uses: actions/create-github-app-token@v1
2909
- with:
2910
- app-id: $JOYCRAFT_APP_ID
2911
- private-key: \${{ secrets.JOYCRAFT_APP_PRIVATE_KEY }}
2912
- repositories: $SCENARIOS_REPO
2913
-
2914
- # \u2500\u2500 2. List open PRs and dispatch run-scenarios for each \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2915
- # If there are no open PRs, exits cleanly \u2014 nothing to do.
2916
- - name: Dispatch run-scenarios for each open PR
2917
- env:
2918
- GH_TOKEN: \${{ steps.app-token.outputs.token }}
2919
- run: |
2920
- OPEN_PRS=$(gh api repos/\${{ github.repository }}/pulls \\
2921
- --jq '.[] | "\\(.number) \\(.head.ref) \\(.head.sha)"')
2922
-
2923
- if [ -z "$OPEN_PRS" ]; then
2924
- echo "No open PRs \u2014 nothing to re-run."
2925
- exit 0
2926
- fi
2927
-
2928
- while IFS=' ' read -r PR_NUMBER BRANCH SHA; do
2929
- [ -z "$PR_NUMBER" ] && continue
2930
-
2931
- echo "Dispatching run-scenarios for PR #$PR_NUMBER (branch: $BRANCH, sha: $SHA)"
2932
-
2933
- gh api repos/\${{ github.repository_owner }}/$SCENARIOS_REPO/dispatches \\
2934
- -f event_type=run-scenarios \\
2935
- -f "client_payload[pr_number]=$PR_NUMBER" \\
2936
- -f "client_payload[branch]=$BRANCH" \\
2937
- -f "client_payload[sha]=$SHA" \\
2938
- -f "client_payload[repo]=\${{ github.repository }}"
2939
-
2940
- done <<< "$OPEN_PRS"
2941
- `,
2942
- "workflows/spec-dispatch.yml": `# Spec Dispatch Workflow
2943
- #
2944
- # Triggered when specs are pushed to main. For each added or modified spec,
2945
- # fires a \`spec-pushed\` repository_dispatch event to the scenarios repo so
2946
- # that a scenario agent can triage the spec and write/update holdout tests.
2947
- #
2948
- # Prerequisites:
2949
- # - JOYCRAFT_APP_PRIVATE_KEY secret: GitHub App private key (.pem)
2950
- # - $JOYCRAFT_APP_ID is replaced with the actual App ID number at install time
2951
- # - $SCENARIOS_REPO is replaced with the actual scenarios repo name at install time
2952
-
2953
- name: Spec Dispatch
2954
-
2955
- on:
2956
- push:
2957
- branches: [main]
2958
- paths:
2959
- - "docs/specs/**"
2960
-
2961
- jobs:
2962
- dispatch:
2963
- name: Dispatch changed specs to scenarios repo
2964
- runs-on: ubuntu-latest
2965
-
2966
- steps:
2967
- # \u2500\u2500 1. Check out with depth 2 to enable HEAD~1 diff \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2968
- - name: Checkout
2969
- uses: actions/checkout@v4
2970
- with:
2971
- fetch-depth: 2
2972
-
2973
- # \u2500\u2500 2. Find added or modified spec files \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2974
- # --diff-filter=AM: Added or Modified only \u2014 ignore deletions.
2975
- - name: Find changed specs
2976
- id: changed
2977
- run: |
2978
- FILES=$(git diff --name-only --diff-filter=AM HEAD~1 HEAD -- 'docs/specs/**/*.md')
2979
- echo "files<<EOF" >> "$GITHUB_OUTPUT"
2980
- echo "$FILES" >> "$GITHUB_OUTPUT"
2981
- echo "EOF" >> "$GITHUB_OUTPUT"
2982
- echo "Changed specs: $FILES"
2983
-
2984
- # \u2500\u2500 3. Generate GitHub App token for cross-repo dispatch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2985
- # Skipped if no specs changed (token unused, save the round-trip).
2986
- - name: Generate GitHub App token
2987
- id: app-token
2988
- if: steps.changed.outputs.files != ''
2989
- uses: actions/create-github-app-token@v1
2990
- with:
2991
- app-id: $JOYCRAFT_APP_ID
2992
- private-key: \${{ secrets.JOYCRAFT_APP_PRIVATE_KEY }}
2993
- repositories: $SCENARIOS_REPO
2994
-
2995
- # \u2500\u2500 4. Dispatch each changed spec to the scenarios repo \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2996
- # Sends a \`spec-pushed\` event with the spec filename, full content,
2997
- # commit SHA, branch, and originating repo. The scenario agent uses
2998
- # this payload to triage and generate/update tests.
2999
- - name: Dispatch spec-pushed events
3000
- if: steps.changed.outputs.files != ''
3001
- env:
3002
- GH_TOKEN: \${{ steps.app-token.outputs.token }}
3003
- run: |
3004
- while IFS= read -r SPEC_FILE; do
3005
- [ -z "$SPEC_FILE" ] && continue
3006
-
3007
- SPEC_FILENAME=$(basename "$SPEC_FILE")
3008
- SPEC_CONTENT=$(cat "$SPEC_FILE")
3009
-
3010
- echo "Dispatching spec-pushed for $SPEC_FILENAME"
3011
-
3012
- gh api repos/\${{ github.repository_owner }}/$SCENARIOS_REPO/dispatches \\
3013
- -f event_type=spec-pushed \\
3014
- -f "client_payload[spec_filename]=$SPEC_FILENAME" \\
3015
- -f "client_payload[spec_content]=$SPEC_CONTENT" \\
3016
- -f "client_payload[commit_sha]=\${{ github.sha }}" \\
3017
- -f "client_payload[branch]=\${{ github.ref_name }}" \\
3018
- -f "client_payload[repo]=\${{ github.repository }}"
3019
-
3020
- done <<< "\${{ steps.changed.outputs.files }}"
3021
- `
3022
- };
3023
- var CODEX_SKILLS = {
3024
- "joycraft-add-fact.md": `---
3025
- name: joycraft-add-fact
3026
- description: Capture a project fact and route it to the correct context document -- production map, dangerous assumptions, decision log, institutional knowledge, or troubleshooting
3027
- ---
3028
-
3029
- # Add Fact
3030
-
3031
- The user has a fact to capture. Your job is to classify it, route it to the correct context document, append it in the right format, and optionally add a boundary rule to CLAUDE.md or AGENTS.md.
3032
-
3033
- ## Step 1: Get the Fact
3034
-
3035
- If the user already provided the fact (e.g., \`$joycraft-add-fact the staging DB resets every Sunday\`), use it directly.
3036
-
3037
- If not, ask: "What fact do you want to capture?" -- then wait for their response.
3038
-
3039
- If the user provides multiple facts at once, process each one separately through all the steps below, then give a combined confirmation at the end.
3040
-
3041
- ## Step 2: Classify the Fact
3042
-
3043
- Route the fact to one of these 5 context documents based on its content:
3044
-
3045
- ### \`docs/context/production-map.md\`
3046
- The fact is about **infrastructure, services, environments, URLs, endpoints, credentials, or what is safe/unsafe to touch**.
3047
- - Signal words: "production", "staging", "endpoint", "URL", "database", "service", "deployed", "hosted", "credentials", "secret", "environment"
3048
- - Examples: "The staging DB is at postgres://staging.example.com", "We use Vercel for the frontend and Railway for the API"
3049
-
3050
- ### \`docs/context/dangerous-assumptions.md\`
3051
- The fact is about **something an AI agent might get wrong -- a false assumption that leads to bad outcomes**.
3052
- - Signal words: "assumes", "might think", "but actually", "looks like X but is Y", "not what it seems", "trap", "gotcha"
3053
- - Examples: "The \`users\` table looks like a test table but it's production", "Deleting a workspace doesn't delete the billing subscription"
3054
-
3055
- ### \`docs/context/decision-log.md\`
3056
- The fact is about **an architectural or tooling choice and why it was made**.
3057
- - Signal words: "decided", "chose", "because", "instead of", "we went with", "the reason we use", "trade-off"
3058
- - Examples: "We chose SQLite over Postgres because this runs on embedded devices", "We use pnpm instead of npm for workspace support"
3059
-
3060
- ### \`docs/context/institutional-knowledge.md\`
3061
- The fact is about **team conventions, unwritten rules, organizational context, or who owns what**.
3062
- - Signal words: "convention", "rule", "always", "never", "team", "process", "review", "approval", "owns", "responsible"
3063
- - Examples: "The design team reviews all color changes", "We never deploy on Fridays", "PR titles must start with the ticket number"
3064
-
3065
- ### \`docs/context/troubleshooting.md\`
3066
- The fact is about **diagnostic knowledge -- when X happens, do Y (or don't do Z)**.
3067
- - Signal words: "when", "fails", "error", "if you see", "stuck", "broken", "fix", "workaround", "before trying", "reboot", "restart", "reset"
3068
- - Examples: "If Wi-Fi disconnects during flash, wait and retry -- don't switch networks", "When tests fail with ECONNREFUSED, check if Docker is running"
3069
-
3070
- ### Ambiguous Facts
3071
-
3072
- If the fact fits multiple categories, pick the **best fit** based on the primary intent. You will mention the alternative in your confirmation message so the user can correct you.
3073
-
3074
- ## Step 3: Ensure the Target Document Exists
3075
-
3076
- 1. If \`docs/context/\` does not exist, create the directory.
3077
- 2. If the target document does not exist, create it from the template structure. Check \`docs/templates/\` for the matching template. If no template exists, use this minimal structure:
3078
-
3079
- For **production-map.md**:
3080
- \`\`\`markdown
3081
- # Production Map
3082
-
3083
- > What's real, what's staging, what's safe to touch.
3084
-
3085
- ## Services
3086
-
3087
- | Service | Environment | URL/Endpoint | Impact if Corrupted |
3088
- |---------|-------------|-------------|-------------------|
3089
- \`\`\`
3090
-
3091
- For **dangerous-assumptions.md**:
3092
- \`\`\`markdown
3093
- # Dangerous Assumptions
3094
-
3095
- > Things the AI agent might assume that are wrong in this project.
3096
-
3097
- ## Assumptions
3098
-
3099
- | Agent Might Assume | But Actually | Impact If Wrong |
3100
- |-------------------|-------------|----------------|
3101
- \`\`\`
3102
-
3103
- For **decision-log.md**:
3104
- \`\`\`markdown
3105
- # Decision Log
3106
-
3107
- > Why choices were made, not just what was chosen.
3108
-
3109
- ## Decisions
3110
-
3111
- | Date | Decision | Why | Alternatives Rejected | Revisit When |
3112
- |------|----------|-----|----------------------|-------------|
3113
- \`\`\`
3114
-
3115
- For **institutional-knowledge.md**:
3116
- \`\`\`markdown
3117
- # Institutional Knowledge
3118
-
3119
- > Unwritten rules, team conventions, and organizational context.
3120
-
3121
- ## Team Conventions
3122
-
3123
- - (none yet)
3124
- \`\`\`
3125
-
3126
- For **troubleshooting.md**:
3127
- \`\`\`markdown
3128
- # Troubleshooting
3129
-
3130
- > What to do when things go wrong for non-code reasons.
3131
-
3132
- ## Common Failures
3133
-
3134
- | When This Happens | Do This | Don't Do This |
3135
- |-------------------|---------|---------------|
3136
- \`\`\`
3137
-
3138
- ## Step 4: Read the Target Document
3139
-
3140
- Read the target document to understand its current structure. Note:
3141
- - Which section to append to
3142
- - Whether it uses tables or lists
3143
- - The column format if it's a table
3144
-
3145
- ## Step 5: Append the Fact
3146
-
3147
- Add the fact to the appropriate section of the target document. Match the existing format exactly:
3148
-
3149
- - **Table-based documents** (production-map, dangerous-assumptions, decision-log, troubleshooting): Add a new table row in the correct columns. Use today's date where a date column exists.
3150
- - **List-based documents** (institutional-knowledge): Add a new list item (\`- \`) to the most appropriate section.
3151
-
3152
- Remove any italic example rows (rows where all cells start with \`_\`) before appending, so the document transitions from template to real content. Only remove examples from the specific table you are appending to.
3153
-
3154
- **Append only. Never modify or remove existing real content.**
3155
-
3156
- ## Step 6: Evaluate Boundary Rule
3157
-
3158
- Decide whether the fact also warrants a rule in the project's boundary configuration (CLAUDE.md and/or AGENTS.md -- check which files the project uses and update accordingly):
3159
-
3160
- **Add a boundary rule if the fact:**
3161
- - Describes something that should ALWAYS or NEVER be done
3162
- - Could cause real damage if violated (data loss, broken deployments, security issues)
3163
- - Is a hard constraint that applies across all work, not just a one-time note
3164
-
3165
- **Do NOT add a boundary rule if the fact is:**
3166
- - Purely informational (e.g., "staging DB is at this URL")
3167
- - A one-time decision that's already captured
3168
- - A diagnostic tip rather than a prohibition
3169
-
3170
- If a rule is warranted, read the project's boundary file(s) -- CLAUDE.md and/or AGENTS.md -- find the appropriate section (ALWAYS, ASK FIRST, or NEVER under Behavioral Boundaries), and append the rule. If no Behavioral Boundaries section exists, append one. Update whichever boundary files the project uses (some projects have CLAUDE.md, some have AGENTS.md, some have both).
3171
-
3172
- ## Step 7: Confirm
3173
-
3174
- Report what you did in this format:
3175
-
3176
- \`\`\`
3177
- Added to [document name]:
3178
- [summary of what was added]
3179
-
3180
- [If boundary file(s) were also updated:]
3181
- Added boundary rule to [CLAUDE.md / AGENTS.md / both]:
3182
- [ALWAYS/ASK FIRST/NEVER]: [rule text]
3183
-
3184
- [If the fact was ambiguous:]
3185
- Routed to [chosen doc] -- move to [alternative doc] if this is more about [alternative category description].
3186
- \`\`\`
3187
- `,
3188
- "joycraft-bugfix.md": `---
3189
- name: joycraft-bugfix
3190
- description: Structured bug fix workflow \u2014 triage, diagnose, discuss with user, write a focused spec, hand off for implementation
3191
- ---
3192
-
3193
- # Bug Fix Workflow
3194
-
3195
- You are fixing a bug. Follow this process in order. Do not skip steps.
3196
-
3197
- **Guard clause:** If this is clearly a new feature, redirect to \`$joycraft-new-feature\` and stop.
3198
-
3199
- ---
3200
-
3201
- ## Phase 1: Triage
3202
-
3203
- Establish what's broken. Gather: symptom, steps to reproduce, expected vs actual behavior, when it started, relevant logs/errors. If an error message or stack trace is provided, read the referenced files immediately. Try to reproduce if steps are given.
3204
-
3205
- **Done when:** You can describe the symptom in one sentence.
3206
-
3207
- ---
3208
-
3209
- ## Phase 2: Diagnose
3210
-
3211
- Find the root cause. Start from the error site and trace backward. Search the codebase and read files \u2014 don't guess. Identify the specific line(s) and logic error. Check git blame if it's a recent regression.
3212
-
3213
- **Done when:** You can explain what's wrong, why, and where in 2-3 sentences.
3214
-
3215
- ---
3216
-
3217
- ## Phase 3: Discuss
3218
-
3219
- Present findings to the user BEFORE writing any code or spec:
3220
- 1. **Symptom** \u2014 confirm it matches what they see
3221
- 2. **Root cause** \u2014 specific file(s) and line(s)
3222
- 3. **Proposed fix** \u2014 what changes, where
3223
- 4. **Risk** \u2014 side effects? scope?
3224
-
3225
- Ask: "Does this match? Comfortable with this approach?" If large/risky, suggest decomposing into multiple specs.
3226
-
3227
- **Done when:** User agrees with the diagnosis and fix direction.
3228
-
3229
- ---
3230
-
3231
- ## Phase 4: Spec the Fix
3232
-
3233
- Write a bug fix spec to \`docs/specs/<feature-or-area>/bugfix-name.md\`. Use the relevant feature name or area as the subdirectory (e.g., \`auth\`, \`cli\`, \`parser\`). Create the \`docs/specs/<feature-or-area>/\` directory if it doesn't exist.
3234
-
3235
- **Why:** Even bug fixes deserve a spec. It forces clarity on what "fixed" means, ensures test-first discipline, and creates a traceable record of the fix.
3236
-
3237
- Use this structure:
3238
-
3239
- \`\`\`markdown
3240
- # [Bug Name] \u2014 Bug Fix Spec
3241
-
3242
- > **Status:** Ready
3243
- > **Date:** YYYY-MM-DD
3244
- > **Estimated scope:** [1 session / N files / ~N lines]
3245
-
3246
- ---
3247
-
3248
- ## Bug
3249
- One sentence \u2014 what's broken?
3250
-
3251
- ## Root Cause
3252
- What's actually wrong, in which file(s) and line(s)?
3253
-
3254
- ## Fix
3255
- What changes, where?
3256
-
3257
- ## Acceptance Criteria
3258
- - [ ] [Observable behavior that proves the fix works]
3259
- - [ ] No regressions \u2014 existing tests still pass
3260
- - [ ] Build passes
3261
-
3262
- ## Test Plan
3263
- 1. Write a reproduction test that fails before the fix
3264
- 2. Apply the fix
3265
- 3. Reproduction test passes
3266
- 4. Full test suite passes
3267
-
3268
- ## Constraints
3269
- - MUST: [hard requirement]
3270
- - MUST NOT: [hard prohibition]
3271
-
3272
- ## Affected Files
3273
- | Action | File | What Changes |
3274
- |--------|------|-------------|
3275
-
3276
- ## Edge Cases
3277
- | Scenario | Expected Behavior |
3278
- |----------|------------------|
3279
- \`\`\`
3280
-
3281
- **For large bugs that span multiple files/systems:** Consider whether this should be decomposed into multiple specs. If so, create a brief first using \`$joycraft-new-feature\`, then decompose.
3282
-
3283
- ---
3284
-
3285
- ## Phase 5: Hand Off
3286
-
3287
- \`\`\`
3288
- Bug fix spec is ready: docs/specs/<feature-or-area>/bugfix-name.md
3289
-
3290
- Summary:
3291
- - Bug: [one sentence]
3292
- - Root cause: [one sentence]
3293
- - Fix: [one sentence]
3294
- - Estimated: 1 session
3295
-
3296
- To execute: Start a fresh session and:
3297
- 1. Read the spec
3298
- 2. Write the reproduction test (must fail)
3299
- 3. Apply the fix (test must pass)
3300
- 4. Run full test suite
3301
- 5. Run $joycraft-session-end to capture discoveries
3302
- 6. Commit and PR
3303
-
3304
- Ready to start?
3305
- \`\`\`
3306
- `,
3307
- "joycraft-decompose.md": `---
3308
- name: joycraft-decompose
3309
- description: Break a feature brief into atomic specs \u2014 small, testable, independently executable units
3310
- ---
3311
-
3312
- # Decompose Feature into Atomic Specs
3313
-
3314
- You have a Feature Brief (or the user has described a feature). Your job is to decompose it into atomic specs that can be executed independently \u2014 one spec per session.
3315
-
3316
- ## Step 1: Verify the Brief Exists
3317
-
3318
- Look for a Feature Brief in \`docs/briefs/\`. If one doesn't exist yet, tell the user:
3319
-
3320
- > No feature brief found. Run \`$joycraft-new-feature\` first to interview and create one, or describe the feature now and I'll work from your description.
3321
-
3322
- If the user describes the feature inline, work from that description directly. You don't need a formal brief to decompose \u2014 but recommend creating one for complex features.
3323
-
3324
- ## Step 2: Identify Natural Boundaries
3325
-
3326
- **Why:** Good boundaries make specs independently testable and committable. Bad boundaries create specs that can't be verified without other specs also being done.
3327
-
3328
- Read the brief (or description) and identify natural split points:
3329
-
3330
- - **Data layer changes** (schemas, types, migrations) \u2014 always a separate spec
3331
- - **Pure functions / business logic** \u2014 separate from I/O
3332
- - **UI components** \u2014 separate from data fetching
3333
- - **API endpoints / route handlers** \u2014 separate from business logic
3334
- - **Test infrastructure** (mocks, fixtures, helpers) \u2014 can be its own spec if substantial
3335
- - **Configuration / environment** \u2014 separate from code changes
3336
-
3337
- Ask yourself: "Can this piece be committed and tested without the other pieces existing?" If yes, it's a good boundary.
3338
-
3339
- ## Step 3: Build the Decomposition Table
3340
-
3341
- For each atomic spec, define:
3342
-
3343
- | # | Spec Name | Description | Dependencies | Size |
3344
- |---|-----------|-------------|--------------|------|
3345
-
3346
- **Rules:**
3347
- - Each spec name is \`verb-object\` format (e.g., \`add-terminal-detection\`, \`extract-prompt-module\`)
3348
- - Each description is ONE sentence \u2014 if you need two, the spec is too big
3349
- - Dependencies reference other spec numbers \u2014 keep the dependency graph shallow
3350
- - More than 2 dependencies on a single spec = it's too big, split further
3351
- - Aim for 3-7 specs per feature. Fewer than 3 = probably not decomposed enough. More than 10 = the feature brief is too big
3352
-
3353
- ## Step 4: Present and Iterate
3354
-
3355
- Show the decomposition table to the user. Ask:
3356
- 1. "Does this breakdown match how you think about this feature?"
3357
- 2. "Are there any specs that feel too big or too small?"
3358
- 3. "Should any of these run in parallel (separate branches)?"
3359
-
3360
- Iterate until the user approves.
3361
-
3362
- ## Step 5: Generate Atomic Specs
3363
-
3364
- For each approved row, create \`docs/specs/<feature-name>/spec-name.md\`. Derive the feature-name from the brief filename (strip the date prefix and \`.md\` \u2014 e.g., \`2026-04-06-token-discipline.md\` \u2192 \`token-discipline\`). If no brief exists, use a user-provided or inferred feature name (slugified to kebab-case). Create the \`docs/specs/<feature-name>/\` directory if it doesn't exist.
3365
-
3366
- **Why:** Each spec must be self-contained \u2014 a fresh session should be able to execute it without reading the Feature Brief. Copy relevant constraints and context into each spec.
3367
-
3368
- Use this structure:
3369
-
3370
- \`\`\`markdown
3371
- # [Verb + Object] \u2014 Atomic Spec
3372
-
3373
- > **Parent Brief:** \`docs/briefs/YYYY-MM-DD-feature-name.md\` (or "standalone")
3374
- > **Status:** Ready
3375
- > **Date:** YYYY-MM-DD
3376
- > **Estimated scope:** [1 session / N files / ~N lines]
3377
-
3378
- ---
3379
-
3380
- ## What
3381
- One paragraph \u2014 what changes when this spec is done?
3382
-
3383
- ## Why
3384
- One sentence \u2014 what breaks or is missing without this?
3385
-
3386
- ## Acceptance Criteria
3387
- - [ ] [Observable behavior]
3388
- - [ ] Build passes
3389
- - [ ] Tests pass
3390
-
3391
- ## Test Plan
3392
-
3393
- | Acceptance Criterion | Test | Type |
3394
- |---------------------|------|------|
3395
- | [Each AC above] | [What to call/assert] | [unit/integration/e2e] |
3396
-
3397
- **Execution order:**
3398
- 1. Write all tests above \u2014 they should fail against current/stubbed code
3399
- 2. Run tests to confirm they fail (red)
3400
- 3. Implement until all tests pass (green)
3401
-
3402
- **Smoke test:** [Identify the fastest test for iteration feedback]
3403
-
3404
- **Before implementing, verify your test harness:**
3405
- 1. Run all tests \u2014 they must FAIL (if they pass, you're testing the wrong thing)
3406
- 2. Each test calls your actual function/endpoint \u2014 not a reimplementation or the underlying library
3407
- 3. Identify your smoke test \u2014 it must run in seconds, not minutes, so you get fast feedback on each change
3408
-
3409
- ## Constraints
3410
- - MUST: [hard requirement]
3411
- - MUST NOT: [hard prohibition]
3412
-
3413
- ## Affected Files
3414
- | Action | File | What Changes |
3415
- |--------|------|-------------|
3416
-
3417
- ## Approach
3418
- Strategy, data flow, key decisions. Name one rejected alternative.
3419
-
3420
- ## Edge Cases
3421
- | Scenario | Expected Behavior |
3422
- |----------|------------------|
3423
- \`\`\`
3424
-
3425
- If \`docs/templates/ATOMIC_SPEC_TEMPLATE.md\` exists, reference it for the full template with additional guidance.
3426
-
3427
- Fill in all sections \u2014 each spec must be self-contained (no "see the brief for context"). Copy relevant constraints from the Feature Brief into each spec. Write acceptance criteria specific to THIS spec, not the whole feature. Every acceptance criterion must have at least one corresponding test in the Test Plan. If the user provided test strategy info from the interview, use it to choose test types and frameworks. Include the test harness verification rules in every Test Plan.
3428
-
3429
- ## Step 6: Recommend Execution Strategy
3430
-
3431
- Based on the dependency graph:
3432
- - **Independent specs** \u2014 "These can run in parallel branches"
3433
- - **Sequential specs** \u2014 "Execute these in order: 1 -> 2 -> 4"
3434
- - **Mixed** \u2014 "Start specs 1 and 3 in parallel. After 1 completes, start 2."
3435
-
3436
- Update the Feature Brief's Execution Strategy section with the plan (if a brief exists).
3437
-
3438
- ## Step 7: Hand Off
3439
-
3440
- Tell the user:
3441
- \`\`\`
3442
- Decomposition complete:
3443
- - [N] atomic specs created in docs/specs/
3444
- - [N] can run in parallel, [N] are sequential
3445
- - Estimated total: [N] sessions
3446
-
3447
- To execute:
3448
- - Sequential: Open a session, point at each spec in order
3449
- - Parallel: One spec per branch, merge when done
3450
- - Each session should end with $joycraft-session-end to capture discoveries
3451
-
3452
- Ready to start execution?
3453
- \`\`\`
3454
-
3455
- **Tip:** Run \`/new\` before starting the next step. Your artifacts are saved to files \u2014 this conversation context is disposable.
3456
- `,
3457
- "joycraft-design.md": `---
3458
- name: joycraft-design
3459
- description: Design discussion before decomposition \u2014 produce a ~200-line design artifact for human review, catching wrong assumptions before they propagate into specs
3460
- ---
3461
-
3462
- # Design Discussion
3463
-
3464
- You are producing a design discussion document for a feature. This sits between research and decomposition \u2014 it captures your understanding so the human can catch wrong assumptions before specs are written.
3465
-
3466
- **Guard clause:** If no brief path is provided and no brief exists in \`docs/briefs/\`, say:
3467
- "No feature brief found. Run \`$joycraft-new-feature\` first to create one, or provide the path to your brief."
3468
- Then stop.
3469
-
3470
- ---
3471
-
3472
- ## Step 1: Read Inputs
3473
-
3474
- Read the feature brief at the path the user provides. If the user also provides a research document path, read that too.
3475
-
3476
- ## Step 2: Explore the Codebase
3477
-
3478
- Spawn concurrent subagent threads to explore the codebase for patterns relevant to the brief. Focus on:
3479
-
3480
- - Files and functions that will be touched or extended
3481
- - Existing patterns this feature should follow
3482
- - Similar features already implemented that serve as models
3483
- - Boundaries and interfaces the feature must integrate with
3484
-
3485
- Each subagent should search the codebase and read files to gather file paths, function signatures, and code snippets.
3486
-
3487
- ## Step 3: Write the Design Document
3488
-
3489
- Create \`docs/designs/\` directory if it doesn't exist. Write to \`docs/designs/YYYY-MM-DD-feature-name.md\`.
3490
-
3491
- The document has exactly five sections:
3492
-
3493
- ### Section 1: Current State
3494
- What exists today in the codebase. Include file paths, function signatures, data flows. Be specific.
3495
-
3496
- ### Section 2: Desired End State
3497
- What the codebase should look like when this feature is complete.
3498
-
3499
- ### Section 3: Patterns to Follow
3500
- Existing patterns in the codebase that this feature should match. Include code snippets and \`file:line\` references.
3501
-
3502
- ### Section 4: Resolved Design Decisions
3503
- Decisions made with rationale. Format: Decision, Rationale, Alternative rejected.
3504
-
3505
- ### Section 5: Open Questions
3506
- Things where multiple valid approaches exist. Each question MUST present 2-3 concrete options with pros and cons.
3507
-
3508
- ## Step 4: Present and STOP
3509
-
3510
- Present the design document. Say:
3511
- \`\`\`
3512
- Design discussion written to docs/designs/YYYY-MM-DD-feature-name.md
3513
-
3514
- Please review. Specifically:
3515
- 1. Are the patterns in Section 3 right?
3516
- 2. Do you agree with the resolved decisions?
3517
- 3. Pick an option for each open question.
3518
-
3519
- Reply with your feedback. I will NOT proceed to decomposition until you have reviewed and approved.
3520
- \`\`\`
3521
-
3522
- **CRITICAL: Do NOT proceed to \`$joycraft-decompose\` or generate specs.** Wait for human review.
3523
-
3524
- ## After Human Review
3525
-
3526
- - Update the design document with corrections
3527
- - Move answered questions to Resolved Design Decisions
3528
- - Present for final confirmation
3529
- - Only after explicit approval: "Design approved. Run \`$joycraft-decompose\` with this brief to generate atomic specs."
3530
- `,
3531
- "joycraft-implement-level5.md": `---
3532
- name: joycraft-implement-level5
3533
- description: Set up Level 5 autonomous development \u2014 autofix loop, holdout scenario testing, and scenario evolution from specs
3534
- ---
3535
-
3536
- # Implement Level 5 \u2014 Autonomous Development Loop
3537
-
3538
- You are guiding the user through setting up Level 5: the autonomous feedback loop where specs go in, validated software comes out. This is a one-time setup that installs workflows, creates a scenarios repo, and configures the autofix loop.
3539
-
3540
- ## Before You Begin
3541
-
3542
- Check prerequisites:
3543
-
3544
- 1. **Project must be initialized.** Search for \`.joycraft-version\`. If missing, tell the user to run \`npx joycraft init\` first.
3545
- 2. **Project should be at Level 4.** Read \`docs/joycraft-assessment.md\` if it exists. If the project hasn't been assessed yet, suggest running \`$joycraft-tune\` first. But don't block -- the user may know they're ready.
3546
- 3. **Git repo with GitHub remote.** This setup requires GitHub Actions. Check for \`.git/\` and a GitHub remote.
3547
-
3548
- If prerequisites aren't met, explain what's needed and stop.
3549
-
3550
- ## Step 1: Explain What Level 5 Means
3551
-
3552
- Tell the user:
3553
-
3554
- > Level 5 is the autonomous loop. When you push specs, three things happen automatically:
3555
- >
3556
- > 1. **Scenario evolution** -- An AI agent reads your specs and writes holdout tests in a private scenarios repo. These tests are invisible to your coding agent.
3557
- > 2. **Autofix** -- When CI fails on a PR, the agent automatically attempts a fix (up to 3 times).
3558
- > 3. **Holdout validation** -- When CI passes, your scenarios repo runs behavioral tests against the PR. Results post as PR comments.
3559
- >
3560
- > The key insight: your coding agent never sees the scenario tests. This prevents it from gaming the test suite -- like a validation set in machine learning.
3561
-
3562
- ## Step 2: Gather Configuration
3563
-
3564
- Ask these questions **one at a time**:
3565
-
3566
- ### Question 1: Scenarios repo name
3567
-
3568
- > What should we call your scenarios repo? It'll be a private repo that holds your holdout tests.
3569
- >
3570
- > Default: \`{current-repo-name}-scenarios\`
3571
-
3572
- Accept the default or the user's choice.
3573
-
3574
- ### Question 2: GitHub App
3575
-
3576
- > Level 5 needs a GitHub App to provide a separate identity for autofix pushes (this avoids GitHub's anti-recursion protection). Creating one takes about 2 minutes:
3577
- >
3578
- > 1. Go to https://github.com/settings/apps/new
3579
- > 2. Give it a name (e.g., "My Project Autofix")
3580
- > 3. Uncheck "Webhook > Active" (not needed)
3581
- > 4. Under **Repository permissions**, set:
3582
- > - **Contents**: Read & Write
3583
- > - **Pull requests**: Read & Write
3584
- > - **Actions**: Read & Write
3585
- > 5. Click **Create GitHub App**
3586
- > 6. Note the **App ID** from the settings page
3587
- > 7. Scroll to **Private keys** > click **Generate a private key** > save the \`.pem\` file
3588
- > 8. Click **Install App** in the left sidebar > install it on your repo
3589
- >
3590
- > What's your App ID?
3591
-
3592
- ## Step 3: Run init-autofix
3593
-
3594
- Run the CLI command with the gathered configuration:
3595
-
3596
- \`\`\`bash
3597
- npx joycraft init-autofix --scenarios-repo {name} --app-id {id}
3598
- \`\`\`
3599
-
3600
- Review the output with the user. Confirm files were created.
3601
-
3602
- ## Step 4: Walk Through Secret Configuration
3603
-
3604
- Guide the user step by step:
3605
-
3606
- ### 4a: Add Secrets to Main Repo
3607
-
3608
- > You should already have the \`.pem\` file from when you created the app in Step 2.
3609
-
3610
- > Go to your repo's Settings > Secrets and variables > Actions, and add:
3611
- > - \`JOYCRAFT_APP_PRIVATE_KEY\` -- paste the contents of your \`.pem\` file
3612
- > - \`ANTHROPIC_API_KEY\` -- your Anthropic API key (or the appropriate AI provider key for your setup)
3613
-
3614
- ### 4b: Create the Scenarios Repo
3615
-
3616
- > Create the private scenarios repo:
3617
- > \`\`\`bash
3618
- > gh repo create {scenarios-repo-name} --private
3619
- > \`\`\`
3620
- >
3621
- > Then copy the scenario templates into it:
3622
- > \`\`\`bash
3623
- > cp -r docs/templates/scenarios/* ../{scenarios-repo-name}/
3624
- > cd ../{scenarios-repo-name}
3625
- > git add -A && git commit -m "init: scaffold scenarios repo from Joycraft"
3626
- > git push
3627
- > \`\`\`
3628
-
3629
- ### 4c: Add Secrets to Scenarios Repo
3630
-
3631
- > The scenarios repo also needs the App private key:
3632
- > - \`JOYCRAFT_APP_PRIVATE_KEY\` -- same \`.pem\` file as the main repo
3633
- > - \`ANTHROPIC_API_KEY\` -- same key (needed for scenario generation)
3634
-
3635
- ## Step 5: Verify Setup
3636
-
3637
- Help the user verify everything is wired correctly:
3638
-
3639
- 1. **Check workflow files exist:** \`ls .github/workflows/autofix.yml .github/workflows/scenarios-dispatch.yml .github/workflows/spec-dispatch.yml .github/workflows/scenarios-rerun.yml\`
3640
- 2. **Check scenario templates were copied:** Verify the scenarios repo has \`example-scenario.test.ts\`, \`workflows/run.yml\`, \`workflows/generate.yml\`, \`prompts/scenario-agent.md\`
3641
- 3. **Check the App ID is correct** in the workflow files (not still a placeholder)
3642
-
3643
- ## Step 6: Update AGENTS.md
3644
-
3645
- If the project's AGENTS.md doesn't already have an "External Validation" section, add one:
3646
-
3647
- > ## External Validation
3648
- >
3649
- > This project uses holdout scenario tests in a separate private repo.
3650
- >
3651
- > ### NEVER
3652
- > - Access, read, or reference the scenarios repo
3653
- > - Mention scenario test names or contents
3654
- > - Modify the scenarios dispatch workflow to leak test information
3655
- >
3656
- > The scenarios repo is deliberately invisible to you. This is the holdout guarantee.
3657
-
3658
- ## Step 7: First Test (Optional)
3659
-
3660
- If the user wants to test the loop:
3661
-
3662
- > Want to do a quick test? Here's how:
3663
- >
3664
- > 1. Write a simple spec in \`docs/specs/\` and push to main -- this triggers scenario generation
3665
- > 2. Create a PR with a small change -- when CI passes, scenarios will run
3666
- > 3. Watch for the scenario test results as a PR comment
3667
- >
3668
- > Or deliberately break something in a PR to test the autofix loop.
3669
-
3670
- ## Step 8: Summary
3671
-
3672
- Print a summary of what was set up:
3673
-
3674
- > **Level 5 is live.** Here's what's running:
3675
- >
3676
- > | Trigger | What Happens |
3677
- > |---------|-------------|
3678
- > | Push specs to \`docs/specs/\` | Scenario agent writes holdout tests |
3679
- > | PR fails CI | Autofix agent attempts a fix (up to 3x) |
3680
- > | PR passes CI | Holdout scenarios run against PR |
3681
- > | Scenarios update | Open PRs re-tested with latest scenarios |
3682
- >
3683
- > Your scenarios repo: \`{name}\`
3684
- > Your coding agent cannot see those tests. The holdout wall is intact.
3685
-
3686
- Update \`docs/joycraft-assessment.md\` if it exists -- set the Level 5 score to reflect the new setup.
3687
- `,
3688
- "joycraft-interview.md": `---
3689
- name: joycraft-interview
3690
- description: Brainstorm freely about what you want to build \u2014 yap, explore ideas, and get a structured summary you can use later
3691
- ---
3692
-
3693
- # Interview \u2014 Idea Exploration
3694
-
3695
- You are helping the user brainstorm and explore what they want to build. This is a lightweight, low-pressure conversation \u2014 not a formal spec process. Let them yap.
3696
-
3697
- ## How to Run the Interview
3698
-
3699
- ### 1. Open the Floor
3700
-
3701
- Start with something like:
3702
- "What are you thinking about building? Just talk \u2014 I'll listen and ask questions as we go."
3703
-
3704
- Let the user talk freely. Do not interrupt their flow. Do not push toward structure yet.
3705
-
3706
- ### 2. Ask Clarifying Questions
3707
-
3708
- As they talk, weave in questions naturally \u2014 don't fire them all at once:
3709
-
3710
- - **What problem does this solve?** Who feels the pain today?
3711
- - **What does "done" look like?** If this worked perfectly, what would a user see?
3712
- - **What are the constraints?** Time, tech, team, budget \u2014 what boxes are we in?
3713
- - **What's NOT in scope?** What's tempting but should be deferred?
3714
- - **What are the edge cases?** What could go wrong? What's the weird input?
3715
- - **What exists already?** Are we building on something or starting fresh?
3716
-
3717
- ### 3. Play Back Understanding
3718
-
3719
- After the user has gotten their ideas out, reflect back:
3720
- "So if I'm hearing you right, you want to [summary]. The core problem is [X], and done looks like [Y]. Is that right?"
3721
-
3722
- Let them correct and refine. Iterate until they say "yes, that's it."
3723
-
3724
- ### 4. Write a Draft Brief
3725
-
3726
- Create a draft file at \`docs/briefs/YYYY-MM-DD-topic-draft.md\`. Create the \`docs/briefs/\` directory if it doesn't exist.
3727
-
3728
- Use this format:
3729
-
3730
- \`\`\`markdown
3731
- # [Topic] \u2014 Draft Brief
3732
-
3733
- > **Date:** YYYY-MM-DD
3734
- > **Status:** DRAFT
3735
- > **Origin:** $joycraft-interview session
3736
-
3737
- ---
3738
-
3739
- ## The Idea
3740
- [2-3 paragraphs capturing what the user described \u2014 their words, their framing]
3741
-
3742
- ## Problem
3743
- [What pain or gap this addresses]
3744
-
3745
- ## What "Done" Looks Like
3746
- [The user's description of success \u2014 observable outcomes]
3747
-
3748
- ## Constraints
3749
- - [constraint 1]
3750
- - [constraint 2]
3751
-
3752
- ## Open Questions
3753
- - [things that came up but weren't resolved]
3754
- - [decisions that need more thought]
3755
-
3756
- ## Out of Scope (for now)
3757
- - [things explicitly deferred]
3758
-
3759
- ## Raw Notes
3760
- [Any additional context, quotes, or tangents worth preserving]
3761
- \`\`\`
3762
-
3763
- ### 5. Hand Off
3764
-
3765
- After writing the draft, tell the user:
3766
-
3767
- \`\`\`
3768
- Draft brief saved to docs/briefs/YYYY-MM-DD-topic-draft.md
3769
-
3770
- When you're ready to move forward:
3771
- - $joycraft-new-feature \u2014 formalize this into a full Feature Brief with specs
3772
- - $joycraft-decompose \u2014 break it directly into atomic specs if scope is clear
3773
- - Or just keep brainstorming \u2014 run $joycraft-interview again anytime
3774
- \`\`\`
3775
-
3776
- ## Guidelines
3777
-
3778
- - **This is NOT $joycraft-new-feature.** Do not push toward formal briefs, decomposition tables, or atomic specs. The point is exploration.
3779
- - **Let the user lead.** Your job is to listen, clarify, and capture \u2014 not to structure or direct.
3780
- - **Mark everything as DRAFT.** The output is a starting point, not a commitment.
3781
- - **Keep it short.** The draft brief should be 1-2 pages max. Capture the essence, not every detail.
3782
- - **Multiple interviews are fine.** The user might run this several times as their thinking evolves. Each creates a new dated draft.
3783
-
3784
- **Tip:** Run \`/new\` before starting the next step. Your artifacts are saved to files \u2014 this conversation context is disposable.
3785
- `,
3786
- "joycraft-lockdown.md": `---
3787
- name: joycraft-lockdown
3788
- description: Generate constrained execution boundaries for an implementation session -- NEVER rules and deny patterns to prevent agent overreach
3789
- ---
3790
-
3791
- # Lockdown Mode
3792
-
3793
- The user wants to constrain agent behavior for an implementation session. Your job is to interview them about what should be off-limits, then generate AGENTS.md NEVER rules and Codex configuration deny patterns they can review and apply.
3794
-
3795
- ## When Is Lockdown Useful?
3796
-
3797
- Lockdown is most valuable for:
3798
- - **Complex tech stacks** (hardware, firmware, multi-device) where agents can cause real damage
3799
- - **Long-running autonomous sessions** where you won't be monitoring every action
3800
- - **Production-adjacent work** where accidental network calls or package installs are risky
3801
-
3802
- For simple feature work on a well-tested codebase, lockdown is usually overkill. Mention this context to the user so they can decide.
3803
-
3804
- ## Step 1: Check for Tests
3805
-
3806
- Before starting the interview, search the codebase for test files or directories (look for \`tests/\`, \`test/\`, \`__tests__/\`, \`spec/\`, or files matching \`*.test.*\`, \`*.spec.*\`).
3807
-
3808
- If no tests are found, tell the user:
3809
-
3810
- > Lockdown mode is most useful when you already have tests in place -- it prevents the agent from modifying them while constraining behavior to writing code and running tests. Consider running \`$joycraft-new-feature\` first to set up a test-driven workflow, then come back to lock it down.
3811
-
3812
- If the user wants to proceed anyway, continue with the interview.
3813
-
3814
- ## Step 2: Interview -- What to Lock Down
3815
-
3816
- Ask these three questions, one at a time. Wait for the user's response before proceeding to the next question.
3817
-
3818
- ### Question 1: Read-Only Files
3819
-
3820
- > What test files or directories should be off-limits for editing? (e.g., \`tests/\`, \`__tests__/\`, \`spec/\`, specific test files)
3821
- >
3822
- > I'll generate NEVER rules to prevent editing these.
3823
-
3824
- If the user isn't sure, suggest the test directories you found in Step 1.
3825
-
3826
- ### Question 2: Allowed Commands
3827
-
3828
- > What commands should the agent be allowed to run? Defaults:
3829
- > - Write and edit source code files
3830
- > - Run the project's smoke test command
3831
- > - Run the full test suite
3832
- >
3833
- > Any other commands to explicitly allow? Or should I restrict to just these?
3834
-
3835
- ### Question 3: Denied Commands
3836
-
3837
- > What commands should be denied? Defaults:
3838
- > - Package installs (\`npm install\`, \`pip install\`, \`cargo add\`, \`go get\`, etc.)
3839
- > - Network tools (\`curl\`, \`wget\`, \`ping\`, \`ssh\`)
3840
- > - Direct log file reading
3841
- >
3842
- > Any specific commands to add or remove from this list?
3843
-
3844
- **Edge case -- user wants to allow some network access:** If the user mentions API tests or specific endpoints that need network access, exclude those from the deny list and note the exception in the output.
3845
-
3846
- **Edge case -- user wants to lock down file writes:** If the user wants to prevent ALL file writes, warn them:
3847
-
3848
- > Denying all file writes would prevent the agent from doing any work. I recommend keeping source code writes allowed and only locking down test files, config files, or other sensitive directories.
3849
-
3850
- ## Step 3: Generate Boundaries
3851
-
3852
- Based on the interview responses, generate output in this exact format:
3853
-
3854
- \`\`\`
3855
- ## Lockdown boundaries generated
3856
-
3857
- Review these suggestions and add them to your project:
3858
-
3859
- ### AGENTS.md -- add to NEVER section:
3860
-
3861
- - Edit any file in \`[user's test directories]\`
3862
- - Run \`[denied package manager commands]\`
3863
- - Use \`[denied network tools]\`
3864
- - Read log files directly -- interact with logs only through test assertions
3865
- - [Any additional NEVER rules based on user responses]
3866
-
3867
- ### Codex configuration -- suggested deny patterns:
3868
-
3869
- Add these to your Codex sandbox configuration to restrict command execution:
3870
-
3871
- ["[command1]", "[command2]", "[command3]"]
3872
-
3873
- ---
3874
-
3875
- Copy these into your project manually, or tell me to apply them now (I'll show you the exact changes for approval first).
3876
- \`\`\`
3877
-
3878
- Adjust the content based on the actual interview responses:
3879
- - Only include deny patterns for commands the user confirmed should be denied
3880
- - Only include NEVER rules for directories/files the user specified
3881
- - If the user allowed certain network tools or package managers, exclude those
3882
-
3883
- ## Recommended Execution Model
3884
-
3885
- After generating the boundaries above, also recommend a Codex execution configuration. Include this section in your output:
3886
-
3887
- \`\`\`
3888
- ### Recommended Execution Configuration
3889
-
3890
- Codex runs in a sandboxed environment by default. To maximize safety during lockdown:
3891
-
3892
- | Your situation | Configuration | Why |
3893
- |---|---|---|
3894
- | Autonomous spec execution | Sandbox with deny patterns above | Only pre-approved commands run |
3895
- | Long session with some trust | Default sandbox | Network-disabled sandbox prevents external access |
3896
- | Interactive development | Default with manual review | Review outputs before applying |
3897
-
3898
- **For lockdown mode, we recommend the default sandboxed execution** combined with the deny patterns above. Codex's sandbox already disables network access by default -- the deny patterns add file-level and command-level restrictions on top.
3899
-
3900
- If you need network access for specific commands (e.g., API tests), configure explicit network allowances in your Codex setup rather than disabling the sandbox entirely.
3901
- \`\`\`
3902
-
3903
- ## Step 4: Offer to Apply
3904
-
3905
- If the user asks you to apply the changes:
3906
-
3907
- 1. **For AGENTS.md:** Read the existing AGENTS.md, find the Behavioral Boundaries section, and show the user the exact diff for the NEVER section. Ask for confirmation before writing.
3908
- 2. **For Codex configuration:** Show the user what the deny patterns will look like after adding the new restrictions. Ask for confirmation before writing.
3909
-
3910
- **Never auto-apply. Always show the exact changes and wait for explicit approval.**
3911
- `,
3912
- "joycraft-new-feature.md": `---
3913
- name: joycraft-new-feature
3914
- description: Guided feature development \u2014 interview the user, produce a Feature Brief, then decompose into atomic specs
3915
- ---
3916
-
3917
- # New Feature Workflow
3918
-
3919
- You are starting a new feature. Follow this process in order. Do not skip steps.
3920
-
3921
- ## Phase 1: Interview
3922
-
3923
- Interview the user about what they want to build. Let them talk \u2014 your job is to listen, then sharpen.
3924
-
3925
- **Ask about:**
3926
- - What problem does this solve? Who is affected?
3927
- - What does "done" look like?
3928
- - Hard constraints? (business rules, tech limitations, deadlines)
3929
- - What is explicitly NOT in scope? (push hard on this)
3930
- - Edge cases or error conditions?
3931
- - What existing code/patterns should this follow?
3932
- - Testing: existing setup? framework? smoke test budget? lockdown mode desired?
3933
-
3934
- **Interview technique:**
3935
- - Let the user "yap" \u2014 don't interrupt their flow
3936
- - Play back your understanding: "So if I'm hearing you right..."
3937
- - Push toward testable statements: "How would we verify that works?"
3938
-
3939
- Keep asking until you can fill out a Feature Brief.
3940
-
3941
- ## Phase 2: Feature Brief
3942
-
3943
- Write a Feature Brief to \`docs/briefs/YYYY-MM-DD-feature-name.md\`. Create the \`docs/briefs/\` directory if it doesn't exist.
3944
-
3945
- **Why:** The brief is the single source of truth for what we're building. It prevents scope creep and gives every spec a shared reference point.
3946
-
3947
- Use this structure:
3948
-
3949
- \`\`\`markdown
3950
- # [Feature Name] \u2014 Feature Brief
3951
-
3952
- > **Date:** YYYY-MM-DD
3953
- > **Project:** [project name]
3954
- > **Status:** Interview | Decomposing | Specs Ready | In Progress | Complete
3955
-
3956
- ---
3957
-
3958
- ## Vision
3959
- What are we building and why? The full picture in 2-4 paragraphs.
3960
-
3961
- ## User Stories
3962
- - As a [role], I want [capability] so that [benefit]
3963
-
3964
- ## Hard Constraints
3965
- - MUST: [constraint that every spec must respect]
3966
- - MUST NOT: [prohibition that every spec must respect]
3967
-
3968
- ## Out of Scope
3969
- - NOT: [tempting but deferred]
3970
-
3971
- ## Test Strategy
3972
- - **Existing setup:** [framework and tools, or "none yet"]
3973
- - **User expertise:** [comfortable / learning / needs guidance]
3974
- - **Test types:** [smoke, unit, integration, e2e, etc.]
3975
- - **Smoke test budget:** [target time for fast-feedback tests]
3976
- - **Lockdown mode:** [yes/no \u2014 constrain agent to code + tests only]
3977
-
3978
- ## Decomposition
3979
- | # | Spec Name | Description | Dependencies | Est. Size |
3980
- |---|-----------|-------------|--------------|-----------|
3981
- | 1 | [verb-object] | [one sentence] | None | [S/M/L] |
3982
-
3983
- ## Execution Strategy
3984
- - [ ] Sequential (specs have chain dependencies)
3985
- - [ ] Parallel (specs are independent)
3986
- - [ ] Mixed
3987
-
3988
- ## Success Criteria
3989
- - [ ] [End-to-end behavior 1]
3990
- - [ ] [No regressions in existing features]
3991
- \`\`\`
3992
-
3993
- If \`docs/templates/FEATURE_BRIEF_TEMPLATE.md\` exists, reference it for the full template with additional guidance.
3994
-
3995
- Present the brief to the user. Focus review on:
3996
- - "Does the decomposition match how you think about this?"
3997
- - "Is anything in scope that shouldn't be?"
3998
- - "Are the specs small enough? Can each be described in one sentence?"
3999
-
4000
- Iterate until approved.
4001
-
4002
- ## Phase 3: Generate Atomic Specs
4003
-
4004
- For each row in the decomposition table, create a self-contained spec file at \`docs/specs/<feature-name>/spec-name.md\`. Derive the feature-name from the brief filename (strip the date prefix and \`.md\` \u2014 e.g., \`2026-04-06-token-discipline.md\` \u2192 \`token-discipline\`). Create the \`docs/specs/<feature-name>/\` directory if it doesn't exist.
4005
-
4006
- **Why:** Each spec must be understandable WITHOUT reading the Feature Brief. This prevents the "Curse of Instructions" \u2014 no spec should require holding the entire feature in context. Copy relevant context into each spec.
4007
-
4008
- Use this structure for each spec:
4009
-
4010
- \`\`\`markdown
4011
- # [Verb + Object] \u2014 Atomic Spec
4012
-
4013
- > **Parent Brief:** \`docs/briefs/YYYY-MM-DD-feature-name.md\`
4014
- > **Status:** Ready
4015
- > **Date:** YYYY-MM-DD
4016
- > **Estimated scope:** [1 session / N files / ~N lines]
4017
-
4018
- ---
4019
-
4020
- ## What
4021
- One paragraph \u2014 what changes when this spec is done?
4022
-
4023
- ## Why
4024
- One sentence \u2014 what breaks or is missing without this?
4025
-
4026
- ## Acceptance Criteria
4027
- - [ ] [Observable behavior]
4028
- - [ ] Build passes
4029
- - [ ] Tests pass
4030
-
4031
- ## Test Plan
4032
-
4033
- | Acceptance Criterion | Test | Type |
4034
- |---------------------|------|------|
4035
- | [Each AC above] | [What to call/assert] | [unit/integration/e2e] |
4036
-
4037
- **Execution order:**
4038
- 1. Write all tests above \u2014 they should fail against current/stubbed code
4039
- 2. Run tests to confirm they fail (red)
4040
- 3. Implement until all tests pass (green)
4041
-
4042
- **Smoke test:** [Identify the fastest test for iteration feedback]
4043
-
4044
- **Before implementing, verify your test harness:**
4045
- 1. Run all tests \u2014 they must FAIL (if they pass, you're testing the wrong thing)
4046
- 2. Each test calls your actual function/endpoint \u2014 not a reimplementation or the underlying library
4047
- 3. Identify your smoke test \u2014 it must run in seconds, not minutes, so you get fast feedback on each change
4048
-
4049
- ## Constraints
4050
- - MUST: [hard requirement]
4051
- - MUST NOT: [hard prohibition]
4052
-
4053
- ## Affected Files
4054
- | Action | File | What Changes |
4055
- |--------|------|-------------|
4056
-
4057
- ## Approach
4058
- Strategy, data flow, key decisions. Name one rejected alternative.
4059
-
4060
- ## Edge Cases
4061
- | Scenario | Expected Behavior |
4062
- |----------|------------------|
4063
- \`\`\`
4064
-
4065
- If \`docs/templates/ATOMIC_SPEC_TEMPLATE.md\` exists, reference it for the full template with additional guidance.
4066
-
4067
- ## Phase 4: Hand Off for Execution
4068
-
4069
- Tell the user:
4070
- \`\`\`
4071
- Feature Brief and [N] atomic specs are ready.
4072
-
4073
- Specs:
4074
- 1. [spec-name] \u2014 [one sentence] [S/M/L]
4075
- 2. [spec-name] \u2014 [one sentence] [S/M/L]
4076
- ...
4077
-
4078
- Recommended execution:
4079
- - [Parallel/Sequential/Mixed strategy]
4080
- - Estimated: [N] sessions total
4081
-
4082
- To execute: Start a fresh session per spec. Each session should:
4083
- 1. Read the spec
4084
- 2. Implement
4085
- 3. Run $joycraft-session-end to capture discoveries
4086
- 4. Commit and PR
4087
-
4088
- Ready to start?
4089
- \`\`\`
4090
-
4091
- **Why:** A fresh session for execution produces better results. The interview session has too much context noise \u2014 a clean session with just the spec is more focused.
4092
-
4093
- You can also use \`$joycraft-decompose\` to re-decompose a brief if the breakdown needs adjustment, or run \`$joycraft-interview\` first for a lighter brainstorm before committing to the full workflow.
4094
-
4095
- **Tip:** Run \`/new\` before starting the next step. Your artifacts are saved to files \u2014 this conversation context is disposable.
4096
- `,
4097
- "joycraft-optimize.md": `---
4098
- name: joycraft-optimize
4099
- description: Audit your Claude Code or Codex session overhead \u2014 harness file sizes, plugins, MCP servers, hooks \u2014 and report actionable recommendations
4100
- ---
4101
-
4102
- # Optimize \u2014 Session Overhead Audit
4103
-
4104
- You are auditing the user's AI development session for token overhead. Produce a conversational diagnostic report \u2014 no files created.
4105
-
4106
- ## Step 1: Detect Platform
4107
-
4108
- Check which platform is active:
4109
- - **Claude Code:** Look for \`.claude/\` directory, \`CLAUDE.md\`
4110
- - **Codex:** Look for \`.agents/\` directory, \`AGENTS.md\`
4111
-
4112
- If both exist, run both checks. If neither, default to Claude Code checks and note the uncertainty.
4113
-
4114
- ## Step 2: Audit Harness Files
4115
-
4116
- ### Claude Code Path
4117
-
4118
- 1. **CLAUDE.md** \u2014 count lines. Threshold: \u2264200 lines.
4119
- 2. **Skill files** \u2014 glob \`.claude/skills/**/*.md\`. Count lines per file. Threshold: \u2264200 lines each.
4120
-
4121
- ### Codex Path
4122
-
4123
- 1. **AGENTS.md** \u2014 count lines. Threshold: \u2264200 lines.
4124
- 2. **Skill files** \u2014 glob \`.agents/skills/**/*.md\`. Count lines per file. Threshold: \u2264200 lines each.
4125
-
4126
- ## Step 3: Audit Plugins & MCP Servers
4127
-
4128
- ### Claude Code Path
4129
-
4130
- 1. **Installed plugins** \u2014 read \`~/.claude/plugins/installed_plugins.json\`. List plugin names and versions. If not found, report "no plugins file found."
4131
- 2. **Enabled plugins** \u2014 read \`~/.claude/settings.json\`, check \`enabledPlugins\` array. Show enabled vs installed count.
4132
- 3. **MCP servers** \u2014 read \`~/.claude/settings.json\`, count entries under \`mcpServers\`. List server names.
4133
-
4134
- ### Codex Path
4135
-
4136
- 1. **Plugin config** \u2014 read \`~/.codex/config.toml\`. List any plugin toggles. Note: Codex syncs its curated plugin marketplace at startup \u2014 this is a boot cost even if you don't use them.
4137
- 2. **MCP servers** \u2014 check \`~/.codex/config.toml\` for MCP server entries. List server names.
4138
-
4139
- ## Step 4: Audit Hooks (Claude Code Only)
4140
-
4141
- Read \`.claude/settings.json\` in the project directory. List all hook definitions under the \`hooks\` key \u2014 show the event name and command for each.
4142
-
4143
- For Codex: note "hook auditing not yet supported on Codex."
4144
-
4145
- ## Step 5: Report
4146
-
4147
- Organize findings by category. Use pass/warn indicators:
4148
-
4149
- \`\`\`
4150
- ## Session Overhead Report
4151
-
4152
- ### Harness Files
4153
- - CLAUDE.md/AGENTS.md: [N] lines [PASS \u2264200 / WARN >200]
4154
- - Skills: [N] files, [list any over 200 lines]
4155
-
4156
- ### Plugins
4157
- - Installed: [N] ([list names])
4158
- - Enabled: [N] of [M] installed
4159
- - [If 0: "No plugins \u2014 zero boot cost from plugins."]
4160
-
4161
- ### MCP Servers
4162
- - Count: [N] ([list names])
4163
- - [If 0: "No MCP servers \u2014 zero boot cost from servers."]
4164
-
4165
- ### Hooks
4166
- - [N] hook definitions ([list event names])
4167
-
4168
- ### Recommendations
4169
- - [Specific, actionable items for anything over threshold]
4170
- - [e.g., "AGENTS.md is 312 lines \u2014 consider splitting reference sections into docs/"]
4171
- - [e.g., "3 MCP servers load at boot \u2014 disable unused ones in config"]
4172
- \`\`\`
4173
-
4174
- ## Step 6: Further Resources
4175
-
4176
- End with:
4177
-
4178
- > For deeper token optimization, see:
4179
- > - [Nate B Jones's token optimization techniques](https://www.youtube.com/watch?v=bDcgHzCBgmQ)
4180
- > - [OB1 repo](https://github.com/nate-b-j/OB1) \u2014 Heavy File Ingestion skill and stupid button prompt kit
4181
- > - [Joycraft's token discipline guide](docs/guides/token-discipline.md)
4182
-
4183
- ## Edge Cases
4184
-
4185
- | Scenario | Behavior |
4186
- |----------|----------|
4187
- | Config files don't exist | Report "not found" for that check, don't error |
4188
- | No plugins installed | Report 0 plugins \u2014 this is good, say so |
4189
- | CLAUDE.md/AGENTS.md exactly 200 lines | PASS \u2014 threshold is \u2264200 |
4190
- | \`~/.claude/\` or \`~/.codex/\` not accessible | Skip user-level checks, note limitation |
4191
- | Both platforms detected | Run both audits, report separately |
4192
- `,
4193
- "joycraft-research.md": `---
4194
- name: joycraft-research
4195
- description: Produce objective codebase research by isolating question generation from fact-gathering \u2014 subagent sees only questions, never the brief
4196
- ---
4197
-
4198
- # Research Codebase for a Feature
4199
-
4200
- You are producing objective codebase research to inform a future spec or implementation. The key insight: the researching agent must never see the brief or ticket \u2014 only research questions. This prevents opinions from contaminating the facts.
4201
-
4202
- **Guard clause:** If the user doesn't provide a brief path or inline description, ask:
4203
- "What feature or change are you researching? Provide a brief path or describe it."
4204
-
4205
- ---
4206
-
4207
- ## Phase 1: Generate Research Questions
4208
-
4209
- Read the brief and identify which zones of the codebase are relevant. Generate 5-10 research questions that are:
4210
- - **Objective and fact-seeking** \u2014 "How does X work?" not "How should we build X?"
4211
- - **Specific to the codebase**
4212
- - **Answerable by reading code**
4213
-
4214
- Write the questions to \`docs/research/.questions-tmp.md\`. **Do NOT include any content from the brief.**
4215
-
4216
- ---
4217
-
4218
- ## Phase 2: Spawn Research Subagent
4219
-
4220
- Spawn a subagent to perform the research. Pass ONLY the research questions \u2014 never the brief.
4221
-
4222
- Subagent prompt:
4223
- \`\`\`
4224
- You are researching a codebase to answer specific questions. You have NO context about why these questions are being asked.
4225
-
4226
- RULES:
4227
- - Answer each question with FACTS ONLY: file paths, function signatures, data flows, patterns, dependencies
4228
- - Do NOT recommend, suggest, or opine
4229
- - Do NOT speculate about what should be built
4230
- - If a question cannot be answered, say "No existing code found for this"
4231
- - Search the codebase and read files thoroughly
4232
- - Include code snippets only when essential evidence
4233
-
4234
- QUESTIONS:
4235
- [INSERT_QUESTIONS_HERE]
4236
-
4237
- OUTPUT FORMAT:
4238
-
4239
- # Codebase Research
4240
-
4241
- **Date:** [today]
4242
- **Questions answered:** [N/total]
4243
-
4244
- ---
4245
-
4246
- ## Q1: [question]
4247
- [Facts only]
4248
-
4249
- ## Q2: [question]
4250
- [Facts only]
4251
- \`\`\`
4252
-
4253
- ## Phase 3: Write the Research Document
4254
-
4255
- Write the subagent's response to \`docs/research/YYYY-MM-DD-feature-name.md\`. Delete the temporary questions file.
4256
-
4257
- Present:
4258
- \`\`\`
4259
- Research complete: docs/research/YYYY-MM-DD-feature-name.md
4260
-
4261
- This document contains objective facts \u2014 no opinions or recommendations.
4262
-
4263
- Next steps:
4264
- - $joycraft-decompose \u2014 break the feature into atomic specs
4265
- - $joycraft-new-feature \u2014 formalize into a full Feature Brief first
4266
- - Read the research and add corrections manually
4267
- \`\`\`
4268
- `,
4269
- "joycraft-session-end.md": `---
4270
- name: joycraft-session-end
4271
- description: Wrap up a session \u2014 capture discoveries, verify, prepare for PR or next session
4272
- ---
4273
-
4274
- # Session Wrap-Up
4275
-
4276
- Before ending this session, complete these steps in order.
4277
-
4278
- ## 1. Capture Discoveries
4279
-
4280
- **Why:** Discoveries are the surprises \u2014 things that weren't in the spec or that contradicted expectations. They prevent future sessions from hitting the same walls.
4281
-
4282
- Check: did anything surprising happen during this session? If yes, create or update a discovery file at \`docs/discoveries/YYYY-MM-DD-topic.md\`. Create the \`docs/discoveries/\` directory if it doesn't exist.
4283
-
4284
- Only capture what's NOT obvious from the code or git diff:
4285
- - "We thought X but found Y" \u2014 assumptions that were wrong
4286
- - "This API/library behaves differently than documented" \u2014 external gotchas
4287
- - "This edge case needs handling in a future spec" \u2014 deferred work with context
4288
- - "The approach in the spec didn't work because..." \u2014 spec-vs-reality gaps
4289
- - Key decisions made during implementation that aren't in the spec
4290
-
4291
- **Do NOT capture:**
4292
- - Files changed (that's the diff)
4293
- - What you set out to do (that's the spec)
4294
- - Step-by-step narrative of the session (nobody re-reads these)
4295
-
4296
- Use this format:
4297
-
4298
- \`\`\`markdown
4299
- # Discoveries \u2014 [topic]
4300
-
4301
- **Date:** YYYY-MM-DD
4302
- **Spec:** [link to spec if applicable]
4303
-
4304
- ## [Discovery title]
4305
- **Expected:** [what we thought would happen]
4306
- **Actual:** [what actually happened]
4307
- **Impact:** [what this means for future work]
4308
- \`\`\`
4309
-
4310
- If nothing surprising happened, skip the discovery file entirely. No discovery is a good sign \u2014 the spec was accurate.
4311
-
4312
- ## 1b. Update Context Documents
4313
-
4314
- If \`docs/context/\` exists, quickly check whether this session revealed anything about:
4315
-
4316
- - **Production risks** \u2014 did you interact with or learn about production vs staging systems? Update \`docs/context/production-map.md\`
4317
- - **Wrong assumptions** \u2014 did you assume something that turned out to be false? Update \`docs/context/dangerous-assumptions.md\`
4318
- - **Key decisions** \u2014 did you make an architectural or tooling choice? Add a row to \`docs/context/decision-log.md\`
4319
- - **Unwritten rules** \u2014 did you discover a convention or constraint not documented anywhere? Update \`docs/context/institutional-knowledge.md\`
4320
-
4321
- Skip this if nothing applies. Don't force it \u2014 only update when there's genuine new context.
4322
-
4323
- ## 2. Run Validation
4324
-
4325
- Run the project's validation commands. Check CLAUDE.md or AGENTS.md for project-specific commands. Common checks:
4326
-
4327
- - Type-check (e.g., \`tsc --noEmit\`, \`mypy\`, \`cargo check\`)
4328
- - Tests (e.g., \`npm test\`, \`pytest\`, \`cargo test\`)
4329
- - Lint (e.g., \`eslint\`, \`ruff\`, \`clippy\`)
4330
-
4331
- Fix any failures before proceeding.
4332
-
4333
- ## 3. Update Spec Status
4334
-
4335
- If working from an atomic spec in \`docs/specs/\` (scan recursively \u2014 specs may be in subdirectories like \`docs/specs/<feature-name>/\`):
4336
- - All acceptance criteria met \u2014 update status to \`Complete\`
4337
- - Partially done \u2014 update status to \`In Progress\`, note what's left
4338
-
4339
- If working from a Feature Brief in \`docs/briefs/\`, check off completed specs in the decomposition table.
4340
-
4341
- ## 4. Commit
4342
-
4343
- Commit all changes including the discovery file (if created) and spec status updates. The commit message should reference the spec if applicable.
4344
-
4345
- ## 5. Push and PR (if autonomous git is enabled)
4346
-
4347
- **Check CLAUDE.md or AGENTS.md for "Git Autonomy" in the Behavioral Boundaries section.** If it says "STRICTLY ENFORCED" or the ALWAYS section includes "Push to feature branches immediately after every commit":
4348
-
4349
- 1. **Push immediately.** Run \`git push origin <branch>\` \u2014 do not ask, do not hesitate.
4350
- 2. **Open a PR if the feature is complete.** Check the parent Feature Brief's decomposition table \u2014 if all specs are done, run \`gh pr create\` with a summary of all completed specs. Do not ask first.
4351
- 3. **If not all specs are done,** still push. The PR comes when the last spec is complete.
4352
-
4353
- If CLAUDE.md or AGENTS.md does NOT have autonomous git rules (or has "ASK FIRST" for pushing), ask the user before pushing.
4354
-
4355
- ## 6. Report
4356
-
4357
- \`\`\`
4358
- Session complete.
4359
- - Spec: [spec name] \u2014 [Complete / In Progress]
4360
- - Build: [passing / failing]
4361
- - Discoveries: [N items / none]
4362
- - Pushed: [yes / no \u2014 and why not]
4363
- - PR: [opened #N / not yet \u2014 N specs remaining]
4364
- - Next: [what the next session should tackle]
4365
- \`\`\`
4366
-
4367
- **Tip:** Run \`/new\` before starting the next step. Your artifacts are saved to files \u2014 this conversation context is disposable.
4368
- `,
4369
- "joycraft-tune.md": `---
4370
- name: joycraft-tune
4371
- description: Assess and upgrade your project's AI development harness \u2014 score 7 dimensions, apply fixes, show path to Level 5
4372
- ---
4373
-
4374
- # Tune \u2014 Project Harness Assessment & Upgrade
4375
-
4376
- You are evaluating and upgrading this project's AI development harness.
4377
-
4378
- ## Step 1: Detect Harness State
4379
-
4380
- Search the codebase for: CLAUDE.md (with meaningful content), \`docs/specs/\`, \`docs/briefs/\`, \`docs/discoveries/\`, \`.agents/skills/\`, and test configuration.
4381
-
4382
- ## Step 2: Route
4383
-
4384
- - **No harness** (no CLAUDE.md or just a README): Recommend \`npx joycraft init\` and stop.
4385
- - **Harness exists**: Continue to assessment.
4386
-
4387
- ## Step 3: Assess \u2014 Score 7 Dimensions (1-5 scale)
4388
-
4389
- Read CLAUDE.md and explore the project. Score each with specific evidence:
4390
-
4391
- | Dimension | What to Check |
4392
- |-----------|--------------|
4393
- | Spec Quality | \`docs/specs/\` (scan recursively) \u2014 structured? acceptance criteria? self-contained? |
4394
- | Spec Granularity | Can each spec be done in one session? |
4395
- | Behavioral Boundaries | ALWAYS/ASK FIRST/NEVER sections (or equivalent rules under any heading) |
4396
- | Skills & Hooks | \`.agents/skills/\` files, hooks config |
4397
- | Documentation | \`docs/\` structure, templates, referenced from CLAUDE.md |
4398
- | Knowledge Capture | \`docs/discoveries/\`, \`docs/context/*.md\` \u2014 existence AND real content |
4399
- | Testing & Validation | Test framework, CI pipeline, validation commands in CLAUDE.md |
4400
-
4401
- Score 1 = absent, 3 = partially there, 5 = comprehensive. Give credit for substance over format.
4402
-
4403
- ## Step 4: Write Assessment
4404
-
4405
- Write to \`docs/joycraft-assessment.md\` AND display it. Include: scores table, detailed findings (evidence + gap + recommendation per dimension), and an upgrade plan (up to 5 actions ordered by impact).
4406
-
4407
- ## Step 5: Apply Upgrades
4408
-
4409
- Apply using three tiers \u2014 do NOT ask per-item permission:
4410
-
4411
- **Tier 1 (silent):** Create missing dirs, install missing skills, copy missing templates, create AGENTS.md.
4412
-
4413
- **Before Tier 2, ask TWO things:**
4414
-
4415
- 1. **Git autonomy:** Cautious (ask before push/PR) or Autonomous (push + PR without asking)?
4416
- 2. **Risk interview (3-5 questions, one at a time):** What could break? What services connect to prod? Unwritten rules? Off-limits files/commands? Skip if \`docs/context/\` already has content.
4417
-
4418
- From answers, generate: CLAUDE.md boundary rules, deny patterns configuration, \`docs/context/\` documents. Also recommend a permission mode (\`auto\` for most; \`dontAsk\` + allowlist for high-risk).
4419
-
4420
- **Tier 2 (show diff):** Add missing CLAUDE.md sections (Boundaries, Workflow, Key Files). Draft from real codebase content. Append only \u2014 never reformat existing content.
4421
-
4422
- **Tier 3 (confirm first):** Rewriting existing sections, overwriting customized files, suggesting test framework installs.
4423
-
4424
- After applying, append to \`docs/joycraft-history.md\` and show a consolidated upgrade results table.
4425
-
4426
- ## Step 6: Show Path to Level 5
4427
-
4428
- Show a tailored roadmap: Level 2-5 table, specific next steps based on actual gaps, and the Level 5 north star (spec queue, autofix, holdout scenarios, self-improving harness).
4429
-
4430
- ## Edge Cases
4431
-
4432
- - **CLAUDE.md is just a README:** Treat as no harness.
4433
- - **Non-Joycraft skills:** Acknowledge, don't replace.
4434
- - **Rules under non-standard headings:** Give credit for substance.
4435
- - **Previous assessment exists:** Read it first. If nothing to upgrade, say so.
4436
- - **Non-Joycraft content in CLAUDE.md:** Preserve as-is. Only append.
4437
-
4438
- **Tip:** Run \`$joycraft-optimize\` to audit your session's token overhead \u2014 plugins, MCP servers, and harness file sizes.
4439
- `,
4440
- "joycraft-verify.md": `---
4441
- name: joycraft-verify
4442
- description: Spawn an independent verifier subagent to check an implementation against its spec -- read-only, no code edits, structured pass/fail verdict
4443
- ---
4444
-
4445
- # Verify Implementation Against Spec
4446
-
4447
- The user wants independent verification of an implementation. Your job is to find the relevant spec, extract its acceptance criteria and test plan, then spawn a separate verifier subagent that checks each criterion and produces a structured verdict.
4448
-
4449
- **Why a separate subagent?** Research found that agents reliably skew positive when grading their own work. Separating the agent doing the work from the agent judging it consistently outperforms self-evaluation. The verifier gets a clean context window with no implementation bias.
4450
-
4451
- ## Step 1: Find the Spec
4452
-
4453
- If the user provided a spec path (e.g., \`$joycraft-verify docs/specs/my-feature/add-widget.md\`), use that path directly.
4454
-
4455
- If no path was provided, scan \`docs/specs/\` recursively for spec files (they may be in subdirectories like \`docs/specs/<feature-name>/\`). Pick the most recently modified \`.md\` file. If \`docs/specs/\` doesn't exist or is empty, tell the user:
4456
-
4457
- > No specs found in \`docs/specs/\`. Please provide a spec path: \`$joycraft-verify path/to/spec.md\`
4458
-
4459
- ## Step 2: Read and Parse the Spec
4460
-
4461
- Read the spec file and extract:
4462
-
4463
- 1. **Spec name** -- from the H1 title
4464
- 2. **Acceptance Criteria** -- the checklist under the \`## Acceptance Criteria\` section
4465
- 3. **Test Plan** -- the table under the \`## Test Plan\` section, including any test commands
4466
- 4. **Constraints** -- the \`## Constraints\` section if present
4467
-
4468
- If the spec has no Acceptance Criteria section, tell the user:
4469
-
4470
- > This spec doesn't have an Acceptance Criteria section. Verification needs criteria to check against. Add acceptance criteria to the spec and try again.
4471
-
4472
- If the spec has no Test Plan section, note this but proceed -- the verifier can still check criteria by reading code and running any available project tests.
4473
-
4474
- ## Step 3: Identify Test Commands
4475
-
4476
- Look for test commands in these locations (in priority order):
4477
-
4478
- 1. The spec's Test Plan section (look for commands in backticks or "Type" column entries like "unit", "integration", "e2e", "build")
4479
- 2. The project's CLAUDE.md or AGENTS.md (look for test/build commands in the Development Workflow section)
4480
- 3. Common defaults based on the project type:
4481
- - Node.js: \`npm test\` or \`pnpm test --run\`
4482
- - Python: \`pytest\`
4483
- - Rust: \`cargo test\`
4484
- - Go: \`go test ./...\`
4485
-
4486
- Build a list of specific commands the verifier should run.
4487
-
4488
- ## Step 4: Spawn the Verifier Subagent
4489
-
4490
- Spawn a concurrent subagent thread with the following prompt. Replace the placeholders with the actual content extracted in Steps 2-3.
4491
-
4492
- **Important:** The subagent must be given read-only constraints. It may search the codebase, read files, and run the specified test/build commands, but it must NOT edit or create any files.
4493
-
4494
- \`\`\`
4495
- You are a QA verifier. Your job is to independently verify an implementation against its spec. You have NO context about how the implementation was done -- you are checking it fresh.
4496
-
4497
- RULES -- these are hard constraints, not suggestions:
4498
- - You may search the codebase and read any file
4499
- - You may RUN these specific test/build commands: [TEST_COMMANDS]
4500
- - You may NOT edit, create, or delete any files
4501
- - You may NOT run commands that modify state (no git commit, no npm install, no file writes)
4502
- - You may NOT install packages or access the network
4503
- - Report what you OBSERVE, not what you expect or hope
4504
-
4505
- SPEC NAME: [SPEC_NAME]
4506
-
4507
- ACCEPTANCE CRITERIA:
4508
- [ACCEPTANCE_CRITERIA]
4509
-
4510
- TEST PLAN:
4511
- [TEST_PLAN]
4512
-
4513
- CONSTRAINTS:
4514
- [CONSTRAINTS_OR_NONE]
4515
-
4516
- YOUR TASK:
4517
- For each acceptance criterion, determine if it PASSES or FAILS based on evidence:
4518
-
4519
- 1. Run the test commands listed above. Record the output.
4520
- 2. For each acceptance criterion:
4521
- a. Check if there is a corresponding test and whether it passes
4522
- b. If no test exists, read the relevant source files to verify the criterion is met
4523
- c. If the criterion cannot be verified by reading code or running tests, mark it MANUAL CHECK NEEDED
4524
- 3. For criteria about build/test passing, actually run the commands and report results.
4525
-
4526
- OUTPUT FORMAT -- you MUST use this exact format:
4527
-
4528
- VERIFICATION REPORT
4529
-
4530
- | # | Criterion | Verdict | Evidence |
4531
- |---|-----------|---------|----------|
4532
- | 1 | [criterion text] | PASS/FAIL/MANUAL CHECK NEEDED | [what you observed] |
4533
- | 2 | [criterion text] | PASS/FAIL/MANUAL CHECK NEEDED | [what you observed] |
4534
- [continue for all criteria]
4535
-
4536
- SUMMARY: X/Y criteria passed. [Z failures need attention. / All criteria verified.]
4537
-
4538
- If any test commands fail to run (missing dependencies, wrong command, etc.), report the error as evidence for a FAIL verdict on the relevant criterion.
4539
- \`\`\`
4540
-
4541
- ## Step 5: Format and Present the Verdict
4542
-
4543
- Take the subagent's response and present it to the user in this format:
4544
-
4545
- \`\`\`
4546
- ## Verification Report -- [Spec Name]
4547
-
4548
- | # | Criterion | Verdict | Evidence |
4549
- |---|-----------|---------|----------|
4550
- | 1 | ... | PASS | ... |
4551
- | 2 | ... | FAIL | ... |
4552
-
4553
- **Overall: X/Y criteria passed.**
4554
-
4555
- [If all passed:]
4556
- All criteria verified. Ready to commit and open a PR.
4557
-
4558
- [If any failed:]
4559
- N failures need attention. Review the evidence above and fix before proceeding.
4560
-
4561
- [If any MANUAL CHECK NEEDED:]
4562
- N criteria need manual verification -- they can't be checked by reading code or running tests alone.
4563
- \`\`\`
4564
-
4565
- ## Step 6: Suggest Next Steps
4566
-
4567
- Based on the verdict:
4568
-
4569
- - **All PASS:** Suggest committing and opening a PR, or running \`$joycraft-session-end\` to capture discoveries.
4570
- - **Some FAIL:** List the failed criteria and suggest the user fix them, then run \`$joycraft-verify\` again.
4571
- - **MANUAL CHECK NEEDED items:** Explain what needs human eyes and why automation couldn't verify it.
4572
-
4573
- **Do NOT offer to fix failures yourself.** The verifier reports; the human (or implementation agent in a separate turn) decides what to do. This separation is the whole point.
4574
-
4575
- ## Edge Cases
4576
-
4577
- | Scenario | Behavior |
4578
- |----------|----------|
4579
- | Spec has no Test Plan | Warn that verification is weaker without a test plan, but proceed by checking criteria through code reading and any available project-level tests |
4580
- | All tests pass but a criterion is not testable | Mark as MANUAL CHECK NEEDED with explanation |
4581
- | Subagent can't run tests (missing deps) | Report the error as FAIL evidence |
4582
- | No specs found and no path given | Tell user to provide a spec path or create a spec first |
4583
- | Spec status is "Complete" | Still run verification -- "Complete" means the implementer thinks it's done, verification confirms |
4584
- `
4585
- };
4586
-
4587
- export {
4588
- SKILLS,
4589
- TEMPLATES,
4590
- CODEX_SKILLS
4591
- };
4592
- //# sourceMappingURL=chunk-JXSFWGIN.js.map