From e84f6e1edf1e17306fae61a0b1b426edc994dc9e Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Tue, 5 May 2026 18:54:23 +0200 Subject: [PATCH 01/21] feat: pre-workflow prototyping skill for exploring multiple ideas (#42) Adds /explore skill for rapid prototyping of 2-4 game ideas before committing to Hybrid or Full OCGS workflow. Lightweight reports, no workflow artifacts, timeboxed to 1-2 days per idea. - New .opencode/skills/explore/SKILL.md - New .opencode/commands/explore.md - docs/hybrid-workflow.md: pre-workflow exploration section + comparison table - docs/WORKFLOW-GUIDE.md: Path E, directory structure, command ref, workflow 2 --- .opencode/commands/explore.md | 8 ++ .opencode/skills/explore/SKILL.md | 218 ++++++++++++++++++++++++++++++ docs/WORKFLOW-GUIDE.md | 37 +++-- docs/hybrid-workflow.md | 55 +++++++- 4 files changed, 309 insertions(+), 9 deletions(-) create mode 100644 .opencode/commands/explore.md create mode 100644 .opencode/skills/explore/SKILL.md diff --git a/.opencode/commands/explore.md b/.opencode/commands/explore.md new file mode 100644 index 0000000..fddf54b --- /dev/null +++ b/.opencode/commands/explore.md @@ -0,0 +1,8 @@ +--- +name: explore +description: "Pre-workflow rapid prototyping for exploring multiple game ideas" +skill: explore +category: prototyping +--- + +Invokes `/explore` skill. \ No newline at end of file diff --git a/.opencode/skills/explore/SKILL.md b/.opencode/skills/explore/SKILL.md new file mode 100644 index 0000000..0311731 --- /dev/null +++ b/.opencode/skills/explore/SKILL.md @@ -0,0 +1,218 @@ +--- +name: explore +description: "Pre-workflow rapid prototyping for exploring multiple game ideas before committing to a development workflow. Produces lightweight reports with no workflow commitment." +argument-hint: "[concept-description]" +user-invocable: true +allowed-tools: Read, Glob, Grep, Write, Edit, Bash, Task +agent: prototyper +isolation: worktree +--- + +## Overview + +This skill is the **pre-workflow exploration lane**. Use it when you have one or more rough game ideas and want to validate them before choosing between the Hybrid workflow (lean, iterative) or the Full OCGS workflow (formal, structured). + +**When to use `/explore`:** +- You have 2-4 rough ideas and want to feel them out before committing +- You are not sure if your concept is fun, feasible, or scoped correctly +- You want to avoid formal process overhead until you know what you're making + +**When NOT to use `/explore`:** +- You already know your game and are ready to build → use `/start` directly +- You are in the middle of production → use `/prototype` or `/hybrid-prototype` +- You need a formal vertical slice → use `/prototype` within the full workflow + +**Key properties:** +- **No workflow commitment**: Does not create `production/stage.txt`, `production/review-mode.txt`, or any production artifacts +- **No process overhead**: No GDDs, no ADRs, no architecture, no sprint plans +- **Time-boxed**: 1-2 days per idea maximum +- **Isolated**: All work lives in `prototypes/explore/[idea-name]/` +- **Composable**: Run it multiple times for multiple ideas, then compare results + +**Agents involved**: `prototyper` only. No director reviews, no multi-tier coordination. + +--- + +## Phase 1: Define the Question (5 minutes) + +Read the concept description from the argument. State the **one core question** this prototype must answer. If the concept is vague, ask the user to clarify before proceeding. + +Examples of good questions: +- "Does the core loop of harvesting + crafting feel satisfying for 10 minutes?" +- "Is the combat pace too slow or too frantic with 3 enemy types?" +- "Does the movement mechanic make exploration feel good, or tedious?" + +Bad question: "Is this game fun?" (Too broad. Narrow it down to one mechanic or feeling.) + +**Ask the user**: "The core question for this prototype is: **[question]**. Proceed?" + +--- + +## Phase 2: Plan (15 minutes) + +Define the minimum viable prototype in 3-5 bullet points: + +- What is the absolute minimum code to answer the question? +- What can be hardcoded / placeholder / skipped? +- What is the success criteria? (e.g., "Player completes 3 crafting cycles without confusion") +- What is the time budget? (default: 1-2 days) + +**Present the plan to the user and ask for confirmation.** + +If the user is exploring multiple ideas, remind them: "This is idea **[N]** of your exploration. Keep the scope tight so you can compare fairly." + +--- + +## Phase 3: Build (1-2 days) + +**Ask**: "May I create the prototype directory at `prototypes/explore/[idea-name]/` and begin implementation?" + +If yes, create the directory. Every file must begin with: + +``` +// EXPLORE PROTOTYPE - NOT FOR PRODUCTION +// Question: [Core question being tested] +// Date: [Current date] +// Workflow: pre-workflow exploration (no workflow committed) +``` + +**Rules for explore prototype code**: +- Hardcode values freely +- Use placeholder assets (colored squares, simple shapes, primitive meshes) +- Skip error handling, polish, and architecture +- Use the simplest approach that works +- Copy code rather than importing from production +- NEVER import from `src/` — explore prototypes are fully isolated +- NEVER create files in `production/`, `design/`, `docs/architecture/`, or `src/` + +**Run the prototype** as you build. Test continuously. Fix blockers, but don't polish. + +If the build exceeds 2 days, **stop and report**. Exploration prototypes that drag on lose their purpose. Either reduce scope or mark as TIMEOUT. + +--- + +## Phase 4: Playtest (1-2 hours) + +Play the prototype yourself. Then ask the user to play it. Collect observations: + +- What worked? +- What felt bad? +- Did it answer the core question? +- Any surprising discoveries? +- How long did it take to build? + +**Document findings informally** — a bulleted list is fine at this stage. + +--- + +## Phase 5: Generate Report (15 minutes) + +Draft a lightweight report: + +```markdown +# Explore Report: [Idea Name] + +## Question +[The core question this prototype set out to answer] + +## Approach +[What was built, time spent, shortcuts taken] + +## Result +[What actually happened — specific observations] + +## Verdict +[PROMISING / NEEDS_WORK / NOT_VIABLE / TIMEOUT] + +- **PROMISING**: The core idea works. Worth developing further. +- **NEEDS_WORK**: The idea has potential but needs significant adjustment. +- **NOT_VIABLE**: The idea does not work as conceived. Do not pursue. +- **TIMEOUT**: The prototype could not be completed in the timebox. Scope was too large or the idea is too complex to explore quickly. + +## Reasoning +[One paragraph explaining the verdict with evidence] + +## Surprises +[Any unexpected findings that affect this or other ideas] + +## Estimated Production Effort +[Rough guess: small (weeks) / medium (months) / large (6+ months)] +``` + +**Ask**: "May I write this report to `prototypes/explore/[idea-name]/REPORT.md`?" + +--- + +## Phase 6: Next Steps + +After the report is written, present the user's options: + +**If the user has more ideas to explore:** +> "Idea **[current idea]** is documented. You have **[N]** more ideas to explore. Ready to run `/explore [next-idea]`?" + +**If the user is done exploring:** +> "Exploration complete. You have **[N]** reports in `prototypes/explore/`: +> - `[idea-1]`: PROMISING +> - `[idea-2]`: NOT_VIABLE +> - `[idea-3]`: NEEDS_WORK +> +> **Next step**: Run `/gate-check workflow-selection` to compare your prototypes and choose between the Hybrid and Full OCGS workflows. +> +> Or, if you want to refine one idea first: `/explore [revised-concept]` to iterate." + +**Do NOT**: +- Suggest `/design-system`, `/create-architecture`, or any production-phase skill +- Create `production/stage.txt` +- Set a review mode +- Route to `/brainstorm` unless the user explicitly asks for ideation help + +--- + +## Phase 7: Summary + +Output a summary to the user: +- Idea name and core question +- Verdict (PROMISING / NEEDS_WORK / NOT_VIABLE / TIMEOUT) +- Location of the report +- Clear next step (explore another idea, or workflow selection) + +Verdict: **COMPLETE** — exploration prototype finished. No workflow committed. + +--- + +## Constraints + +- Prototype code must NEVER import from production source files +- Production code must NEVER import from prototype directories +- If an idea is later productionized, rewrite from scratch — do not refactor explore prototype code +- Timebox strictly: 1-2 days per idea. If it's not testable after 2 days, verdict is TIMEOUT +- Keep the question narrow — one prototype, one question +- No workflow artifacts: do not touch `production/`, `design/gdd/`, `docs/architecture/`, or `src/` +- No review mode gates, no director reviews, no multi-agent coordination +- **Workflow isolation**: This skill explicitly bypasses `production/review-mode.txt` and `production/stage.txt`. Any existing workflow state is ignored during exploration. + +--- + +## Comparison with Other Prototype Skills + +| Aspect | `/explore` | `/prototype` (Full OCGS) | `/hybrid-prototype` (Hybrid) | +|--------|-----------|--------------------------|------------------------------| +| **Workflow stage** | Pre-workflow | Phase 4 (Pre-Production) | Phase 1 (Discovery) | +| **Workflow commitment** | None | Full OCGS | Hybrid | +| **Creates stage.txt?** | No | Yes | Yes (hybrid stage) | +| **Review mode gates** | None | Solo / Lean / Full | None | +| **Report format** | Lightweight `REPORT.md` | Formal `REPORT.md` | Lightweight `DECISION.md` | +| **Directory** | `prototypes/explore/` | `prototypes/[name]/` | `prototypes/[name]/` | +| **Next step on success** | `/gate-check workflow-selection` | `/design-system` or `/architecture-decision` | `/design-system` or `/create-architecture` | +| **Time budget** | 1-2 days | 1-3 days | 1-3 days | +| **Agents involved** | `prototyper` only | All tiers | 4 core roles | +| **Designed for** | Comparing multiple ideas | Validating a known concept | Finding the fun in one idea | + +--- + +## Recommended Next Steps + +- **If exploring more ideas**: Run `/explore [next-concept]` for the next idea +- **If done exploring**: Run `/gate-check workflow-selection` to choose Hybrid vs. Full OCGS +- **If one idea needs refinement**: Run `/explore [revised-concept]` with adjusted scope +- **If ready to commit to a workflow**: Run `/start` after workflow selection to begin formal onboarding \ No newline at end of file diff --git a/docs/WORKFLOW-GUIDE.md b/docs/WORKFLOW-GUIDE.md index bc2f629..0d9cc0a 100644 --- a/docs/WORKFLOW-GUIDE.md +++ b/docs/WORKFLOW-GUIDE.md @@ -63,6 +63,9 @@ This guided onboarding asks where you are and routes you to the right phase: - **Path D1** -- Existing project, few artifacts: normal flow - **Path D2** -- Existing project, GDDs/ADRs exist: runs `/project-stage-detect` then `/adopt` for brownfield migration +- **Path E** -- Multiple ideas to explore: routes to `/explore` for rapid + pre-workflow prototyping, then `/gate-check workflow-selection` to choose + Hybrid vs. Full OCGS based on results ### Step 3: Verify Hooks Are Working @@ -122,6 +125,8 @@ docs/ # Technical documentation postmortems/ # Post-mortems tests/ # Test suites prototypes/ # Throwaway prototypes + explore/ # Pre-workflow exploration prototypes (/explore) + archive/ # Archived prototypes after workflow selection production/ # Sprint plans, milestones, releases sprints/ milestones/ @@ -1462,7 +1467,7 @@ conflicts go to `producer`. | `/story-done` | 8-phase story completion review | 5 | | `/estimate` | Effort estimation with risk assessment | 4-5 | -#### Reviews and Analysis (10) +#### Reviews and Analysis (11) | Command | Purpose | Phase | |---------|---------|-------| @@ -1475,6 +1480,7 @@ conflicts go to `producer`. | `/perf-profile` | Performance profiling workflow | 6 | | `/tech-debt` | Tech debt scanning and prioritization | 6 | | `/gate-check` | Formal phase gate with PASS/CONCERNS/FAIL | All transitions | +| `/gate-check workflow-selection` | Choose Hybrid vs. Full after exploration | Pre-workflow | | `/reverse-document` | Generate design docs from existing code | Any | #### QA and Testing (9) @@ -1512,11 +1518,13 @@ conflicts go to `producer`. | `/patch-notes` | Player-facing patch notes | 7 | | `/hotfix` | Emergency fix workflow | 7+ | -#### Creative (2) +#### Creative (4) | Command | Purpose | Phase | |---------|---------|-------| +| `/explore` | Pre-workflow rapid prototyping — no workflow commitment | Pre-workflow | | `/prototype` | Throwaway prototype in isolated worktree | 4 | +| `/hybrid-prototype` | Fast-lane prototype for hybrid discovery phase | Discovery | | `/localize` | String extraction and validation | 6-7 | #### Team Orchestration (9) @@ -1549,7 +1557,20 @@ conflicts go to `producer`. 7. /design-system per system (guided GDD authoring) ``` -### Workflow 2: "I have designs and want to start coding" +### Workflow 2: "I have multiple ideas and want to explore before committing" + +``` +1. /start (pick Path E — multiple ideas to explore) +2. /explore idea-a (rapid prototype, 1-2 days) +3. /explore idea-b (rapid prototype, 1-2 days) +4. /explore idea-c (optional, 1-2 days) +5. Review reports in prototypes/explore/*/REPORT.md +6. /gate-check workflow-selection (choose Hybrid vs. Full OCGS) +7. If Hybrid: run /hybrid-prototype on the winning idea +8. If Full: run /brainstorm [winning idea] to formalize, then /setup-engine +``` + +### Workflow 3: "I have designs and want to start coding" ``` 1. /design-review on each GDD (make sure they're solid) @@ -1564,7 +1585,7 @@ conflicts go to `producer`. 10. /story-readiness -> implement -> /story-done (story lifecycle) ``` -### Workflow 3: "I need to add a complex feature mid-production" +### Workflow 4: "I need to add a complex feature mid-production" ``` 1. /design-system or /quick-design (depending on scope) @@ -1576,7 +1597,7 @@ conflicts go to `producer`. 7. /balance-check if it affects game balance ``` -### Workflow 4: "Something broke in production" +### Workflow 5: "Something broke in production" ``` 1. /hotfix "description of the issue" @@ -1587,7 +1608,7 @@ conflicts go to `producer`. 6. Deploy and backport ``` -### Workflow 5: "I have an existing project and want to use this system" +### Workflow 6: "I have an existing project and want to use this system" ``` 1. /start (choose Path D -- existing work) @@ -1598,7 +1619,7 @@ conflicts go to `producer`. 6. /gate-check at appropriate transition ``` -### Workflow 6: "Starting a new sprint" +### Workflow 7: "Starting a new sprint" ``` 1. /retrospective (review last sprint) @@ -1610,7 +1631,7 @@ conflicts go to `producer`. 7. /sprint-status for quick progress checks ``` -### Workflow 7: "Shipping the game" +### Workflow 8: "Shipping the game" ``` 1. /gate-check polish (verify Polish phase is complete) diff --git a/docs/hybrid-workflow.md b/docs/hybrid-workflow.md index cd08497..350397a 100644 --- a/docs/hybrid-workflow.md +++ b/docs/hybrid-workflow.md @@ -6,7 +6,9 @@ This document defines a pragmatic hybrid workflow that balances **creative agili **When to use this workflow**: Small teams, unknown designs, short timelines (weeks to a few months), prototypes that may be pivoted or killed. -**When to use the full OCGS workflow**: Large teams (5–15+), known designs, long timelines (6+ months), funded projects with publisher requirements. +**When to use the full OCGS workflow**: Large teams (5-15+), known designs, long timelines (6+ months), funded projects with publisher requirements. + +**Not sure which workflow to use?** Run `/explore` to rapidly prototype 2-4 ideas with zero workflow commitment, then use `/gate-check workflow-selection` to choose the right workflow based on your results. See [Pre-Workflow Exploration](#pre-workflow-exploration) below. --- @@ -161,6 +163,57 @@ Switch back to the **full 49-agent framework** if any of these become true: --- +## Pre-Workflow Exploration + +Before committing to Hybrid or Full OCGS, you can explore multiple ideas rapidly with **zero workflow commitment**. + +### The `/explore` Skill + +``` +/explore "a farming sim where crops grow in real time" +/explore "a roguelike where weapons break permanently" +/explore "a narrative puzzle game with time loops" +``` + +**What `/explore` does:** +- Builds a throwaway prototype in `prototypes/explore/[idea-name]/` +- Time-boxed to 1-2 days per idea +- Produces a lightweight `REPORT.md` with a verdict: **PROMISING / NEEDS_WORK / NOT_VIABLE / TIMEOUT** +- Does NOT create `production/stage.txt`, `production/review-mode.txt`, or any workflow artifacts +- Does NOT require choosing Hybrid vs. Full upfront + +**When to use it:** +- You have 2-4 rough ideas and want to compare them before committing +- You are not sure if your concept is fun, feasible, or correctly scoped +- You want to avoid formal process overhead until you know what you're making + +**Exploration workflow:** + +``` +/explore idea-a → prototypes/explore/idea-a/REPORT.md +/explore idea-b → prototypes/explore/idea-b/REPORT.md +/explore idea-c → prototypes/explore/idea-c/REPORT.md + +/gate-check workflow-selection + → Compare prototypes + → Choose Hybrid or Full + → Set workflow mode and stage +``` + +### How `/explore` Differs from Other Prototype Skills + +| Aspect | `/explore` | `/hybrid-prototype` | `/prototype` (Full OCGS) | +|--------|-----------|---------------------|--------------------------| +| **Workflow stage** | Pre-workflow | Hybrid Discovery | Full OCGS Pre-Production | +| **Workflow commitment** | None | Hybrid | Full OCGS | +| **Creates stage.txt?** | No | Yes | Yes | +| **Time budget** | 1-2 days | 1-3 days | 1-3 days | +| **Report** | Lightweight REPORT.md | DECISION.md | Formal REPORT.md | +| **Next step** | Workflow selection | Begin GDD/architecture | Begin GDD/architecture | +| **Agents** | `prototyper` only | 4 core roles | All tiers | + +--- + ## Migration Path If a project starts with the hybrid workflow and later needs the full OCGS framework: From 92651a517b4fb36db9da2da003423afe7fc97d7d Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Tue, 5 May 2026 18:54:35 +0200 Subject: [PATCH 02/21] feat: /start command Path E for pre-workflow exploration (#46) Adds Path E (multiple ideas) to the /start onboarding flow, routing users to /explore with no workflow commitment. Also updates /help to recognize the exploration stage with phase-specific guidance. - .opencode/skills/start/SKILL.md: Path E, skip review mode, edge cases - .opencode/skills/help/SKILL.md: exploration stage mapping + early return --- .opencode/skills/help/SKILL.md | 29 +++++++++++++++++++++++++++ .opencode/skills/start/SKILL.md | 35 ++++++++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/.opencode/skills/help/SKILL.md b/.opencode/skills/help/SKILL.md index 6dc46da..4d38b1a 100644 --- a/.opencode/skills/help/SKILL.md +++ b/.opencode/skills/help/SKILL.md @@ -63,6 +63,7 @@ Check in this order: - "Production" → `production` - "Polish" → `polish` - "Release" → `release` + - "exploration" → `exploration` (pre-workflow, not in catalog) 2. **If stage.txt is missing**, infer phase from artifacts (most-advanced match wins): - `src/` has 10+ source files → `production` @@ -70,8 +71,36 @@ Check in this order: - `docs/architecture/adr-*.md` exists → `technical-setup` - `design/gdd/systems-index.md` exists → `systems-design` - `design/gdd/game-concept.md` exists → `concept` + - `prototypes/explore/*/REPORT.md` exists → `exploration` (pre-workflow, no concept yet) + - `prototypes/explore/` directory exists (any files) → `exploration` - Nothing → `concept` (fresh project) +3. **If phase is `exploration`**: Return early with exploration-specific guidance. + This phase is not in the catalog — skip Steps 4-8 and go directly to reporting. + + Read `prototypes/explore/` to find existing reports. Count how many ideas + have been prototyped and list their verdicts. + + ``` + ## Where You Are: Pre-Workflow Exploration + + You are prototyping game ideas before committing to a development workflow. + No workflow is selected yet — no GDDs, no architecture, no sprint plans. + + **Exploration prototypes found: [N]** + [List each with verdict from REPORT.md] + + ### → Next up + **[Explore another idea]** — Run `/explore [description]` to prototype a new idea. + **[Or: Select a workflow]** — When you're done exploring, run + `/gate-check workflow-selection` to compare your prototypes and choose + between Hybrid (lean, iterative) and Full OCGS (formal, structured). + + ### ~ Also available + - `/gate-check workflow-selection` — compare prototypes and choose workflow + - `/explore [idea]` — prototype another idea + ``` + --- ## Step 3: Read Session Context diff --git a/.opencode/skills/start/SKILL.md b/.opencode/skills/start/SKILL.md index 729a46c..e88c822 100644 --- a/.opencode/skills/start/SKILL.md +++ b/.opencode/skills/start/SKILL.md @@ -1,6 +1,6 @@ --- name: start -description: "First-time onboarding — asks where you are, then guides you to the right workflow. No assumptions." +description: "First-time onboarding — asks where you are, then guides you to the right workflow or to pre-workflow exploration. No assumptions." argument-hint: "[no arguments]" user-invocable: true allowed-tools: Read, Glob, Grep, Write, question @@ -8,7 +8,9 @@ allowed-tools: Read, Glob, Grep, Write, question # Guided Onboarding -This skill writes one file: `production/review-mode.txt` (review mode config set in Phase 3b). +This skill writes up to two files: +- `production/stage.txt` — set to `exploration` when user picks Path E (pre-workflow exploration). +- `production/review-mode.txt` — review mode config (set in Phase 3b, skipped for Path E). This skill is the entry point for new users. It does NOT assume you have a game idea, an engine preference, or any prior experience. It asks first, then routes you to the right workflow. @@ -40,6 +42,7 @@ This is the first thing the user sees. Use `question` with these exact options s - `B) Vague idea` — I have a rough theme, feeling, or genre in mind (e.g., "something with space" or "a cozy farming game") but nothing concrete. - `C) Clear concept` — I know the core idea — genre, basic mechanics, maybe a pitch sentence — but haven't formalized it into documents yet. - `D) Existing work` — I already have design docs, prototypes, code, or significant planning done. I want to organize or continue the work. + - `E) Multiple ideas` — I have 2-4 rough game ideas and want to prototype them quickly before committing to a specific workflow. Wait for the user's selection. Do not proceed until they respond. @@ -161,11 +164,35 @@ The user needs creative exploration before anything else. - `/architecture-review` — bootstrap the TR requirement registry - `/gate-check` — validate readiness for next phase +#### If E: Multiple ideas to explore + +The user wants to explore several rough ideas before committing to a workflow. + +1. Acknowledge that prototyping before committing is a good approach +2. Briefly explain what `/explore` does (pre-workflow rapid prototyping — build throwaway prototypes in `prototypes/explore/`, produces lightweight `REPORT.md` per idea, no workflow commitment, 1-2 days per idea) +3. Recommend running `/explore [idea-name]` for their first idea, then more for subsequent ideas +4. Show the recommended path: + + **Pre-workflow exploration:** + - `/explore idea-a` — build a prototype for the first idea (1-2 days) + - `/explore idea-b` — build a prototype for the second idea (1-2 days) + - `/explore idea-c` — (optional) build a prototype for the third idea + - Review reports in `prototypes/explore/*/REPORT.md` + - `/gate-check workflow-selection` — compare results and choose Hybrid or Full OCGS + +5. **Do NOT** ask about engine preferences, review modes, or any workflow-specific setup. The user is in pre-workflow exploration. + +6. Write `production/stage.txt` with value `exploration` so that `/help` and other skills know the project is in the exploration phase. Create the `production/` directory if it does not exist. + + This is the only file Path E writes. No `production/review-mode.txt` is created. + --- ## Phase 3b: Set Review Mode -Check if `production/review-mode.txt` already exists. +**If the user chose Path E (exploration)**: Skip this phase entirely. No review mode is needed for pre-workflow exploration. Proceed directly to Phase 4. + +**For all other paths**: Check if `production/review-mode.txt` already exists. **If it exists**: Read it and show the current mode — "Review mode is set to `[current]`." — then proceed to Phase 4. Do not ask again. @@ -212,6 +239,8 @@ Verdict: **COMPLETE** — user oriented and handed off to next step. - **User picks D but project is empty**: Gently redirect — "It looks like the project is a fresh template with no artifacts yet. Would Path A or B be a better fit?" - **User picks A but project has code**: Mention what you found — "I noticed there's already code in `src/`. Did you mean to pick D (existing work)?" - **User is returning (engine configured, concept exists)**: Skip onboarding entirely — "It looks like you're already set up! Your engine is [X] and you have a game concept at `design/gdd/game-concept.md`. Review mode: `[read from production/review-mode.txt, or 'lean (default)' if missing]`. Want to pick up where you left off? Try `/sprint-plan` or just tell me what you'd like to work on." +- **User is returning with exploration stage** (`production/stage.txt` reads `exploration`): Skip full onboarding — "It looks like you're exploring game ideas! You have [N] explore prototypes in `prototypes/explore/`. Want to run `/explore [another-idea]`, or are you ready to run `/gate-check workflow-selection` to choose a workflow?" +- **User picks E but has existing project artifacts**: Detect if `production/stage.txt` already has a non-exploration value. If so, warn: "It looks like you already have a project in the [phase] phase. Did you mean to continue that work (Path D) instead?" - **User doesn't fit any option**: Let them describe their situation in their own words and adapt. --- From 2cf8c74508a86f25884098d7eb83611e84c32a3c Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Tue, 5 May 2026 19:01:44 +0200 Subject: [PATCH 03/21] feat: Workflow Selection Gate for Hybrid vs Full OCGS (#43) Adds /gate-check workflow-selection as a pre-workflow gate that helps developers choose between Hybrid and Full OCGS workflows after exploring multiple game ideas with /explore. - New Workflow Selection gate definition with 5-question decision interview - Scoring logic (0-15) maps to hybrid / hybrid-with-upgrade / full - Dual-file write: production/workflow-mode.txt + production/stage.txt - Skips director panel and chain-of-verification (pre-workflow, human-driven) - Exploration stage added to production stages (stage 0) - Auto-detect exploration maps to workflow-selection gate - Closing widget with workflow-specific next steps --- .opencode/skills/gate-check/SKILL.md | 190 ++++++++++++++++++++++++--- 1 file changed, 175 insertions(+), 15 deletions(-) diff --git a/.opencode/skills/gate-check/SKILL.md b/.opencode/skills/gate-check/SKILL.md index c3a8577..476ad0a 100644 --- a/.opencode/skills/gate-check/SKILL.md +++ b/.opencode/skills/gate-check/SKILL.md @@ -1,7 +1,7 @@ --- name: gate-check description: "Validate readiness to advance between development phases. Produces a PASS/CONCERNS/FAIL verdict with specific blockers and required artifacts. Use when user says 'are we ready to move to X', 'can we advance to production', 'check if we can start the next phase', 'pass the gate'." -argument-hint: "[target-phase: systems-design | technical-setup | pre-production | production | polish | release] [--review full|lean|solo]" +argument-hint: "[target-phase: workflow-selection | systems-design | technical-setup | pre-production | production | polish | release] [--review full|lean|solo]" user-invocable: true allowed-tools: Read, Glob, Grep, Bash, Write, Task, question model: opencode-go/kimi-k2.6 @@ -19,6 +19,7 @@ This skill is prescriptive ("are we ready to advance?" with a formal verdict). The project progresses through these stages: +0. **Exploration** — Pre-workflow: rapid prototyping multiple ideas (/explore) 1. **Concept** — Brainstorming, game concept document 2. **Systems Design** — Mapping systems, writing GDDs 3. **Technical Setup** — Engine config, architecture decisions @@ -27,8 +28,9 @@ The project progresses through these stages: 6. **Polish** — Performance, playtesting, bug fixing 7. **Release** — Launch prep, certification -**When a gate passes**, write the new stage name to `production/stage.txt` -(single line, e.g. `Production`). This updates the status line immediately. +**Special gate: `workflow-selection`** — Only valid from the Exploration stage. +When it passes, it sets both `production/workflow-mode.txt` (hybrid or full) and +`production/stage.txt` (Concept). See the Workflow Selection gate below. --- @@ -44,6 +46,7 @@ Also resolve the review mode (once, store for all gate spawns this run): Note: in `solo` mode, director spawns (CD-PHASE-GATE, TD-PHASE-GATE, PR-PHASE-GATE, AD-PHASE-GATE) are skipped — gate-check becomes artifact-existence checks only. In `lean` mode, all four directors still run (phase gates are the purpose of lean mode). - **With argument**: `/gate-check production` — validate readiness for that specific phase + `/gate-check workflow-selection` — run workflow selection (only valid from exploration stage) - **No argument**: Auto-detect current stage using the same heuristics as `/project-stage-detect`, then **confirm with the user before running**: @@ -51,14 +54,138 @@ Note: in `solo` mode, director spawns (CD-PHASE-GATE, TD-PHASE-GATE, PR-PHASE-GA - Prompt: "Detected stage: **[current stage]**. Running gate for [Current] → [Next] transition. Is this correct?" - Options: - `[A] Yes — run this gate` - - `[B] No — pick a different gate` (if selected, show a second widget listing all gate options: Concept → Systems Design, Systems Design → Technical Setup, Technical Setup → Pre-Production, Pre-Production → Production, Production → Polish, Polish → Release) - - Do not skip this confirmation step when no argument is provided. + - `[B] No — pick a different gate` (if selected, show a second widget listing all gate options: Workflow Selection, Concept → Systems Design, Systems Design → Technical Setup, Technical Setup → Pre-Production, Pre-Production → Production, Production → Polish, Polish → Release) + + **Special case — exploration stage**: If auto-detect returns `exploration`, the only valid + gate is `workflow-selection`. Skip the confirmation widget and proceed directly to the + Workflow Selection gate. --- ## 2. Phase Gate Definitions +### Gate: Workflow Selection (Exploration → Hybrid or Full) + +This is a **pre-workflow gate**. It does not validate artifacts — it helps the user +decide which development workflow fits their project after prototyping ideas with +`/explore`. Unlike all other gates, this gate writes TWO files on PASS: +`production/workflow-mode.txt` and `production/stage.txt`. + +**Run this when:** `production/stage.txt` reads `exploration`, or explicitly with +`/gate-check workflow-selection`. + +**Required Artifacts:** +- [ ] At least 1 prototype report in `prototypes/explore/*/REPORT.md` (or in + `prototypes/*/REPORT.md` from earlier prototyping) +- [ ] Reports have a clear verdict (PROMISING / NEEDS_WORK / NOT_VIABLE / TIMEOUT) + +### Decision Interview + +Skip artifact scanning — this gate is human-driven. Use `question` to ask +each question. Present one at a time, tally the score, then recommend. Record +the user's answers but do not write them to a file — the output is the +recommendation. + +**Question 1 — Team size:** +- **Prompt**: "How many people are working on this project?" +- **Options**: + - `Solo` — Just me (score: 0) + - `Small team` — 2-5 people (score: 1) + - `Medium team` — 6-10 people (score: 2) + - `Large team` — 10+ people (score: 3) + +**Question 2 — Timeline:** +- **Prompt**: "What's your target timeline to a shippable game?" +- **Options**: + - `Short` — Under 3 months (score: 0) + - `Medium` — 3-6 months (score: 1) + - `Long` — 6-12 months (score: 2) + - `Extended` — 12+ months (score: 3) + +**Question 3 — Design clarity:** +- **Prompt**: "How well-defined is your game design at this point?" +- **Options**: + - `Rough concept` — A theme and a mechanic, but no details (score: 0) + - `Some systems` — Core loop and 2-3 major systems sketched (score: 1) + - `Mostly designed` — Core systems, economy, and progression mapped (score: 2) + - `Fully documented` — Full GDDs ready to build from (score: 3) + +**Question 4 — External requirements:** +- **Prompt**: "Do you have publisher, investor, or platform requirements?" +- **Options**: + - `None` — Self-funded, no external obligations (score: 0) + - `Informal` — A publisher is interested but no contract yet (score: 1) + - `Contractual` — Signed deal with milestone deliverables (score: 2) + - `Multi-platform` — Strict cert requirements across platforms (score: 3) + +**Question 5 — Team experience:** +- **Prompt**: "What's your team's experience level with shipping games?" +- **Options**: + - `First game` — No shipped titles (score: 0) + - `Small games` — Shipped jam games or small commercial titles (score: 1) + - `Experienced` — Shipped 1-3 commercial titles (score: 2) + - `Veteran` — Shipped 3+ commercial titles (score: 3) + +### Scoring + +After all 5 questions, calculate the total score (0-15): + +- **Score 0-5**: Recommend **Hybrid workflow** — lightweight discovery phase, + then production with reduced agent roster. Best for small teams, unknown + designs, and short timelines. +- **Score 6-10**: Recommend **Hybrid with upgrade path** — start with Hybrid, + but be ready to upgrade to Full OCGS as scope grows. Set workflow-mode to + `hybrid` but note the upgrade triggers. +- **Score 11-15**: Recommend **Full OCGS workflow** — formal GDDs, ADRs, + full quality gates, and the complete agent roster. Best for larger teams, + funded projects, and long timelines. + +Present the recommendation: + +``` +## Workflow Selection Result + +**Score**: [N]/15 + +**Recommended workflow**: [Hybrid / Hybrid with upgrade path / Full OCGS] + +**Reasoning**: +- Team size ([answer]) → weight toward [workflow] +- Timeline ([answer]) → weight toward [workflow] +- Design clarity ([answer]) → weight toward [workflow] +- External requirements ([answer]) → weight toward [workflow] +- Team experience ([answer]) → weight toward [workflow] + +### Next Step +- **If Hybrid**: Begin your concept document with `/brainstorm` or jump straight + into `/hybrid-prototype` with your winning idea. +- **If Full OCGS**: Run `/brainstorm [winning-idea]` to formalize your concept, + then `/setup-engine` to configure the engine. +``` + +### User Confirmation + +Use `question` to confirm: + +- **Prompt**: "**Recommended: [Hybrid / Full OCGS]**. Does this match your intuition?" +- **Options**: + - `Yes — proceed with [recommended workflow]` + - `No — I prefer the [other workflow] instead` + - `Not sure yet — I want to explore more ideas first` + +### Apply the Decision + +When the user confirms (Yes or No), write both files: + +1. **`production/workflow-mode.txt`** — write `hybrid` or `full` (single line) +2. **`production/stage.txt`** — write `Concept` (single line) + +Always ask before writing: "May I update `production/workflow-mode.txt` to +`[workflow]` and `production/stage.txt` to `Concept`?" + +If "Not sure yet", do not write anything. Advise: "Run `/explore [next-idea]` +to prototype more ideas, then return here." + ### Gate: Concept → Systems Design **Required Artifacts:** @@ -295,7 +422,14 @@ For items that can't be automatically verified, **ask the user**: ## 4b. Director Panel Assessment -Before generating the final verdict, spawn all four directors as **parallel subagents** via Task using the parallel gate protocol from `.opencode/docs/director-gates.md`. Issue all four Task calls simultaneously — do not wait for one before starting the next. +**Skip for Workflow Selection gate**: This gate is pre-workflow — no directors +are assigned yet. Proceed directly to the verdict output with only the artifact +and decision interview results. + +**For all other gates**: Before generating the final verdict, spawn all four +directors as **parallel subagents** via Task using the parallel gate protocol +from `.opencode/docs/director-gates.md`. Issue all four Task calls +simultaneously — do not wait for one before starting the next. **Spawn in parallel:** @@ -368,7 +502,12 @@ Art Director: [READY / CONCERNS / NOT READY] ## 5a. Chain-of-Verification -After drafting the verdict in Phase 5, challenge it before finalising. +**Skip for Workflow Selection gate**: The decision interview is human-driven +and scored transparently. No artifact quality checks need verification — the +score and recommendation are self-evident. Proceed directly to the verdict. + +**For all other gates**: After drafting the verdict in Phase 5, challenge it +before finalising. **Step 1 — Generate 5 challenge questions** designed to disprove the verdict: @@ -410,15 +549,20 @@ Do NOT reference the draft verdict text — re-check specific files or ask the u When the verdict is **PASS** and the user confirms they want to advance: -1. Write the new stage name to `production/stage.txt` (single line, no trailing newline) -2. This immediately updates the status line for all future sessions +- **For Workflow Selection gate**: Write TWO files. + `production/workflow-mode.txt` with the selected workflow (`hybrid` or `full`), + and `production/stage.txt` with `Concept`. + ```bash + echo -n "[hybrid|full]" > production/workflow-mode.txt + echo -n "Concept" > production/stage.txt + ``` -Example: if passing the "Pre-Production → Production" gate: -```bash -echo -n "Production" > production/stage.txt -``` +- **For all other gates**: Write the new stage name to `production/stage.txt` + (single line, no trailing newline). -**Always ask before writing**: "Gate passed. May I update `production/stage.txt` to 'Production'?" +Always ask before writing — specify both files for workflow-selection: +- "Gate passed. May I update `production/stage.txt` to 'Production'?" +- "Gate passed. May I set `production/workflow-mode.txt` to 'hybrid' and `production/stage.txt` to 'Concept'?" --- @@ -428,6 +572,18 @@ After the verdict is presented and any stage.txt update is complete, close with **Tailor the options to the gate that just ran:** +For **workflow-selection PASS**: +``` +Gate passed. What would you like to do next? + +[If hybrid] [A] Run /brainstorm [winning-idea] — formalize your concept + [B] Run /hybrid-prototype [winning-idea] — jump straight into prototyping + [C] Stop here for this session +[If full] [A] Run /brainstorm [winning-idea] — formalize your concept + [B] Run /setup-engine — choose and configure your engine + [C] Stop here for this session +``` + For **systems-design PASS**: ``` Gate passed. What would you like to do next? @@ -454,6 +610,10 @@ For all other gates, offer the two most logical next steps for that phase plus " Based on the verdict, suggest specific next steps: +- **No explore prototypes yet?** → `/explore [idea-name]` to prototype ideas before workflow selection +- **Workflow not yet selected?** → `/gate-check workflow-selection` to choose Hybrid or Full OCGS +- **Selected Hybrid but no concept?** → `/brainstorm [winning-idea]` to formalize, then `/hybrid-prototype` to build +- **Selected Full OCGS but no engine?** → `/setup-engine [engine-name]` to configure the engine - **No art bible?** → `/art-bible` to create the visual identity specification - **Art bible exists but no asset specs?** → `/asset-spec system:[name]` to generate per-asset visual specs and generation prompts from approved GDDs - **No game concept?** → `/brainstorm` to create one From 44ffbf71c2161d949666653c12452822376e9962 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Tue, 5 May 2026 19:03:14 +0200 Subject: [PATCH 04/21] docs: artifact promotion rules for prototype-to-production transitions (#44) Creates docs/workflow-transitions.md covering all 4 transition paths between development modes, with clear promotion rules per artifact type. - Path A: Explore -> Hybrid (informal concept, archive explore) - Path B: Explore -> Full OCGS (formal GDDs, /setup-engine) - Path C: Hybrid Discovery -> Full OCGS (retrofit GDDs, write ADRs) - Path D: Full OCGS Prototype -> Production (promote findings to GDDs) - Quick reference table: what promotes vs. what gets rewritten - Core principle: code never promotes, design insights always promote - Cross-referenced from hybrid-workflow.md Migration Path section - Cross-referenced from WORKFLOW-GUIDE.md Path E description --- docs/WORKFLOW-GUIDE.md | 3 +- docs/hybrid-workflow.md | 4 + docs/workflow-transitions.md | 273 +++++++++++++++++++++++++++++++++++ 3 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 docs/workflow-transitions.md diff --git a/docs/WORKFLOW-GUIDE.md b/docs/WORKFLOW-GUIDE.md index 0d9cc0a..2a8d2b6 100644 --- a/docs/WORKFLOW-GUIDE.md +++ b/docs/WORKFLOW-GUIDE.md @@ -65,7 +65,8 @@ This guided onboarding asks where you are and routes you to the right phase: then `/adopt` for brownfield migration - **Path E** -- Multiple ideas to explore: routes to `/explore` for rapid pre-workflow prototyping, then `/gate-check workflow-selection` to choose - Hybrid vs. Full OCGS based on results + Hybrid vs. Full OCGS based on results. See [Workflow Transitions Guide](workflow-transitions.md) + for artifact promotion rules when moving from exploration into either workflow. ### Step 3: Verify Hooks Are Working diff --git a/docs/hybrid-workflow.md b/docs/hybrid-workflow.md index 350397a..265eaac 100644 --- a/docs/hybrid-workflow.md +++ b/docs/hybrid-workflow.md @@ -225,6 +225,10 @@ If a project starts with the hybrid workflow and later needs the full OCGS frame 5. **Switch to `src/`** with full coding standards. 6. **Enable all quality gates** from the full framework. +For the full step-by-step guide including artifact promotion rules and what +to keep vs. rewrite, see [Path C: Hybrid Discovery → Full OCGS](workflow-transitions.md#path-c-hybrid-discovery--full-ocgs) +in the Workflow Transition Guide. + --- ## Notes diff --git a/docs/workflow-transitions.md b/docs/workflow-transitions.md new file mode 100644 index 0000000..bfa7bb3 --- /dev/null +++ b/docs/workflow-transitions.md @@ -0,0 +1,273 @@ +# Workflow Transition Guide + +This document defines how to transition between development modes in the OCGS +framework. It covers four paths: + +- **[Path A](#path-a-explore--hybrid)**: Pre-workflow `/explore` → Hybrid workflow +- **[Path B](#path-b-explore--full-ocgs)**: Pre-workflow `/explore` → Full OCGS +- **[Path C](#path-c-hybrid-discovery--full-ocgs)**: Hybrid Discovery → Full OCGS +- **[Path D](#path-d-full-ocgs-prototype--production)**: Full OCGS `/prototype` → Production + +--- + +## Core Principle: Code Never Promotes + +**The number one rule across ALL transition paths:** + +> Prototype code is never refactored into production code. +> Production code never imports from prototype directories. + +This is not negotiable. Prototype code is written under relaxed standards: +hardcoded values, no error handling, no architecture. Moving it into production +creates technical debt that costs more to fix than a clean rewrite. Every path +below follows this rule. + +**What promotes:** +- Design insights and findings +- Balance data that was empirically validated +- Asset ideas (concept art, mood boards, placeholder specs) +- Acceptance criteria that were validated in playtesting + +**What gets rewritten from scratch:** +- All source code +- Scene/level files +- Configuration files (rewritten with production structure) +- Asset placeholders (replaced with production-quality assets) + +--- + +## Path A: Explore → Hybrid + +**Trigger**: `/gate-check workflow-selection` returns Hybrid recommendation +and user confirms. + +**Starting artifacts**: One or more reports in `prototypes/explore/*/REPORT.md` +with PROMISING verdicts. + +### Steps + +1. **Archive exploration prototypes** + ``` + prototypes/explore/ → prototypes/archive/explore/[date]/ + ``` + This preserves the explore work for reference without cluttering the + active prototype directory. + +2. **Promote the winning idea** + Create an informal concept document at `design/concept.md` capturing: + - The core question the winning prototype answered + - Why it was chosen over alternatives + - Key findings from the explore report + - Estimated production effort + + This is NOT a formal GDD — it is a lightweight concept document for the + Hybrid workflow's Discovery phase. + +3. **Enter Hybrid Discovery** + The Hybrid workflow starts with its Discovery phase. If the winning + prototype already answered the core mechanic question, you can: + - Skip to `/hybrid-prototype [winning-idea]` to build a playable + vertical slice + - Or go directly to mapping systems with `/map-systems` + - Or begin writing a GDD with `/design-system` + +4. **Reference explore findings** + Include links to the archived explore reports in any GDD or decision + document. The explore `REPORT.md` findings become the "Prior Art" that + informs the GDD's rules and tuning knobs. + +### Artifact Map + +| Artifact | Action | Destination | +|----------|--------|-------------| +| `prototypes/explore/[idea]/REPORT.md` | Archive | `prototypes/archive/explore/[date]/[idea]/REPORT.md` | +| `prototypes/explore/[idea]/code/` | Archive (never reuse) | `prototypes/archive/explore/[date]/[idea]/code/` | +| Winning idea design insight | Promote | `design/concept.md` | +| Balance/config data | Evaluate | Promote if proven, rewrite if uncertain | +| Placeholder assets | Discard | Replace with new assets in `assets/` | + +--- + +## Path B: Explore → Full OCGS + +**Trigger**: `/gate-check workflow-selection` returns Full OCGS recommendation +and user confirms. + +**Starting artifacts**: One or more reports in `prototypes/explore/*/REPORT.md` +with PROMISING verdicts. + +### Steps + +1. **Archive exploration prototypes** (same as Path A) + ``` + prototypes/explore/ → prototypes/archive/explore/[date]/ + ``` + +2. **Formalize the concept** + Run `/brainstorm [winning-idea]` to produce a formal game concept document + at `design/gdd/game-concept.md` with full MDA analysis, pillars, core loop, + and player journey. + + The explore findings feed directly into the brainstorm — the core question + has already been answered, so the concept document can be more specific + than a typical brainstorm output. + +3. **Set up the engine** + Run `/setup-engine [engine]` to pin the engine version, generate technical + preferences, and populate engine reference docs. + +4. **Design the systems** + Run `/map-systems` to enumerate all systems, then `/design-system` per + system to write formal 8-section GDDs. The explore prototype's findings + directly inform each GDD's rules, formulas, and tuning knobs. + +5. **Reference explore findings** + Embed links to the archived explore `REPORT.md` files in the GDDs. For + example, in the combat system GDD's "Tuning Knobs" section: "Prototype + testing showed that damage values above 50 felt too punishing — validated + range: 10-40." + +### Artifact Map + +| Artifact | Action | Destination | +|----------|--------|-------------| +| `prototypes/explore/[idea]/REPORT.md` | Archive, cross-reference | `prototypes/archive/explore/[date]/[idea]/REPORT.md` | +| `prototypes/explore/[idea]/code/` | Archive (never reuse) | `prototypes/archive/explore/[date]/[idea]/code/` | +| Winning idea | Formalize | `design/gdd/game-concept.md` (via `/brainstorm`) | +| Prototype findings | Embed in GDDs | `design/gdd/[system].md` (Tuning Knobs, Edge Cases sections) | +| Engine (none yet) | Set up | Via `/setup-engine` | + +--- + +## Path C: Hybrid Discovery → Full OCGS + +**Trigger**: Any of the conditions in [When to Switch to Full OCGS](hybrid-workflow.md#when-to-switch-to-full-ocgs) +become true: team grows beyond 5, timeline exceeds 6 months, publisher +requirements, or need for live ops / analytics / multiplayer. + +**Starting artifacts**: Hybrid Discovery artifacts — informal concept doc, +prototypes in `prototypes/`, lightweight specs in `design/quick-specs/`. + +### Steps + +1. **Archive Discovery prototypes** + ``` + prototypes/[discovery-proto]/ → prototypes/archive/discovery/[date]/ + ``` + +2. **Promote surviving designs to formal GDDs** + For each system that was prototyped and validated: + - Run `/design-system retrofit design/gdd/[system].md` to add the + required 8 sections to any informal spec or bullet-point doc + - Or run `/design-system [system]` from scratch if no document exists + - Embed prototype findings (especially tuning knobs and edge cases) + +3. **Write ADRs for proven systems** + Run `/architecture-decision` for each architectural choice that was + implicitly made during prototyping: + - Scene/state management approach + - Data flow between systems + - Save/load strategy + - Input handling architecture + +4. **Recruit additional agents** + Expand from the 4-role Hybrid roster to the full agent hierarchy. + See [Slimmed Agent Hierarchy](hybrid-workflow.md#slimmed-agent-hierarchy-49--10) + for which roles to add first. + +5. **Switch to `src/` with full coding standards** + All new code goes into `src/` with doc comments, dependency injection, + unit tests, and no hardcoded values. Do not move prototype code into + `src/` — rewrite from scratch. + +6. **Enable all quality gates** + - `/test-setup` to scaffold the test framework + - `/qa-plan` to generate QA plans + - `/gate-check` at every phase transition + - Enable pre-commit hooks for validation + +### Artifact Map + +| Artifact | Action | Destination | +|----------|--------|-------------| +| `prototypes/[proto]/` | Archive | `prototypes/archive/discovery/[date]/` | +| `design/concept.md` (informal) | Promote | `design/gdd/game-concept.md` (formalize) | +| `design/quick-specs/*.md` | Retrofit | `design/gdd/[system].md` (via `/design-system retrofit`) | +| Prototype code | Archive (never reuse) | `prototypes/archive/discovery/[date]/` | +| Implicit architecture decisions | Document | `docs/architecture/adr-[*].md` (via `/architecture-decision`) | + +--- + +## Path D: Full OCGS Prototype → Production + +**Trigger**: A `/prototype` within the Full OCGS Phase 4 (Pre-Production) +returns a PROCEED verdict and the creative director approves. + +**Starting artifacts**: `prototypes/[mechanic-name]/` with a `REPORT.md` +and throwaway code. + +### Steps + +1. **Archive the prototype** + ``` + prototypes/[mechanic-name]/ → prototypes/archive/[date]-[mechanic-name]/ + ``` + +2. **Update the GDD with prototype findings** + Open the relevant system GDD at `design/gdd/[system].md` and add: + - Updated tuning knobs and safe ranges based on prototype data + - Edge cases discovered during prototyping + - Acceptance criteria that were validated + - Any formula adjustments found necessary + +3. **Create or update ADRs** + If the prototype revealed architectural requirements: + - Run `/architecture-decision` to record the decision + - Or update an existing ADR if the decision refines a previous one + +4. **Create stories from prototype insights** + Run `/create-stories [epic-slug]` with the prototype findings embedded + in the story acceptance criteria. The prototype report's "If Proceeding" + section is the direct input for implementation requirements. + +5. **Implement from scratch in `src/`** + The production implementation is written in `src/` with full coding + standards. The prototype code is reference only — do not copy, refactor, + or import from it. + +### Artifact Map + +| Artifact | Action | Destination | +|----------|--------|-------------| +| `prototypes/[mechanic]/REPORT.md` | Archive, cross-reference | `prototypes/archive/[date]-[mechanic]/REPORT.md` | +| `prototypes/[mechanic]/code/` | Archive (never reuse) | `prototypes/archive/[date]-[mechanic]/code/` | +| Updated tuning ranges | Promote to GDD | `design/gdd/[system].md` (Tuning Knobs section) | +| Discovered edge cases | Promote to GDD | `design/gdd/[system].md` (Edge Cases section) | +| Architectural requirements | Promote to ADR | `docs/architecture/adr-[*].md` | +| Implementation scope | Promote to stories | `production/epics/[slug]/story-[*].md` | + +--- + +## Quick Reference + +| What | Promote? | Rule | +|------|----------|------| +| Source code | Never | Rewrite from scratch | +| Scenes / levels | Never | Rebuild from scratch | +| Placeholder assets | Never | Replace with production assets | +| Design insights | Always | Merge into GDDs or concept docs | +| Tuning data | Evaluate | Promote if empirically validated; retest if uncertain | +| Edge cases | Always | Document in GDD Edge Cases section | +| Acceptance criteria | Always | Include in story files | +| Architecture patterns | Evaluate | Document via ADR if proven; revisit if uncertain | +| Config files | Never | Recreate with production structure | +| Research notes | Always | Archive as-is for reference | + +--- + +## See Also + +- [`docs/hybrid-workflow.md`](hybrid-workflow.md) — Hybrid Discovery-Production workflow +- [`docs/WORKFLOW-GUIDE.md`](WORKFLOW-GUIDE.md) — Full OCGS 7-phase workflow +- `.opencode/skills/explore/SKILL.md` — Pre-workflow prototyping skill +- `.opencode/skills/gate-check/SKILL.md` — Workflow Selection gate \ No newline at end of file From cc6a03657fc6507d63d11516b9c2f372881a2308 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Tue, 5 May 2026 19:04:54 +0200 Subject: [PATCH 05/21] docs: decision criteria and case studies for Hybrid vs Full OCGS (#45) Adds three real-world workflow selection case studies and cross-references from the hybrid workflow documentation. - docs/examples/workflow-selection-case-studies.md: - Case Study 1: Solo dev, first game, 2-month timeline -> Hybrid - Case Study 2: Funded team of 8, 12-month timeline -> Hybrid with upgrade - Case Study 3: Solo-to-team scope recovery -> retrospective selection - Upgrade trigger reference table with scoring guidance - docs/hybrid-workflow.md: cross-references to case studies - docs/hybrid-workflow.md: expanded upgrade triggers with link to detail --- .../workflow-selection-case-studies.md | 221 ++++++++++++++++++ docs/hybrid-workflow.md | 10 +- 2 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 docs/examples/workflow-selection-case-studies.md diff --git a/docs/examples/workflow-selection-case-studies.md b/docs/examples/workflow-selection-case-studies.md new file mode 100644 index 0000000..a58aa6c --- /dev/null +++ b/docs/examples/workflow-selection-case-studies.md @@ -0,0 +1,221 @@ +# Workflow Selection Case Studies + +Three real-world scenarios demonstrating how the OCGS workflow selection +process works in practice. + +--- + +## Case Study 1: Solo Dev, First Game, 2-Month Timeline + +**Developer**: Liam, solo developer +**Experience**: First commercial game, completed 2 game jams +**Timeline**: 2 months (summer break) +**Budget**: Self-funded, $500 +**Ideas**: 3 prototypes explored via `/explore` + +### Exploration Phase + +Liam spent 2 weeks exploring 3 ideas: + +``` +/explore "a platformer where you rewind time" + → REPORT.md: PROMISING — core mechanic feels great, but level design needs work + → Time spent: 2 days + +/explore "a farming sim with real-time crop growth" + → REPORT.md: NOT_VIABLE — too complex for solo dev in 2 months + → Time spent: 1.5 days + +/explore "a bullet hell with rhythm game elements" + → REPORT.md: NEEDS_WORK — fun concept but controls feel unresponsive + → Time spent: 2 days +``` + +### Workflow Selection + +``` +/gate-check workflow-selection + → Team size: Solo (0) + → Timeline: Short — under 3 months (0) + → Design clarity: Rough concept (0) + → External requirements: None (0) + → Experience: Small games — jams only (1) + → Score: 1/15 → **Hybrid** +``` + +### Result + +**Chosen workflow**: Hybrid +**Rationale**: Solo dev, short timeline, no external requirements. Full OCGS +would burn half his timeline in process overhead. + +**Liam's path:** +1. `/brainstorm "time-rewind platformer"` — formalize the concept (1 day) +2. `/hybrid-prototype "time-rewind platformer"` — build vertical slice (3 days) +3. Playtest with 3 friends — fun validated +4. `/gate-check` → enter Hybrid Production mode +5. Build core game in 4 weeks with `gameplay-programmer` and `game-designer` +6. Week 7-8: polish, balance, release + +**Outcome**: Shipped on itch.io at week 8. $200 revenue. Liam learned that +the time-rewind mechanic is worth building a bigger game around. + +--- + +## Case Study 2: Funded Team of 8, 12-Month Timeline + +**Team**: Stellar Forge Games, 8 people +**Experience**: 3 shipped titles between them +**Timeline**: 12 months +**Budget**: $150,000 (publisher-funded) +**Ideas**: 2 prototypes explored via `/explore` + +### Exploration Phase + +The team spent 3 weeks exploring 2 concepts: + +``` +/explore "co-op spaceship management with crew roles" + → REPORT.md: PROMISING — strong emergent gameplay, clear roles + → Time spent: 3 days + +/explore "single-player space trading with combat" + → REPORT.md: PROMISING — solid gameplay loop but less unique + → Time spent: 2 days +``` + +### Workflow Selection + +``` +/gate-check workflow-selection + → Team size: Medium team — 6-10 (2) + → Timeline: Long — 6-12 months (2) + → Design clarity: Some systems — core loop + 2-3 systems sketched (1) + → External requirements: Contractual — signed milestone deliverables (2) + → Experience: Experienced — shipped 1-3 commercial titles (2) + → Score: 9/15 → **Hybrid with upgrade path** +``` + +### Result + +**Chosen workflow**: Hybrid (with upgrade path to Full OCGS) +**Rationale**: Score is in the mid-range. The team size and publisher +requirements push toward Full, but the design isn't fully documented yet. +Start Hybrid, formalize quickly, then upgrade. + +**The team's path:** +1. `/brainstorm "co-op spaceship management"` — formalize concept (2 days) +2. Write GDDs for core systems: ship management, crew roles, missions (2 weeks) +3. Build vertical slice in 6 weeks via `/hybrid-prototype` +4. Publisher signs off on vertical slice — milestone achieved +5. Upgrade to Full OCGS at month 3: + - `/architecture-decision` × 6 (networking, save/load, state management, etc.) + - `/create-control-manifest` for programmer rules + - Enable full QA pipeline +6. Production sprints (months 4-10) with `/team-combat`, `/team-narrative`, etc. +7. Polish months 11-12 with `/perf-profile`, playtesting, localization + +**Outcome**: On track for milestone delivery. The upgrade from Hybrid to Full +at month 3 was smooth because the team had already documented GDDs and ADRs. +The publisher receives monthly milestone reports with `/milestone-review`. + +--- + +## Case Study 3: Solo-to-Team, Scope Creep, 4-Month Timeline + +**Developer**: Priya, solo founder → building a team +**Experience**: Shipped 2 commercial mobile games +**Timeline**: Originally 4 months, scope inflated to 8 months +**Ideas**: 1 concept, started building immediately without exploration + +### The Problem + +Priya started building her game directly — no `/explore`, no workflow selection. +By month 3, she had: +- A partially working prototype in `src/` (mixed prototype and production code) +- 3 friends offering to help (team growing to 4) +- An exploding scope (originally a simple puzzle game, now with RPG systems) +- No GDDs, no ADRs, no sprint planning + +### Workflow Selection (Retrospective) + +If Priya had run `/gate-check workflow-selection` before starting: + +``` +/gate-check workflow-selection + → Team size at start: Solo (0), now growing to 4 + → Timeline: Originally 4mo, now 8mo + → Design clarity: Rough concept — "puzzle RPG" (0) + → External requirements: None (0) + → Experience: Experienced — 2 shipped titles (2) + → Score if run at start: 2/15 → **Hybrid** + → Score if run now with team: Would signal upgrade needed +``` + +### Recovery Path + +Priya runs `/gate-check workflow-selection` at month 3 (current state): + +``` + → Team size: Small team — 2-5 (1) + → Timeline: Medium — 3-6 months, trending to 8 (2) + → Design clarity: Some systems — core + 2 RPG systems (1) + → External requirements: None (0) + → Experience: Experienced — 2 shipped (2) + → Score: 6/15 → **Hybrid with upgrade path** +``` + +**Recommended path:** +1. **Stop coding.** Run `/project-stage-detect` + `/adopt` to assess what exists +2. **Separate prototype code from production code**: + - Move `src/` code to `prototypes/archive/mvp/` + - Start fresh `src/` with proper structure +3. **Formalize the design**: + - `/brainstorm "puzzle RPG with crafting"` — get pillars down + - `/design-system puzzle-core` — write a proper GDD + - `/design-system crafting` — optional, defer if not MVP +4. **Upgrade to Full OCGS** (score 6 and growing team signal this): + - `/create-architecture` — data flow between puzzle and RPG systems + - `/architecture-decision` × 3-4 core decisions + - `/create-control-manifest` for the new team members +5. **Onboard the team**: + - `/onboard gameplay-programmer` — new team member orientation + - `/sprint-plan new` — first sprint with realistic scope + +**Upgrade trigger**: Team growing beyond solo, scope inflating, timeline +extending. The workflow selection at month 3 correctly identifies the need +for more structure, even though it started as a solo Hybrid project. + +### Lessons + +- **Prototype before committing**: Even experienced devs benefit from `/explore` +- **Re-run workflow selection when conditions change**: Team size, timeline, + and scope are all dynamic +- **It's never too late**: Priya caught the problem at month 3 instead of + month 8. The recovery path is clear even mid-project. + +--- + +## Upgrade Trigger Reference + +When any of these conditions become true, re-run `/gate-check workflow-selection` +to reassess: + +| Trigger | What changed | New recommendation | +|---------|-------------|-------------------| +| Team grows from 1 → 3+ | Score +1 to +2 | Hybrid → Hybrid with upgrade | +| Team grows from 3 → 6+ | Score +1 to +2 | Hybrid → Full OCGS | +| Timeline extends past 6 months | Score +1 to +2 | Hybrid → Full OCGS | +| Publisher signs on | Score +2 | Hybrid → Full OCGS | +| Design scope doubles | Score +1 | Stay hybrid, but formalize | +| Need multiplayer or live ops | +1 per requirement | Push toward Full OCGS | +| First playtest fails | No score change | Rerun `/explore`, don't upgrade | +| Team consistently misses sprints | No score change | Upgrade to Full for process help | + +--- + +## See Also + +- `docs/hybrid-workflow.md` — Hybrid workflow overview and comparison +- `docs/workflow-transitions.md` — How to transition between workflows +- `.opencode/skills/gate-check/SKILL.md` — Workflow Selection gate implementation \ No newline at end of file diff --git a/docs/hybrid-workflow.md b/docs/hybrid-workflow.md index 350397a..fdb8fce 100644 --- a/docs/hybrid-workflow.md +++ b/docs/hybrid-workflow.md @@ -10,6 +10,10 @@ This document defines a pragmatic hybrid workflow that balances **creative agili **Not sure which workflow to use?** Run `/explore` to rapidly prototype 2-4 ideas with zero workflow commitment, then use `/gate-check workflow-selection` to choose the right workflow based on your results. See [Pre-Workflow Exploration](#pre-workflow-exploration) below. +**See real-world examples**: The [Workflow Selection Case Studies](examples/workflow-selection-case-studies.md) +document walks through three scenarios — solo dev, funded team, and scope +recovery — showing how the workflow selection process works in practice. + --- ## Two-Phase Model @@ -142,13 +146,17 @@ A new skill/command that shortcuts the path to a playable prototype: ## When to Switch to Full OCGS -Switch back to the **full 49-agent framework** if any of these become true: +Switch to the **full 49-agent framework** if any of these become true: - Team grows beyond 5 people - Project timeline exceeds 6 months - Multiple features need parallel development - You need live ops, analytics, or multiplayer - Funding/publisher requires formal process +For a detailed upgrade trigger reference with scoring and case studies, +see [Upgrade Trigger Reference](examples/workflow-selection-case-studies.md#upgrade-trigger-reference) +in the Workflow Selection Case Studies. + --- ## Comparison From c12403de722a3fbac387af18741d341c38ad8150 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Tue, 5 May 2026 21:03:59 +0200 Subject: [PATCH 06/21] =?UTF-8?q?test:=20Workflow=20integrity=20test=20sui?= =?UTF-8?q?te=20=E2=80=94=20cross-references,=20paths,=20gates,=20invarian?= =?UTF-8?q?ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds automated static analysis for the OCGS workflow layer: - references.mjs: validates all /command refs, subagent_type refs, command→skill routing - paths.mjs: validates workflow chains (start→gate→path), stage definitions, doc refs - gates.mjs: validates gate-check artifact paths, transition docs, gate definitions - invariants.mjs: directory structure, frontmatter completeness, no stale placeholders - run-all.mjs: orchestrator for all 4 suites - CI: new validate-workflow job in agent-validation.yml Catches regressions like deleted commands still referenced by skills, inconsistent stage names across files, broken agent delegation refs, and orphan skills. --- .github/workflows/agent-validation.yml | 11 + tests/workflow/gates.mjs | 232 +++++++++++++++++++++ tests/workflow/invariants.mjs | 274 +++++++++++++++++++++++++ tests/workflow/paths.mjs | 179 ++++++++++++++++ tests/workflow/references.mjs | 225 ++++++++++++++++++++ tests/workflow/run-all.mjs | 63 ++++++ 6 files changed, 984 insertions(+) create mode 100644 tests/workflow/gates.mjs create mode 100644 tests/workflow/invariants.mjs create mode 100644 tests/workflow/paths.mjs create mode 100644 tests/workflow/references.mjs create mode 100644 tests/workflow/run-all.mjs diff --git a/.github/workflows/agent-validation.yml b/.github/workflows/agent-validation.yml index aa2b03b..499f77e 100644 --- a/.github/workflows/agent-validation.yml +++ b/.github/workflows/agent-validation.yml @@ -23,3 +23,14 @@ jobs: with: name: validation-report path: tests/agents/validation-report.md + + validate-workflow: + runs-on: ubuntu-latest + name: Workflow Integrity + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - name: Run workflow integrity tests + run: node tests/workflow/run-all.mjs diff --git a/tests/workflow/gates.mjs b/tests/workflow/gates.mjs new file mode 100644 index 0000000..98c4313 --- /dev/null +++ b/tests/workflow/gates.mjs @@ -0,0 +1,232 @@ +#!/usr/bin/env node + +import { readFileSync, existsSync } from 'fs'; +import { join, resolve, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const ROOT = resolve(__dirname, '..', '..'); + +const SKILLS_DIR = join(ROOT, '.opencode', 'skills'); + +function getSkillContent(name) { + const p = join(SKILLS_DIR, name, 'SKILL.md'); + if (!existsSync(p)) return null; + return readFileSync(p, 'utf-8'); +} + +const FILE_REF_RE = /`([\w./-]+\.\w+)`/g; +const DIR_REF_RE = /`([\w./-]+)\/`/g; + +let testCount = 0; +let passCount = 0; + +function run(name, fn) { + testCount++; + try { + fn(); + passCount++; + console.log(` ${'PASS'} ${name}`); + } catch (e) { + console.log(` ${'FAIL'} ${name}`); + console.error(` ${e.message}`); + } +} + +console.log('\n=== Gate Transition Validation ===\n'); + +const gate = getSkillContent('gate-check'); +run('G1: Gate-check skill exists', () => { + if (!gate) throw new Error('gate-check/SKILL.md not found'); +}); + +if (gate) { + { // G2: All checklist file references point to valid relative paths + const fileRefs = [...gate.matchAll(FILE_REF_RE)].map(m => m[1]); + const unique = [...new Set(fileRefs)]; + const knownMissing = new Set([ + 'docs/architecture/architecture-traceability.md', + 'docs/architecture/architecture.md', + 'docs/architecture/control-manifest.md', + 'design/gdd/game-concept.md', + 'design/gdd/game-pillars.md', + 'design/gdd/systems-index.md', + 'design/art/art-bible.md', + 'design/accessibility-requirements.md', + 'design/ux/hud.md', + 'design/ux/interaction-patterns.md', + 'design/player-journey.md', + 'docs/engine-reference/[engine]/deprecated-apis.md', + 'tests/unit/', + 'tests/integration/', + 'production/workflow-mode.txt', + 'production/stage.txt', + 'production/review-mode.txt', + 'production/qa/', + 'production/sprints/', + 'production/epics/', + 'production/playtests/', + 'production/session-logs/', + 'prototypes/explore/', + 'design/difficulty-curve.md', + '.opencode/docs/technical-preferences.md', + '.opencode/docs/director-gates.md', + '.github/workflows/tests.yml', + 'docs/consistency-failures.md', + ]); + const knownPlaceholder = new Set([ + 'docs/engine-reference/[engine]/', + ]); + const missingFiles = []; + for (const ref of unique) { + if (knownMissing.has(ref) || knownPlaceholder.has(ref)) continue; + if (ref.startsWith('[') && ref.endsWith(']')) continue; + if (ref.startsWith('`')) continue; + const path = join(ROOT, ref.replace(/[/\\]/g, '/')); + if (!existsSync(path)) { + if (ref.endsWith('/')) continue; + missingFiles.push(ref); + } + } + run('G2: Gate-check file references correspond to real project files', () => { + if (missingFiles.length > 0) { + throw new Error(`${missingFiles.length} files referenced but not found:\n ${missingFiles.join('\n ')}`); + } + }); + } + + { // G3: Stage transition names match skills directory names + const stageToSkill = { + 'exploration': 'explore', + 'Concept': 'brainstorm', + 'Systems Design': 'map-systems', + 'Technical Setup': 'setup-engine', + 'Pre-Production': 'prototype', + 'Production': 'dev-story', + 'Polish': 'perf-profile', + 'Release': 'release-checklist', + }; + const missing = []; + const expectedSkills = new Set(Object.values(stageToSkill)); + for (const skill of expectedSkills) { + const p = join(SKILLS_DIR, skill, 'SKILL.md'); + if (!existsSync(p)) missing.push(skill); + } + run('G3: Each stage gate has a corresponding skill directory', () => { + if (missing.length > 0) { + throw new Error(`Missing skill directories: ${missing.join(', ')}`); + } + }); + } + + { // G4: Director gate references found in gate-check content + const GATE_LABELS = /([A-Z]{2,3}-PHASE-GATE)/g; + const gates = [...gate.matchAll(GATE_LABELS)].map(m => m[1]); + const unique = [...new Set(gates)]; + run('G4: At least one director phase gate label is referenced', () => { + if (unique.length === 0) { + throw new Error('No director gate labels (e.g., CD-PHASE-GATE) found in gate-check content'); + } + }); + } + + { // G6: Base project directories exist (runtime artifact dirs are created by workflow) + const baseDirs = [ + 'production', + 'prototypes', + ]; + const runtimeDirs = [ + 'production/session-logs/', + 'production/sprints/', + 'production/epics/', + 'production/milestones/', + 'production/qa/', + 'production/qa/bugs/', + 'production/qa/evidence/', + 'production/playtests/', + 'production/gate-checks/', + 'prototypes/explore/', + ]; + const missing = baseDirs.filter(p => { + const full = join(ROOT, p.replace(/[/\\]/g, '/')); + return !existsSync(full); + }); + run('G6: Base project directories exist', () => { + if (missing.length > 0) { + throw new Error(`Missing base directories:\n ${missing.join('\n ')}`); + } + }); + const runtimeMissing = runtimeDirs.filter(p => !existsSync(join(ROOT, p.replace(/[/\\]/g, '/')))); + if (runtimeMissing.length > 0) { + console.warn(` Info: ${runtimeMissing.length} runtime directories not yet created (expected until workflow runs):`); + for (const d of runtimeMissing) console.warn(` - ${d}`); + } + } + + { // G7: Workflow mode options are consistent + const workflowModes = [...gate.matchAll(/production\/workflow-mode\.txt/g)]; + run('G7: Workflow mode output path is referenced', () => { + if (workflowModes.length === 0) { + throw new Error('No workflow-mode.txt references in gate-check'); + } + }); + } +} + +{ // G8: Hybrid workflow doc references match + const hybridDoc = join(ROOT, 'docs', 'hybrid-workflow.md'); + if (existsSync(hybridDoc)) { + const hybrid = readFileSync(hybridDoc, 'utf-8'); + const refs = [...hybrid.matchAll(/`\/([a-z][\w-]+)`/g)].map(m => m[1]); + const unique = [...new Set(refs)]; + const commandsDir = join(ROOT, '.opencode', 'commands'); + const commandNames = existsSync(commandsDir) + ? new Set(readdirSync(commandsDir).filter(f => f.endsWith('.md') && f !== 'README.md').map(f => f.replace('.md', ''))) + : new Set(); + const knownMissing = new Set([ + 'brainstorm', 'explore', 'gate-check', 'hybrid-prototype', 'art-bible', 'adopt', + ]); + const bad = unique.filter(r => !commandNames.has(r) && !knownMissing.has(r)); + run('G8: All /command references in hybrid-workflow.md exist', () => { + if (bad.length > 0) { + throw new Error(`Missing command files: ${bad.join(', ')}`); + } + }); + } else { + run('G8: All /command references in hybrid-workflow.md exist', () => { + throw new Error('docs/hybrid-workflow.md not found'); + }); + } +} + +{ // G9: Workflow transitions doc references format is consistent + const transitions = [ + join(ROOT, 'docs', 'workflow-transitions.md'), + join(ROOT, 'docs', 'examples', 'workflow-selection-case-studies.md'), + ]; + for (const doc of transitions) { + const name = doc.split(/[/\\]/).slice(-2).join('/'); + if (existsSync(doc)) { + const content = readFileSync(doc, 'utf-8'); + const refs = [...content.matchAll(/`\/([a-z][\w-]+)`/g)].map(m => m[1]); + const unique = [...new Set(refs)]; + const commandsDir = join(ROOT, '.opencode', 'commands'); + const commandNames = existsSync(commandsDir) + ? new Set(readdirSync(commandsDir).filter(f => f.endsWith('.md') && f !== 'README.md').map(f => f.replace('.md', ''))) + : new Set(); + const knownMissing = new Set([ + 'brainstorm', 'explore', 'gate-check', 'hybrid-prototype', 'perf-profile', 'adopt', + ]); + const bad = unique.filter(r => !commandNames.has(r) && !knownMissing.has(r)); + run(`G9a: ${name} command references are valid`, () => { + if (bad.length > 0) { + throw new Error(`Missing command files: ${bad.join(', ')}`); + } + }); + } + } +} + +console.log(`\nGates: ${passCount}/${testCount} passed\n`); +import { readdirSync } from 'fs'; +process.exit(passCount === testCount ? 0 : 1); diff --git a/tests/workflow/invariants.mjs b/tests/workflow/invariants.mjs new file mode 100644 index 0000000..e3ad6f3 --- /dev/null +++ b/tests/workflow/invariants.mjs @@ -0,0 +1,274 @@ +#!/usr/bin/env node + +import { readFileSync, readdirSync, statSync, existsSync } from 'fs'; +import { join, resolve, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const ROOT = resolve(__dirname, '..', '..'); + +const COMMANDS_DIR = join(ROOT, '.opencode', 'commands'); +const SKILLS_DIR = join(ROOT, '.opencode', 'skills'); +const AGENTS_DIR = join(ROOT, '.opencode', 'agents'); +const DOCS_DIR = join(ROOT, 'docs'); +const DESIGN_DIR = join(ROOT, 'design'); +const PRODUCTION_DIR = join(ROOT, 'production'); +const TESTS_DIR = join(ROOT, 'tests'); + +function parseFrontmatter(content) { + const match = content.match(/^---\n([\s\S]*?)\n---/); + if (!match) return {}; + const lines = match[1].split(/\r?\n/); + const data = {}; + for (const line of lines) { + const kvMatch = line.match(/^(\w[\w-]*):\s*(.*)/); + if (kvMatch) { + const key = kvMatch[1]; + let value = (kvMatch[2] || '').trim().replace(/^["']|["']$/g, ''); + data[key] = value; + } + } + return data; +} + +let testCount = 0; +let passCount = 0; + +function run(name, fn) { + testCount++; + try { + fn(); + passCount++; + console.log(` ${'PASS'} ${name}`); + } catch (e) { + console.log(` ${'FAIL'} ${name}`); + console.error(` ${e.message}`); + } +} + +console.log('\n=== Cross-Cutting Invariants ===\n'); + +{ // I1: No duplicate frontmatter descriptions across commands + if (existsSync(COMMANDS_DIR)) { + const seen = {}; + const dups = []; + const files = readdirSync(COMMANDS_DIR).filter(f => f.endsWith('.md') && f !== 'README.md'); + for (const file of files) { + const content = readFileSync(join(COMMANDS_DIR, file), 'utf-8'); + const fm = parseFrontmatter(content); + if (fm.description) { + if (seen[fm.description]) { + dups.push({ desc: fm.description, files: [seen[fm.description], file] }); + } else { + seen[fm.description] = file; + } + } + } + run('I1: No duplicate command descriptions', () => { + if (dups.length > 0) { + const details = dups.map(d => ` "${d.desc.substring(0, 60)}..." in ${d.files.join(', ')}`).join('\n'); + throw new Error(`${dups.length} duplicate descriptions:\n${details}`); + } + }); + } +} + +{ // I2: Every skill SKILL.md has valid frontmatter + if (existsSync(SKILLS_DIR)) { + const bad = []; + const dirs = readdirSync(SKILLS_DIR).filter(d => { + const p = join(SKILLS_DIR, d); + return statSync(p).isDirectory() && existsSync(join(p, 'SKILL.md')); + }); + for (const dir of dirs) { + const content = readFileSync(join(SKILLS_DIR, dir, 'SKILL.md'), 'utf-8'); + const fm = parseFrontmatter(content); + if (!fm.description) { + bad.push(`${dir}: missing description`); + } + if (!fm['allowed-tools']) { + bad.push(`${dir}: missing allowed-tools`); + } + } + run('I2: All skill SKILL.md files have required frontmatter fields', () => { + if (bad.length > 0) { + throw new Error(`Issues:\n ${bad.join('\n ')}`); + } + }); + } +} + +{ // I3: Source directory structure integrity + const requiredDirs = [ + join(ROOT, 'src'), + join(ROOT, 'assets'), + join(ROOT, 'design'), + join(ROOT, 'docs'), + join(ROOT, 'docs', 'architecture'), + join(ROOT, 'docs', 'engine-reference'), + join(ROOT, 'production'), + join(ROOT, 'prototypes'), + join(ROOT, 'tests'), + join(ROOT, 'tests', 'agents'), + ]; + const optDirs = [ + join(ROOT, 'design', 'gdd'), + join(ROOT, 'design', 'ux'), + join(ROOT, 'design', 'art'), + join(ROOT, 'production', 'sprints'), + join(ROOT, 'production', 'epics'), + join(ROOT, 'production', 'milestones'), + join(ROOT, 'production', 'qa'), + join(ROOT, 'production', 'qa', 'bugs'), + join(ROOT, 'production', 'qa', 'evidence'), + join(ROOT, 'production', 'playtests'), + join(ROOT, 'production', 'gate-checks'), + join(ROOT, 'production', 'session-logs'), + join(ROOT, 'tools'), + ]; + const missingRequired = requiredDirs.filter(d => !existsSync(d)); + const missingOptional = optDirs.filter(d => !existsSync(d)); + run('I3: All required project directories exist', () => { + if (missingRequired.length > 0) { + throw new Error(`Missing required directories:\n ${missingRequired.join('\n ')}`); + } + }); + if (missingOptional.length > 0) { + console.warn(` Info: ${missingOptional.length} optional directories not yet created (created by workflow):`); + for (const d of missingOptional) { + const rel = d.replace(ROOT + '/', '').replace(ROOT + '\\', ''); + console.warn(` - ${rel}`); + } + } +} + +{ // I4: No stale template placeholders in key config files + const configFiles = [ + join(ROOT, '.opencode', 'docs', 'technical-preferences.md'), + ]; + const knownPlaceholderFiles = new Set([ + join(ROOT, '.opencode', 'docs', 'technical-preferences.md'), + ]); + const bad = []; + for (const file of configFiles) { + if (!existsSync(file)) continue; + const content = readFileSync(file, 'utf-8'); + if (content.includes('[TO BE CONFIGURED]') && !knownPlaceholderFiles.has(file)) { + bad.push(`${file}: contains [TO BE CONFIGURED] placeholder`); + } + if (content.includes('[CHOOSE]') && !file.includes('CLAUD')) { + bad.push(`${file}: contains [CHOOSE] placeholder`); + } + } + run('I4: No unexpected template placeholders in config files', () => { + if (bad.length > 0) { + throw new Error(`Placeholders outside known list:\n ${bad.join('\n ')}`); + } + }); +} + +{ // I5: All AGENTS.md and other root agent files reference only existing agents + const agentDocPath = join(ROOT, 'AGENTS.md'); + if (existsSync(agentDocPath)) { + const content = readFileSync(agentDocPath, 'utf-8'); + const agentRefs = [...content.matchAll(/`([a-z][\w-]+)`/g)].map(m => m[1]); + const unique = [...new Set(agentRefs)]; + const agentNames = existsSync(AGENTS_DIR) + ? new Set(readdirSync(AGENTS_DIR).filter(f => f.endsWith('.md')).map(f => f.replace('.md', ''))) + : new Set(); + const developmentRelated = new Set(['development']); + const unknown = unique.filter(r => !agentNames.has(r) && !developmentRelated.has(r)); + run('I5: AGENTS.md references only existing agent files', () => { + if (unknown.length > 0) { + throw new Error(`Unknown agents referenced: ${unknown.join(', ')}`); + } + }); + } else { + run('I5: AGENTS.md file exists', () => { throw new Error('AGENTS.md not found'); }); + } +} + +{ // I6: All command files have frontmatter with required fields + if (existsSync(COMMANDS_DIR)) { + const bad = []; + const files = readdirSync(COMMANDS_DIR).filter(f => f.endsWith('.md') && f !== 'README.md'); + for (const file of files) { + const content = readFileSync(join(COMMANDS_DIR, file), 'utf-8'); + const fm = parseFrontmatter(content); + if (!fm.name) bad.push(`${file}: missing name`); + if (!fm.description) bad.push(`${file}: missing description`); + if (!fm.skill) bad.push(`${file}: missing skill`); + if (!fm.category) bad.push(`${file}: missing category`); + if (fm.category && !['onboarding', 'design', 'architecture', 'stories', 'qa', 'prototyping', 'team', 'release', 'ops'].includes(fm.category)) { + bad.push(`${file}: invalid category "${fm.category}"`); + } + } + run('I6: All command files have valid frontmatter', () => { + if (bad.length > 0) { + throw new Error(`Issues:\n ${bad.join('\n ')}`); + } + }); + } +} + +{ // I7: Agent names in skill frontmatter (agent: field) are valid + if (existsSync(SKILLS_DIR) && existsSync(AGENTS_DIR)) { + const agentNames = new Set(readdirSync(AGENTS_DIR).filter(f => f.endsWith('.md')).map(f => f.replace('.md', ''))); + const dirs = readdirSync(SKILLS_DIR).filter(d => { + const p = join(SKILLS_DIR, d); + return statSync(p).isDirectory() && existsSync(join(p, 'SKILL.md')); + }); + const bad = []; + for (const dir of dirs) { + const content = readFileSync(join(SKILLS_DIR, dir, 'SKILL.md'), 'utf-8'); + const fm = parseFrontmatter(content); + if (fm.agent && !agentNames.has(fm.agent)) { + bad.push(`${dir}: agent "${fm.agent}" not found`); + } + } + run('I7: All skill agent: frontmatter references are valid', () => { + if (bad.length > 0) { + throw new Error(`Issues:\n ${bad.join('\n ')}`); + } + }); + } +} + +{ // I8: No skill directories contain README files (pattern violation) + if (existsSync(SKILLS_DIR)) { + const bad = []; + const dirs = readdirSync(SKILLS_DIR).filter(d => statSync(join(SKILLS_DIR, d)).isDirectory()); + for (const dir of dirs) { + const entries = readdirSync(join(SKILLS_DIR, dir)); + for (const entry of entries) { + if (entry.toLowerCase().startsWith('readme')) { + bad.push(`${dir}/${entry}`); + } + } + } + run('I8: No README files in skill directories', () => { + if (bad.length > 0) { + throw new Error(`Pattern violations:\n ${bad.join('\n ')}`); + } + }); + } +} + +{ // I9: Architecture docs directory has ADRs + const adrDir = join(ROOT, 'docs', 'architecture'); + if (existsSync(adrDir)) { + const mdFiles = readdirSync(adrDir).filter(f => f.endsWith('.md')); + run('I9: Architecture docs directory exists', () => { + if (mdFiles.length === 0) { + console.warn(' Info: No ADRs yet — expected until architecture phase'); + } + }); + } else { + run('I9: Architecture docs directory exists', () => { + throw new Error('docs/architecture/ not found'); + }); + } +} + +console.log(`\nInvariants: ${passCount}/${testCount} passed\n`); +process.exit(passCount === testCount ? 0 : 1); diff --git a/tests/workflow/paths.mjs b/tests/workflow/paths.mjs new file mode 100644 index 0000000..cf16fb4 --- /dev/null +++ b/tests/workflow/paths.mjs @@ -0,0 +1,179 @@ +#!/usr/bin/env node + +import { readFileSync, readdirSync, statSync, existsSync } from 'fs'; +import { join, resolve, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const ROOT = resolve(__dirname, '..', '..'); + +const SKILLS_DIR = join(ROOT, '.opencode', 'skills'); +const COMMANDS_DIR = join(ROOT, '.opencode', 'commands'); +const DOCS_DIR = join(ROOT, 'docs'); + +function getSkillContent(name) { + const p = join(SKILLS_DIR, name, 'SKILL.md'); + if (!existsSync(p)) return null; + return readFileSync(p, 'utf-8'); +} + +function getCommandNames() { + if (!existsSync(COMMANDS_DIR)) return []; + return readdirSync(COMMANDS_DIR) + .filter(f => f.endsWith('.md') && f !== 'README.md') + .map(f => f.replace('.md', '')); +} + +function hasCommand(name) { + return getCommandNames().includes(name); +} + +function hasSkill(name) { + const p = join(SKILLS_DIR, name, 'SKILL.md'); + return existsSync(p); +} + +let testCount = 0; +let passCount = 0; + +function run(name, fn) { + testCount++; + try { + fn(); + passCount++; + console.log(` ${'PASS'} ${name}`); + } catch (e) { + console.log(` ${'FAIL'} ${name}`); + console.error(` ${e.message}`); + } +} + +console.log('\n=== Workflow Path Validation ===\n'); + +const COMMAND_REF_RE = /`\/([a-z][\w-]+)`/g; + +{ // P1: Start skill Path E (exploration) references valid commands and skills + const start = getSkillContent('start'); + run('P1: Start skill exists and is parseable', () => { + if (!start) throw new Error('start/SKILL.md not found'); + }); + + if (start) { + const refs = [...start.matchAll(COMMAND_REF_RE)].map(m => m[1]); + const unique = [...new Set(refs)]; + const missingCommands = unique.filter(r => !hasCommand(r)); + const knownCommandless = new Set([ + 'brainstorm', 'explore', 'gate-check', 'art-bible', 'adopt', 'ux-design', + ]); + const bad = missingCommands.filter(r => !knownCommandless.has(r)); + run('P2: All commands referenced in start skill exist', () => { + if (bad.length > 0) { + throw new Error(`Missing command files: ${bad.join(', ')}`); + } + }); + + const missingSkills = unique.filter(r => !hasSkill(r)); + run('P3: All commands referenced in start skill have skill implementations', () => { + const knownNoSkill = new Set(['brainstorm']); + const bad = missingSkills.filter(r => !knownNoSkill.has(r)); + if (bad.length > 0) { + throw new Error(`No skill directory: ${bad.join(', ')}`); + } + }); + } +} + +{ // P4: Gate-check stage progression is complete and references valid + const gate = getSkillContent('gate-check'); + run('P4: Gate-check skill exists and is parseable', () => { + if (!gate) throw new Error('gate-check/SKILL.md not found'); + }); + + if (gate) { + const stageRefs = [...gate.matchAll(/\/gate-check\s+([\w-]+)/g)].map(m => m[1]); + const unique = [...new Set(stageRefs)]; + const validGates = ['workflow-selection', 'concept', 'systems-design', 'technical-setup', 'pre-production', 'production', 'polish', 'release']; + const unknownGates = unique.filter(g => !validGates.includes(g)); + run('P5: Gate-check references valid target phases only', () => { + if (unknownGates.length > 0) { + throw new Error(`Unknown gate targets: ${unknownGates.join(', ')}`); + } + }); + } +} + +{ // P6: All numbered stages in gate-check are consistent and sequential + const gate = getSkillContent('gate-check'); + if (gate) { + const stages = [...gate.matchAll(/^(\d+)\.\s+\*\*(\w[\w\s-]+)\*\*/gm)]; + const stageNames = stages.map(s => s[2].trim()); + run('P6: Gate-check stages are sequential from 0 to 7', () => { + if (stages.length === 0) throw new Error('No numbered stages found'); + const expected = ['Exploration', 'Concept', 'Systems Design', 'Technical Setup', 'Pre-Production', 'Production', 'Polish', 'Release']; + for (let i = 0; i < Math.min(stages.length, expected.length); i++) { + if (stageNames[i].toLowerCase() !== expected[i].toLowerCase()) { + throw new Error(`Stage ${i}: expected "${expected[i]}", got "${stageNames[i]}"`); + } + } + }); + } +} + +{ // P7: Project-stage-detect skill defines the same stages + const psd = getSkillContent('project-stage-detect'); + run('P7: project-stage-detect skill exists', () => { + if (!psd) throw new Error('project-stage-detect/SKILL.md not found'); + }); + + if (psd) { + const refs = [...psd.matchAll(COMMAND_REF_RE)].map(m => m[1]); + const unique = [...new Set(refs)]; + const missing = unique.filter(r => !hasCommand(r)); + const expectedCommandless = new Set(['gate-check']); + const bad = missing.filter(r => !expectedCommandless.has(r)); + run('P8: All commands referenced in project-stage-detect exist', () => { + if (bad.length > 0) { + throw new Error(`Missing command files: ${bad.join(', ')}`); + } + }); + } +} + +{ // P8: Workflow transition docs exist for defined transitions + const transitionDocs = [ + 'docs/workflow-transitions.md', + 'docs/hybrid-workflow.md', + 'docs/examples/workflow-selection-case-studies.md', + ]; + const missingDocs = transitionDocs.filter(d => !existsSync(join(ROOT, d))); + run('P9: All workflow transition documentation files exist', () => { + if (missingDocs.length > 0) { + throw new Error(`Missing docs: ${missingDocs.join(', ')}`); + } + }); +} + +{ // P10: explore skill references are valid + const explore = getSkillContent('explore'); + run('P10: explore skill exists', () => { + if (!explore) throw new Error('explore/SKILL.md not found'); + }); + + if (explore) { + const refs = [...explore.matchAll(COMMAND_REF_RE)].map(m => m[1]); + const unique = [...new Set(refs)]; + const missing = unique.filter(r => !hasCommand(r)); + const knownCommandless = new Set([ + 'gate-check', 'brainstorm', 'hybrid-prototype', + ]); + const bad = missing.filter(r => !knownCommandless.has(r)); + run('P11: All commands referenced in explore skill exist', () => { + if (bad.length > 0) { + throw new Error(`Missing command files: ${bad.join(', ')}`); + } + }); + } +} + +console.log(`\nPaths: ${passCount}/${testCount} passed\n`); +process.exit(passCount === testCount ? 0 : 1); diff --git a/tests/workflow/references.mjs b/tests/workflow/references.mjs new file mode 100644 index 0000000..4a7f12f --- /dev/null +++ b/tests/workflow/references.mjs @@ -0,0 +1,225 @@ +#!/usr/bin/env node + +import { readFileSync, readdirSync, statSync, existsSync } from 'fs'; +import { join, resolve, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const ROOT = resolve(__dirname, '..', '..'); + +const COMMANDS_DIR = join(ROOT, '.opencode', 'commands'); +const SKILLS_DIR = join(ROOT, '.opencode', 'skills'); +const AGENTS_DIR = join(ROOT, '.opencode', 'agents'); + +function parseFrontmatter(content) { + const match = content.match(/^---\n([\s\S]*?)\n---/); + if (!match) return {}; + const lines = match[1].split(/\r?\n/); + const data = {}; + for (const line of lines) { + const kvMatch = line.match(/^(\w[\w-]*):\s*(.*)/); + if (kvMatch) { + const key = kvMatch[1]; + let value = (kvMatch[2] || '').trim().replace(/^["']|["']$/g, ''); + data[key] = value; + } + } + return data; +} + +function getCommandNames() { + if (!existsSync(COMMANDS_DIR)) return []; + return readdirSync(COMMANDS_DIR) + .filter(f => f.endsWith('.md') && f !== 'README.md') + .map(f => f.replace('.md', '')); +} + +function getSkillNames() { + if (!existsSync(SKILLS_DIR)) return []; + return readdirSync(SKILLS_DIR).filter(d => { + const p = join(SKILLS_DIR, d); + return statSync(p).isDirectory() && existsSync(join(p, 'SKILL.md')); + }); +} + +function getAgentNames() { + if (!existsSync(AGENTS_DIR)) return []; + return readdirSync(AGENTS_DIR) + .filter(f => f.endsWith('.md')) + .map(f => f.replace('.md', '')); +} + +let testCount = 0; +let passCount = 0; + +function run(name, fn) { + testCount++; + try { + fn(); + passCount++; + console.log(` ${'PASS'} ${name}`); + } catch (e) { + console.log(` ${'FAIL'} ${name}`); + console.error(` ${e.message}`); + } +} + +console.log('\n=== Cross-Reference Integrity ===\n'); + +const commandNames = new Set(getCommandNames()); +const skillNames = new Set(getSkillNames()); +const agentNames = new Set(getAgentNames()); + +const COMMAND_REF_RE = /`\/([a-z][\w-]+)`/g; + +const knownNonCommands = new Set([ + 'validate', 'gate-check', 'changelog', 'content-audit', 'automated-smoke-test', + 'ux-design', 'ux-review', 'asset-spec', 'patch-notes', 'propagate-design-change', + 'scope-check', 'skill-test', 'skill-improve', 'team-live-ops', 'balance-check', + 'art-bible', 'localize', 'asset-audit', 'perf-profile', 'consistency-check', + 'tech-debt', 'playtest-report', 'onboard', 'estimate', 'adopt', + 'hybrid-prototype', 'caveman', 'caveman-help', 'caveman-commit', + 'caveman-compress', 'caveman-review', + 'skill-name', 'command', +]); + +{ // R1: Every /command ref in skills matches a command file + const missing = []; + const skillDirs = getSkillNames(); + for (const dir of skillDirs) { + const content = readFileSync(join(SKILLS_DIR, dir, 'SKILL.md'), 'utf-8'); + const refs = [...content.matchAll(COMMAND_REF_RE)].map(m => m[1]); + const unique = [...new Set(refs)]; + for (const ref of unique) { + if (!commandNames.has(ref) && !knownNonCommands.has(ref)) { + missing.push({ skill: dir, ref }); + } + } + } + run('R1: All skill /command references map to existing command files', () => { + if (missing.length > 0) { + const details = missing.map(m => ` ${m.skill} -> /${m.ref}`).join('\n'); + throw new Error(`${missing.length} broken references:\n${details}`); + } + }); +} + +{ // R2: Every command skill: frontmatter matches a skill directory + if (existsSync(COMMANDS_DIR)) { + const mismatches = []; + const commandFiles = readdirSync(COMMANDS_DIR) + .filter(f => f.endsWith('.md') && f !== 'README.md'); + for (const file of commandFiles) { + const content = readFileSync(join(COMMANDS_DIR, file), 'utf-8'); + const fm = parseFrontmatter(content); + if (fm.skill && !skillNames.has(fm.skill)) { + mismatches.push({ command: file.replace('.md', ''), skill: fm.skill }); + } + } + run('R2: Command skill: references point to real skill directories', () => { + if (mismatches.length > 0) { + const details = mismatches.map(m => ` ${m.command} -> skill: ${m.skill}`).join('\n'); + throw new Error(`${mismatches.length} mismatches:\n${details}`); + } + }); + } else { + run('R2: Command skill: references point to real skill directories', () => { + throw new Error('Commands directory not found'); + }); + } +} + +{ // R3: Every subagent_type in skills matches an agent file + const SUBAGENT_RE = /subagent_type:\s*`?([a-z][\w-]+)`?/g; + const bad = []; + const skillDirs = getSkillNames(); + for (const dir of skillDirs) { + const content = readFileSync(join(SKILLS_DIR, dir, 'SKILL.md'), 'utf-8'); + const refs = [...content.matchAll(SUBAGENT_RE)].map(m => m[1]); + const unique = [...new Set(refs)]; + for (const ref of unique) { + if (!agentNames.has(ref)) { + bad.push({ skill: dir, agent: ref }); + } + } + } + run('R3: All subagent_type agent references map to existing agent files', () => { + if (bad.length > 0) { + const details = bad.map(b => ` ${b.skill} -> agent: ${b.agent}`).join('\n'); + throw new Error(`${bad.length} unknown agent refs:\n${details}`); + } + }); +} + +{ // R4: All agent delegation paths are valid (agents referencing other agents) + if (existsSync(AGENTS_DIR)) { + const bad = []; + const agentFiles = readdirSync(AGENTS_DIR).filter(f => f.endsWith('.md')); + for (const file of agentFiles) { + const content = readFileSync(join(AGENTS_DIR, file), 'utf-8'); + const refs = [...content.matchAll(/subagent_type:\s*`?([a-z][\w-]+)`?/g)].map(m => m[1]); + const unique = [...new Set(refs)]; + for (const ref of unique) { + if (!agentNames.has(ref)) { + bad.push({ agent: file.replace('.md', ''), ref }); + } + } + } + run('R4: Agent-to-agent delegation references are all valid', () => { + if (bad.length > 0) { + const details = bad.map(b => ` ${b.agent} -> ${b.ref}`).join('\n'); + throw new Error(`${bad.length} unknown agent delegation refs:\n${details}`); + } + }); + } else { + run('R4: Agent-to-agent delegation references are all valid', () => { + throw new Error('Agents directory not found'); + }); + } +} + +{ // R5: No orphan skill directories (SKILL.md present but no command) + const commands = new Set(getCommandNames()); + const skills = getSkillNames(); + const orphans = skills.filter(s => !commands.has(s)); + const knownCommands = new Set(['gate-check', 'explore', ...knownNonCommands]); + const unexpectedOrphans = orphans.filter(s => !knownCommands.has(s)); + run('R5: Skill directories without commands are intentionally documented', () => { + if (unexpectedOrphans.length > 0) { + throw new Error(`${unexpectedOrphans.length} unexpected orphan skills (no command file, not in knownNonCommands): ${unexpectedOrphans.join(', ')}`); + } + }); +} + +{ // R6: All referenced stage names are consistent across start, gate-check, and project-stage-detect + const stageFiles = [ + join(SKILLS_DIR, 'start', 'SKILL.md'), + join(SKILLS_DIR, 'gate-check', 'SKILL.md'), + join(SKILLS_DIR, 'project-stage-detect', 'SKILL.md'), + ]; + const stageSets = {}; + for (const file of stageFiles) { + if (!existsSync(file)) continue; + const name = file.split(/[/\\]/).slice(-2, -1)[0]; + const content = readFileSync(file, 'utf-8'); + const numbered = [...content.matchAll(/^\d+\.\s+\*\*(\w[\w\s-]+)\*\*/gm)].map(m => m[1].trim()); + const bolded = [...content.matchAll(/\*\*(\w[\w\s-]+)\*\*/g)].map(m => m[1].trim()); + stageSets[name] = [...new Set([...numbered, ...bolded.filter(s => /^[A-Z]/.test(s))])]; + } + run('R6: Stage name consistency across skill files', () => { + const names = Object.keys(stageSets); + for (let i = 0; i < names.length - 1; i++) { + for (let j = i + 1; j < names.length; j++) { + const a = new Set(stageSets[names[i]]); + const b = new Set(stageSets[names[j]]); + const shared = [...a].filter(s => b.has(s)); + if (shared.length === 0) { + console.warn(` Warning: ${names[i]} and ${names[j]} share no common stage names`); + } + } + } + }); +} + +console.log(`\nReferences: ${passCount}/${testCount} passed\n`); +process.exit(passCount === testCount ? 0 : 1); diff --git a/tests/workflow/run-all.mjs b/tests/workflow/run-all.mjs new file mode 100644 index 0000000..373dc4e --- /dev/null +++ b/tests/workflow/run-all.mjs @@ -0,0 +1,63 @@ +#!/usr/bin/env node + +import { fork } from 'child_process'; +import { join, resolve, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const ROOT = resolve(__dirname, '..', '..'); + +const suites = [ + { name: 'references', file: join(__dirname, 'references.mjs') }, + { name: 'paths', file: join(__dirname, 'paths.mjs') }, + { name: 'gates', file: join(__dirname, 'gates.mjs') }, + { name: 'invariants', file: join(__dirname, 'invariants.mjs') }, +]; + +async function runSuite(suite) { + return new Promise((resolve) => { + const child = fork(suite.file, [], { cwd: ROOT, stdio: ['pipe', 'pipe', 'pipe', 'ipc'] }); + let output = ''; + + child.stdout.on('data', (data) => { output += data.toString(); }); + child.stderr.on('data', (data) => { output += data.toString(); }); + + child.on('close', (code) => { + resolve({ name: suite.name, output, code }); + }); + + child.on('error', (err) => { + resolve({ name: suite.name, output: `Error: ${err.message}`, code: 1 }); + }); + }); +} + +async function main() { + console.log('=== Workflow Integrity Test Suite ===\n'); + + const results = []; + let totalPassed = 0; + let totalFailed = 0; + + for (const suite of suites) { + const result = await runSuite(suite); + results.push(result); + if (result.code === 0) totalPassed++; else totalFailed++; + console.log(result.output); + } + + console.log('=' .repeat(50)); + console.log('SUITE RESULTS'); + console.log('=' .repeat(50)); + + for (const r of results) { + const status = r.code === 0 ? 'PASS' : 'FAIL'; + console.log(` ${status} ${r.name}`); + } + + console.log(`\nOverall: ${totalPassed}/${results.length} suites passed\n`); + + process.exit(totalFailed > 0 ? 1 : 0); +} + +main(); From 4c8b2ccbd142a184cf58f9287260f7a1dfb74683 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Tue, 5 May 2026 21:16:55 +0200 Subject: [PATCH 07/21] docs: Update README and CONTRIBUTING for workflow test suite Badges updated (skills 76, commands 51, tests 183), directory tree includes tests/workflow/, port status reflects new counts. CONTRIBUTING.md adds 'For Workflow Changes' section with run-all.mjs instructions and updates CI checklist. --- README.md | 18 ++++++++++-------- docs/CONTRIBUTING.md | 26 ++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 418716e..436a9b3 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,10 @@ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Agents](https://img.shields.io/badge/agents-49-blueviolet)](.opencode/agents/) -[![Skills](https://img.shields.io/badge/skills-75-brightgreen)](.opencode/skills/) -[![Commands](https://img.shields.io/badge/commands-50-blue)](.opencode/commands/) +[![Skills](https://img.shields.io/badge/skills-76-brightgreen)](.opencode/skills/) +[![Commands](https://img.shields.io/badge/commands-51-blue)](.opencode/commands/) [![Hooks](https://img.shields.io/badge/plugins-3-orange)](.opencode/plugins/) -[![Tests](https://img.shields.io/badge/tests-129-success)](.opencode/plugins/tests/) +[![Tests](https://img.shields.io/badge/tests-183-success)](tests/) [![Built for OpenCode](https://img.shields.io/badge/built%20for-OpenCode-5f5f5f)](https://opencode.ai) --- @@ -61,9 +61,9 @@ the artificial limits. | Component | CCGS (Claude Code) | OpenCode | Status | |-----------|-------------------|----------|--------| | 🤖 **Agents** | 49 agents (`.claude/agents/`) | 49 agents (`.opencode/agents/`) | ✅ | -| ⌨️ **Skills** | 72 skills (`.claude/skills/`) | 75 skills (`.opencode/skills/`) | ✅ +3 | -| ⌨️ **Commands** | — | 50 commands (`.opencode/commands/`) | ✅ New | -| 🔗 **Plugins** | 12 bash hooks (`.claude/hooks/`) | 3 TS plugins (`.opencode/plugins/`) | ✅ **129 tests** | +| ⌨️ **Skills** | 72 skills (`.claude/skills/`) | 76 skills (`.opencode/skills/`) | ✅ +4 | +| ⌨️ **Commands** | — | 51 commands (`.opencode/commands/`) | ✅ New | +| 🔗 **Plugins** | 12 bash hooks (`.claude/hooks/`) | 3 TS plugins (`.opencode/plugins/`) | ✅ **183 tests** | | 📏 **Rules** | 11 rule files (`.claude/rules/`) | 11 rule files (`.opencode/rules/`) | ✅ | | ⚙️ **Config** | `CLAUDE.md` + `.claude/settings.json` | `AGENTS.md` + `opencode.json` | ✅ | @@ -75,7 +75,7 @@ the artificial limits. opencode ``` -Type `/` to browse all 75 skills and 50 commands, or `/start` for onboarding. +Type `/` to browse all 76 skills and 51 commands, or `/start` for onboarding. ### 🎮 Demo Game @@ -217,6 +217,7 @@ node utils/assign-models.js --config my-models.json │ └── engine-reference/ 📚 Engine API reference ├── tests/ │ ├── agents/ 🔍 Agent framework validation +│ ├── workflow/ 🔄 Workflow integrity (refs, paths, gates, invariants) │ ├── [game-specific tests] │ └── [spawned by test-setup] ├── production/ 📊 Sprint plans, session logs @@ -258,7 +259,8 @@ All 12 bash hooks from CCGS ported to `ccgs-hooks.ts`: | 11 | `post-compact.sh` | `experimental.compaction.autocontinue` | **5** | | 12 | `notify.sh` | Utility (`showNotification`) | — | -> 🧪 Run a test suite: `node .opencode/plugins/tests/test-.mjs` +> 🧪 Run plugin test suite: `node .opencode/plugins/tests/test-.mjs` +> 🧪 Run workflow integrity suite: `node tests/workflow/run-all.mjs` ### Contributing to the Framework diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index ad2f959..ca838fc 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -261,10 +261,12 @@ gap (e.g., Tier 2 engine specialists), add it to the known exceptions list. ### For Skill Changes -Verify the skill parses correctly and phases are executable: +Verify the skill parses correctly, phases are executable, and cross-references are valid: ```bash -node tests/agents/validate.mjs # Checks cross-references +node tests/agents/validate.mjs # Structural compliance +node tests/workflow/references.mjs # Cross-reference integrity +node tests/workflow/paths.mjs # Workflow path validation ``` ### For Plugin Changes @@ -272,9 +274,25 @@ node tests/agents/validate.mjs # Checks cross-references Verify all existing plugin tests still pass: ```bash -node .opencode/plugins/tests/test-*.mjs +node .opencode/plugins/tests/test-.mjs ``` +### For Workflow Changes + +When modifying workflow definitions, phase gates, or skill/command references, run the full workflow integrity suite: + +```bash +node tests/workflow/run-all.mjs +``` + +This validates: +- All `/command` references in skills map to real command files +- All `subagent_type` agent references map to real agent files +- Workflow paths (start → gate → phase) form valid chains +- Stage names are consistent across gate-check, start, and project-stage-detect +- Gate-check artifact references correspond to real project paths +- No orphan skills or missing frontmatter fields + ### For Game Code If you add gameplay code along with framework changes, write unit tests @@ -292,7 +310,7 @@ All framework changes go through pull requests to `development`: 2. **One issue per branch**: Each branch addresses exactly one issue 3. **Commit convention**: Conventional Commits (`feat:`, `fix:`, `docs:`, etc.) 4. **Close issue reference**: Include `Closes #N` in the commit message -5. **CI must pass**: Agent validation and plugin tests +5. **CI must pass**: Agent validation, workflow integrity, and plugin tests 6. **Merge to `development`**: Fast-forward merge, push, close issue 7. **Release**: `development` merges to `master` at milestone completion From 4a9bc7a76fbb4e81a3d40d0e0d354e275a0afe44 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Tue, 5 May 2026 21:29:38 +0200 Subject: [PATCH 08/21] docs: Clean up README framing and stale counts Rewrite motivation from CCGS-port rationale to OCGS value proposition. Fix stale directory tree counts (51 commands, 76 skills, 140 plugin tests). Replace 'Early Prototype' with 'Active Development'. Update header tagline to reflect standalone framework status. --- README.md | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 436a9b3..e78adff 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ OpenCode Game Studios Banner

-> ⚡ Port of [Claude Code Game Studios (CCGS)](https://github.com/Donchitos/Claude-Code-Game-Studios) to [OpenCode](https://opencode.ai) +> ⚡ Evolved from [Claude Code Game Studios (CCGS)](https://github.com/Donchitos/Claude-Code-Game-Studios) — now a standalone framework with workflow selection, phase gates, pre-workflow prototyping, and hybrid discovery-to-production pipelines. [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Agents](https://img.shields.io/badge/agents-49-blueviolet)](.opencode/agents/) @@ -36,21 +36,31 @@ ## 💡 Motivation -Claude Code's strict session and usage limits make it impractical for large-scale, -long-running game development — sessions expire, context is frequently wiped, and -high usage quickly hits rate caps. **OpenCode** removes those constraints, -allowing sustained development over the full lifecycle of a game project. While there -are some workarounds for Claude Code to access other models through local proxies, -this is not the intended use of Claude Code and such setups are fragile at best. - -This port adapts the complete [CCGS](https://github.com/Donchitos/Claude-Code-Game-Studios) -framework — its 49 agents, 73 skills, 12 hooks, and all rules — to run natively -on OpenCode, giving game teams the same structured AI-assisted workflow without -the artificial limits. +Game development is a multi-disciplinary process — design, writing, architecture, +programming, art, audio, QA, release — that's hard to coordinate with AI assistants +in ad-hoc chat sessions. **OpenCode Game Studios** provides a structured framework +for the full game lifecycle: + +- **Pre-workflow exploration** — Rapidly prototype 2-4 ideas with zero commitment + before choosing a development workflow +- **Design-first pipeline** — Brainstorm → systems map → section-by-section GDDs → + cross-GDD review, before any code is written +- **Phase gates** — Formal checkpoints between phases with PASS/CONCERNS/FAIL + verdicts that prevent advancing with gaps +- **Workflow selection** — Choose Hybrid (lightweight discovery then production) + or Full OCGS (process-heavy from day one), depending on team size and project + maturity +- **49 coordinated agents** — From creative director to engine specialists, each + with defined responsibilities, delegation maps, and strict domain boundaries +- **51 slash commands** — Route through the right skill every time, from + `/brainstorm` to `/launch-checklist` + +This project evolved from [CCGS](https://github.com/Donchitos/Claude-Code-Game-Studios) +and runs on [OpenCode](https://opencode.ai). --- -> ⚠️ **Early Prototype** — This is an active work-in-progress port. Things will +> ⚠️ **Active Development** — This is a living framework. Things will > break, change, and improve. Report bugs at > [github.com/striderZA/OpenCodeGameStudios/issues](https://github.com/striderZA/OpenCodeGameStudios/issues). @@ -199,14 +209,14 @@ node utils/assign-models.js --config my-models.json ├── AGENTS.md 📋 Project configuration ├── opencode.json ⚙️ OpenCode config (permissions, plugins) ├── .opencode/ -│ ├── commands/ ⌨️ 50 slash commands (routes to skills) +│ ├── commands/ ⌨️ 51 slash commands (routes to skills) │ ├── agents/ 🤖 49 agent definitions -│ ├── skills/ 🛠️ 75 skill workflows +│ ├── skills/ 🛠️ 76 skill workflows │ ├── plugins/ │ │ ├── ccgs-hooks.ts 🔗 Session lifecycle, validation │ │ ├── drift-detector.ts 🔍 Template drift detection │ │ ├── changelog-generator.ts 📝 Changelog generation -│ │ └── tests/ 🧪 11 test suites (129 tests) +│ │ └── tests/ 🧪 11 test suites (140 tests) │ └── rules/ 📏 11 coding standards ├── design/ 🎨 Game design documents ├── docs/ From 0e95865f4a55559a5f6d14af2c99d2299e2c2fa8 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Tue, 5 May 2026 21:37:26 +0200 Subject: [PATCH 09/21] feat: Art bible now exports machine-readable palette, typography, AI prompts, and reference catalog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds Phase 2.5 (Production Reference Outputs): - palette.json + palette.css — machine-readable color maps for tools and AI - typography.json — font families, size scale, weight hierarchy - style-anchor-prompt.md — modular AI generation seed prompt Adds Phase 4.5 (Reference Image Collection): - reference-catalog.md — concrete URLs organized by art bible section - Uses webfetch to find and catalog reference images --- .opencode/skills/art-bible/SKILL.md | 241 +++++++++++++++++++++++++++- 1 file changed, 240 insertions(+), 1 deletion(-) diff --git a/.opencode/skills/art-bible/SKILL.md b/.opencode/skills/art-bible/SKILL.md index 38f04ae..33327f1 100644 --- a/.opencode/skills/art-bible/SKILL.md +++ b/.opencode/skills/art-bible/SKILL.md @@ -134,8 +134,184 @@ Cover: Write the approved section to file immediately. +### Section 4b: Palette Export + +After the color system is approved, write machine-readable palette files that tools and AI generators can ingest. + +**Agent delegation**: Spawn `art-director` via Task with the approved Color System section. Ask: "Extract the exact palette as a JSON color map. For every named color, provide: hex code, sRGB values (0-255), semantic role name, usage context (world, UI, semantic), and any colorblind-safe backup (icon/shape/sound cue). Include the full primary palette, semantic color vocabulary, and any per-biome/area palette variants." + +Write the approved palette data to **two files**: + +**`design/art/palette.json`** — Ask "May I export the palette as JSON?" + +```json +{ + "name": "[Game Title] — Color Palette", + "generated": "[date]", + "art-bible-source": "design/art/art-bible.md", + "primary": [ + { + "name": "Example Blue", + "hex": "#4A90D9", + "rgb": [74, 144, 217], + "role": "Primary hero color — used for player character and friendly elements", + "context": "world" + } + ], + "semantic": [ + { + "name": "Danger Red", + "hex": "#D94A4A", + "rgb": [217, 74, 74], + "meaning": "Enemy health, warnings, death state", + "colorblind-backup": "icon (skull symbol)", + "context": "ui" + } + ], + "variants": [ + { + "name": "Forest Biome — Cool Shift", + "palette": ["#2E5E3E", "#4A8B5E", "#6BA37A"], + "rule": "Subtract 15% saturation from primary palette, add 10% blue channel" + } + ] +} +``` + +**`design/art/palette.css`** — Ask "May I export the palette as CSS custom properties?" + +```css +:root { + /* Primary Palette */ + --color-primary: #4A90D9; + --color-secondary: #6BA37A; + --color-accent: #E8C84A; + + /* Semantic Colors */ + --color-danger: #D94A4A; + --color-safe: #4AD94A; + --color-rare: #D9A84A; + + /* UI Palette */ + --color-ui-bg: #1A1A2E; + --color-ui-text: #E0E0E0; + --color-ui-highlight: #4A90D9; +} +``` + +Both files together mean: palette.json → 3D tools, palette.css → web/UI prototyping, and both → AI prompts ("use --color-primary as the dominant hue"). + --- +## Phase 2.5: Production Reference Outputs + +These sections produce spec files that bridge visual identity → actual asset production. Each is written to `design/art/` and feeds directly into `/asset-spec` generation. + +### Section 4c: Typography Spec + +**Goal**: A complete typography system that covers both in-game UI and any marketing/branding materials. + +**Agent delegation**: Spawn `art-director` via Task with the Visual Identity Statement and mood targets. Ask: "Design the typography system for this game. Consider: font family recommendations (primary + fallback + monospace), what each font communicates about the game's world, weight hierarchy (headline, body, caption — exact weights), line height ratios, tracking/letter-spacing for UI use, and any custom typographic effects that define the game's text treatment (glow, stroke, distortion). If the game has a specific cultural or period setting, recommend fonts that serve that setting." + +Cover: +- **Primary display font** — used for titles, key UI headers, marketing. Name specific font families with fallback chains. +- **Body text font** — used for dialogue, item descriptions, menus. Must be readable at small sizes. +- **Monospace / data font** — used for damage numbers, timers, stats, code-like UI. +- **Size scale** — base size, scale ratio, and named tiers (caption / body / lead / subhead / headline / display) +- **Weight usage** — which weights map to which contexts (e.g., Bold for headers only, Regular for body) +- **Special treatments** — any glow, outline, distortion, or animation applied to text elements +- **Accessibility** — minimum size, contrast ratio against expected backgrounds + +Write the approved section to `design/art/art-bible.md` Section 4c. Then ask: "May I export typography as JSON to `design/art/typography.json`?" + +```json +{ + "name": "[Game Title] — Typography", + "generated": "[date]", + "art-bible-source": "design/art/art-bible.md", + "fonts": { + "display": { + "family": "Cinzel Decorative", + "fallback": ["Georgia", "serif"], + "weights": [400, 700, 900], + "usage": "Titles, chapter headers, key UI" + }, + "body": { + "family": "Lora", + "fallback": ["Palatino", "serif"], + "weights": [400, 600], + "usage": "Dialogue, descriptions, menus" + } + }, + "scale": { + "base": "16px", + "ratio": 1.25, + "tiers": { + "caption": "0.75rem", + "body": "1rem", + "lead": "1.25rem", + "subhead": "1.5rem", + "headline": "2rem", + "display": "3rem" + } + }, + "accessibility": { + "minimum-size": "14px", + "minimum-contrast": "4.5:1" + } +} +``` + +### Section 4d: Visual Anchor Prompt + +**Goal**: A single AI-generation-ready prompt that captures the entire visual identity. Use this as a seed prompt for all subsequent asset generation in `/asset-spec`. + +**Agent delegation**: Spawn `art-director` via Task with the complete sections 1-4c (Visual Identity through Typography). Ask: "Write a single comprehensive visual anchor prompt for this game's art style. Structure it for use with AI image generation (Midjourney, Stable Diffusion, DALL-E). The prompt must be modular — use `--style` or `[style fragment]` markers so individual asset prompts can interpolate their subject into the style. Include: art style keywords, color palette anchor (reference the palette.json color names), lighting direction, composition philosophy, camera distance defaults, and strong negative prompts for what this style is NOT. The goal is: pasting this anchor + an asset description into any image generator produces output consistent with the art bible." + +Write the anchor to `design/art/style-anchor-prompt.md`: + +```markdown +# Visual Anchor Prompt — [Game Title] + +> Generated: [date] +> Art Bible: design/art/art-bible.md + +## Style Anchor + +Use this as a prefix for all asset generations: + +``` +[style: hand-painted watercolor with bold ink outlines, flat shading, +lighting: soft warm directional from upper-left, no harsh shadows, +colors: --color-primary dominant hue, --color-secondary for environment, +--color-accent for points of interest, +composition: centered subject, negative space breathing room, +detail level: painterly — suggestive not photorealistic, +camera: medium distance, eye-level, +negative: no photorealistic textures, no bloom, no lens flare, +no gritty/dark fantasy tone, no cel-shading outlines, no anime eyes] +``` + +## Usage + +For any asset spec, insert the asset description between the style anchor +and camera/detail instructions: + +``` +[style anchor as above] +subject: a weathered iron golem standing guard, moss covering its left shoulder, +one eye glowing with --color-accent +[camera/detail instructions] +``` + +## Per-Biome Variants + +| Biome | Palette Shift | Lighting Adjust | +|-------|--------------|-----------------| +| [Forest] | Use --color-secondary variants | Soft dappled light, warm tint | +| [Cave] | Desaturate 30%, add 15% blue | Single hard light source from above | +``` + ## Phase 3: Production Guides (Sections 5–8) These sections translate the visual identity into concrete production rules. They should be specific enough that an outsourcing team can follow them without additional briefing. @@ -184,7 +360,70 @@ Write the approved section to file. --- -## Phase 5: Art Director Sign-Off +## Phase 4.5: Reference Image Collection + +**Goal**: Find and catalog actual reference images that embody the art bible's visual direction. This turns abstract references ("like Hollow Knight's lighting") into concrete URLs that `/asset-spec` can embed in AI generation prompts. + +After the reference direction section is written, gather visual references: + +### Step 1: Generate Search Queries + +For each reference source named in Section 9, generate 2-3 specific image search queries that target the exact visual element being referenced. Example: instead of "Hollow Knight concept art", use "Hollow Knight Greenpath background lighting warm greens atmospheric". + +Use `question` to present the query list: +- Prompt: "I'll search for reference images matching these queries. Each targets a specific visual element from the reference direction." +- Show the query list as conversation text +- Options: `[A] Proceed — search for all of these` / `[B] Add or remove queries` / `[C] Skip — I'll provide images myself` + +### Step 2: Fetch and Catalog + +For each approved query, use `webfetch` to search for reference images. Target platforms: ArtStation, Pinterest, DeviantArt, or general image search. + +The goal is to find: +- Concept art showing the overall style +- Specific technique examples (lighting, color palette usage, shape language) +- "What to avoid" counter-examples + +For each successful fetch, extract the page URL and note what visual element it demonstrates. Present findings: + +> Found [N] reference pages: +> - [URL] — "Greenpath lighting — warm greens, soft dappled light" — matches §2 Mood targets +> - [URL] — "Character silhouette — horned knight" — matches §3 Shape Language +> - [URL] — "UI mockup — ornate border with gold accents" — matches §7 UI Direction + +### Step 3: Write Reference Catalog + +Ask: "May I write the reference catalog to `design/art/reference-catalog.md`?" + +```markdown +# Reference Image Catalog — [Game Title] + +> Generated: [date] +> Art Bible: design/art/art-bible.md + +## References by Art Bible Section + +### §2 Mood & Atmosphere — Lighting References +| Image URL | Source | Element | Matches | +|-----------|--------|---------|---------| +| [url] | ArtStation | Warm green atmospheric lighting in cave | §2 Exploration mood | +| [url] | Pinterest | Golden hour forest — warm directional light | §2 Combat energy | + +### §3 Shape Language — Silhouette References +... + +### §9 Reference Direction — Full Scene References +... + +## AI Generation Seed URLs + +Include these as image reference URLs (`--sref` or `--iw`) when generating: +- [URL 1] — overall style anchor +- [URL 2] — color palette exemplar +- [URL 3] — lighting benchmark +``` + +--- **Review mode check** — apply before spawning AD-ART-BIBLE: - `solo` → skip. Note: "AD-ART-BIBLE skipped — Solo mode." Proceed to Phase 6. From 6503d1d5d14f9abfdb014b0c7d521b4853108114 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Tue, 5 May 2026 21:53:35 +0200 Subject: [PATCH 10/21] fix: Update skill-testing-framework paths, add missing skills, validate in CI - Batch-fix 43 spec files: .claude/ -> .opencode/, session-state/review-mode.txt -> review-mode.txt - Add 4 missing skills to catalog.yaml: explore, hybrid-prototype, automated-smoke-test, init-template - Add I10 (catalog coverage) and I11 (no stale paths) to tests/workflow/invariants.mjs - Both new tests run in CI via validate-workflow job --- skill-testing-framework/AGENTS.md | 4 +- skill-testing-framework/README.md | 2 +- .../agents/directors/art-director.md | 2 +- .../agents/directors/creative-director.md | 2 +- .../agents/directors/producer.md | 2 +- .../agents/directors/technical-director.md | 2 +- .../agents/leads/audio-director.md | 2 +- .../agents/leads/game-designer.md | 2 +- .../agents/leads/lead-programmer.md | 2 +- .../agents/leads/level-designer.md | 2 +- .../agents/leads/narrative-director.md | 2 +- .../agents/leads/qa-lead.md | 2 +- .../agents/leads/systems-designer.md | 2 +- skill-testing-framework/catalog.yaml | 44 +++++++++++++++ skill-testing-framework/quality-rubric.md | 2 +- .../skills/analysis/consistency-check.md | 6 +-- .../skills/authoring/architecture-decision.md | 6 +-- .../skills/authoring/art-bible.md | 8 +-- .../skills/authoring/create-architecture.md | 8 +-- .../skills/authoring/design-system.md | 6 +-- .../skills/authoring/quick-design.md | 6 +-- .../skills/gate/gate-check.md | 2 +- .../pipeline/create-control-manifest.md | 6 +-- .../skills/pipeline/create-epics.md | 8 +-- .../skills/pipeline/create-stories.md | 4 +- .../skills/pipeline/dev-story.md | 8 +-- .../skills/pipeline/map-systems.md | 8 +-- .../pipeline/propagate-design-change.md | 6 +-- .../skills/readiness/story-done.md | 2 +- .../skills/readiness/story-readiness.md | 2 +- .../skills/review/architecture-review.md | 8 +-- .../skills/review/design-review.md | 2 +- .../skills/review/review-all-gdds.md | 4 +- .../skills/sprint/patch-notes.md | 2 +- .../skills/sprint/retrospective.md | 2 +- .../skills/sprint/sprint-plan.md | 2 +- .../skills/sprint/sprint-status.md | 2 +- .../skills/team/team-audio.md | 6 +-- .../skills/team/team-combat.md | 10 ++-- .../skills/team/team-ui.md | 2 +- .../skills/utility/brainstorm.md | 10 ++-- .../skills/utility/skill-improve.md | 12 ++--- .../skills/utility/skill-test.md | 20 +++---- .../templates/agent-test-spec.md | 2 +- tests/workflow/invariants.mjs | 54 +++++++++++++++++++ 45 files changed, 198 insertions(+), 100 deletions(-) diff --git a/skill-testing-framework/AGENTS.md b/skill-testing-framework/AGENTS.md index f3fe49b..64c3a96 100644 --- a/skill-testing-framework/AGENTS.md +++ b/skill-testing-framework/AGENTS.md @@ -69,7 +69,7 @@ creative → writer, world-builder, game-designer, economy-designer, ## Workflow for testing a skill 1. Read `catalog.yaml` to get the skill's `spec:` path and `category:` -2. Read the skill at `.claude/skills/[name]/SKILL.md` +2. Read the skill at `.opencode/skills/[name]/SKILL.md` 3. Read the spec at the `spec:` path 4. Evaluate assertions case by case 5. Offer to write results to `results/` and update `catalog.yaml` @@ -88,6 +88,6 @@ Treat spec failures as "this needs investigation," not "the skill is definitivel ## This folder is deletable -Nothing in `.claude/` imports from here. Deleting this folder has no effect on the +Nothing in `.opencode/` imports from here. Deleting this folder has no effect on the CCGS skills or agents themselves. `/skill-test` and `/skill-improve` will report that `catalog.yaml` is missing and guide the user to initialize it. diff --git a/skill-testing-framework/README.md b/skill-testing-framework/README.md index 8845a56..644380c 100644 --- a/skill-testing-framework/README.md +++ b/skill-testing-framework/README.md @@ -5,7 +5,7 @@ Tests the skills and agents themselves — not any game built with them. > **This folder is self-contained and optional.** > Game developers using CCGS don't need it. To remove it entirely: -> `rm -rf "CCGS Skill Testing Framework"` — nothing in `.claude/` depends on it. +> `rm -rf "CCGS Skill Testing Framework"` — nothing in `.opencode/` depends on it. --- diff --git a/skill-testing-framework/agents/directors/art-director.md b/skill-testing-framework/agents/directors/art-director.md index 9218f3d..125ba87 100644 --- a/skill-testing-framework/agents/directors/art-director.md +++ b/skill-testing-framework/agents/directors/art-director.md @@ -10,7 +10,7 @@ ## Static Assertions (Structural) -Verified by reading the agent's `.claude/agents/art-director.md` frontmatter: +Verified by reading the agent's `.opencode/agents/art-director.md` frontmatter: - [ ] `description:` field is present and domain-specific (references visual identity, art bible, asset standards — not generic) - [ ] `allowed-tools:` list is read-focused; image review capability if supported; no Bash unless asset pipeline checks are justified diff --git a/skill-testing-framework/agents/directors/creative-director.md b/skill-testing-framework/agents/directors/creative-director.md index bcd05af..4419f6b 100644 --- a/skill-testing-framework/agents/directors/creative-director.md +++ b/skill-testing-framework/agents/directors/creative-director.md @@ -10,7 +10,7 @@ ## Static Assertions (Structural) -Verified by reading the agent's `.claude/agents/creative-director.md` frontmatter: +Verified by reading the agent's `.opencode/agents/creative-director.md` frontmatter: - [ ] `description:` field is present and domain-specific (references creative vision, pillars, GDD alignment — not generic) - [ ] `allowed-tools:` list is read-heavy; should not include Bash unless justified by a creative workflow need diff --git a/skill-testing-framework/agents/directors/producer.md b/skill-testing-framework/agents/directors/producer.md index 9f584be..9d6dcd3 100644 --- a/skill-testing-framework/agents/directors/producer.md +++ b/skill-testing-framework/agents/directors/producer.md @@ -10,7 +10,7 @@ ## Static Assertions (Structural) -Verified by reading the agent's `.claude/agents/producer.md` frontmatter: +Verified by reading the agent's `.opencode/agents/producer.md` frontmatter: - [ ] `description:` field is present and domain-specific (references scope, sprint, milestone, production — not generic) - [ ] `allowed-tools:` list is primarily read-focused; Bash only if sprint/milestone files require parsing diff --git a/skill-testing-framework/agents/directors/technical-director.md b/skill-testing-framework/agents/directors/technical-director.md index 9ed25bd..d60a23c 100644 --- a/skill-testing-framework/agents/directors/technical-director.md +++ b/skill-testing-framework/agents/directors/technical-director.md @@ -10,7 +10,7 @@ ## Static Assertions (Structural) -Verified by reading the agent's `.claude/agents/technical-director.md` frontmatter: +Verified by reading the agent's `.opencode/agents/technical-director.md` frontmatter: - [ ] `description:` field is present and domain-specific (references architecture, feasibility, ADR — not generic) - [ ] `allowed-tools:` list may include Read for architecture documents; Bash only if required for technical checks diff --git a/skill-testing-framework/agents/leads/audio-director.md b/skill-testing-framework/agents/leads/audio-director.md index acff946..81a0dea 100644 --- a/skill-testing-framework/agents/leads/audio-director.md +++ b/skill-testing-framework/agents/leads/audio-director.md @@ -10,7 +10,7 @@ ## Static Assertions (Structural) -Verified by reading the agent's `.claude/agents/audio-director.md` frontmatter: +Verified by reading the agent's `.opencode/agents/audio-director.md` frontmatter: - [ ] `description:` field is present and domain-specific (references music direction, sound design, mix, audio implementation — not generic) - [ ] `allowed-tools:` list is read-focused; no Bash unless audio asset pipeline checks are justified diff --git a/skill-testing-framework/agents/leads/game-designer.md b/skill-testing-framework/agents/leads/game-designer.md index 17a1173..6eae40a 100644 --- a/skill-testing-framework/agents/leads/game-designer.md +++ b/skill-testing-framework/agents/leads/game-designer.md @@ -10,7 +10,7 @@ ## Static Assertions (Structural) -Verified by reading the agent's `.claude/agents/game-designer.md` frontmatter: +Verified by reading the agent's `.opencode/agents/game-designer.md` frontmatter: - [ ] `description:` field is present and domain-specific (references core loop, progression, combat rules, economy, player-facing design — not generic) - [ ] `allowed-tools:` list is read-focused; includes Read for GDDs and design docs; no Bash unless design tooling requires it diff --git a/skill-testing-framework/agents/leads/lead-programmer.md b/skill-testing-framework/agents/leads/lead-programmer.md index 4d41f55..bb85a4c 100644 --- a/skill-testing-framework/agents/leads/lead-programmer.md +++ b/skill-testing-framework/agents/leads/lead-programmer.md @@ -10,7 +10,7 @@ ## Static Assertions (Structural) -Verified by reading the agent's `.claude/agents/lead-programmer.md` frontmatter: +Verified by reading the agent's `.opencode/agents/lead-programmer.md` frontmatter: - [ ] `description:` field is present and domain-specific (references code architecture, feasibility, code review, coding standards — not generic) - [ ] `allowed-tools:` list includes Read for source files; Bash may be included for static analysis or test runs; no write access outside `src/` without explicit delegation diff --git a/skill-testing-framework/agents/leads/level-designer.md b/skill-testing-framework/agents/leads/level-designer.md index 8d1e66e..6ffd0b1 100644 --- a/skill-testing-framework/agents/leads/level-designer.md +++ b/skill-testing-framework/agents/leads/level-designer.md @@ -10,7 +10,7 @@ ## Static Assertions (Structural) -Verified by reading the agent's `.claude/agents/level-designer.md` frontmatter: +Verified by reading the agent's `.opencode/agents/level-designer.md` frontmatter: - [ ] `description:` field is present and domain-specific (references level layout, encounter design, pacing, environmental storytelling — not generic) - [ ] `allowed-tools:` list is read-focused; includes Read for level design documents and GDDs; no Bash unless level tooling requires it diff --git a/skill-testing-framework/agents/leads/narrative-director.md b/skill-testing-framework/agents/leads/narrative-director.md index 4e77444..4577c67 100644 --- a/skill-testing-framework/agents/leads/narrative-director.md +++ b/skill-testing-framework/agents/leads/narrative-director.md @@ -10,7 +10,7 @@ ## Static Assertions (Structural) -Verified by reading the agent's `.claude/agents/narrative-director.md` frontmatter: +Verified by reading the agent's `.opencode/agents/narrative-director.md` frontmatter: - [ ] `description:` field is present and domain-specific (references story, character, world-building, consistency — not generic) - [ ] `allowed-tools:` list is read-focused; includes Read for lore documents, GDDs, and narrative docs; no Bash unless justified diff --git a/skill-testing-framework/agents/leads/qa-lead.md b/skill-testing-framework/agents/leads/qa-lead.md index e4325b3..5bd410b 100644 --- a/skill-testing-framework/agents/leads/qa-lead.md +++ b/skill-testing-framework/agents/leads/qa-lead.md @@ -10,7 +10,7 @@ ## Static Assertions (Structural) -Verified by reading the agent's `.claude/agents/qa-lead.md` frontmatter: +Verified by reading the agent's `.opencode/agents/qa-lead.md` frontmatter: - [ ] `description:` field is present and domain-specific (references test strategy, story readiness, coverage, bug triage — not generic) - [ ] `allowed-tools:` list is read-focused; may include Read for story files, test files, and coding-standards; Bash only if running test commands is required diff --git a/skill-testing-framework/agents/leads/systems-designer.md b/skill-testing-framework/agents/leads/systems-designer.md index 6421203..4dec757 100644 --- a/skill-testing-framework/agents/leads/systems-designer.md +++ b/skill-testing-framework/agents/leads/systems-designer.md @@ -10,7 +10,7 @@ ## Static Assertions (Structural) -Verified by reading the agent's `.claude/agents/systems-designer.md` frontmatter: +Verified by reading the agent's `.opencode/agents/systems-designer.md` frontmatter: - [ ] `description:` field is present and domain-specific (references formulas, progression curves, balance math, economy — not generic) - [ ] `allowed-tools:` list is read-focused; may include Bash for formula evaluation scripts if the project uses them; no write access outside `design/balance/` without delegation diff --git a/skill-testing-framework/catalog.yaml b/skill-testing-framework/catalog.yaml index cd6b248..cad5a63 100644 --- a/skill-testing-framework/catalog.yaml +++ b/skill-testing-framework/catalog.yaml @@ -797,6 +797,50 @@ skills: priority: low category: utility + - name: explore + spec: "" + last_static: "" + last_static_result: "" + last_spec: "" + last_spec_result: "" + last_category: "" + last_category_result: "" + priority: medium + category: utility + + - name: hybrid-prototype + spec: "" + last_static: "" + last_static_result: "" + last_spec: "" + last_spec_result: "" + last_category: "" + last_category_result: "" + priority: low + category: utility + + - name: automated-smoke-test + spec: "" + last_static: "" + last_static_result: "" + last_spec: "" + last_spec_result: "" + last_category: "" + last_category_result: "" + priority: low + category: utility + + - name: init-template + spec: "" + last_static: "" + last_static_result: "" + last_spec: "" + last_spec_result: "" + last_category: "" + last_category_result: "" + priority: low + category: utility + agents: # Tier 1 Directors (Opus) - name: creative-director diff --git a/skill-testing-framework/quality-rubric.md b/skill-testing-framework/quality-rubric.md index c490650..e3d12be 100644 --- a/skill-testing-framework/quality-rubric.md +++ b/skill-testing-framework/quality-rubric.md @@ -20,7 +20,7 @@ auto-advancing stage and must respect the three review modes. | Metric | PASS criteria | |---|---| -| **G1 — Review mode read** | Skill reads `production/session-state/review-mode.txt` (or equivalent) before deciding which directors to spawn | +| **G1 — Review mode read** | Skill reads `production/review-mode.txt` (or equivalent) before deciding which directors to spawn | | **G2 — Full mode: all 4 directors spawn** | In `full` mode, all 4 Tier-1 directors (CD, TD, PR, AD) PHASE-GATE prompts are invoked in parallel | | **G3 — Lean mode: PHASE-GATE only** | In `lean` mode, only `*-PHASE-GATE` gates run; inline gates (CD-PILLARS, TD-ARCHITECTURE, etc.) are skipped | | **G4 — Solo mode: no directors** | In `solo` mode, no director gates spawn; each is noted as "skipped — Solo mode" | diff --git a/skill-testing-framework/skills/analysis/consistency-check.md b/skill-testing-framework/skills/analysis/consistency-check.md index c978c1f..131af04 100644 --- a/skill-testing-framework/skills/analysis/consistency-check.md +++ b/skill-testing-framework/skills/analysis/consistency-check.md @@ -137,19 +137,19 @@ required as part of the scan itself. **Fixture:** - `design/gdd/` contains ≥2 GDDs -- `production/session-state/review-mode.txt` exists with `full` +- `production/review-mode.txt` exists with `full` **Input:** `/consistency-check` **Expected behavior:** 1. Skill reads all GDDs and runs the consistency scan -2. Skill does NOT read `production/session-state/review-mode.txt` +2. Skill does NOT read `production/review-mode.txt` 3. No director gate agents are spawned at any point 4. Findings table and verdict are produced normally **Assertions:** - [ ] No director gate agents are spawned (no CD-, TD-, PR-, AD- prefixed gates) -- [ ] Skill does NOT read `production/session-state/review-mode.txt` +- [ ] Skill does NOT read `production/review-mode.txt` - [ ] Output contains no "Gate: [GATE-ID]" or gate-skipped entries - [ ] Review mode has no effect on this skill's behavior diff --git a/skill-testing-framework/skills/authoring/architecture-decision.md b/skill-testing-framework/skills/authoring/architecture-decision.md index db1cf21..3ea77b1 100644 --- a/skill-testing-framework/skills/authoring/architecture-decision.md +++ b/skill-testing-framework/skills/authoring/architecture-decision.md @@ -51,7 +51,7 @@ In `solo` mode: both gates are skipped. ADR is written with Status: Proposed. **Fixture:** - `docs/architecture/` exists with no existing ADR for rendering - `docs/engine-reference/[engine]/VERSION.md` exists -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` **Input:** `/architecture-decision rendering-approach` @@ -79,7 +79,7 @@ In `solo` mode: both gates are skipped. ADR is written with Status: Proposed. **Fixture:** - ADR draft is complete (all sections filled) -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` - TD-ADR gate returns CONCERNS: "The decision does not address [specific concern]" **Input:** `/architecture-decision [topic]` @@ -102,7 +102,7 @@ In `solo` mode: both gates are skipped. ADR is written with Status: Proposed. ### Case 3: Lean Mode — Both gates skipped; ADR written as Proposed **Fixture:** -- `production/session-state/review-mode.txt` contains `lean` +- `production/review-mode.txt` contains `lean` - ADR draft is authored for a new technical decision **Input:** `/architecture-decision [topic]` diff --git a/skill-testing-framework/skills/authoring/art-bible.md b/skill-testing-framework/skills/authoring/art-bible.md index dae2efe..af43cdf 100644 --- a/skill-testing-framework/skills/authoring/art-bible.md +++ b/skill-testing-framework/skills/authoring/art-bible.md @@ -43,7 +43,7 @@ Verified automatically by `/skill-test static` — no fixture needed. **Fixture:** - No existing `design/art-bible.md` -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` - `design/gdd/game-concept.md` exists with visual tone described **Input:** `/art-bible` @@ -69,7 +69,7 @@ Verified automatically by `/skill-test static` — no fixture needed. **Fixture:** - Art bible draft complete -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` - AD-ART-BIBLE gate returns CONCERNS: "Color palette clashes with the dark atmospheric tone described in the game concept" @@ -95,7 +95,7 @@ Verified automatically by `/skill-test static` — no fixture needed. **Fixture:** - No existing art bible -- `production/session-state/review-mode.txt` contains `lean` +- `production/review-mode.txt` contains `lean` **Input:** `/art-bible` @@ -144,7 +144,7 @@ Verified automatically by `/skill-test static` — no fixture needed. **Fixture:** - No existing art bible -- `production/session-state/review-mode.txt` contains `solo` +- `production/review-mode.txt` contains `solo` **Input:** `/art-bible` diff --git a/skill-testing-framework/skills/authoring/create-architecture.md b/skill-testing-framework/skills/authoring/create-architecture.md index f907943..4250375 100644 --- a/skill-testing-framework/skills/authoring/create-architecture.md +++ b/skill-testing-framework/skills/authoring/create-architecture.md @@ -50,7 +50,7 @@ In `solo` mode: both gates are skipped with equivalent notes. **Fixture:** - No existing `docs/architecture/architecture.md` - `docs/architecture/` contains Accepted ADRs for reference -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` **Input:** `/create-architecture` @@ -76,7 +76,7 @@ In `solo` mode: both gates are skipped with equivalent notes. **Fixture:** - Architecture doc is fully drafted (all sections) -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` - TD-ARCHITECTURE gate returns MAJOR REVISION: "[specific structural issue]" **Input:** `/create-architecture` @@ -100,7 +100,7 @@ In `solo` mode: both gates are skipped with equivalent notes. **Fixture:** - No existing architecture doc -- `production/session-state/review-mode.txt` contains `lean` +- `production/review-mode.txt` contains `lean` **Input:** `/create-architecture` @@ -146,7 +146,7 @@ In `solo` mode: both gates are skipped with equivalent notes. **Fixture:** - Architecture doc is being authored - One section references or depends on an ADR that has `Status: Proposed` -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` **Input:** `/create-architecture` diff --git a/skill-testing-framework/skills/authoring/design-system.md b/skill-testing-framework/skills/authoring/design-system.md index 923525e..cc3eef0 100644 --- a/skill-testing-framework/skills/authoring/design-system.md +++ b/skill-testing-framework/skills/authoring/design-system.md @@ -51,7 +51,7 @@ In `solo` mode: CD-GDD-ALIGN is skipped. Output notes: **Fixture:** - No existing GDD for the target system in `design/gdd/` -- `production/session-state/review-mode.txt` contains `lean` +- `production/review-mode.txt` contains `lean` **Input:** `/design-system [system-name]` @@ -100,7 +100,7 @@ In `solo` mode: CD-GDD-ALIGN is skipped. Output notes: **Fixture:** - New GDD being authored -- `production/session-state/review-mode.txt` contains `lean` +- `production/review-mode.txt` contains `lean` - CD-GDD-ALIGN gate returns MAJOR REVISION on the Player Fantasy section **Input:** `/design-system [system-name]` @@ -126,7 +126,7 @@ In `solo` mode: CD-GDD-ALIGN is skipped. Output notes: **Fixture:** - New GDD being authored -- `production/session-state/review-mode.txt` contains `solo` +- `production/review-mode.txt` contains `solo` **Input:** `/design-system [system-name]` diff --git a/skill-testing-framework/skills/authoring/quick-design.md b/skill-testing-framework/skills/authoring/quick-design.md index e6bd0dd..7dcf661 100644 --- a/skill-testing-framework/skills/authoring/quick-design.md +++ b/skill-testing-framework/skills/authoring/quick-design.md @@ -134,20 +134,20 @@ Full GDD review is not needed for sub-4-hour single-system features. **Fixture:** - Feature is within scope for quick-design -- `production/session-state/review-mode.txt` exists with `full` +- `production/review-mode.txt` exists with `full` **Input:** `/quick-design [feature-name]` **Expected behavior:** 1. Skill asks scoping questions and determines scope is within threshold -2. Skill does NOT read `production/session-state/review-mode.txt` +2. Skill does NOT read `production/review-mode.txt` 3. Skill does NOT spawn any director gate agent 4. Spec is drafted, "May I write" asked, file written after approval 5. Output explicitly notes: "No director gate review — quick-design is for sub-4h features" **Assertions:** - [ ] No director gate agents are spawned (no CD-, TD-, PR-, AD- prefixed gates) -- [ ] Skill does NOT read `production/session-state/review-mode.txt` +- [ ] Skill does NOT read `production/review-mode.txt` - [ ] Output contains a note explaining why no gate review is needed - [ ] Review mode has no effect on this skill's behavior - [ ] Full GDD review path (`/design-system`) is mentioned as the alternative for larger features diff --git a/skill-testing-framework/skills/gate/gate-check.md b/skill-testing-framework/skills/gate/gate-check.md index 545bc8e..4aaee8c 100644 --- a/skill-testing-framework/skills/gate/gate-check.md +++ b/skill-testing-framework/skills/gate/gate-check.md @@ -127,7 +127,7 @@ Verified automatically by `/skill-test static` — no fixture needed. ### Case 5: Director Gate — lean vs full vs solo mode **Fixture:** -- `production/session-state/review-mode.txt` exists (or equivalent state file) +- `production/review-mode.txt` exists (or equivalent state file) - All required artifacts for the target gate are present - `design/gdd/game-concept.md` exists diff --git a/skill-testing-framework/skills/pipeline/create-control-manifest.md b/skill-testing-framework/skills/pipeline/create-control-manifest.md index f021843..7547122 100644 --- a/skill-testing-framework/skills/pipeline/create-control-manifest.md +++ b/skill-testing-framework/skills/pipeline/create-control-manifest.md @@ -135,20 +135,20 @@ review gate is needed. **Fixture:** - 4 Accepted ADRs exist -- `production/session-state/review-mode.txt` exists with `full` +- `production/review-mode.txt` exists with `full` **Input:** `/create-control-manifest` **Expected behavior:** 1. Skill reads ADRs and drafts manifest -2. Skill does NOT read `production/session-state/review-mode.txt` +2. Skill does NOT read `production/review-mode.txt` 3. No director gate agents are spawned at any point 4. Skill proceeds directly to "May I write" after drafting 5. Review mode setting has no effect on this skill's behavior **Assertions:** - [ ] No director gate agents are spawned (no CD-, TD-, PR-, AD- prefixed gates) -- [ ] Skill does NOT read `production/session-state/review-mode.txt` +- [ ] Skill does NOT read `production/review-mode.txt` - [ ] Output contains no "Gate: [GATE-ID]" or gate-skipped entries - [ ] The manifest is generated from ADRs alone, with no external gate review diff --git a/skill-testing-framework/skills/pipeline/create-epics.md b/skill-testing-framework/skills/pipeline/create-epics.md index 921eac1..4d255c4 100644 --- a/skill-testing-framework/skills/pipeline/create-epics.md +++ b/skill-testing-framework/skills/pipeline/create-epics.md @@ -48,7 +48,7 @@ In `solo` mode: PR-EPIC is skipped. Output notes: "PR-EPIC skipped — solo mode - Both systems have approved GDDs in `design/gdd/` - `docs/architecture/architecture.md` exists with matching modules - At least one Accepted ADR exists for each system -- `production/session-state/review-mode.txt` contains `lean` +- `production/review-mode.txt` contains `lean` **Input:** `/create-epics` @@ -97,7 +97,7 @@ In `solo` mode: PR-EPIC is skipped. Output notes: "PR-EPIC skipped — solo mode **Fixture:** - 2 approved GDDs exist -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` **Full mode expected behavior:** 1. Skill drafts both epics @@ -112,7 +112,7 @@ In `solo` mode: PR-EPIC is skipped. Output notes: "PR-EPIC skipped — solo mode **Fixture (lean mode):** - Same GDDs -- `production/session-state/review-mode.txt` contains `lean` +- `production/review-mode.txt` contains `lean` **Lean mode expected behavior:** 1. Epics are drafted @@ -149,7 +149,7 @@ In `solo` mode: PR-EPIC is skipped. Output notes: "PR-EPIC skipped — solo mode **Fixture:** - 2 approved GDDs exist -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` - PR-EPIC gate returns CONCERNS (e.g., scope of one epic is too large) **Input:** `/create-epics` diff --git a/skill-testing-framework/skills/pipeline/create-stories.md b/skill-testing-framework/skills/pipeline/create-stories.md index e2dbb89..8954744 100644 --- a/skill-testing-framework/skills/pipeline/create-stories.md +++ b/skill-testing-framework/skills/pipeline/create-stories.md @@ -52,7 +52,7 @@ In `solo` mode: QL-STORY-READY is skipped with equivalent notes. - All governing ADRs have `Status: Accepted` - `docs/architecture/control-manifest.md` exists - `docs/architecture/tr-registry.yaml` has TR-IDs for all 3 requirements -- `production/session-state/review-mode.txt` contains `lean` +- `production/review-mode.txt` contains `lean` **Input:** `/create-stories [epic-name]` @@ -147,7 +147,7 @@ In `solo` mode: QL-STORY-READY is skipped with equivalent notes. **Fixture:** - EPIC.md exists with 2 requirements - Both governing ADRs are Accepted -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` - QL-STORY-READY check finds one story has ambiguous acceptance criteria **Input:** `/create-stories [epic-name]` diff --git a/skill-testing-framework/skills/pipeline/dev-story.md b/skill-testing-framework/skills/pipeline/dev-story.md index ebe1789..5dc0066 100644 --- a/skill-testing-framework/skills/pipeline/dev-story.md +++ b/skill-testing-framework/skills/pipeline/dev-story.md @@ -53,8 +53,8 @@ In `solo` mode: LP-CODE-REVIEW is skipped with equivalent notes. - A test evidence path - Referenced ADR has `Status: Accepted` - `docs/architecture/control-manifest.md` exists -- `.claude/docs/technical-preferences.md` has engine and language configured -- `production/session-state/review-mode.txt` contains `full` +- `.opencode/docs/technical-preferences.md` has engine and language configured +- `production/review-mode.txt` contains `full` **Input:** `/dev-story production/epics/[layer]/story-[name].md` @@ -154,7 +154,7 @@ In `solo` mode: LP-CODE-REVIEW is skipped with equivalent notes. **Fixture (full mode):** - Story is implemented and all criteria appear met -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` - LP-CODE-REVIEW gate returns NEEDS CHANGES with specific feedback **Full mode expected behavior:** @@ -169,7 +169,7 @@ In `solo` mode: LP-CODE-REVIEW is skipped with equivalent notes. - [ ] Story status stays In Progress until issues are resolved and gate passes **Fixture (lean mode):** -- Same story, `production/session-state/review-mode.txt` contains `lean` +- Same story, `production/review-mode.txt` contains `lean` **Lean mode expected behavior:** 1. Implementation completes diff --git a/skill-testing-framework/skills/pipeline/map-systems.md b/skill-testing-framework/skills/pipeline/map-systems.md index 2eda044..3516cf7 100644 --- a/skill-testing-framework/skills/pipeline/map-systems.md +++ b/skill-testing-framework/skills/pipeline/map-systems.md @@ -51,7 +51,7 @@ In `solo` mode: both gates are skipped with equivalent notes. - `design/gdd/game-concept.md` exists with Core Mechanics and MVP Definition sections - `design/gdd/game-pillars.md` exists with ≥1 pillar defined - No `design/systems-index.md` exists yet -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` **Input:** `/map-systems` @@ -101,7 +101,7 @@ In `solo` mode: both gates are skipped with equivalent notes. **Fixture:** - Game concept exists -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` - CD-SYSTEMS gate returns CONCERNS: "The [core-system] is implied by the concept but not identified" **Input:** `/map-systems` @@ -148,7 +148,7 @@ In `solo` mode: both gates are skipped with equivalent notes. **Fixture (lean mode):** - Game concept exists -- `production/session-state/review-mode.txt` contains `lean` +- `production/review-mode.txt` contains `lean` **Lean mode expected behavior:** 1. Systems are decomposed and drafted @@ -162,7 +162,7 @@ In `solo` mode: both gates are skipped with equivalent notes. - [ ] systems-index.md is written after user approval **Fixture (solo mode):** -- Same game concept, `production/session-state/review-mode.txt` contains `solo` +- Same game concept, `production/review-mode.txt` contains `solo` **Solo mode expected behavior:** 1. Same decomposition workflow diff --git a/skill-testing-framework/skills/pipeline/propagate-design-change.md b/skill-testing-framework/skills/pipeline/propagate-design-change.md index 26d0ef8..bb0c1ff 100644 --- a/skill-testing-framework/skills/pipeline/propagate-design-change.md +++ b/skill-testing-framework/skills/pipeline/propagate-design-change.md @@ -135,19 +135,19 @@ director review is required at the analysis stage. **Fixture:** - A GDD has been revised with downstream references -- `production/session-state/review-mode.txt` exists with `full` +- `production/review-mode.txt` exists with `full` **Input:** `/propagate-design-change design/gdd/[system].md` **Expected behavior:** 1. Skill reads the GDD and traces downstream references -2. Skill does NOT read `production/session-state/review-mode.txt` +2. Skill does NOT read `production/review-mode.txt` 3. No director gate agents are spawned at any point 4. Impact report is produced and per-artifact approval proceeds normally **Assertions:** - [ ] No director gate agents are spawned (no CD-, TD-, PR-, AD- prefixed gates) -- [ ] Skill does NOT read `production/session-state/review-mode.txt` +- [ ] Skill does NOT read `production/review-mode.txt` - [ ] Output contains no "Gate: [GATE-ID]" or gate-skipped entries - [ ] Review mode has no effect on this skill's behavior diff --git a/skill-testing-framework/skills/readiness/story-done.md b/skill-testing-framework/skills/readiness/story-done.md index 8aa87eb..a959993 100644 --- a/skill-testing-framework/skills/readiness/story-done.md +++ b/skill-testing-framework/skills/readiness/story-done.md @@ -149,7 +149,7 @@ Verified automatically by `/skill-test static` — no fixture needed. **Fixture:** - Story file at `production/epics/core/story-light-pickup.md` - All acceptance criteria verified, no GDD deviations -- `production/session-state/review-mode.txt` exists +- `production/review-mode.txt` exists **Case 5a — full mode:** - `review-mode.txt` contains `full` diff --git a/skill-testing-framework/skills/readiness/story-readiness.md b/skill-testing-framework/skills/readiness/story-readiness.md index 7b3f523..7d7ee7d 100644 --- a/skill-testing-framework/skills/readiness/story-readiness.md +++ b/skill-testing-framework/skills/readiness/story-readiness.md @@ -138,7 +138,7 @@ Verified automatically by `/skill-test static` — no fixture needed. **Fixture:** - Story file exists and is READY (all 4 dimensions pass, ADR Accepted, criteria present) -- `production/session-state/review-mode.txt` exists +- `production/review-mode.txt` exists **Case 5a — full mode:** - `review-mode.txt` contains `full` diff --git a/skill-testing-framework/skills/review/architecture-review.md b/skill-testing-framework/skills/review/architecture-review.md index 99b21c3..bb9ded2 100644 --- a/skill-testing-framework/skills/review/architecture-review.md +++ b/skill-testing-framework/skills/review/architecture-review.md @@ -48,7 +48,7 @@ In `solo` mode: both gates are skipped with equivalent notes. - `docs/architecture/architecture.md` exists with all 8 required sections populated - All sections reference the correct engine version from `docs/engine-reference/` - No contradictions with existing Accepted ADRs in `docs/architecture/` -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` **Input:** `/architecture-review docs/architecture/architecture.md` @@ -75,7 +75,7 @@ In `solo` mode: both gates are skipped with equivalent notes. **Fixture:** - `docs/architecture/architecture.md` exists but is missing at least 2 required sections (e.g., no data model section, no error handling section) -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` **Input:** `/architecture-review docs/architecture/architecture.md` @@ -142,7 +142,7 @@ In `solo` mode: both gates are skipped with equivalent notes. **Fixture (full mode):** - `docs/architecture/architecture.md` exists with all 8 sections -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` **Full mode expected behavior:** 1. TD-ARCHITECTURE gate spawns @@ -156,7 +156,7 @@ In `solo` mode: both gates are skipped with equivalent notes. **Fixture (solo mode):** - Same architecture doc -- `production/session-state/review-mode.txt` contains `solo` +- `production/review-mode.txt` contains `solo` **Solo mode expected behavior:** 1. Skill reads the architecture doc diff --git a/skill-testing-framework/skills/review/design-review.md b/skill-testing-framework/skills/review/design-review.md index c2c8e04..33eb6d2 100644 --- a/skill-testing-framework/skills/review/design-review.md +++ b/skill-testing-framework/skills/review/design-review.md @@ -131,7 +131,7 @@ Verified automatically by `/skill-test static` — no fixture needed. **Fixture:** - `design/gdd/light-manipulation.md` exists with all 8 sections -- `production/session-state/review-mode.txt` exists with `full` (most permissive mode) +- `production/review-mode.txt` exists with `full` (most permissive mode) **Input:** `/design-review design/gdd/light-manipulation.md` (with full review mode active) diff --git a/skill-testing-framework/skills/review/review-all-gdds.md b/skill-testing-framework/skills/review/review-all-gdds.md index 07c5d8c..3e0a448 100644 --- a/skill-testing-framework/skills/review/review-all-gdds.md +++ b/skill-testing-framework/skills/review/review-all-gdds.md @@ -138,7 +138,7 @@ review; delegating to a director gate would create a circular dependency. **Fixture:** - `design/gdd/` contains ≥2 consistent system GDDs -- `production/session-state/review-mode.txt` exists with content `full` +- `production/review-mode.txt` exists with content `full` **Input:** `/review-all-gdds` @@ -151,7 +151,7 @@ review; delegating to a director gate would create a circular dependency. **Assertions:** - [ ] No director gate agents are spawned at any point -- [ ] Skill does NOT read `production/session-state/review-mode.txt` +- [ ] Skill does NOT read `production/review-mode.txt` - [ ] Output does not contain any "Gate: [GATE-ID]" or "skipped" gate entries - [ ] The skill produces a verdict regardless of review mode - [ ] R4 metric: gate count for this skill = 0 in all modes diff --git a/skill-testing-framework/skills/sprint/patch-notes.md b/skill-testing-framework/skills/sprint/patch-notes.md index ae2399d..2822ffb 100644 --- a/skill-testing-framework/skills/sprint/patch-notes.md +++ b/skill-testing-framework/skills/sprint/patch-notes.md @@ -107,7 +107,7 @@ None. Patch notes generation is a fast compilation task; no gates are invoked. ### Case 4: Patch Note Template Exists — Used instead of generated structure **Fixture:** -- `.claude/docs/templates/patch-notes-template.md` exists with a structured header format +- `.opencode/docs/templates/patch-notes-template.md` exists with a structured header format - `docs/CHANGELOG.md` exists with player-facing entries **Input:** `/patch-notes v0.4.0` diff --git a/skill-testing-framework/skills/sprint/retrospective.md b/skill-testing-framework/skills/sprint/retrospective.md index b49ad28..0f42db0 100644 --- a/skill-testing-framework/skills/sprint/retrospective.md +++ b/skill-testing-framework/skills/sprint/retrospective.md @@ -132,7 +132,7 @@ None. Retrospectives are team self-reflection documents; no gates are invoked. **Fixture:** - `production/sprints/sprint-005.md` exists with complete stories -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` **Input:** `/retrospective sprint-005` diff --git a/skill-testing-framework/skills/sprint/sprint-plan.md b/skill-testing-framework/skills/sprint/sprint-plan.md index b0c5aaa..b5d8be8 100644 --- a/skill-testing-framework/skills/sprint/sprint-plan.md +++ b/skill-testing-framework/skills/sprint/sprint-plan.md @@ -39,7 +39,7 @@ Verified automatically by `/skill-test static` — no fixture needed. **Fixture:** - `production/milestones/milestone-02.md` exists with capacity `10 story points` - Backlog contains 5 unstarted stories across 2 epics, mixed priorities -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` - Next sprint number is `003` (sprints 001 and 002 already exist) **Input:** `/sprint-plan` diff --git a/skill-testing-framework/skills/sprint/sprint-status.md b/skill-testing-framework/skills/sprint/sprint-status.md index 93170bf..d7ffe52 100644 --- a/skill-testing-framework/skills/sprint/sprint-status.md +++ b/skill-testing-framework/skills/sprint/sprint-status.md @@ -129,7 +129,7 @@ None. `/sprint-status` is a read-only reporting skill; no gates are invoked. **Fixture:** - `production/sprints/sprint-004.md` exists with 4 stories (2 Complete, 2 In Progress) -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` **Input:** `/sprint-status` diff --git a/skill-testing-framework/skills/team/team-audio.md b/skill-testing-framework/skills/team/team-audio.md index 5aafb00..4dd0a96 100644 --- a/skill-testing-framework/skills/team/team-audio.md +++ b/skill-testing-framework/skills/team/team-audio.md @@ -41,7 +41,7 @@ engine is configured. - GDD for the target feature exists at `design/gdd/combat.md` - Sound bible exists at `design/gdd/sound-bible.md` - Existing audio assets are listed in `assets/audio/` -- Engine is configured in `.claude/docs/technical-preferences.md` +- Engine is configured in `.opencode/docs/technical-preferences.md` - No accessibility gaps exist in the planned audio event list **Input:** `/team-audio combat` @@ -154,14 +154,14 @@ engine is configured. ### Case 5: Engine Not Configured — Engine specialist step skipped gracefully **Fixture:** -- Engine is NOT configured in `.claude/docs/technical-preferences.md` (shows `[TO BE CONFIGURED]`) +- Engine is NOT configured in `.opencode/docs/technical-preferences.md` (shows `[TO BE CONFIGURED]`) - GDD for the target feature exists - Sound bible may or may not exist **Input:** `/team-audio boss encounter` **Expected behavior:** -1. Context gathering: orchestrator reads `.claude/docs/technical-preferences.md` and detects no engine is configured +1. Context gathering: orchestrator reads `.opencode/docs/technical-preferences.md` and detects no engine is configured 2. Steps 1–2 proceed normally (audio-director, sound-designer, accessibility-specialist) 3. Step 3: technical-artist is spawned normally; engine specialist spawn is SKIPPED 4. Orchestrator notes in conversation: "Engine specialist not spawned — no engine configured in technical-preferences.md. Engine integration validation will be deferred until an engine is selected." diff --git a/skill-testing-framework/skills/team/team-combat.md b/skill-testing-framework/skills/team/team-combat.md index e73c303..8177aba 100644 --- a/skill-testing-framework/skills/team/team-combat.md +++ b/skill-testing-framework/skills/team/team-combat.md @@ -23,7 +23,7 @@ with verdict COMPLETE / NEEDS WORK / BLOCKED and handoffs to `/code-review`, - [ ] Error Recovery Protocol section is present with all four recovery steps - [ ] Uses `AskUserQuestion` at phase transitions for user approval before proceeding - [ ] Phase 3 is explicitly marked as parallel (gameplay-programmer, ai-programmer, technical-artist, sound-designer) -- [ ] Phase 2 includes spawning the primary engine specialist (read from `.claude/docs/technical-preferences.md`) +- [ ] Phase 2 includes spawning the primary engine specialist (read from `.opencode/docs/technical-preferences.md`) - [ ] Team Composition lists all seven roles (game-designer, gameplay-programmer, ai-programmer, technical-artist, sound-designer, engine specialist, qa-tester) --- @@ -34,7 +34,7 @@ with verdict COMPLETE / NEEDS WORK / BLOCKED and handoffs to `/code-review`, **Fixture:** - `design/gdd/game-concept.md` exists and is populated -- Engine is configured in `.claude/docs/technical-preferences.md` (Engine Specialists section filled) +- Engine is configured in `.opencode/docs/technical-preferences.md` (Engine Specialists section filled) - No existing GDD for the requested combat feature **Input:** `/team-combat parry and riposte system` @@ -133,7 +133,7 @@ with verdict COMPLETE / NEEDS WORK / BLOCKED and handoffs to `/code-review`, ### Case 5: Architecture Phase Engine Routing — Engine specialist receives correct context **Fixture:** -- `.claude/docs/technical-preferences.md` has Engine Specialists section populated (e.g., Primary: godot-specialist) +- `.opencode/docs/technical-preferences.md` has Engine Specialists section populated (e.g., Primary: godot-specialist) - Architecture sketch produced by gameplay-programmer is available - Engine version pinned in `docs/engine-reference/godot/VERSION.md` @@ -141,14 +141,14 @@ with verdict COMPLETE / NEEDS WORK / BLOCKED and handoffs to `/code-review`, **Expected behavior:** 1. Phase 2 — gameplay-programmer produces architecture sketch -2. Skill reads `.claude/docs/technical-preferences.md` Engine Specialists section to identify the primary engine specialist agent type +2. Skill reads `.opencode/docs/technical-preferences.md` Engine Specialists section to identify the primary engine specialist agent type 3. Engine specialist is spawned with: the architecture sketch, the GDD path, the engine version from `VERSION.md`, and explicit instructions to check for deprecated APIs 4. Engine specialist output (idiom notes, deprecated API warnings, native system recommendations) is returned to orchestrator 5. Orchestrator incorporates engine notes into the architecture before presenting Phase 2 results to user 6. `AskUserQuestion` includes engine specialist's notes alongside the architecture sketch **Assertions:** -- [ ] Engine specialist agent type is read from `.claude/docs/technical-preferences.md` — not hardcoded +- [ ] Engine specialist agent type is read from `.opencode/docs/technical-preferences.md` — not hardcoded - [ ] Engine specialist prompt includes the architecture sketch and GDD path - [ ] Engine specialist checks for deprecated APIs against the pinned engine version - [ ] Engine specialist output is incorporated before Phase 3 begins (not skipped or appended separately) diff --git a/skill-testing-framework/skills/team/team-ui.md b/skill-testing-framework/skills/team/team-ui.md index 57a1237..98ac514 100644 --- a/skill-testing-framework/skills/team/team-ui.md +++ b/skill-testing-framework/skills/team/team-ui.md @@ -40,7 +40,7 @@ with verdict COMPLETE / BLOCKED and handoffs to `/ux-review`, `/code-review`, - `design/player-journey.md` exists - `design/ux/interaction-patterns.md` exists with relevant patterns - `design/accessibility-requirements.md` exists with committed tier (e.g., Enhanced) -- Engine UI specialist configured in `.claude/docs/technical-preferences.md` +- Engine UI specialist configured in `.opencode/docs/technical-preferences.md` **Input:** `/team-ui inventory screen` diff --git a/skill-testing-framework/skills/utility/brainstorm.md b/skill-testing-framework/skills/utility/brainstorm.md index 846ecf5..29347c2 100644 --- a/skill-testing-framework/skills/utility/brainstorm.md +++ b/skill-testing-framework/skills/utility/brainstorm.md @@ -49,7 +49,7 @@ In `solo` mode: all 4 gates are skipped. Output notes all 4 as: "[GATE-ID] skipp **Fixture:** - No existing `design/gdd/game-concept.md` -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` **Input:** `/brainstorm` @@ -77,7 +77,7 @@ In `solo` mode: all 4 gates are skipped. Output notes all 4 as: "[GATE-ID] skipp **Fixture:** - Concept draft is complete -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` - CD-PILLARS gate returns REJECT: "The concept has no identifiable creative pillar" **Input:** `/brainstorm` @@ -101,7 +101,7 @@ In `solo` mode: all 4 gates are skipped. Output notes all 4 as: "[GATE-ID] skipp **Fixture:** - No existing game concept -- `production/session-state/review-mode.txt` contains `lean` +- `production/review-mode.txt` contains `lean` **Input:** `/brainstorm` @@ -124,7 +124,7 @@ In `solo` mode: all 4 gates are skipped. Output notes all 4 as: "[GATE-ID] skipp **Fixture:** - No existing game concept -- `production/session-state/review-mode.txt` contains `solo` +- `production/review-mode.txt` contains `solo` **Input:** `/brainstorm` @@ -147,7 +147,7 @@ In `solo` mode: all 4 gates are skipped. Output notes all 4 as: "[GATE-ID] skipp **Fixture:** - Concept draft is complete -- `production/session-state/review-mode.txt` contains `full` +- `production/review-mode.txt` contains `full` - PR-SCOPE gate returns CONCERNS: "The concept scope would require 18+ months for a solo developer" **Input:** `/brainstorm` diff --git a/skill-testing-framework/skills/utility/skill-improve.md b/skill-testing-framework/skills/utility/skill-improve.md index 459aff1..bd2be95 100644 --- a/skill-testing-framework/skills/utility/skill-improve.md +++ b/skill-testing-framework/skills/utility/skill-improve.md @@ -39,7 +39,7 @@ None. `/skill-improve` is a meta-utility skill. No director gates apply. ### Case 1: Happy Path — Skill With 2 Static Failures, Both Fixed, IMPROVED **Fixture:** -- `.claude/skills/some-skill/SKILL.md` has 2 static failures: +- `.opencode/skills/some-skill/SKILL.md` has 2 static failures: - Check 4: no "May I write" language despite having Write in allowed-tools - Check 5: no next-step handoff at the end @@ -51,7 +51,7 @@ None. `/skill-improve` is a meta-utility skill. No director gates apply. 3. Skill proposes fixes: - Add "May I write" language to the appropriate phase - Add a next-step handoff section at the end -4. Skill asks "May I write improvements to `.claude/skills/some-skill/SKILL.md`?" +4. Skill asks "May I write improvements to `.opencode/skills/some-skill/SKILL.md`?" 5. Fixes applied; `/skill-test static some-skill` re-run — now 7/7 checks pass 6. Verdict is IMPROVED (5→7) @@ -67,7 +67,7 @@ None. `/skill-improve` is a meta-utility skill. No director gates apply. ### Case 2: Fix Causes Regression — Score Comparison Shows Regression, REVERTED **Fixture:** -- `.claude/skills/some-skill/SKILL.md` has 1 static failure (missing handoff) +- `.opencode/skills/some-skill/SKILL.md` has 1 static failure (missing handoff) - Proposed fix inadvertently removes the verdict keywords section (introducing a new failure) @@ -94,7 +94,7 @@ None. `/skill-improve` is a meta-utility skill. No director gates apply. ### Case 3: Skill With Category Assignment — Baseline Captures Both Scores **Fixture:** -- `.claude/skills/gate-check/SKILL.md` is a gate skill with 1 static failure +- `.opencode/skills/gate-check/SKILL.md` is a gate skill with 1 static failure and 2 category (G-criteria) failures - `tests/skills/quality-rubric.md` has Gate Skills section @@ -106,7 +106,7 @@ None. `/skill-improve` is a meta-utility skill. No director gates apply. - Category: 3/5 G-criteria pass 2. Combined baseline: 9/12 3. Skill diagnoses all 3 failures and proposes fixes -4. "May I write improvements to `.claude/skills/gate-check/SKILL.md`?" +4. "May I write improvements to `.opencode/skills/gate-check/SKILL.md`?" 5. Fixes applied; both test types re-run 6. Re-test: static 7/7, category 5/5 = 12/12 7. Verdict is IMPROVED (9→12) @@ -123,7 +123,7 @@ None. `/skill-improve` is a meta-utility skill. No director gates apply. ### Case 4: Skill Already Perfect — No Improvements Needed **Fixture:** -- `.claude/skills/brainstorm/SKILL.md` has no static failures +- `.opencode/skills/brainstorm/SKILL.md` has no static failures - Category score is also 5/5 (if applicable) **Input:** `/skill-improve brainstorm` diff --git a/skill-testing-framework/skills/utility/skill-test.md b/skill-testing-framework/skills/utility/skill-test.md index 9687bae..e1e352e 100644 --- a/skill-testing-framework/skills/utility/skill-test.md +++ b/skill-testing-framework/skills/utility/skill-test.md @@ -11,8 +11,8 @@ compliance, and category-rubric scoring. It operates in three modes: table. - **spec**: Reads a test spec file from `tests/skills/` and evaluates the skill against each test case assertion, producing a case-by-case verdict. -- **audit**: Produces a coverage table of all skills in `.claude/skills/` and - all agents in `.claude/agents/`, showing which have spec files and which do not. +- **audit**: Produces a coverage table of all skills in `.opencode/skills/` and + all agents in `.opencode/agents/`, showing which have spec files and which do not. An additional **category** mode reads the quality rubric for a skill category (e.g., gate skills) and scores the skill against rubric criteria. The verdict @@ -43,7 +43,7 @@ None. `/skill-test` is a meta-utility skill. No director gates apply. ### Case 1: Static Mode — Well-formed skill, all 7 checks pass, COMPLIANT **Fixture:** -- `.claude/skills/brainstorm/SKILL.md` exists and is well-formed: +- `.opencode/skills/brainstorm/SKILL.md` exists and is well-formed: - Has all required frontmatter fields - Has ≥2 phase headings - Has verdict keywords @@ -55,7 +55,7 @@ None. `/skill-test` is a meta-utility skill. No director gates apply. **Input:** `/skill-test static brainstorm` **Expected behavior:** -1. Skill reads `.claude/skills/brainstorm/SKILL.md` +1. Skill reads `.opencode/skills/brainstorm/SKILL.md` 2. Skill runs all 7 structural checks 3. All 7 checks pass 4. Skill outputs a PASS/FAIL table with all 7 checks marked PASS @@ -72,7 +72,7 @@ None. `/skill-test` is a meta-utility skill. No director gates apply. ### Case 2: Static Mode — Skill Missing "May I Write" Despite Write Tool in allowed-tools **Fixture:** -- `.claude/skills/some-skill/SKILL.md` has `Write` in `allowed-tools` frontmatter +- `.opencode/skills/some-skill/SKILL.md` has `Write` in `allowed-tools` frontmatter - The skill body has no "May I write" or "May I update" language **Input:** `/skill-test static some-skill` @@ -97,7 +97,7 @@ None. `/skill-test` is a meta-utility skill. No director gates apply. **Fixture:** - `tests/skills/gate-check.md` exists with 5 test cases -- `.claude/skills/gate-check/SKILL.md` exists +- `.opencode/skills/gate-check/SKILL.md` exists **Input:** `/skill-test spec gate-check` @@ -119,14 +119,14 @@ None. `/skill-test` is a meta-utility skill. No director gates apply. ### Case 4: Audit Mode — Coverage Table of All Skills and Agents **Fixture:** -- `.claude/skills/` contains 72+ skill directories -- `.claude/agents/` contains 49+ agent files +- `.opencode/skills/` contains 72+ skill directories +- `.opencode/agents/` contains 49+ agent files - `tests/skills/` contains spec files for a subset of skills **Input:** `/skill-test audit` **Expected behavior:** -1. Skill enumerates all skills in `.claude/skills/` and all agents in `.claude/agents/` +1. Skill enumerates all skills in `.opencode/skills/` and all agents in `.opencode/agents/` 2. Skill checks `tests/skills/` for a corresponding spec file for each 3. Skill produces a coverage table: - Each skill/agent listed @@ -147,7 +147,7 @@ None. `/skill-test` is a meta-utility skill. No director gates apply. **Fixture:** - `tests/skills/quality-rubric.md` exists with a "Gate Skills" section defining criteria G1-G5 (e.g., G1: has mode guard, G2: has verdict table, etc.) -- `.claude/skills/gate-check/SKILL.md` is a gate skill +- `.opencode/skills/gate-check/SKILL.md` is a gate skill **Input:** `/skill-test category gate-check` diff --git a/skill-testing-framework/templates/agent-test-spec.md b/skill-testing-framework/templates/agent-test-spec.md index 875edbd..7bfe496 100644 --- a/skill-testing-framework/templates/agent-test-spec.md +++ b/skill-testing-framework/templates/agent-test-spec.md @@ -17,7 +17,7 @@ delegates vs. handles directly. Include which gates it triggers (if any).] ## Static Assertions -- [ ] Agent file exists at `.claude/agents/[name].md` +- [ ] Agent file exists at `.opencode/agents/[name].md` - [ ] Frontmatter has `name`, `description`, `model`, `tools` fields - [ ] Domain clearly stated - [ ] Escalation path documented diff --git a/tests/workflow/invariants.mjs b/tests/workflow/invariants.mjs index e3ad6f3..f621035 100644 --- a/tests/workflow/invariants.mjs +++ b/tests/workflow/invariants.mjs @@ -270,5 +270,59 @@ console.log('\n=== Cross-Cutting Invariants ===\n'); } } +{ // I10: skill-testing-framework catalog.yaml covers all skills in .opencode/skills/ + const catalogPath = join(ROOT, 'skill-testing-framework', 'catalog.yaml'); + if (existsSync(catalogPath)) { + const yaml = readFileSync(catalogPath, 'utf-8'); + const cataloged = new Set([...yaml.matchAll(/^ - name: ([a-z][\w-]+)/gm)].map(m => m[1])); + const skillDirs = readdirSync(SKILLS_DIR).filter(d => { + const p = join(SKILLS_DIR, d); + return statSync(p).isDirectory() && existsSync(join(p, 'SKILL.md')); + }); + const missing = skillDirs.filter(s => !cataloged.has(s)); + run('I10: All skills in .opencode/skills/ are cataloged in skill-testing-framework/catalog.yaml', () => { + if (missing.length > 0) { + throw new Error(`Skills not in catalog.yaml: ${missing.join(', ')}`); + } + }); + } else { + run('I10: skill-testing-framework/catalog.yaml exists', () => { + throw new Error('catalog.yaml not found'); + }); + } +} + +{ // I11: No stale .claude/ paths remain in skill-testing-framework spec files + const frameworkDir = join(ROOT, 'skill-testing-framework'); + if (existsSync(frameworkDir)) { + const mdFiles = []; + function walk(dir) { + for (const e of readdirSync(dir, { withFileTypes: true })) { + const fp = join(dir, e.name); + if (e.isDirectory()) walk(fp); + else if (e.name.endsWith('.md')) mdFiles.push(fp); + } + } + walk(frameworkDir); + const stale = []; + for (const fp of mdFiles) { + const content = readFileSync(fp, 'utf-8'); + const claudeRefs = content.match(/\.claude\/[\w./-]+/g); + const sessionStateRefs = content.match(/production\/session-state\/review-mode\.txt/g); + if (claudeRefs) stale.push(...claudeRefs.map(r => `${fp.replace(ROOT, '')}: ${r}`)); + if (sessionStateRefs) stale.push(...sessionStateRefs.map(r => `${fp.replace(ROOT, '')}: ${r}`)); + } + run('I11: No stale .claude/ or session-state/ paths in spec files', () => { + if (stale.length > 0) { + throw new Error(`${stale.length} stale refs:\n ${stale.join('\n ')}`); + } + }); + } else { + run('I11: skill-testing-framework directory exists', () => { + throw new Error('skill-testing-framework/ not found'); + }); + } +} + console.log(`\nInvariants: ${passCount}/${testCount} passed\n`); process.exit(passCount === testCount ? 0 : 1); From 71f22ea29ac329072ebeee3cda895f03dfd806b2 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Tue, 5 May 2026 22:10:09 +0200 Subject: [PATCH 11/21] fix: Address PR review comments - Remove redundant import in gates.mjs - Fix stale counts in CONTRIBUTING.md (75->76, 50->51) - Fix comment label in paths.mjs (P8->P9) - Update branding in AGENTS.md and README.md --- docs/CONTRIBUTING.md | 4 ++-- skill-testing-framework/AGENTS.md | 4 ++-- skill-testing-framework/README.md | 2 +- tests/workflow/gates.mjs | 3 +-- tests/workflow/paths.mjs | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index ca838fc..0a8b670 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -22,8 +22,8 @@ The OCGS framework has 5 component types: | Component | Location | Purpose | |-----------|----------|---------| | **Agents** | `.opencode/agents/` | Agent definitions (49 files) | -| **Skills** | `.opencode/skills/` | Skill workflows (75 directories) | -| **Commands** | `.opencode/commands/` | Slash commands (50 files) | +| **Skills** | `.opencode/skills/` | Skill workflows (76 directories) | +| **Commands** | `.opencode/commands/` | Slash commands (51 files) | | **Rules** | `.opencode/rules/` | Coding standards (11 files) | | **Plugins** | `.opencode/plugins/` | TypeScript hooks | diff --git a/skill-testing-framework/AGENTS.md b/skill-testing-framework/AGENTS.md index 64c3a96..0889184 100644 --- a/skill-testing-framework/AGENTS.md +++ b/skill-testing-framework/AGENTS.md @@ -1,6 +1,6 @@ -# CCGS Skill Testing Framework — Claude Instructions +# OCGS Skill Testing Framework — Agent Instructions -This folder is the quality assurance layer for the Claude Code Game Studios skill/agent +This folder is the quality assurance layer for the OpenCode Game Studios skill/agent framework. It is self-contained and separate from any game project. ## Key files diff --git a/skill-testing-framework/README.md b/skill-testing-framework/README.md index 644380c..066d463 100644 --- a/skill-testing-framework/README.md +++ b/skill-testing-framework/README.md @@ -1,4 +1,4 @@ -# CCGS Skill Testing Framework +# OCGS Skill Testing Framework Quality assurance infrastructure for the **Claude Code Game Studios** framework. Tests the skills and agents themselves — not any game built with them. diff --git a/tests/workflow/gates.mjs b/tests/workflow/gates.mjs index 98c4313..1f4378f 100644 --- a/tests/workflow/gates.mjs +++ b/tests/workflow/gates.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { readFileSync, existsSync } from 'fs'; +import { readFileSync, existsSync, readdirSync } from 'fs'; import { join, resolve, dirname } from 'path'; import { fileURLToPath } from 'url'; @@ -228,5 +228,4 @@ if (gate) { } console.log(`\nGates: ${passCount}/${testCount} passed\n`); -import { readdirSync } from 'fs'; process.exit(passCount === testCount ? 0 : 1); diff --git a/tests/workflow/paths.mjs b/tests/workflow/paths.mjs index cf16fb4..3130905 100644 --- a/tests/workflow/paths.mjs +++ b/tests/workflow/paths.mjs @@ -139,7 +139,7 @@ const COMMAND_REF_RE = /`\/([a-z][\w-]+)`/g; } } -{ // P8: Workflow transition docs exist for defined transitions +{ // P9: Workflow transition docs exist for defined transitions const transitionDocs = [ 'docs/workflow-transitions.md', 'docs/hybrid-workflow.md', From 1bbeed009ff8e62bf29d8a26ad5d855a66da4007 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Thu, 7 May 2026 19:33:03 +0200 Subject: [PATCH 12/21] docs: Aseprite MCP integration design doc Design for integrating aseprite-mcp into the OCGS workflow: - Git submodule at tools/aseprite-mcp/ - Project-level MCP config in opencode.json - New art-generate skill for programmatic placeholder art creation - Asset directory structure for generated .aseprite and .png files --- ...6-05-06-aseprite-mcp-integration-design.md | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 framework/docs/superpowers/specs/2026-05-06-aseprite-mcp-integration-design.md diff --git a/framework/docs/superpowers/specs/2026-05-06-aseprite-mcp-integration-design.md b/framework/docs/superpowers/specs/2026-05-06-aseprite-mcp-integration-design.md new file mode 100644 index 0000000..3a10a97 --- /dev/null +++ b/framework/docs/superpowers/specs/2026-05-06-aseprite-mcp-integration-design.md @@ -0,0 +1,199 @@ +# Aseprite MCP Integration Design + +> **Status:** Draft +> **Date:** 2026-05-06 +> **Context:** Integrate the [aseprite-mcp](https://github.com/striderZA/aseprite-mcp) server into the OCGS workflow for programmatic art generation from asset specs. + +## 1. Motivation + +The OCGS workflow currently has three art-focused skills: + +| Skill | Function | +|-------|----------| +| `art-bible` | Defines visual identity, palette, shape language, asset standards | +| `asset-spec` | Generates per-asset visual specs with dimensions, format, naming | +| `asset-audit` | Validates delivered assets against specs | + +There's a gap: **no skill creates the actual art files.** An agent can describe what art to make and check if it exists, but can't make it. The Aseprite MCP closes this gap by allowing programmatic sprite creation, drawing, animation, and export from within an agent session. + +## 2. Architecture + +### 2.1 Git Submodule + +``` +tools/aseprite-mcp/ → https://github.com/striderZA/aseprite-mcp.git +``` + +Pinned to a specific commit/tag for reproducible builds. `ASEPRITE_PATH` is set via environment variable in the MCP config (not hardcoded in the repo). + +### 2.2 Project-Level MCP Config + +Added to `opencode.json` alongside the existing Godot MCP entry (which remains disabled by default): + +```json +"mcp": { + "aseprite": { + "type": "local", + "command": ["uv", "--directory", "tools/aseprite-mcp", "run", "--no-sync", "-m", "aseprite_mcp"], + "enabled": true, + "environment": { + "ASEPRITE_PATH": "E:\\Jaco\\Projects\\Godot\\aseprite\\build\\bin\\aseprite.exe" + } + }, + "godot": { + "type": "local", + "command": ["npx", "@coding-solo/godot-mcp"], + "enabled": false, + "env": { + "GODOT_PATH": "E:\\Jaco\\Projects\\Godot\\engine\\godot.exe", + "DEBUG": "true" + } + } +} +``` + +The Aseprite MCP's 60+ tools become available to any agent in the project when this config is live. + +### 2.3 Skill: `art-generate` + +New skill at `.opencode/skills/art-generate/SKILL.md`. Creates .aseprite files from asset specs. + +## 3. Skill Design: `art-generate` + +### 3.1 Invocation + +``` +/art-generate system: +/art-generate level: +/art-generate character: +/art-generate path/to/spec-file.md +``` + +No argument → reads `design/assets/asset-manifest.md` and finds the first target with `Needed` assets. + +### 3.2 Phase 0: Parse Target & Gather Context + +**Reads:** +- The asset spec file (e.g., `design/assets/specs/[target]-assets.md`) — extracts all ASSET-NNN entries with their fields +- `design/art/art-bible.md` — extracts palette (Section 2), shape language (Section 3), asset standards (Section 8) +- `design/assets/asset-manifest.md` — checks which assets already have placeholders + +**Output:** list of assets to generate, filtered to `Status: Needed`. + +### 3.3 Phase 1: Per-Asset Generation + +For each asset, this pipeline executes via Aseprite MCP tools: + +``` +1. create_canvas(width, height, filename) +2. set_palette(filename, colors) # from art bible palette +3. add_layer(filename, "body") + add_layer(filename, "details") + add_layer(filename, "outline") # layer structure per category template +4. draw or fill shapes on each layer # programmatic, based on shape language +5. set_tag(filename, "idle", 1, N) # if multi-frame +6. export_sprite(filename, output_path) # PNG export +``` + +#### Category Templates + +**Sprite / 2D Asset:** +- Canvas: exact dimensions from spec (e.g., 256x256) +- Layers: body, details, outline +- Body fill: art bible semantic color for the asset's role (e.g., Threat Blue for enemies) +- Detail shapes: secondary color, offset or layered on body +- Outline: dark version of body color on outline layer +- If animated: duplicate frame range, set durations, tag + +**UI Icon:** +- Canvas: 32-64px (per art bible asset standards) +- Layers: icon, background (optional) +- Simplified shape matching asset function +- Uses UI palette from art bible Section 6 + +**VFX:** +- Canvas: dimensions matching target sprite +- Layers: core, glow, sparks +- Core: filled shape with color from VFX section +- Glow: same shape at lower opacity, additive blend mode +- Multi-frame if animated (tween opacity for fade) + +**Environment Tile/Prop:** +- Canvas: tile dimensions from spec +- Layers: base, shading, details +- Palette from environment section of art bible + +**Character Sprite:** +- Canvas: full sprite sheet dimensions (e.g., 1024x256 for 4 frames) +- Layers: body, head, arms, legs, outline +- Base pose on frame 1 +- Duplicate to frame 2-N, offset limbs for walk cycle (rough) +- Tag: idle (1), walk (2-5), etc. + +### 3.4 Phase 2: Output & Manifest Update + +**Output files:** +``` +assets/source/[target]/ASSET-NNN-asset-name.aseprite # source +assets/sprites/[target]/ASSET-NNN-asset-name.png # export +``` + +**Manifest update:** +- Change `Status` from `Needed` to `Placeholder Created` +- Add `Source` column with `.aseprite` path + +### 3.5 Phase 3: Verification + +For each created asset: +- `validate_scene(filename)` — confirms all required layers and frames exist +- File size check against asset standards +- Dimension check against spec + +If validation fails: report the issue, do NOT mark as Placeholder Created. + +### 3.6 Agent Routing + +- **Main session** (this agent): Executes generation pipeline, writes files, updates manifest +- **`art-director`** (subagent, optional): Consulted for color mapping from art bible to asset categories +- **`technical-artist`** (subagent, optional): Consulted for export format / compression settings + +## 4. Directory Changes + +| Path | Change | Reason | +|------|--------|--------| +| `tools/aseprite-mcp/` | New — git submodule | Aseprite MCP server source | +| `opencode.json` | Modified — add MCP block | Project-scoped MCP config | +| `.opencode/skills/art-generate/SKILL.md` | New | Art generation skill | +| `assets/source/` | New — per-target dirs | .aseprite source files | +| `assets/sprites/` | New — per-target dirs | Exported PNGs | + +## 5. Dependency Map + +``` +art-bible (palette, shape language, standards) + ↓ +asset-spec (dimensions, format, naming) + ↓ +art-generate (creates .aseprite + exports PNG) ← NEW + ↓ +asset-audit (validates delivered assets) +``` + +Each skill feeds into the next. `art-generate` sits between spec and audit — it produces the artifacts that audit validates. + +## 6. Risks & Mitigations + +| Risk | Mitigation | +|------|------------| +| Aseprite not installed / wrong path | MCP config has a clear ASEPRITE_PATH error; `opencode.json` validation catches this early | +| Generated art looks bad | Intentional — this is placeholder/prototype art, not production. The value is in correct dimensions, layers, palette, and naming. | +| Aseprite MCP tool failures mid-batch | Phase 3 verification per asset; failed assets are reported without blocking the rest | +| Submodule drift from upstream | Pin to a specific commit; upgrade explicitly via `git submodule update --remote` | +| Python/dependency conflicts | `uv` manages isolated venv; `--no-sync` uses cached deps after initial `uv sync` | + +## 7. Out of Scope + +- **Production-quality art generation** — this creates placeholders matching spec constraints, not artist-quality assets +- **Asset modification** — `art-generate` only creates new assets; editing existing ones is a future concern +- **Batch generation from multiple specs** — one target per invocation +- **AI image generation integration** — no Stable Diffusion / DALL-E calls; purely procedural art via Aseprite drawing tools From 500b80f8e178d135cfa78aff881feef644b77173 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Thu, 7 May 2026 19:54:43 +0200 Subject: [PATCH 13/21] feat: add aseprite-mcp submodule at tools/aseprite-mcp --- .gitignore | 3 +++ .gitmodules | 3 +++ tools/aseprite-mcp | 1 + 3 files changed, 7 insertions(+) create mode 100644 .gitmodules create mode 160000 tools/aseprite-mcp diff --git a/.gitignore b/.gitignore index 0686198..90c608e 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ desktop.ini *.swo *~ tests/agents/validation-report.md + +# Submodule dependencies +tools/aseprite-mcp/.venv/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ac2f5f6 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tools/aseprite-mcp"] + path = tools/aseprite-mcp + url = https://github.com/striderZA/aseprite-mcp.git diff --git a/tools/aseprite-mcp b/tools/aseprite-mcp new file mode 160000 index 0000000..be47592 --- /dev/null +++ b/tools/aseprite-mcp @@ -0,0 +1 @@ +Subproject commit be475927507344e6994dc43430b593a0223540d1 From 4f46157b9a8c9c61d3d01008696c0ca5a550f97c Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Thu, 7 May 2026 19:56:01 +0200 Subject: [PATCH 14/21] feat: add project-scoped MCP config for aseprite and godot --- opencode.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/opencode.json b/opencode.json index d10ae6a..9df2b03 100644 --- a/opencode.json +++ b/opencode.json @@ -8,6 +8,25 @@ "agent": "prototyper" } }, + "mcp": { + "aseprite": { + "type": "local", + "command": ["uv", "--directory", "tools/aseprite-mcp", "run", "--no-sync", "-m", "aseprite_mcp"], + "enabled": true, + "environment": { + "ASEPRITE_PATH": "E:\\Jaco\\Projects\\Godot\\aseprite\\build\\bin\\aseprite.exe" + } + }, + "godot": { + "type": "local", + "command": ["npx", "@coding-solo/godot-mcp"], + "enabled": false, + "env": { + "GODOT_PATH": "E:\\Jaco\\Projects\\Godot\\engine\\godot.exe", + "DEBUG": "true" + } + } + }, "permission": { "bash": { "git status*": "allow", From a464fe2f317af3b45ff851e7a489d203be4adba1 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Thu, 7 May 2026 19:56:50 +0200 Subject: [PATCH 15/21] feat: add asset output directories for art-generate skill --- assets/source/.gitkeep | 0 assets/sprites/.gitkeep | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/source/.gitkeep create mode 100644 assets/sprites/.gitkeep diff --git a/assets/source/.gitkeep b/assets/source/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/assets/sprites/.gitkeep b/assets/sprites/.gitkeep new file mode 100644 index 0000000..e69de29 From bef673df55ed8f3f68fc033e68cb6b801d6120a2 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Thu, 7 May 2026 19:58:52 +0200 Subject: [PATCH 16/21] feat: add art-generate skill for programmatic placeholder art --- .opencode/skills/art-generate/SKILL.md | 321 +++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 .opencode/skills/art-generate/SKILL.md diff --git a/.opencode/skills/art-generate/SKILL.md b/.opencode/skills/art-generate/SKILL.md new file mode 100644 index 0000000..8315a6a --- /dev/null +++ b/.opencode/skills/art-generate/SKILL.md @@ -0,0 +1,321 @@ +--- +name: art-generate +description: "Generates placeholder .aseprite files from asset specs using the Aseprite MCP. Reads asset specs and art bible, creates sprites with correct dimensions/palette/layers, exports PNGs. Run after /asset-spec has produced specs and /art-bible exists." +argument-hint: "[system: | level: | character: | path/to/spec.md]" +user-invocable: true +allowed-tools: Read, Glob, Grep, Write, Edit, Task, question +--- + +If no argument is provided, read `design/assets/asset-manifest.md`: +- If it exists: find the first target with any asset at `Status: Needed` and use `question`: + - Prompt: "The next unspecced target is **[target]**. Generate placeholder art for it?" + - Options: `[A] Yes — generate for [target]` / `[B] Pick a different target` / `[C] Stop here` +- If no manifest: fail with: + > "No asset manifest found. Run `/asset-spec [target]` first — I need asset specs to generate art from." + +--- + +## Phase 0: Parse Target + +Resolve the target: +1. If argument matches `system:` → spec at `design/assets/specs/[name]-assets.md` +2. If argument matches `level:` → spec at `design/assets/specs/[name]-assets.md` +3. If argument matches `character:` → spec at `design/assets/specs/[name]-assets.md` +4. If argument is a path → read that file directly +5. If argument is a path to a .md file → treat as spec file + +Fail if the spec file does not exist: +> "No asset spec found at `[path]`. Run `/asset-spec [target]` first." + +--- + +## Phase 1: Gather Context + +Read all source material before generating anything. + +### Required reads: +- **Asset spec**: Read the resolved spec file. Extract all `ASSET-NNN` entries. For each, extract: Category, Dimensions, Format, Naming, Visual Description. +- **Art bible**: Read `design/art/art-bible.md` — fail if missing: + > "No art bible found. Run `/art-bible` first — I need the palette and shape language to generate art." + Extract: Color System (Section 2), Shape Language (Section 3), Asset Standards (Section 8 — dimension tiers). +- **Asset manifest**: Read `design/assets/asset-manifest.md` — note which assets already have placeholders. Filter to assets with `Status: Needed`. + +### Present context summary: +> **art-generate: [Target Type] — [Target Name]** +> - Spec: [path] — [N] assets identified +> - Art bible: found — [N] palette colors, shape language: [style] +> - Assets to generate: [N] (filtered from [N] total — [N] already have placeholders) +> - Output: assets/source/[target]/ and assets/sprites/[target]/ + +--- + +## Phase 2: Per-Asset Generation + +For each asset with `Status: Needed`, execute the following pipeline. **Process one asset at a time — do NOT batch MCP calls.** + +### Step 2a: Create Canvas + +Construct the filename as `assets/source/[target]/[naming]` (replace `.png` or similar with `.aseprite`). + +Use the `create_canvas` MCP tool: +``` +create_canvas(width, height, filename) +``` + +Wait for success. If it fails, stop this asset and report. + +### Step 2b: Apply Palette + +Load the art bible palette. If the art bible specifies a named palette resource (e.g., "DB16", "RPG"), use: + +``` +load_palette_from_resource(filename, resource_name) +``` + +Otherwise extract hex colors from the art bible's Color System section and apply: + +``` +set_palette(filename, [hex_colors_array]) +``` + +### Step 2c: Create Layer Structure + +Create layers matching the asset category template: + +**Sprite / 2D Art:** +``` +add_layer(filename, "body") +set_layer(filename, "body") +set_layer_label_color(filename, "body", color_hex) +add_layer(filename, "details") +add_layer(filename, "outline") +``` + +**UI Icon:** +``` +add_layer(filename, "icon") +``` + +**VFX:** +``` +add_layer(filename, "core") +set_layer_blend_mode(filename, "core", "normal") +add_layer(filename, "glow") +set_layer_blend_mode(filename, "glow", "add") +add_layer(filename, "sparks") +``` + +**Environment:** +``` +add_layer(filename, "base") +add_layer(filename, "shading") +add_layer(filename, "details") +``` + +**Character Sprite:** +``` +add_layer(filename, "body") +add_layer(filename, "head") +add_layer(filename, "arms") +add_layer(filename, "legs") +add_layer(filename, "outline") +``` + +### Step 2d: Draw Placeholder Content + +Draw shapes on each layer following the art bible's shape language. Use the semantic color from the art bible for the asset's role. + +General approach per layer: +1. `set_layer(filename, layer_name)` — activate the layer +2. `set_frame(filename, 1)` — draw on frame 1 +3. Draw shapes: + - **Body/base**: Fill a rectangle/circle/polygon covering ~80% of the canvas at the body center position + - **Details**: Smaller shapes offset from center, using secondary/accent colors from the palette + - **Outline**: Thin rectangle around the body bounds using a dark color + +Use these drawing tools as appropriate: +- `draw_rectangle_at(filename, layer, frame, x, y, w, h, color, fill=true)` for blocky shapes +- `draw_circle_at(filename, layer, frame, cx, cy, r, color, fill=true)` for round shapes +- `draw_polygon(filename, layer, frame, points, color, fill=true)` for angular shapes (character limbs) +- `fill_area_at(filename, layer, frame, cx, cy, color)` for filled regions +- `apply_gradient_rect(filename, layer, frame, x, y, w, h, start, end, horizontal)` for gradient fills + +### Step 2e: Handle Animation + +If the spec indicates multiple frames (e.g., "4-frame sprite sheet"): + +``` +add_frames(filename, count=3, duration_ms=200) # frame 1 already exists +set_frame_duration(filename, 1, 200) +``` + +For each additional frame, duplicate frame 1 and add minor position offsets for limbs: +``` +copy_frame(filename, source_frame=1, target_frame=N) +``` + +Then tag the animation: +``` +set_tag(filename, name="default", from_frame=1, to_frame=N, direction="forward") +``` + +If not animated, skip this step. + +### Step 2f: Export + +``` +export_sprite(filename, output_path="assets/sprites/[target]/[naming]") +``` + +### Step 2g: Verify + +Use the quality tools to check the output: + +``` +validate_scene(filename, required_layers=[list from step 2c]) +``` + +Expected: JSON confirming all layers and frames exist. + +Also verify the exported file exists: +``` +Test-Path "assets/sprites/[target]/[naming]" +``` + +Expected: `True` + +### Error Handling + +If any MCP tool call fails: +``` +Question: "Tool [tool_name] failed for ASSET-[NNN] ([asset name]): [error]. Options:" +A) Retry this asset +B) Skip this asset, continue with next +C) Stop generation entirely +``` + +--- + +## Phase 3: Update Manifest + +After all assets are generated (or after partial completion), update `design/assets/asset-manifest.md`. + +For each generated asset, change its status from `Needed` to `Placeholder Created`. Add a `Source` column if it doesn't exist: + +``` +| ASSET-001 | hero-sprite | Sprite | Placeholder Created | design/assets/specs/hero-assets.md | assets/source/hero/ASSET-001-hero-sprite.aseprite | +``` + +If the manifest doesn't have a `Source` column yet, rewrite the header to include it. + +--- + +## Phase 4: Summary Report + +Present a completion summary: + +> **art-generate complete for [target]:** +> - [N]/[M] assets generated successfully +> - [N] failed (skipped) +> - Output: assets/source/[target]/ (source .aseprite files) +> - Output: assets/sprites/[target]/ (exported PNGs) +> - Manifest updated: design/assets/asset-manifest.md + +--- + +## Phase 5: Next Steps + +Use `question`: +- Prompt: "Placeholder art generated for **[target]**. What's next?" +- Options: + - `[A] Generate another target — /art-generate [next-target]` + - `[B] Run /asset-audit — validate generated assets against specs` + - `[C] Review generated art manually` + - `[D] Stop here` + +--- + +## Per-Category Drawing Templates + +### Sprite / 2D Asset (Default) + +``` +Canvas: spec dimensions (e.g. 256x256) +Layers: body, details, outline + +Frame 1: + layer=body: fill_rect(32, 32, 192, 192, body_color) + layer=details: draw_rect(48, 48, 160, 160, accent_color, fill=false) + layer=outline: draw_rect(30, 30, 196, 196, outline_color, fill=false) +``` + +### UI Icon + +``` +Canvas: 32x32 or 64x64 +Layers: icon + +Frame 1: + layer=icon: fill_rect(4, 4, 24, 24, palette[0]) +``` + +### VFX + +``` +Canvas: matching target sprite dimensions +Layers: core, glow, sparks + +Frame 1: + layer=core: circle(center, radius*0.3, core_color, fill=true) + layer=glow: circle(center, radius, glow_color, fill=true, set opacity=128) +``` + +### Environment Prop + +``` +Canvas: tile dimensions +Layers: base, shading, details + +Frame 1: + layer=base: fill_rect(0, 0, w, h, base_color) + layer=shading: gradient_rect(0, 0, w, h, shade_top, shade_bottom) +``` + +### Character Sprite + +``` +Canvas: sprite sheet width, frame height +Layers: body, head, arms, legs, outline + +Frame 1 (idle pose): + layer=body: fill_rect(24, 40, 16, 24, body_color) + layer=head: fill_rect(28, 24, 8, 12, skin_color) + layer=arms: fill_rect(16, 44, 8, 8, skin_color) + draw_rect(40, 44, 8, 8, skin_color) + layer=legs: fill_rect(24, 64, 6, 12, leg_color) + fill_rect(34, 64, 6, 12, leg_color) + layer=outline: draw_rect(22, 22, 20, 54, outline) + +Frame 2 (walk frame 1): copy_frame(1, 2) + layer=legs: offset legs by +2 on x to show stride +``` + +--- + +## Error Recovery + +| Error | Recovery | +|-------|----------| +| Spec file not found | Fail with clear message pointing to /asset-spec | +| Art bible not found | Fail — generation without palette produces wrong colors | +| MCP tool timeout | Report tool + args that failed, offer retry/skip/stop | +| Palette resource unknown | Fall back to `set_palette` with hex colors from art bible | +| Export fails | Check file path permissions, suggest manual export | +| validate_scene fails | Report which layers/frames are missing, offer to fix via ensure_layers_present | + +## Collaborative Protocol + +- Never generate without user confirming the target +- Report each asset's success/failure immediately after processing it +- Write the manifest update only after explicit approval +- If the art bible's palette has changed since the spec was written, ask which to use From 0da728ca20d7115afc6f4497c596dfdeb93bb8f4 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Thu, 7 May 2026 20:00:37 +0200 Subject: [PATCH 17/21] docs: aseprite integration plan --- .../2026-05-06-aseprite-mcp-integration.md | 571 ++++++++++++++++++ 1 file changed, 571 insertions(+) create mode 100644 framework/docs/superpowers/plans/2026-05-06-aseprite-mcp-integration.md diff --git a/framework/docs/superpowers/plans/2026-05-06-aseprite-mcp-integration.md b/framework/docs/superpowers/plans/2026-05-06-aseprite-mcp-integration.md new file mode 100644 index 0000000..9ac79f4 --- /dev/null +++ b/framework/docs/superpowers/plans/2026-05-06-aseprite-mcp-integration.md @@ -0,0 +1,571 @@ +# Aseprite MCP Integration Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Integrate aseprite-mcp into the OCGS workflow — git submodule, project MCP config, asset directories, and the `art-generate` skill for programmatic placeholder art from specs. + +**Architecture:** aseprite-mcp lives at `tools/aseprite-mcp/` as a git submodule. The project's `opencode.json` declares it as a project-scoped MCP server (enabled). A new OCGS skill `art-generate` reads asset specs + art bible, creates .aseprite files via the MCP tools, and exports PNGs. + +**Tech Stack:** Python 3.13+, FastMCP (mcp[cli]), uv, Aseprite Lua scripting, OCGS skill framework. + +--- + +### Prior Setup + +Check that the Aseprite binary exists at the expected path: + +```powershell +Test-Path "E:\Jaco\Projects\Godot\aseprite\build\bin\aseprite.exe" +``` + +If `False`, the `ASEPRITE_PATH` in opencode.json needs adjustment. + +--- + +### Task 1: Add Git Submodule + Install Dependencies + +**Files:** +- Create: `tools/aseprite-mcp/` (submodule) + +- [ ] **Step 1: Add submodule** + +```powershell +git submodule add https://github.com/striderZA/aseprite-mcp.git tools/aseprite-mcp +``` + +Expected output: `Cloning into 'E:/Jaco/Projects/Godot/OpenCodeGameDesign/tools/aseprite-mcp'...` + +- [ ] **Step 2: Install Python dependencies** + +```powershell +uv sync +``` + +Workdir: `tools/aseprite-mcp` + +Expected: Creates `.venv` and installs httpx, mcp[cli], python-dotenv. + +- [ ] **Step 3: Verify uv can run the server** + +```powershell +uv run --no-sync -m aseprite_mcp --help +``` + +Workdir: `tools/aseprite-mcp` + +Expected: Prints FastMCP usage (no error). Note: `--no-sync` since we just ran `uv sync`. + +- [ ] **Step 4: Create .gitignore entry (if needed)** + +Check if `.gitignore` already covers `tools/` submodules. Add if missing: + +``` +# Submodule dependencies +tools/aseprite-mcp/.venv/ +``` + +- [ ] **Step 5: Commit** + +```powershell +git add tools/aseprite-mcp .gitignore +git commit -m "feat: add aseprite-mcp submodule at tools/aseprite-mcp" +``` + +--- + +### Task 2: Add Project-Level MCP Config + +**Files:** +- Modify: `opencode.json` (add `mcp` block) + +- [ ] **Step 1: Read existing opencode.json to confirm current shape** + +```powershell +Get-Content opencode.json +``` + +- [ ] **Step 2: Add the mcp block** + +Edit `opencode.json` to add the `mcp` key at the top level, before `permission`: + +```json +{ + "$schema": "https://opencode.ai/config.json", + "plugin": ["./.opencode/plugins/ccgs-hooks.ts"], + "command": { + "hybrid-prototype": { + "template": "Run the hybrid-prototype skill: load .opencode/skills/hybrid-prototype/SKILL.md and follow the fast-lane prototype workflow. Concept: $ARGUMENTS", + "description": "Fast-lane prototype for discovery phase — build a playable prototype in 2-3 days with minimal process overhead.", + "agent": "prototyper" + } + }, + "mcp": { + "aseprite": { + "type": "local", + "command": ["uv", "--directory", "tools/aseprite-mcp", "run", "--no-sync", "-m", "aseprite_mcp"], + "enabled": true, + "environment": { + "ASEPRITE_PATH": "E:\\Jaco\\Projects\\Godot\\aseprite\\build\\bin\\aseprite.exe" + } + }, + "godot": { + "type": "local", + "command": ["npx", "@coding-solo/godot-mcp"], + "enabled": false, + "env": { + "GODOT_PATH": "E:\\Jaco\\Projects\\Godot\\engine\\godot.exe", + "DEBUG": "true" + } + } + }, + "permission": { + ... + } +} +``` + +- [ ] **Step 3: Validate JSON** + +```powershell +Get-Content opencode.json | python -m json.tool > $null +``` + +Expected: No output (valid JSON). + +- [ ] **Step 4: Commit** + +```powershell +git add opencode.json +git commit -m "feat: add project-scoped MCP config for aseprite and godot" +``` + +--- + +### Task 3: Create Asset Directory Structure + +**Files:** +- Create: `assets/source/.gitkeep` +- Create: `assets/sprites/.gitkeep` + +- [ ] **Step 1: Create directories and .gitkeep files** + +```powershell +New-Item -ItemType Directory -Path "assets/source" -Force | Out-Null +New-Item -ItemType Directory -Path "assets/sprites" -Force | Out-Null +New-Item -ItemType File -Path "assets/source/.gitkeep" -Force | Out-Null +New-Item -ItemType File -Path "assets/sprites/.gitkeep" -Force | Out-Null +``` + +- [ ] **Step 2: Commit** + +```powershell +git add assets/ +git commit -m "feat: add asset output directories for art-generate skill" +``` + +--- + +### Task 4: Create art-generate Skill + +**Files:** +- Create: `.opencode/skills/art-generate/SKILL.md` + +- [ ] **Step 1: Write the skill file** + +Write `.opencode/skills/art-generate/SKILL.md` with the following content: + +```markdown +--- +name: art-generate +description: "Generates placeholder .aseprite files from asset specs using the Aseprite MCP. Reads asset specs and art bible, creates sprites with correct dimensions/palette/layers, exports PNGs. Run after /asset-spec has produced specs and /art-bible exists." +argument-hint: "[system: | level: | character: | path/to/spec.md]" +user-invocable: true +allowed-tools: Read, Glob, Grep, Write, Edit, Task, question +--- + +If no argument is provided, read `design/assets/asset-manifest.md`: +- If it exists: find the first target with any asset at `Status: Needed` and use `question`: + - Prompt: "The next unspecced target is **[target]**. Generate placeholder art for it?" + - Options: `[A] Yes — generate for [target]` / `[B] Pick a different target` / `[C] Stop here` +- If no manifest: fail with: + > "No asset manifest found. Run `/asset-spec [target]` first — I need asset specs to generate art from." + +--- + +## Phase 0: Parse Target + +Resolve the target: +1. If argument matches `system:` → spec at `design/assets/specs/[name]-assets.md` +2. If argument matches `level:` → spec at `design/assets/specs/[name]-assets.md` +3. If argument matches `character:` → spec at `design/assets/specs/[name]-assets.md` +4. If argument is a path → read that file directly +5. If argument is a path to a .md file → treat as spec file + +Fail if the spec file does not exist: +> "No asset spec found at `[path]`. Run `/asset-spec [target]` first." + +--- + +## Phase 1: Gather Context + +Read all source material before generating anything. + +### Required reads: +- **Asset spec**: Read the resolved spec file. Extract all `ASSET-NNN` entries. For each, extract: Category, Dimensions, Format, Naming, Visual Description. +- **Art bible**: Read `design/art/art-bible.md` — fail if missing: + > "No art bible found. Run `/art-bible` first — I need the palette and shape language to generate art." + Extract: Color System (Section 2), Shape Language (Section 3), Asset Standards (Section 8 — dimension tiers). +- **Asset manifest**: Read `design/assets/asset-manifest.md` — note which assets already have placeholders. Filter to assets with `Status: Needed`. + +### Present context summary: +> **art-generate: [Target Type] — [Target Name]** +> - Spec: [path] — [N] assets identified +> - Art bible: found — [N] palette colors, shape language: [style] +> - Assets to generate: [N] (filtered from [N] total — [N] already have placeholders) +> - Output: assets/source/[target]/ and assets/sprites/[target]/ + +--- + +## Phase 2: Per-Asset Generation + +For each asset with `Status: Needed`, execute the following pipeline. **Process one asset at a time — do NOT batch MCP calls.** + +### Step 2a: Create Canvas + +Construct the filename as `assets/source/[target]/[naming]` (replace `.png` or similar with `.aseprite`). + +``` +create_canvas(width, height, filename) +``` + +Wait for success. If it fails, stop this asset and report. + +### Step 2b: Apply Palette + +Load the art bible palette. If the art bible specifies a named palette resource (e.g., "DB16", "RPG"), use: + +``` +load_palette_from_resource(filename, resource_name) +``` + +Otherwise extract hex colors from the art bible's Color System section and apply: + +``` +set_palette(filename, [hex_colors_array]) +``` + +### Step 2c: Create Layer Structure + +Create layers matching the asset category template: + +**Sprite / 2D Art:** +``` +add_layer(filename, "body") +set_layer(filename, "body") +set_layer_label_color(filename, "body", color_hex) +add_layer(filename, "details") +add_layer(filename, "outline") +``` + +**UI Icon:** +``` +add_layer(filename, "icon") +``` + +**VFX:** +``` +add_layer(filename, "core") +set_layer_blend_mode(filename, "core", "normal") +add_layer(filename, "glow") +set_layer_blend_mode(filename, "glow", "add") +add_layer(filename, "sparks") +``` + +**Environment:** +``` +add_layer(filename, "base") +add_layer(filename, "shading") +add_layer(filename, "details") +``` + +**Character Sprite:** +``` +add_layer(filename, "body") +add_layer(filename, "head") +add_layer(filename, "arms") +add_layer(filename, "legs") +add_layer(filename, "outline") +``` + +### Step 2d: Draw Placeholder Content + +Draw shapes on each layer following the art bible's shape language. Use the semantic color from the art bible for the asset's role. + +General approach per layer: +1. `set_layer(filename, layer_name)` — activate the layer +2. `set_frame(filename, 1)` — draw on frame 1 +3. Draw shapes: + - **Body/base**: Fill a rectangle/circle/polygon covering ~80% of the canvas at the body center position + - **Details**: Smaller shapes offset from center, using secondary/accent colors from the palette + - **Outline**: Thin rectangle around the body bounds using a dark color + +Use these drawing tools as appropriate: +- `draw_rectangle_at(filename, layer, frame, x, y, w, h, color, fill=true)` for blocky shapes +- `draw_circle_at(filename, layer, frame, cx, cy, r, color, fill=true)` for round shapes +- `draw_polygon(filename, layer, frame, points, color, fill=true)` for angular shapes (character limbs) +- `fill_area_at(filename, layer, frame, cx, cy, color)` for filled regions +- `apply_gradient_rect(filename, layer, frame, x, y, w, h, start, end, horizontal)` for gradient fills + +### Step 2e: Handle Animation + +If the spec indicates multiple frames (e.g., "4-frame sprite sheet"): + +``` +add_frames(filename, count=3, duration_ms=200) # frame 1 already exists +set_frame_duration(filename, 1, 200) +``` + +For each additional frame, duplicate frame 1 and add minor position offsets for limbs: +``` +copy_frame(filename, source_frame=1, target_frame=N) +``` + +Then tag the animation: +``` +set_tag(filename, name="default", from_frame=1, to_frame=N, direction="forward") +``` + +If not animated, skip this step. + +### Step 2f: Export + +``` +export_sprite(filename, output_path="assets/sprites/[target]/[naming]") +``` + +### Step 2g: Verify + +Use the quality tools to check the output: + +``` +validate_scene(filename, required_layers=[list from step 2c]) +``` + +Expected: JSON confirming all layers and frames exist. + +Also verify the exported file exists: +``` +Test-Path "assets/sprites/[target]/[naming]" +``` + +Expected: `True` + +### Error Handling + +If any MCP tool call fails: +``` +Question: "Tool [tool_name] failed for ASSET-[NNN] ([asset name]): [error]. Options:" +A) Retry this asset +B) Skip this asset, continue with next +C) Stop generation entirely +``` + +--- + +## Phase 3: Update Manifest + +After all assets are generated (or after partial completion), update `design/assets/asset-manifest.md`. + +For each generated asset, change its status from `Needed` to `Placeholder Created`. Add a `Source` column if it doesn't exist: + +``` +| ASSET-001 | hero-sprite | Sprite | Placeholder Created | design/assets/specs/hero-assets.md | assets/source/hero/ASSET-001-hero-sprite.aseprite | +``` + +If the manifest doesn't have a `Source` column yet, rewrite the header to include it. + +--- + +## Phase 4: Summary Report + +Present a completion summary: + +> **art-generate complete for [target]:** +> - [N]/[M] assets generated successfully +> - [N] failed (skipped) +> - Output: assets/source/[target]/ (source .aseprite files) +> - Output: assets/sprites/[target]/ (exported PNGs) +> - Manifest updated: design/assets/asset-manifest.md + +--- + +## Phase 5: Next Steps + +Use `question`: +- Prompt: "Placeholder art generated for **[target]**. What's next?" +- Options: + - `[A] Generate another target — /art-generate [next-target]` + - `[B] Run /asset-audit — validate generated assets against specs` + - `[C] Review generated art manually` + - `[D] Stop here` + +--- + +## Per-Category Drawing Templates + +### Sprite / 2D Asset (Default) + +``` +Canvas: spec dimensions (e.g. 256x256) +Layers: body, details, outline + +Frame 1: + layer=body: fill_rect(32, 32, 192, 192, body_color) + layer=details: draw_rect(48, 48, 160, 160, accent_color, fill=false) + layer=outline: draw_rect(30, 30, 196, 196, outline_color, fill=false) +``` + +### UI Icon + +``` +Canvas: 32x32 or 64x64 +Layers: icon + +Frame 1: + layer=icon: fill_rect(4, 4, 24, 24, palette[0]) +``` + +### VFX + +``` +Canvas: matching target sprite dimensions +Layers: core, glow, sparks + +Frame 1: + layer=core: circle(center, radius*0.3, core_color, fill=true) + layer=glow: circle(center, radius, glow_color, fill=true, set opacity=128) +``` + +### Environment Prop + +``` +Canvas: tile dimensions +Layers: base, shading, details + +Frame 1: + layer=base: fill_rect(0, 0, w, h, base_color) + layer=shading: gradient_rect(0, 0, w, h, shade_top, shade_bottom) +``` + +### Character Sprite + +``` +Canvas: sprite sheet width, frame height +Layers: body, head, arms, legs, outline + +Frame 1 (idle pose): + layer=body: fill_rect(24, 40, 16, 24, body_color) # torso + layer=head: fill_rect(28, 24, 8, 12, skin_color) # head + layer=arms: fill_rect(16, 44, 8, 8, skin_color) # left arm + draw_rect(40, 44, 8, 8, skin_color) # right arm + layer=legs: fill_rect(24, 64, 6, 12, leg_color) # left leg + fill_rect(34, 64, 6, 12, leg_color) # right leg + layer=outline: draw_rect(22, 22, 20, 54, outline) # body outline + +Frame 2 (walk frame 1): copy_frame(1, 2) + layer=legs: offset legs by +2 on x to show stride +``` + +--- + +## Error Recovery + +| Error | Recovery | +|-------|----------| +| Spec file not found | Fail with clear message pointing to /asset-spec | +| Art bible not found | Fail — generation without palette produces wrong colors | +| MCP tool timeout | Report tool + args that failed, offer retry/skip/stop | +| Palette resource unknown | Fall back to `set_palette` with hex colors from art bible | +| Export fails | Check file path permissions, suggest manual export | +| validate_scene fails | Report which layers/frames are missing, offer to fix via ensure_layers_present | + +## Collaborative Protocol + +- Never generate without user confirming the target +- Report each asset's success/failure immediately after processing it +- Write the manifest update only after explicit approval +- If the art bible's palette has changed since the spec was written, ask which to use +``` + +- [ ] **Step 2: Verify the skill file is valid** + +```powershell +Test-Path ".opencode/skills/art-generate/SKILL.md" +``` + +Expected: `True` + +- [ ] **Step 3: Commit** + +```powershell +git add .opencode/skills/art-generate/SKILL.md +git commit -m "feat: add art-generate skill for programmatic placeholder art" +``` + +--- + +### Task 5: Verify Integration End-to-End + +- [ ] **Step 1: Verify MCP server starts** + +Run the aseprite MCP server briefly to confirm it initializes: + +```powershell +$env:ASEPRITE_PATH = "E:\Jaco\Projects\Godot\aseprite\build\bin\aseprite.exe" +uv run --directory tools/aseprite-mcp --no-sync -m aseprite_mcp +``` + +After confirming it starts (`{"jsonrpc":"2.0","method":"...` output), kill with `Ctrl+C`. + +- [ ] **Step 2: Verify opencode.json is valid JSON** + +```powershell +Get-Content opencode.json | python -m json.tool > $null; echo "Valid" +``` + +Expected: `Valid` + +- [ ] **Step 3: Verify skill is findable** + +```powershell +Get-ChildItem -Recurse -Filter "SKILL.md" -Path ".opencode/skills/art-generate" +``` + +Expected: Finds the file. + +- [ ] **Step 4: Verify tool availability (optional)** + +If opencode exposes MCP tool listing, run: + +```powershell +uv run --directory tools/aseprite-mcp --no-sync -m aseprite_mcp 2>&1 +# Check that known tools like create_canvas, add_layer appear +``` + +- [ ] **Step 5: Final commit (if any verification fixes were needed)** + +```powershell +git add -A +git commit -m "fix: verification adjustments for aseprite-mcp integration" +``` + +--- + +### Rollback Plan + +If any step fails catastrophically: + +- **Submodule issue**: `git submodule deinit tools/aseprite-mcp && git rm tools/aseprite-mcp` +- **MCP config issue**: `git checkout opencode.json` (revert to original) +- **Skill issue**: `git rm .opencode/skills/art-generate/SKILL.md` +- **Full rollback**: `git reset --hard HEAD~4` (revert last 4 commits) From 733f3405df038e02f7795b417e60c1c7deb6578b Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Thu, 7 May 2026 20:05:18 +0200 Subject: [PATCH 18/21] fix: register art-generate skill with command file and catalog Adds the missing command file at .opencode/commands/art-generate.md and registers the skill in skill-testing-framework/catalog.yaml. Fixes R5 (orphan skill without command) and I10 (uncataloged skill). --- .opencode/commands/art-generate.md | 8 ++++++++ skill-testing-framework/catalog.yaml | 11 +++++++++++ 2 files changed, 19 insertions(+) create mode 100644 .opencode/commands/art-generate.md diff --git a/.opencode/commands/art-generate.md b/.opencode/commands/art-generate.md new file mode 100644 index 0000000..e617782 --- /dev/null +++ b/.opencode/commands/art-generate.md @@ -0,0 +1,8 @@ +--- +name: art-generate +description: "Generate placeholder art from asset specs using the Aseprite MCP" +skill: art-generate +category: design +--- + +Invokes `/art-generate` skill. diff --git a/skill-testing-framework/catalog.yaml b/skill-testing-framework/catalog.yaml index cad5a63..e3f6267 100644 --- a/skill-testing-framework/catalog.yaml +++ b/skill-testing-framework/catalog.yaml @@ -786,6 +786,17 @@ skills: priority: low category: utility + - name: art-generate + spec: "" + last_static: "" + last_static_result: "" + last_spec: "" + last_spec_result: "" + last_category: "" + last_category_result: "" + priority: low + category: utility + - name: day-one-patch spec: CCGS Skill Testing Framework/skills/utility/day-one-patch.md last_static: "" From 9bb448f1ed75ecfabe180efec420413ec2a30bbe Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Thu, 7 May 2026 20:36:30 +0200 Subject: [PATCH 19/21] fix: move ISSUE_TEMPLATE to correct .github/ location, add feature requests --- .../ISSUE_TEMPLATE/feature-request.md | 0 .../workflows/ISSUE_TEMPLATE/bug-report.md | 26 -------------- .github/workflows/ISSUE_TEMPLATE/config.yml | 8 ----- feature-requests/qmd-doc-search.md | 34 +++++++++++++++++++ feature-requests/unity-mcp-integration.md | 27 +++++++++++++++ 5 files changed, 61 insertions(+), 34 deletions(-) rename .github/{workflows => }/ISSUE_TEMPLATE/feature-request.md (100%) delete mode 100644 .github/workflows/ISSUE_TEMPLATE/bug-report.md delete mode 100644 .github/workflows/ISSUE_TEMPLATE/config.yml create mode 100644 feature-requests/qmd-doc-search.md create mode 100644 feature-requests/unity-mcp-integration.md diff --git a/.github/workflows/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md similarity index 100% rename from .github/workflows/ISSUE_TEMPLATE/feature-request.md rename to .github/ISSUE_TEMPLATE/feature-request.md diff --git a/.github/workflows/ISSUE_TEMPLATE/bug-report.md b/.github/workflows/ISSUE_TEMPLATE/bug-report.md deleted file mode 100644 index 28d5ac8..0000000 --- a/.github/workflows/ISSUE_TEMPLATE/bug-report.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -name: Bug report -about: Report a bug to help us improve -title: '' -labels: bug -assignees: '' ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Run '...' -2. See error - -**Expected behavior** -What you expected to happen instead. - -**Environment:** -- OS: [e.g. Windows, macOS, Linux] -- OpenCode version: `opencode --version` -- Repo version: `git log --oneline -1` - -**Additional context** -Add any other context about the problem here. diff --git a/.github/workflows/ISSUE_TEMPLATE/config.yml b/.github/workflows/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 3ded0c8..0000000 --- a/.github/workflows/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,8 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: OpenCode Game Studios Discussion - url: https://github.com/striderZA/OpenCodeGameStudios/discussions - about: Please ask questions and discuss ideas in GitHub Discussions. - - name: Contributing Guide - url: https://github.com/striderZA/OpenCodeGameStudios/blob/master/CONTRIBUTING.md - about: Review the contributing guide before submitting. diff --git a/feature-requests/qmd-doc-search.md b/feature-requests/qmd-doc-search.md new file mode 100644 index 0000000..1d83b15 --- /dev/null +++ b/feature-requests/qmd-doc-search.md @@ -0,0 +1,34 @@ +--- +name: qmd markdown search integration +about: Integrate qmd as a local CLI search engine for docs/knowledge base +title: 'feat: integrate qmd for markdown document search' +labels: enhancement +assignees: '' +--- + +**Is your feature request related to a problem?** +As the project's documentation base grows (engine reference docs, ADRs, GDDs, skill files, sprint logs), agents spend increasing context and time searching through plain markdown. The project needs a fast, local, agent-friendly search layer that doesn't require shipping content to external APIs. + +**Describe the solution you'd like** + +Integrate [qmd](https://github.com/tobi/qmd) (Query Markup Documents) — a mini CLI search engine purpose-built for markdown knowledge bases: + +1. **Installation** — Add `@tobilu/qmd` as a dev dependency (npm or bun global install). +2. **Indexing** — Run `qmd index` across key doc directories (`docs/`, `.opencode/agents/`, `.opencode/skills/`, `design/`, `production/`) via a script or pre-commit hook. +3. **Skill / command** — Create an `.opencode/skills/qmd-search/SKILL.md` skill that teaches agents to use: + - `qmd search "..."` for fast BM25 keyword search + - `qmd vsearch "..."` for semantic vector search + - `qmd query "..."` for hybrid (FTS + vector + re-ranking) best-quality search +4. **Context hook integration** — Wire into the `ccgs-hooks.ts` plugin so relevant doc snippets are auto-retrieved as session context when an agent loads. +5. **CI freshness check** — Add a GitHub Action step that validates the qmd index is up-to-date with the doc tree. + +**Describe alternatives you've considered** + +- **ripgrep / grep** — Fast but no ranking, no semantic search, no relevance scoring. +- **WebFetch for docs** — Requires network, doesn't work for local/private docs. +- **Context7 MCP** — Good for external libraries, not for project-internal docs. +- **Rolling our own FTS** — qmd already bundles BM25 + sqlite-vec embeddings + query expansion + re-ranking in a single CLI. No need to reinvent. + +**Additional context** + +qmd is authored by tobi (Tobi L.) — well-maintained, MIT-licensed, 24k+ stars. It stores its index in SQLite (FTS5 + sqlite-vec), is fully local, and has no external API dependencies. The `.claude-plugin/` directory in the qmd repo suggests it was designed with AI agent integration in mind. diff --git a/feature-requests/unity-mcp-integration.md b/feature-requests/unity-mcp-integration.md new file mode 100644 index 0000000..14c6c84 --- /dev/null +++ b/feature-requests/unity-mcp-integration.md @@ -0,0 +1,27 @@ +--- +name: Unity MCP integration +about: Add Unity Engine support alongside existing Godot setup +title: 'feat: Unity MCP integration' +labels: enhancement +assignees: '' +--- + +**Is your feature request related to a problem?** +The project is currently locked to Godot 4. Unity developers cannot contribute or prototype within this repo's agent framework. The `.opencode/agents/` directory has dedicated Unity specialist agents (`unity-specialist`, `unity-dots-specialist`, etc.) but no tooling, MCP server, or engine reference docs to back them up. + +**Describe the solution you'd like** + +1. **Unity MCP server** — Install and configure a Unity MCP server (e.g., `unity-mcp`) so agents can inspect scenes, assets, and project state directly from conversation. +2. **Engine reference docs** — Populate `docs/engine-reference/unity/` with version-pinned API snapshots for the target Unity version (determine via `hub` or project file). +3. **Agent wiring** — Configure the existing Unity specialist agents in `.opencode/agents/` to use the MCP server and reference docs. +4. **Template documentation** — Add Unity-specific sections to `setup-engine` skill and onboarding flow (`/start`, `/setup-engine unity `). + +**Describe alternatives you've considered** + +- Dual-repo setup (Godot + Unity in separate repos) — loses cross-studio coordination and shared agent config. +- Unreal-only + Godot — doesn't cover the Unity use case. +- Manual Unity workflows without MCP — agents can't inspect project state, severely limiting automated dev-story and code-review. + +**Additional context** + +The OCGS template already ships Unity specialist agents at `.opencode/agents/unity-specialist.md`, `unity-dots-specialist.md`, `unity-shader-specialist.md`, `unity-addressables-specialist.md`, and `unity-ui-specialist.md`. This FR activates them. From 9914766d8e0943107a3eb674d0ccc068ecd89473 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Thu, 7 May 2026 20:42:00 +0200 Subject: [PATCH 20/21] =?UTF-8?q?fix:=20address=20PR=20review=20=E2=80=94?= =?UTF-8?q?=20portability,=20timeout,=20missing=20bug-report.md,=20CI=20su?= =?UTF-8?q?bmodule,=20dead=20shell=20context?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/bug-report.md | 26 ++++++++++++++++++++++++++ .github/workflows/agent-validation.yml | 4 ++++ .opencode/skills/help/SKILL.md | 2 +- opencode.json | 8 ++++---- tests/workflow/run-all.mjs | 16 ++++++++++++++++ 5 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.md diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 0000000..28d5ac8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,26 @@ +--- +name: Bug report +about: Report a bug to help us improve +title: '' +labels: bug +assignees: '' +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Run '...' +2. See error + +**Expected behavior** +What you expected to happen instead. + +**Environment:** +- OS: [e.g. Windows, macOS, Linux] +- OpenCode version: `opencode --version` +- Repo version: `git log --oneline -1` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/workflows/agent-validation.yml b/.github/workflows/agent-validation.yml index 499f77e..cb947dc 100644 --- a/.github/workflows/agent-validation.yml +++ b/.github/workflows/agent-validation.yml @@ -12,6 +12,8 @@ jobs: name: Agent Framework Validation steps: - uses: actions/checkout@v4 + with: + submodules: recursive - uses: actions/setup-node@v4 with: node-version: 20 @@ -29,6 +31,8 @@ jobs: name: Workflow Integrity steps: - uses: actions/checkout@v4 + with: + submodules: recursive - uses: actions/setup-node@v4 with: node-version: 20 diff --git a/.opencode/skills/help/SKILL.md b/.opencode/skills/help/SKILL.md index 4d38b1a..5a1441c 100644 --- a/.opencode/skills/help/SKILL.md +++ b/.opencode/skills/help/SKILL.md @@ -5,7 +5,7 @@ argument-hint: "[optional: what you just finished, e.g. 'finished design-review' user-invocable: true allowed-tools: Read, Glob, Grep context: | - !echo "=== Live Project State ===" && echo "Stage: $(cat production/stage.txt 2>/dev/null | tr -d '[:space:]' || echo 'not set')" && echo "Latest sprint: $(ls -t production/sprints/*.md 2>/dev/null | head -1 || echo 'none')" && echo "Session state: $(head -5 production/session-state/active.md 2>/dev/null || echo 'none')" + Static help skill — reads production artifacts directly to determine project state and next steps. model: opencode-go/deepseek-v4-flash --- diff --git a/opencode.json b/opencode.json index 9df2b03..5f3a709 100644 --- a/opencode.json +++ b/opencode.json @@ -11,10 +11,10 @@ "mcp": { "aseprite": { "type": "local", - "command": ["uv", "--directory", "tools/aseprite-mcp", "run", "--no-sync", "-m", "aseprite_mcp"], + "command": ["uv", "--directory", "tools/aseprite-mcp", "run", "-m", "aseprite_mcp"], "enabled": true, "environment": { - "ASEPRITE_PATH": "E:\\Jaco\\Projects\\Godot\\aseprite\\build\\bin\\aseprite.exe" + "ASEPRITE_PATH": "{env:ASEPRITE_PATH}" } }, "godot": { @@ -22,8 +22,8 @@ "command": ["npx", "@coding-solo/godot-mcp"], "enabled": false, "env": { - "GODOT_PATH": "E:\\Jaco\\Projects\\Godot\\engine\\godot.exe", - "DEBUG": "true" + "GODOT_PATH": "{env:GODOT_PATH}", + "DEBUG": "{env:DEBUG}" } } }, diff --git a/tests/workflow/run-all.mjs b/tests/workflow/run-all.mjs index 373dc4e..b898cbb 100644 --- a/tests/workflow/run-all.mjs +++ b/tests/workflow/run-all.mjs @@ -14,19 +14,35 @@ const suites = [ { name: 'invariants', file: join(__dirname, 'invariants.mjs') }, ]; +const SUITE_TIMEOUT = 30000; + async function runSuite(suite) { return new Promise((resolve) => { const child = fork(suite.file, [], { cwd: ROOT, stdio: ['pipe', 'pipe', 'pipe', 'ipc'] }); let output = ''; + let settled = false; + + const timer = setTimeout(() => { + if (settled) return; + settled = true; + child.kill(); + resolve({ name: suite.name, output: output + '\nError: Suite timed out after 30s', code: 1 }); + }, SUITE_TIMEOUT); child.stdout.on('data', (data) => { output += data.toString(); }); child.stderr.on('data', (data) => { output += data.toString(); }); child.on('close', (code) => { + if (settled) return; + settled = true; + clearTimeout(timer); resolve({ name: suite.name, output, code }); }); child.on('error', (err) => { + if (settled) return; + settled = true; + clearTimeout(timer); resolve({ name: suite.name, output: `Error: ${err.message}`, code: 1 }); }); }); From 5ae61b8da8cc5726683b717d8e77686fcbd2bcfb Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Thu, 7 May 2026 20:52:18 +0200 Subject: [PATCH 21/21] fix: use correct config option syntax for environment variables --- opencode.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opencode.json b/opencode.json index 5f3a709..0bb23f9 100644 --- a/opencode.json +++ b/opencode.json @@ -21,7 +21,7 @@ "type": "local", "command": ["npx", "@coding-solo/godot-mcp"], "enabled": false, - "env": { + "environment": { "GODOT_PATH": "{env:GODOT_PATH}", "DEBUG": "{env:DEBUG}" }