diff --git a/.github/workflows/sync-catalog.yml b/.github/workflows/sync-catalog.yml
new file mode 100644
index 0000000..ff136ba
--- /dev/null
+++ b/.github/workflows/sync-catalog.yml
@@ -0,0 +1,87 @@
+name: Sync catalog
+
+on:
+ pull_request:
+ branches: [main]
+ paths:
+ - 'patterns/**'
+ - 'categories.yml'
+ - 'scripts/build.mjs'
+ - 'package.json'
+ - 'package-lock.json'
+ push:
+ branches: [main]
+ paths:
+ - 'patterns/**'
+ - 'categories.yml'
+ - 'scripts/build.mjs'
+ - 'package.json'
+ - 'package-lock.json'
+
+permissions:
+ contents: write
+
+jobs:
+ snapshot-check:
+ if: github.event_name == 'pull_request'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: npm
+ - run: npm ci
+ - run: npm run build
+ - name: Verify the committed snapshot is up to date
+ run: |
+ if ! git diff --quiet -- skills/skill-patterns/references/patterns.md; then
+ echo "::error::Snapshot is stale. Run 'npm run build' and commit skills/skill-patterns/references/patterns.md."
+ git --no-pager diff -- skills/skill-patterns/references/patterns.md
+ exit 1
+ fi
+ echo "Snapshot is up to date."
+
+ sync-to-pages:
+ if: github.event_name == 'push'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out main
+ uses: actions/checkout@v4
+ with:
+ path: main
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: npm
+ cache-dependency-path: main/package-lock.json
+ - name: Build catalog outputs
+ working-directory: main
+ run: |
+ npm ci
+ npm run build
+ - name: Check out gh-pages
+ uses: actions/checkout@v4
+ with:
+ ref: gh-pages
+ path: pages
+ - name: Sync generated files into gh-pages
+ run: |
+ rm -rf pages/_patterns
+ mkdir -p pages/_patterns pages/_data
+ cp main/patterns/*.md pages/_patterns/
+ cp main/categories.yml pages/_data/categories.yml
+ cp main/build/llms.txt pages/llms.txt
+ cp main/build/patterns.json pages/patterns.json
+ - name: Commit and push to gh-pages
+ working-directory: pages
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ git add _patterns _data/categories.yml llms.txt patterns.json
+ if git diff --cached --quiet; then
+ echo "No catalog changes to sync."
+ else
+ git commit -m "chore: sync catalog from main@${GITHUB_SHA::7}"
+ git push
+ fi
diff --git a/.gitignore b/.gitignore
index 84be8e3..ae4f721 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
.DS_Store
node_modules/
+build/
# Build/tooling artifacts that may linger from the gh-pages (site) branch
_site/
diff --git a/AGENTS.md b/AGENTS.md
index 4f6a794..6b81031 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -4,35 +4,29 @@ Guidance for AI agents (and humans) working in this repository.
## Two branches, two jobs
-- **`main`** (default) — the installable **plugin** for Claude / Codex / Gemini. Holds the `.claude-plugin/` manifests and the `skills/skill-patterns/` skill.
-- **`gh-pages`** — the **website** that publishes [skillpatterns.ai](https://skillpatterns.ai) (a Jekyll site). It holds the **canonical pattern catalog** in `_patterns/*.md` and generates `/llms.txt` and `/patterns.json` on build.
+- **`main`** (default) — the canonical home of the **catalog** *and* the installable **plugin** for Claude / Codex / Gemini. Holds `patterns/*.md` (the catalog source), `categories.yml`, the generator `scripts/build.mjs`, the `.claude-plugin/` manifests, and `skills/skill-patterns/`.
+- **`gh-pages`** — the **website** that publishes [skillpatterns.ai](https://skillpatterns.ai) (a Jekyll site). Its catalog inputs (`_patterns/`, `_data/categories.yml`, `llms.txt`, `patterns.json`) are **generated** from `main` and synced in by CI. Do not hand-edit them there.
-## The catalog lives on gh-pages; the plugin carries a snapshot
+## Adding or editing a pattern
-The source of truth for the patterns is `_patterns/*.md` on **gh-pages**. The plugin on **main** ships a *generated snapshot* at `skills/skill-patterns/references/patterns.md` — never hand-edit it.
+1. Edit (or add) **one file** in `patterns/` on `main`. Frontmatter: `title`, `slug` (must match the filename), `icon` (FontAwesome Free), `category` (a key in `categories.yml`), `summary`, `adds` (list), `related` (list of `{slug, note}`, optional), `prompt` (block scalar).
+2. Run `npm run build` — regenerates the plugin snapshot at `skills/skill-patterns/references/patterns.md` (and `build/llms.txt`, `build/patterns.json`).
+3. Open **one PR** against `main`. The `Sync catalog` workflow's `snapshot-check` job fails the PR if you skipped step 2. On merge, the `sync-to-pages` job regenerates and pushes `_patterns/`, `_data/categories.yml`, `llms.txt`, and `patterns.json` to `gh-pages`, and the site rebuilds.
-## ⚠️ On ANY catalog change, update BOTH branches
+No Jekyll, no second branch to edit.
-When you add, edit, rename, or remove a pattern (or change categories), do both:
+## Never hand-edit generated files
-1. **`gh-pages`** — edit the source in `_patterns/` (and `_data/categories.yml` for category changes), then rebuild and verify:
- ```
- bundle exec jekyll build
- ```
-2. **`main`** — regenerate the plugin's snapshot from the rebuilt catalog and commit:
- ```
- curl -s https://skillpatterns.ai/llms.txt > skills/skill-patterns/references/patterns.md
- ```
- (Before the site is live, copy the freshly built `_site/llms.txt` instead.)
+All produced by `scripts/build.mjs` — edit `patterns/` + `categories.yml` and rebuild:
-Commit on **both** branches. A change that lands on only one branch leaves the site and the plugin out of sync.
+- on `main`: `skills/skill-patterns/references/patterns.md`
+- on `gh-pages`: `_patterns/*.md`, `_data/categories.yml`, `llms.txt`, `patterns.json`
## Conventions
-- Patterns sort **alphabetically by title** within their category; the `order` frontmatter field is unused.
-- `/llms.txt` and `/patterns.json` regenerate from `_patterns/` automatically on build — don't edit them by hand.
-- Pattern frontmatter: `title`, `slug`, `icon` (FontAwesome Free), `category` (a key in `_data/categories.yml`), `summary`, `adds` (list), `prompt` (block scalar).
+- Patterns sort **alphabetically by title** within their category; the pattern `order` field is unused. Category order comes from `order` in `categories.yml`.
+- The build **validates input** and fails with a named error on: unknown `category`; duplicate or filename-mismatched `slug`; `adds` that isn't a list; a `related` entry missing `slug`/`note` or pointing at a nonexistent pattern; a category missing a numeric `order`.
## Deploy
-GitHub Pages builds from the **`gh-pages`** branch (`CNAME` → skillpatterns.ai lives there). `main` is the default branch and the plugin source.
+GitHub Pages builds from the **`gh-pages`** branch (`CNAME` → skillpatterns.ai lives there). `main` is the default branch, the catalog source, and the plugin source; the `Sync catalog` workflow (`.github/workflows/sync-catalog.yml`) keeps `gh-pages` in sync. Actions minutes are free (public repo).
diff --git a/categories.yml b/categories.yml
new file mode 100644
index 0000000..577e75a
--- /dev/null
+++ b/categories.yml
@@ -0,0 +1,24 @@
+- key: grounding
+ title: "Grounding & accuracy"
+ description: "Keep the agent tethered to truth and honest about what it knows."
+ order: 1
+- key: decision
+ title: "Decision-making"
+ description: "Structure how choices get made and recorded."
+ order: 2
+- key: output
+ title: "Output shaping"
+ description: "Control the form and structure of what comes out."
+ order: 3
+- key: critique
+ title: "Critique & stress-testing"
+ description: "Find weaknesses before the work ships."
+ order: 4
+- key: control
+ title: "Control"
+ description: "Govern how the agent behaves within a task — when it pauses, asks, stops, and the stance it takes."
+ order: 5
+- key: composition
+ title: "Composition"
+ description: "Structure work across multiple steps and skills — sequencing, shared state, and staged context."
+ order: 6
diff --git a/docs/superpowers/plans/2026-05-23-skill-patterns-site.md b/docs/superpowers/plans/2026-05-23-skill-patterns-site.md
new file mode 100644
index 0000000..8317017
--- /dev/null
+++ b/docs/superpowers/plans/2026-05-23-skill-patterns-site.md
@@ -0,0 +1,1270 @@
+# Skill Patterns Site 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:** Build a clean, public, light/dark Jekyll site that presents the 14 skill patterns as a searchable, purpose-grouped catalog with copyable example prompts, deployed on GitHub Pages at the apex domain `skillpatterns.ai`.
+
+**Architecture:** A static Jekyll site built natively by GitHub Pages (no CI). Patterns are a `_patterns` collection (`output: false`) authored as Markdown-with-frontmatter; categories live in `_data/categories.yml`. A single home page renders a sticky sidebar (search + category nav) beside a content column that groups all patterns by category with anchor IDs. Vanilla JS (no dependencies) provides search filtering, scroll-spy active-link highlighting, per-prompt copy buttons, and a persistent light/dark theme toggle. A separate Resources page lists external links and reference skills.
+
+**Tech Stack:** Jekyll (via the `github-pages` gem), Liquid templates, Kramdown Markdown, CSS custom properties for theming, vanilla ES5-compatible JavaScript. Verification uses `bundle exec jekyll build` + HTML assertions and Playwright (MCP browser tools) for runtime behavior.
+
+**Source of truth for content:** `docs/superpowers/specs/2026-05-23-skill-patterns-site-design.md` (full transcription of all 14 patterns). This plan inlines every value needed; you do not need to open the spec to execute.
+
+**Conventions used throughout:**
+- All internal links/assets use Liquid `relative_url` (harmless with empty `baseurl`, future-proof).
+- Run all commands from the repo root: `/Users/matt/git/skill-patterns`.
+- Owner placeholder: the GitHub repo URL is assumed to be `https://github.com/borkweb/skill-patterns`. If the owner differs, change `repo_url` in `_config.yml` (Task 2) — it is referenced only there.
+
+---
+
+## File structure (created by this plan)
+
+```
+/
+├── .gitignore # add _site/, .jekyll-cache/, vendor/ (Task 1)
+├── Gemfile # github-pages gem (Task 1)
+├── _config.yml # site config, collection, excludes (Task 1 → 2)
+├── CNAME # skillpatterns.ai (Task 9)
+├── index.html # home page (layout: home) + intro (Task 3)
+├── resources.md # resources page (layout: page) (Task 8)
+├── _data/
+│ └── categories.yml # 5 categories (Task 3)
+├── _patterns/ # 14 Markdown files (output: false) (Task 3 → 4)
+├── _layouts/
+│ ├── default.html # html shell (Task 2)
+│ ├── home.html # sidebar + content + pattern loop (Task 3)
+│ └── page.html # simple centered page (Task 8)
+├── _includes/
+│ ├── head.html # meta + no-flash theme script + CSS (Task 2)
+│ ├── header.html # brand, nav, theme toggle (Task 2)
+│ ├── footer.html # credit, license, repo link (Task 2)
+│ ├── sidebar.html # search + category nav (Task 3)
+│ └── pattern.html # one rendered pattern block (Task 3)
+└── assets/
+ ├── css/style.css # tokens + themes + layout + components (Task 5)
+ └── js/app.js # theme, search, scroll-spy, copy (Task 6)
+```
+
+---
+
+## Task 1: Branch + Jekyll scaffold + build green
+
+**Files:**
+- Create: `Gemfile`
+- Create: `_config.yml`
+- Create: `.gitignore` (append)
+- Create: `index.html` (temporary minimal page; replaced in Task 3)
+
+- [ ] **Step 1: Create the feature branch**
+
+We are on `main` (default). Branch first.
+
+Run:
+```bash
+cd /Users/matt/git/skill-patterns
+git checkout -b skill-patterns-site
+```
+
+- [ ] **Step 2: Add ignore entries**
+
+Append to `.gitignore` (it already contains `.superpowers/`):
+```
+_site/
+.jekyll-cache/
+vendor/
+Gemfile.lock
+```
+
+- [ ] **Step 3: Create the `Gemfile`**
+
+`Gemfile`:
+```ruby
+source "https://rubygems.org"
+
+# Pin to GitHub Pages' Jekyll toolchain so local builds match production.
+gem "github-pages", group: :jekyll_plugins
+
+# Faraday/webrick shims sometimes needed on modern Ruby for `jekyll serve`.
+gem "webrick", "~> 1.8"
+```
+
+- [ ] **Step 4: Create a minimal `_config.yml`**
+
+`_config.yml`:
+```yaml
+title: "Skill Patterns"
+description: "A catalog of reusable patterns for composing AI Skills."
+url: "https://skillpatterns.ai"
+baseurl: ""
+repo_url: "https://github.com/borkweb/skill-patterns"
+
+collections:
+ patterns:
+ output: false
+
+markdown: kramdown
+
+exclude:
+ - Gemfile
+ - Gemfile.lock
+ - README.md
+ - LICENSE
+ - docs/
+ - .superpowers/
+ - vendor/
+ - "*.pdf"
+```
+
+- [ ] **Step 5: Create a temporary `index.html` so the build has a page**
+
+`index.html`:
+```html
+---
+title: Skill Patterns
+---
+
Skill Patterns (scaffold)
+```
+
+- [ ] **Step 6: Install gems (failing build check first)**
+
+Run:
+```bash
+cd /Users/matt/git/skill-patterns
+bundle install
+```
+Expected: resolves and installs `github-pages`. If `bundle` is missing: `gem install bundler` first. If Ruby is too old for the gem, install a current Ruby (e.g. via `rbenv`/`asdf`) and retry.
+
+- [ ] **Step 7: Build and verify output exists**
+
+Run:
+```bash
+bundle exec jekyll build
+test -f _site/index.html && echo "BUILD_OK"
+```
+Expected: prints `BUILD_OK` (the build wrote `_site/index.html`).
+
+- [ ] **Step 8: Commit**
+
+```bash
+git add .gitignore Gemfile _config.yml index.html
+git commit -m "chore: scaffold Jekyll site (github-pages, base config)"
+```
+
+---
+
+## Task 2: Base layout, head (no-flash theme), header, footer
+
+**Files:**
+- Create: `_layouts/default.html`
+- Create: `_includes/head.html`
+- Create: `_includes/header.html`
+- Create: `_includes/footer.html`
+- Modify: `index.html` (use `layout: default`)
+
+- [ ] **Step 1: Create `_includes/head.html`**
+
+The inline script sets the theme before first paint to avoid a flash of the wrong theme. CSS is referenced now even though `style.css` arrives in Task 5 (a 404 for CSS does not break the build or these tasks' assertions).
+
+`_includes/head.html`:
+```html
+
+
+{% if page.title and page.title != site.title %}{{ page.title }} · {{ site.title }}{% else %}{{ site.title }}{% endif %}
+
+
+
+```
+
+- [ ] **Step 2: Create `_includes/header.html`**
+
+`_includes/header.html`:
+```html
+
+ SkillPatterns
+
+
+```
+
+- [ ] **Step 3: Create `_includes/footer.html`**
+
+`_includes/footer.html`:
+```html
+
+```
+
+- [ ] **Step 4: Create `_layouts/default.html`**
+
+`_layouts/default.html`:
+```html
+
+
+
+ {%- include head.html -%}
+
+
+ {%- include header.html -%}
+ {{ content }}
+ {%- include footer.html -%}
+
+
+
+```
+
+- [ ] **Step 5: Point `index.html` at the layout**
+
+Replace `index.html` with:
+```html
+---
+layout: default
+title: Skill Patterns
+---
+
Skill Patterns (scaffold)
+```
+
+- [ ] **Step 6: Build and assert header/footer/theme hooks render**
+
+Run:
+```bash
+bundle exec jekyll build
+grep -q 'id="theme-toggle"' _site/index.html && \
+grep -q 'class="brand"' _site/index.html && \
+grep -q 'site-footer' _site/index.html && \
+grep -q "getAttribute('data-theme'" _site/index.html && \
+echo "LAYOUT_OK"
+```
+Expected: prints `LAYOUT_OK`.
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add _layouts/default.html _includes/head.html _includes/header.html _includes/footer.html index.html
+git commit -m "feat: base layout with header, footer, and no-flash theme script"
+```
+
+---
+
+## Task 3: Categories data, sidebar, pattern include, home layout, first pattern
+
+**Files:**
+- Create: `_data/categories.yml`
+- Create: `_includes/sidebar.html`
+- Create: `_includes/pattern.html`
+- Create: `_layouts/home.html`
+- Create: `_patterns/trusted-sources.md`
+- Modify: `index.html` (use `layout: home`, add intro)
+
+- [ ] **Step 1: Create `_data/categories.yml`**
+
+`_data/categories.yml`:
+```yaml
+- key: grounding
+ title: "Grounding & accuracy"
+ description: "Keep the agent tethered to truth and honest about what it knows."
+ order: 1
+- key: critique
+ title: "Critique & stress-testing"
+ description: "Find weaknesses before the work ships."
+ order: 2
+- key: decision
+ title: "Decision-making"
+ description: "Structure how choices get made and recorded."
+ order: 3
+- key: output
+ title: "Output shaping"
+ description: "Control the form and structure of what comes out."
+ order: 4
+- key: control
+ title: "Control & composition"
+ description: "Govern flow, stance, and how Skills combine."
+ order: 5
+```
+
+- [ ] **Step 2: Create `_includes/sidebar.html`**
+
+`_includes/sidebar.html`:
+```html
+
+```
+
+- [ ] **Step 3: Create `_includes/pattern.html`**
+
+`_includes/pattern.html`:
+```html
+{% assign p = include.pattern %}
+
+
+ {%- include sidebar.html -%}
+
+ {{ content }}
+ {% assign cats = site.data.categories | sort: "order" %}
+ {% for cat in cats %}
+
+
{{ cat.title }}
+
{{ cat.description }}
+ {% assign pats = site.patterns | where: "category", cat.key | sort: "order" %}
+ {% for p in pats %}
+ {% include pattern.html pattern=p %}
+ {% endfor %}
+
+ {% endfor %}
+
+
+```
+
+- [ ] **Step 5: Create the first pattern `_patterns/trusted-sources.md`**
+
+`_patterns/trusted-sources.md`:
+```markdown
+---
+title: "Trusted sources / grounding"
+slug: trusted-sources
+category: grounding
+order: 1
+summary: "Anchors the agent in specific authoritative references so it stops improvising from training data."
+adds:
+ - "Cites which source supports each claim"
+ - "Defers to specified sources when they conflict with general knowledge"
+ - "Flags gaps instead of filling them silently"
+prompt: |
+ Ground this Skill in the following authoritative sources: [URLs / paths / docs]. When the task touches this area, consult these first. If your training contradicts these sources, the sources win. Cite which source each claim comes from. If a source is missing or ambiguous, flag the gap rather than filling it from prior knowledge.
+---
+```
+
+- [ ] **Step 6: Replace `index.html` with the real home page**
+
+`index.html`:
+```html
+---
+layout: home
+title: Skill Patterns
+---
+
+
Skill patterns
+
Reusable techniques you can drop into a Skill to bake in specific behaviors — grounding an agent in trusted sources, pausing for a human, stress-testing its own work, shaping its output, and more.
+
Each pattern below has a short definition, what it adds, and an example prompt partial you can copy straight into your own Skill. Search to filter, or jump around from the sidebar.
+
+```
+
+- [ ] **Step 7: Build and assert the first pattern renders**
+
+Run:
+```bash
+bundle exec jekyll build
+grep -q 'id="trusted-sources"' _site/index.html && \
+grep -q 'Grounding & accuracy' _site/index.html && \
+grep -q 'data-copy="trusted-sources"' _site/index.html && \
+grep -q 'id="prompt-trusted-sources"' _site/index.html && \
+grep -q 'href="#trusted-sources"' _site/index.html && \
+echo "PATTERN_OK"
+```
+Expected: prints `PATTERN_OK` (pattern block, category header, copy button, prompt body, and sidebar link all present).
+
+- [ ] **Step 8: Commit**
+
+```bash
+git add _data/categories.yml _includes/sidebar.html _includes/pattern.html _layouts/home.html _patterns/trusted-sources.md index.html
+git commit -m "feat: home layout with sidebar, category grouping, and first pattern"
+```
+
+---
+
+## Task 4: Add the remaining 13 patterns
+
+**Files:**
+- Create: `_patterns/exemplars-over-instruction.md`, `_patterns/confidence-calibration.md`, `_patterns/encoded-reasoning.md`, `_patterns/self-critique.md`, `_patterns/adversarial-push-back.md`, `_patterns/premortem.md`, `_patterns/bounded-option-generation.md`, `_patterns/decision-capture.md`, `_patterns/format-projection.md`, `_patterns/artifact-creation.md`, `_patterns/human-in-the-loop.md`, `_patterns/role-priming.md`, `_patterns/workflows-as-superset.md`
+
+- [ ] **Step 1: Create the Grounding & accuracy patterns**
+
+`_patterns/exemplars-over-instruction.md`:
+```markdown
+---
+title: "Exemplars over instruction"
+slug: exemplars-over-instruction
+category: grounding
+order: 2
+summary: "Anchors the Skill's output in concrete examples of \"good\" rather than describing it in rules."
+adds:
+ - "Matches the shape, voice, and structure of provided examples"
+ - "Surfaces which exemplar it drew from when the choice is ambiguous"
+ - "Asks for a new exemplar when the work falls outside the set"
+prompt: |
+ Here are exemplars of [strong outputs / preferred voice / target format]: [paste 2-4 examples]. Match the shape and voice of these rather than following rules I might write down. When the task falls outside what the exemplars cover, say so and ask for a new exemplar instead of guessing. Cite which exemplar most influenced the output.
+---
+```
+
+`_patterns/confidence-calibration.md`:
+```markdown
+---
+title: "Confidence calibration"
+slug: confidence-calibration
+category: grounding
+order: 3
+summary: "Requires the agent to mark which parts of its output it's confident about and which are guesses."
+adds:
+ - "Tags claims by certainty so high-risk pieces are visible at a glance"
+ - "Distinguishes what's verified against sources from what's inferred or assumed"
+ - "Tells you where to spend your verification time and where you can move fast"
+prompt: |
+ As you produce [output], mark each substantive claim with a confidence level: high (verified against a source or directly observable), medium (inferred from pattern or adjacent evidence), low (filling a gap, best guess, please verify). For low-confidence claims, briefly note what would raise the confidence — a source to check, a test to run, a person to ask. Don't smooth out uncertainty in the final wording; if it's a guess, it should read like one.
+---
+```
+
+- [ ] **Step 2: Create the Critique & stress-testing patterns**
+
+`_patterns/encoded-reasoning.md`:
+```markdown
+---
+title: "Encoded reasoning"
+slug: encoded-reasoning
+category: critique
+order: 1
+summary: "Bakes review rubrics, validation steps, and quality checks into how the Skill operates."
+adds:
+ - "Runs outputs against a defined rubric before returning them"
+ - "Surfaces which criteria passed, failed, or are uncertain"
+ - "Catches predictable failure modes the team has seen before"
+prompt: |
+ Before returning output, check the work against these criteria: [rubric items]. Report which criteria passed, failed, or are uncertain. Don't return work that fails [hard criteria] — revise and retry. Surface the rubric results alongside the output so I can see the reasoning.
+---
+```
+
+`_patterns/self-critique.md`:
+```markdown
+---
+title: "Self-critique"
+slug: self-critique
+category: critique
+order: 2
+summary: "Has the agent review its own output against criteria, identify weaknesses, and revise before returning."
+adds:
+ - "Produces a first draft, then critiques it against the brief"
+ - "Names the weakest reasoning and the most fragile assumption"
+ - "Returns the revised output with a note on what changed and why"
+prompt: |
+ After producing [output], step back and critique your own work against [criteria: the original brief, the rubric, what a strong reviewer would notice]. Identify the weakest reasoning, the most fragile assumption, and the part most likely to be wrong. Revise. Return the revised output along with a brief note on what changed and why.
+---
+```
+
+`_patterns/adversarial-push-back.md`:
+```markdown
+---
+title: "Adversarial push back"
+slug: adversarial-push-back
+category: critique
+order: 3
+summary: "Pits a challenger persona or parallel agent against the work to expose weaknesses before it ships."
+adds:
+ - "Argues the strongest case against the proposal, with reasoning"
+ - "Surfaces assumptions that wouldn't survive scrutiny"
+ - "Forces defense of choices instead of quiet acceptance"
+prompt: |
+ Before finalizing [output], take the role of [adversary: skeptical reviewer, hostile architect, opposing counsel, competitor's CTO]. Argue the strongest case against the proposal. Identify the assumptions most likely to fail, the evidence that's missing, and the decisions that would look wrong in hindsight. Return the pushback and the original work side by side.
+---
+```
+
+`_patterns/premortem.md`:
+```markdown
+---
+title: "Premortem"
+slug: premortem
+category: critique
+order: 4
+summary: "Skill imagines the work has already failed and reasons backward to why."
+adds:
+ - "Generates the most plausible failure stories before the work ships"
+ - "Surfaces risks that wouldn't appear in a forward-looking review"
+ - "Names which current assumptions, if wrong, cause the failure"
+prompt: |
+ Before finalizing [the plan / the decision / the proposal], run a premortem. Imagine it's [6 months / a year / one quarter] from now and this work has clearly failed. Generate the 3 most plausible failure stories — what went wrong, in what order, and why it wasn't caught in time. For each, name the assumption in the current plan that, if wrong, made the failure inevitable. Return the failure stories alongside the original work, with the riskiest assumptions called out.
+---
+```
+
+- [ ] **Step 3: Create the Decision-making patterns**
+
+`_patterns/bounded-option-generation.md`:
+```markdown
+---
+title: "Bounded option generation"
+slug: bounded-option-generation
+category: decision
+order: 1
+summary: "Forces a fixed number of distinct alternatives with trade-offs before converging on a recommendation."
+adds:
+ - "Generates options that are genuinely different, not variations"
+ - "Names what each option optimizes for and what it gives up"
+ - "Recommends one, addressing why not the others"
+prompt: |
+ Before recommending [a decision / an approach], generate [3] meaningfully different options. Each must take a different bet — not variations of the same shape. For each, name what it's optimizing for and what it's giving up. Then recommend one, including why the other options were rejected rather than only why this one wins.
+---
+```
+
+`_patterns/decision-capture.md`:
+```markdown
+---
+title: "Decision capture"
+slug: decision-capture
+category: decision
+order: 2
+summary: "Surfaces the assumptions, alternatives considered, and reasoning trail alongside the output so the decision is auditable."
+adds:
+ - "Records what was assumed and what was uncertain"
+ - "Lists alternatives considered and why they were rejected"
+ - "Writes the reasoning trail for a reader who wasn't in the room"
+prompt: |
+ Alongside [the output / the recommendation], capture: the assumptions you made, the alternatives you considered, the reasoning that led to this choice, and the conditions under which you'd revisit it. Write it for a reader who wasn't in the room. Keep it short — enough that someone three months from now can tell whether the decision still holds.
+---
+```
+
+- [ ] **Step 4: Create the Output shaping patterns**
+
+`_patterns/format-projection.md`:
+```markdown
+---
+title: "Format projection"
+slug: format-projection
+category: output
+order: 1
+summary: "Renders one canonical artifact into multiple downstream forms while preserving the underlying content."
+adds:
+ - "Produces the source artifact once, then derives variants from it"
+ - "Each variant matches its channel's conventions (length, tone, format)"
+ - "Surfaces what was cut or compressed in each derivation"
+prompt: |
+ Produce the canonical [artifact: decision doc, spec, research summary] first. Then derive these variants from it: [list: P2 post, Slack summary, exec brief, email update]. Each variant should match the conventions of its channel. Don't re-reason — derive. Note what was cut or compressed in each variant so I can spot if something important got lost.
+---
+```
+
+`_patterns/artifact-creation.md`:
+```markdown
+---
+title: "Artifact creation"
+slug: artifact-creation
+category: output
+order: 2
+summary: "Directs the Skill to produce a concrete, standalone deliverable rather than a conversational response."
+adds:
+ - "Returns a finished artifact (doc, deck outline, spec, mockup, dataset) you can lift out and use"
+ - "Matches a defined structure or template so the output is predictable"
+ - "Separates the artifact from the surrounding chatter — you know what to keep"
+prompt: |
+ Produce a standalone [artifact type: brief, spec, one-pager, dashboard outline, draft P2 post] rather than answering conversationally. Follow this structure: [sections / template / required fields]. Return the artifact as a self-contained block I can copy out. Keep commentary about the artifact separate from the artifact itself — if you need to flag assumptions or open questions, put them after, not inside.
+---
+```
+
+- [ ] **Step 5: Create the Control & composition patterns**
+
+`_patterns/human-in-the-loop.md`:
+```markdown
+---
+title: "Human in the loop"
+slug: human-in-the-loop
+category: control
+order: 1
+summary: "Inserts explicit checkpoints where the agent pauses for discernment before proceeding."
+adds:
+ - "Stops before destructive, irreversible, or high-stakes steps"
+ - "Surfaces what it's about to do and waits for confirmation"
+ - "Distinguishes routine steps (proceed) from judgment calls (pause)"
+prompt: |
+ Before [specific actions: deploying, sending, deleting, committing, finalizing], pause and summarize what you're about to do and why. Wait for my confirmation, redirect, or override before proceeding. Routine steps can run without checkpoints; judgment calls always pause. [When presenting me with options, allow me to keep the default, give me two more, and let me enter my own.]
+---
+```
+
+`_patterns/role-priming.md`:
+```markdown
+---
+title: "Role priming"
+slug: role-priming
+category: control
+order: 2
+summary: "Puts the agent in a specific stance for the duration of the Skill so its reasoning carries that perspective."
+adds:
+ - "Approaches the work from the named role's priorities and constraints"
+ - "Uses the vocabulary and reference points of that role"
+ - "Stays in role across follow-ups within the same task"
+prompt: |
+ Approach this work as [role: staff engineer reviewing a PR, finance partner reviewing a forecast, support lead reviewing a flow]. Use the priorities, vocabulary, and constraints that role brings. Stay in role across follow-up questions within this task. If you'd break role to be more helpful, say so and ask before switching.
+---
+```
+
+`_patterns/workflows-as-superset.md`:
+```markdown
+---
+title: "Workflows as superset"
+slug: workflows-as-superset
+category: control
+order: 3
+summary: "Composes this Skill with others into a sequenced flow."
+adds:
+ - "Triggers other Skills in a defined order"
+ - "Passes outputs from one stage as inputs to the next"
+ - "Surfaces workflow state so you can see where you are in the chain"
+prompt: |
+ Run this as a workflow: [Skill 1] → [Skill 2] → [Skill 3]. Pass the output of each stage as input to the next. After each stage, summarize what was produced and confirm before moving on. If a stage fails its checks, stop and surface the issue rather than continuing.
+---
+```
+
+- [ ] **Step 6: Build and assert all 14 patterns render, grouped, with matching sidebar links**
+
+Run:
+```bash
+bundle exec jekyll build
+echo "patterns: $(grep -c 'class="pattern"' _site/index.html) (want 14)"
+echo "sections: $(grep -c 'class="cat-section"' _site/index.html) (want 5)"
+echo "copy btns: $(grep -c 'class="prompt__copy"' _site/index.html) (want 14)"
+echo "nav links: $(grep -c 'data-link=' _site/index.html) (want 14)"
+```
+Expected: `patterns: 14`, `sections: 5`, `copy btns: 14`, `nav links: 14`.
+
+- [ ] **Step 7: Assert each slug has both a content anchor and a sidebar link**
+
+Run:
+```bash
+for slug in trusted-sources exemplars-over-instruction confidence-calibration encoded-reasoning self-critique adversarial-push-back premortem bounded-option-generation decision-capture format-projection artifact-creation human-in-the-loop role-priming workflows-as-superset; do
+ grep -q "id=\"$slug\"" _site/index.html && grep -q "href=\"#$slug\"" _site/index.html || echo "MISSING: $slug";
+done; echo "SLUG_CHECK_DONE"
+```
+Expected: prints only `SLUG_CHECK_DONE` (no `MISSING:` lines).
+
+- [ ] **Step 8: Commit**
+
+```bash
+git add _patterns/
+git commit -m "feat: add remaining 13 patterns across all five categories"
+```
+
+---
+
+## Task 5: Stylesheet (tokens, light/dark themes, layout, components)
+
+**Files:**
+- Create: `assets/css/style.css`
+
+- [ ] **Step 1: Create `assets/css/style.css`**
+
+`assets/css/style.css`:
+```css
+:root {
+ --bg: #ffffff;
+ --bg-elevated: #f7f8fa;
+ --border: #e7e9ee;
+ --border-strong: #dfe2e8;
+ --text: #0b1020;
+ --text-muted: #4b5263;
+ --text-faint: #8a90a0;
+ --accent: #3858E9;
+ --accent-contrast: #ffffff;
+ --prompt-bg: #fdf6dd;
+ --prompt-bg-head: #fbf0c9;
+ --prompt-border: #f0e4b0;
+ --prompt-label: #7a6a1f;
+ --prompt-text: #4a431f;
+ --radius: 10px;
+ --sidebar-w: 264px;
+ --content-max: 720px;
+ --header-h: 57px;
+ --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
+ --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+}
+[data-theme="dark"] {
+ --bg: #0f1115;
+ --bg-elevated: #14161c;
+ --border: #23262f;
+ --border-strong: #2a2e38;
+ --text: #f1f3f8;
+ --text-muted: #a9b0be;
+ --text-faint: #6b7280;
+ --accent: #6b8aff;
+ --accent-contrast: #0b1020;
+ --prompt-bg: #211d10;
+ --prompt-bg-head: #2a2412;
+ --prompt-border: #463d1d;
+ --prompt-label: #d9c373;
+ --prompt-text: #e8dcae;
+}
+* { box-sizing: border-box; }
+html { scroll-behavior: smooth; scroll-padding-top: 72px; }
+@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
+body { margin: 0; font-family: var(--sans); color: var(--text); background: var(--bg); line-height: 1.5; }
+a { color: var(--accent); text-decoration: none; }
+a:hover { text-decoration: underline; }
+
+/* Header */
+.site-header {
+ position: sticky; top: 0; z-index: 10;
+ display: flex; align-items: center; justify-content: space-between;
+ height: var(--header-h); padding: 0 24px; background: var(--bg);
+ border-bottom: 1px solid var(--border);
+}
+.brand { font-weight: 800; font-size: 18px; color: var(--text); letter-spacing: -.01em; }
+.brand span { color: var(--accent); }
+.header-nav { display: flex; align-items: center; gap: 18px; }
+.header-nav a { color: var(--text-muted); font-size: 14px; font-weight: 500; }
+.theme-toggle {
+ width: 34px; height: 34px; border-radius: 8px; border: 1px solid var(--border-strong);
+ background: var(--bg-elevated); cursor: pointer; display: grid; place-items: center; padding: 0;
+}
+.theme-toggle__icon::before { content: "🌙"; font-size: 15px; }
+[data-theme="dark"] .theme-toggle__icon::before { content: "☀️"; }
+
+/* Layout */
+.layout { display: flex; align-items: flex-start; max-width: 1120px; margin: 0 auto; }
+.sidebar {
+ position: sticky; top: var(--header-h); align-self: flex-start;
+ width: var(--sidebar-w); flex: 0 0 var(--sidebar-w);
+ height: calc(100vh - var(--header-h)); overflow-y: auto;
+ padding: 22px 16px; border-right: 1px solid var(--border);
+}
+.search input {
+ width: 100%; padding: 8px 12px; font-size: 14px; font-family: var(--sans);
+ border: 1px solid var(--border-strong); border-radius: 8px;
+ background: var(--bg); color: var(--text);
+}
+.sidebar-cat { margin-top: 18px; }
+.sidebar-cat__title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em; color: var(--text-faint); margin: 0 0 6px; }
+.sidebar-cat ul { list-style: none; margin: 0; padding: 0; }
+.sidebar-cat a { display: block; padding: 4px 10px; font-size: 13.5px; color: var(--text-muted); border-radius: 6px; }
+.sidebar-cat a:hover { text-decoration: none; background: var(--bg-elevated); }
+.sidebar-cat a.is-active { background: var(--accent); color: var(--accent-contrast); font-weight: 600; }
+.sidebar-cat a.is-active:hover { background: var(--accent); }
+
+/* Content */
+.content { flex: 1 1 auto; min-width: 0; padding: 32px 40px; }
+.intro { margin-bottom: 8px; }
+.intro h1 { font-size: 34px; font-weight: 800; letter-spacing: -.02em; margin: 0 0 12px; }
+.intro p { color: var(--text-muted); max-width: var(--content-max); font-size: 16px; margin: 0 0 10px; }
+
+.cat-section { padding-top: 26px; }
+.cat-section__title { font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--accent); margin: 0 0 2px; }
+.cat-section__desc { color: var(--text-faint); margin: 0 0 8px; font-size: 14px; }
+
+.pattern { padding: 22px 0; border-top: 1px solid var(--border); max-width: var(--content-max); }
+.pattern__title { font-size: 22px; font-weight: 800; letter-spacing: -.01em; margin: 0 0 6px; }
+.pattern__summary { color: var(--text-muted); margin: 0 0 14px; }
+.pattern__adds-label { font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: var(--text); margin: 0 0 8px; }
+.pattern__adds { list-style: none; margin: 0 0 16px; padding: 0; }
+.pattern__adds li { position: relative; padding: 4px 0 4px 22px; color: var(--text-muted); }
+.pattern__adds li::before { content: "+"; position: absolute; left: 0; color: var(--accent); font-weight: 800; }
+
+.prompt { border: 1px solid var(--prompt-border); border-radius: var(--radius); overflow: hidden; background: var(--prompt-bg); }
+.prompt__head { display: flex; justify-content: space-between; align-items: center; padding: 9px 14px; background: var(--prompt-bg-head); border-bottom: 1px solid var(--prompt-border); }
+.prompt__label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--prompt-label); }
+.prompt__copy { background: var(--accent); color: var(--accent-contrast); border: none; border-radius: 6px; font-size: 12px; font-weight: 600; padding: 5px 12px; cursor: pointer; }
+.prompt__copy:hover { filter: brightness(1.05); }
+.prompt__copy.is-copied { background: #2c9c4a; color: #fff; }
+.prompt__body { margin: 0; padding: 14px; font-family: var(--mono); font-size: 13px; line-height: 1.6; color: var(--prompt-text); white-space: pre-wrap; word-break: break-word; }
+
+.is-hidden { display: none !important; }
+
+/* Resources / simple pages */
+.page { max-width: var(--content-max); margin: 0 auto; padding: 40px 24px; }
+.page h1 { font-size: 30px; font-weight: 800; letter-spacing: -.02em; }
+.page h2 { margin-top: 28px; font-size: 15px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); }
+.page ul { padding-left: 18px; }
+.page li { margin: 8px 0; color: var(--text-muted); }
+
+/* Footer */
+.site-footer { border-top: 1px solid var(--border); padding: 28px 24px; text-align: center; color: var(--text-faint); font-size: 13px; }
+.site-footer p { margin: 4px 0; }
+.site-footer a { color: var(--text-muted); }
+
+/* Responsive */
+@media (max-width: 820px) {
+ .layout { flex-direction: column; }
+ .sidebar { position: static; width: 100%; height: auto; flex-basis: auto; border-right: none; border-bottom: 1px solid var(--border); }
+ .content { padding: 24px 20px; }
+}
+```
+
+- [ ] **Step 2: Build and assert the stylesheet is present and themed**
+
+Run:
+```bash
+bundle exec jekyll build
+test -f _site/assets/css/style.css && \
+grep -q '\[data-theme="dark"\]' _site/assets/css/style.css && \
+grep -q '.prompt__copy' _site/assets/css/style.css && \
+echo "CSS_OK"
+```
+Expected: prints `CSS_OK`.
+
+- [ ] **Step 3: Visually verify both themes (Playwright)**
+
+Start a local server (leave it running for Tasks 5–6):
+```bash
+bundle exec jekyll serve --detach --port 4000
+```
+Then use the Playwright MCP browser tools:
+1. `browser_navigate` → `http://localhost:4000/`
+2. `browser_take_screenshot` (light theme) — confirm: sticky header with brand + toggle, left sidebar with categories/patterns, content with category sections and amber prompt panels.
+3. `browser_evaluate` → `() => { localStorage.setItem('theme','dark'); document.documentElement.setAttribute('data-theme','dark'); return document.documentElement.getAttribute('data-theme'); }` → expect `"dark"`
+4. `browser_take_screenshot` (dark theme) — confirm dark surfaces, brighter blue accent, dark amber prompt panels.
+
+Manual fallback (if Playwright is unavailable): open `http://localhost:4000/` in a browser, confirm the light layout, then run `localStorage.setItem('theme','dark')` in the console and reload to confirm dark mode.
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add assets/css/style.css
+git commit -m "feat: stylesheet with light/dark themes, layout, and prompt component"
+```
+
+---
+
+## Task 6: Interactivity — theme toggle, search, scroll-spy, copy (app.js)
+
+**Files:**
+- Create: `assets/js/app.js`
+
+Ensure the dev server from Task 5 is still running (`bundle exec jekyll serve --detach --port 4000`); `jekyll serve` rebuilds on file changes, so after each step reload the page in Playwright to pick up changes.
+
+- [ ] **Step 1: Create `assets/js/app.js` with all four behaviors**
+
+`assets/js/app.js`:
+```javascript
+(function () {
+ 'use strict';
+
+ /* Theme toggle */
+ var toggle = document.getElementById('theme-toggle');
+ if (toggle) {
+ toggle.addEventListener('click', function () {
+ var current = document.documentElement.getAttribute('data-theme');
+ var next = current === 'dark' ? 'light' : 'dark';
+ document.documentElement.setAttribute('data-theme', next);
+ try { localStorage.setItem('theme', next); } catch (e) {}
+ });
+ }
+
+ /* Search filter */
+ var search = document.getElementById('pattern-search');
+ var patterns = Array.prototype.slice.call(document.querySelectorAll('.pattern'));
+ var catSections = Array.prototype.slice.call(document.querySelectorAll('.cat-section'));
+ var sidebarCats = Array.prototype.slice.call(document.querySelectorAll('.sidebar-cat'));
+
+ function applyFilter(q) {
+ q = (q || '').trim().toLowerCase();
+ var visibleByCat = {};
+ patterns.forEach(function (el) {
+ var match = q === '' || el.textContent.toLowerCase().indexOf(q) !== -1;
+ el.classList.toggle('is-hidden', !match);
+ if (match) { visibleByCat[el.getAttribute('data-cat')] = true; }
+ });
+ catSections.forEach(function (sec) {
+ sec.classList.toggle('is-hidden', !visibleByCat[sec.getAttribute('data-cat')]);
+ });
+ sidebarCats.forEach(function (sc) {
+ var cat = sc.getAttribute('data-cat');
+ sc.classList.toggle('is-hidden', !visibleByCat[cat]);
+ Array.prototype.forEach.call(sc.querySelectorAll('a[data-link]'), function (a) {
+ var pat = document.getElementById(a.getAttribute('data-link'));
+ var matched = pat && !pat.classList.contains('is-hidden');
+ a.parentNode.classList.toggle('is-hidden', !matched);
+ });
+ });
+ }
+
+ if (search) {
+ search.addEventListener('input', function () { applyFilter(search.value); });
+ }
+
+ document.addEventListener('keydown', function (e) {
+ if (e.key === '/' && document.activeElement !== search) {
+ e.preventDefault();
+ if (search) search.focus();
+ } else if (e.key === 'Escape' && document.activeElement === search) {
+ search.value = '';
+ applyFilter('');
+ }
+ });
+
+ /* Scroll-spy: highlight the active pattern's sidebar link */
+ var navLinks = {};
+ Array.prototype.forEach.call(document.querySelectorAll('.sidebar-cat a[data-link]'), function (a) {
+ navLinks[a.getAttribute('data-link')] = a;
+ });
+ if ('IntersectionObserver' in window && patterns.length) {
+ var currentId = null;
+ var observer = new IntersectionObserver(function (entries) {
+ entries.forEach(function (entry) {
+ if (entry.isIntersecting) {
+ if (currentId && navLinks[currentId]) navLinks[currentId].classList.remove('is-active');
+ currentId = entry.target.id;
+ if (navLinks[currentId]) navLinks[currentId].classList.add('is-active');
+ }
+ });
+ }, { rootMargin: '-80px 0px -70% 0px', threshold: 0 });
+ patterns.forEach(function (p) { observer.observe(p); });
+ }
+
+ /* Copy buttons */
+ function fallbackCopy(text, cb) {
+ var ta = document.createElement('textarea');
+ ta.value = text;
+ ta.style.position = 'fixed';
+ ta.style.opacity = '0';
+ document.body.appendChild(ta);
+ ta.select();
+ try { document.execCommand('copy'); } catch (e) {}
+ document.body.removeChild(ta);
+ cb();
+ }
+
+ Array.prototype.forEach.call(document.querySelectorAll('.prompt__copy'), function (btn) {
+ btn.addEventListener('click', function () {
+ var pre = document.getElementById('prompt-' + btn.getAttribute('data-copy'));
+ if (!pre) return;
+ var text = pre.textContent;
+ var done = function () {
+ btn.textContent = 'Copied!';
+ btn.classList.add('is-copied');
+ setTimeout(function () {
+ btn.textContent = 'Copy';
+ btn.classList.remove('is-copied');
+ }, 1500);
+ };
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ navigator.clipboard.writeText(text).then(done).catch(function () { fallbackCopy(text, done); });
+ } else {
+ fallbackCopy(text, done);
+ }
+ });
+ });
+})();
+```
+
+- [ ] **Step 2: Build and assert the script is present**
+
+Run:
+```bash
+bundle exec jekyll build
+test -f _site/assets/js/app.js && \
+grep -q 'IntersectionObserver' _site/assets/js/app.js && \
+grep -q 'writeText' _site/assets/js/app.js && \
+echo "JS_OK"
+```
+Expected: prints `JS_OK`.
+
+- [ ] **Step 3: Verify theme toggle (Playwright)**
+
+With the server running, use Playwright MCP:
+1. `browser_navigate` → `http://localhost:4000/`
+2. `browser_evaluate` → `() => document.documentElement.getAttribute('data-theme')` → note value (e.g. `"light"`)
+3. `browser_click` the theme toggle (ref the `#theme-toggle` button from a `browser_snapshot`)
+4. `browser_evaluate` → `() => document.documentElement.getAttribute('data-theme')` → expect the opposite value
+5. `browser_evaluate` → `() => localStorage.getItem('theme')` → expect it to match step 4 (persisted)
+
+- [ ] **Step 4: Verify search filtering (Playwright)**
+
+1. `browser_navigate` → `http://localhost:4000/` (fresh load)
+2. `browser_type` into `#pattern-search` the text `premortem`
+3. `browser_evaluate` → `() => document.querySelectorAll('.pattern:not(.is-hidden)').length` → expect `1`
+4. `browser_evaluate` → `() => document.querySelectorAll('.cat-section:not(.is-hidden)').length` → expect `1` (only "Critique & stress-testing" remains)
+5. `browser_evaluate` → clear and restore: `() => { var s=document.getElementById('pattern-search'); s.value=''; s.dispatchEvent(new Event('input')); return document.querySelectorAll('.pattern:not(.is-hidden)').length; }` → expect `14`
+
+- [ ] **Step 5: Verify copy button (Playwright)**
+
+1. `browser_navigate` → `http://localhost:4000/`
+2. `browser_evaluate` to grant clipboard read for assertion is unreliable across browsers; instead assert the button feedback and the source text:
+ - `browser_click` the first `.prompt__copy` button (ref from `browser_snapshot`)
+ - `browser_evaluate` → `() => document.querySelector('.prompt__copy').textContent` → expect `"Copied!"`
+ - `browser_evaluate` → `() => document.getElementById('prompt-trusted-sources').textContent.slice(0,16)` → expect it begins with `"Ground this Skil"`
+
+Manual fallback: load the page, click a Copy button, confirm it flips to "Copied!" then back, and paste into a text field to confirm the prompt text copied.
+
+- [ ] **Step 6: Verify scroll-spy (Playwright)**
+
+1. `browser_navigate` → `http://localhost:4000/#premortem`
+2. `browser_evaluate` → `() => { window.scrollBy(0, 1); return true; }` (nudge to trigger the observer)
+3. `browser_evaluate` → `() => { var a=document.querySelector('.sidebar-cat a.is-active'); return a ? a.getAttribute('data-link') : null; }` → expect a non-null slug (the active link tracks the visible pattern)
+
+- [ ] **Step 7: Stop the dev server**
+
+Run:
+```bash
+pkill -f "jekyll serve" || true
+```
+
+- [ ] **Step 8: Commit**
+
+```bash
+git add assets/js/app.js
+git commit -m "feat: search, scroll-spy, copy buttons, and theme toggle"
+```
+
+---
+
+## Task 7: Resources page
+
+**Files:**
+- Create: `_layouts/page.html`
+- Create: `resources.md`
+
+- [ ] **Step 1: Create `_layouts/page.html`**
+
+`_layouts/page.html`:
+```html
+---
+layout: default
+---
+
+ {{ content }}
+
+```
+
+- [ ] **Step 2: Create `resources.md`**
+
+`resources.md`:
+```markdown
+---
+layout: page
+title: Resources
+description: Links and reference skills for building AI Skills.
+---
+
+# Resources
+
+A short, curated set of places to learn more and skills worth studying.
+
+## Learn & explore
+
+- [Agent Skills open standard](https://agentskills.io)
+- [Anthropic Skills repo](https://github.com/anthropics/skills)
+- [Claude Code / Skills docs](https://docs.anthropic.com/en/docs/claude-code)
+- [Equipping agents for the real world with agent skills](https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills)
+- [skills.sh — the open agent skills ecosystem](https://skills.sh) — searchable, with ratings. Try `npx skills find `.
+- [WordPress agent skills](https://github.com/WordPress/agent-skills)
+- [Automattic design skills](https://github.com/Automattic/design-skills)
+
+## Reference skills to study
+
+Single-purpose skills and plugins that show the patterns in action:
+
+- **caveman** — ultra-compressed communication mode
+- **council** — structured adversarial assessment with a verdict
+- **grill-with-docs** — interview-style plan challenge against your domain model
+- **humanize** — detects and removes AI writing patterns
+- **prototype** — scaffolds a throwaway frontend or backend prototype
+- **red-pen** — strict editorial review (Orwell's rules + Practical Typography)
+- **voiceprint** — extracts a linguistic fingerprint into a writer skill
+- **frontend-designer** — distinctive, production-grade frontend interfaces
+- **last30days** — research a topic across Reddit, X, YouTube, HN, and more
+- **superpowers** — core skills library for Claude Code (TDD, debugging, collaboration)
+```
+
+- [ ] **Step 3: Build and assert the Resources page renders**
+
+Run:
+```bash
+bundle exec jekyll build
+test -f _site/resources/index.html && \
+grep -q 'agentskills.io' _site/resources/index.html && \
+grep -q 'class="page"' _site/resources/index.html && \
+grep -q 'Reference skills to study' _site/resources/index.html && \
+echo "RESOURCES_OK"
+```
+Expected: prints `RESOURCES_OK`.
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add _layouts/page.html resources.md
+git commit -m "feat: resources page with links and reference skills"
+```
+
+---
+
+## Task 8: Custom domain (CNAME) + production URL config
+
+**Files:**
+- Create: `CNAME`
+
+- [ ] **Step 1: Create the `CNAME` file**
+
+`CNAME` (exact contents, single line, no trailing path):
+```
+skillpatterns.ai
+```
+
+- [ ] **Step 2: Build and assert CNAME is published to the site root**
+
+Run:
+```bash
+bundle exec jekyll build
+test -f _site/CNAME && grep -qx 'skillpatterns.ai' _site/CNAME && echo "CNAME_OK"
+```
+Expected: prints `CNAME_OK`.
+
+- [ ] **Step 3: Commit**
+
+```bash
+git add CNAME
+git commit -m "chore: configure custom apex domain skillpatterns.ai"
+```
+
+---
+
+## Task 9: README (local dev, adding patterns, deploy + DNS) and final smoke
+
+**Files:**
+- Modify: `README.md`
+
+- [ ] **Step 1: Replace `README.md`**
+
+`README.md`:
+```markdown
+# Skill Patterns
+
+A clean, searchable catalog of reusable patterns for composing AI Skills — published at
+[skillpatterns.ai](https://skillpatterns.ai).
+
+## Local development
+
+Requires Ruby + Bundler.
+
+```bash
+bundle install
+bundle exec jekyll serve --port 4000
+# open http://localhost:4000
+```
+
+## Adding or editing a pattern
+
+Each pattern is one Markdown file in `_patterns/`. Copy an existing one and edit the frontmatter:
+
+```yaml
+---
+title: "My pattern"
+slug: my-pattern # unique; becomes the #anchor and copy target
+category: grounding # one of the keys in _data/categories.yml
+order: 4 # sort order within the category
+summary: "One-line definition."
+adds:
+ - "What it adds, bullet one"
+ - "Bullet two"
+prompt: |
+ The example prompt partial users can copy.
+---
+```
+
+Categories (titles, descriptions, order) live in `_data/categories.yml`.
+
+## Deployment
+
+GitHub Pages builds this site natively (no Action). In repo **Settings → Pages**:
+set **Source: Deploy from a branch**, branch `main`, folder `/ (root)`.
+
+### DNS for the apex domain `skillpatterns.ai`
+
+At your DNS registrar, create:
+
+| Type | Host | Value |
+|------|------|-------|
+| A | @ | 185.199.108.153 |
+| A | @ | 185.199.109.153 |
+| A | @ | 185.199.110.153 |
+| A | @ | 185.199.111.153 |
+| AAAA | @ | 2606:50c0:8000::153 |
+| AAAA | @ | 2606:50c0:8001::153 |
+| AAAA | @ | 2606:50c0:8002::153 |
+| AAAA | @ | 2606:50c0:8003::153 |
+| CNAME | www | .github.io |
+
+After DNS propagates, enable **Enforce HTTPS** in Settings → Pages.
+
+## License
+
+MIT — see `LICENSE`.
+```
+
+- [ ] **Step 2: Final full-site build smoke test**
+
+Run:
+```bash
+bundle exec jekyll build
+echo "index: $(test -f _site/index.html && echo ok)"
+echo "resources: $(test -f _site/resources/index.html && echo ok)"
+echo "css: $(test -f _site/assets/css/style.css && echo ok)"
+echo "js: $(test -f _site/assets/js/app.js && echo ok)"
+echo "cname: $(test -f _site/CNAME && echo ok)"
+echo "patterns: $(grep -c 'class="pattern"' _site/index.html)"
+```
+Expected: five `ok` lines and `patterns: 14`.
+
+- [ ] **Step 3: Commit**
+
+```bash
+git add README.md
+git commit -m "docs: README with local dev, authoring, and deploy/DNS instructions"
+```
+
+- [ ] **Step 4: Hand off for review / PR**
+
+Use superpowers:finishing-a-development-branch to decide how to integrate `skill-patterns-site` (open a PR or merge). Do not push or open a PR without the user's go-ahead.
+
+---
+
+## Self-review (completed during planning)
+
+- **Spec coverage:** Build/deploy (Tasks 1, 8, 9) · content model & collection (Tasks 1, 3) · all 14 patterns (Tasks 3–4) · category taxonomy (Task 3) · sidebar + single-page anchors (Task 3) · search/scroll-spy/copy/theme (Task 6) · light+dark themes & prompt component (Task 5) · resources page (Task 7) · custom domain + DNS (Tasks 8–9). All spec sections map to a task.
+- **Placeholder scan:** Bracketed text inside `prompt:` values is intentional pattern content, not plan placeholders. No TBD/TODO steps; every code/file step contains full content.
+- **Type/name consistency:** Frontmatter keys (`slug`, `category`, `order`, `summary`, `adds`, `prompt`), CSS classes (`.pattern`, `.cat-section`, `.sidebar-cat`, `.prompt__copy`, `.is-hidden`, `.is-active`), element IDs (`#pattern-search`, `#theme-toggle`, `#prompt-`), and `data-` attributes (`data-cat`, `data-link`, `data-copy`) are used identically across the include, layout, CSS, and JS tasks.
+```
diff --git a/docs/superpowers/plans/2026-05-27-catalog-source-on-main.md b/docs/superpowers/plans/2026-05-27-catalog-source-on-main.md
new file mode 100644
index 0000000..24b0402
--- /dev/null
+++ b/docs/superpowers/plans/2026-05-27-catalog-source-on-main.md
@@ -0,0 +1,688 @@
+# Catalog Source on `main` — 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:** Move the canonical pattern catalog to `main` (the default branch) and generate everything downstream (the plugin snapshot, plus the site's `_patterns/`, `llms.txt`, `patterns.json`) from it, so a contributor edits one file on `main` and opens one PR.
+
+**Architecture:** A single Node generator (`scripts/build.mjs`) on `main` reads `patterns/*.md` + `categories.yml` and emits the plugin snapshot, `llms.txt`, and `patterns.json`. A GitHub Action verifies snapshot freshness on PRs and, on push to `main`, syncs the generated files into the `gh-pages` Jekyll branch. Correctness is proven by a two-phase byte-parity gate against today's published output before cutover.
+
+**Tech Stack:** Node 20 (ESM), `js-yaml`, GitHub Actions, Jekyll (existing, `gh-pages` only).
+
+**Branch strategy:** Most work lands on a branch off `main` (`catalog-source-on-main`). Golden references are captured from the **current** `gh-pages` state first (Task 0). A small `gh-pages` cleanup happens on a branch off `gh-pages` (Task 10).
+
+**Commit convention (per repo owner):** Use the `/commit` (bork:commit) skill for every commit — include all required headings, **no emojis**. The `git commit -m` lines below are the intent; generate the real message with `/commit`.
+
+**Parity is the test.** This project has no unit-test suite; the verification at each gate is a byte-level `diff` against captured golden output. "Expected: empty diff" is a passing test. Liquid whitespace is the main hazard — if a diff isn't empty, adjust `build.mjs` and re-run until it is.
+
+---
+
+## File structure
+
+On `main` (after this plan):
+
+| Path | Responsibility |
+|---|---|
+| `patterns/*.md` | Canonical catalog — one file per pattern (moved verbatim from `gh-pages:_patterns/`) |
+| `categories.yml` | Canonical category metadata (moved from `gh-pages:_data/categories.yml`) |
+| `scripts/build.mjs` | The one generator — emits snapshot + `llms.txt` + `patterns.json` |
+| `package.json`, `package-lock.json` | `npm run build`; devDep `js-yaml` |
+| `.gitignore` | ignores `node_modules/`, `build/` |
+| `skills/skill-patterns/references/patterns.md` | GENERATED snapshot (committed, verified by PR check) |
+| `.github/workflows/sync-catalog.yml` | PR freshness check + push-to-`gh-pages` sync |
+| `AGENTS.md`, `CLAUDE.md` | Updated contributor flow |
+
+`build/` (git-ignored) holds the transient `llms.txt` / `patterns.json` the sync job copies to `gh-pages`.
+
+---
+
+## Task 0: Capture golden reference outputs (from current `gh-pages`)
+
+**Why:** The parity gate compares the new generator's output to today's published output. Capture that output **before** changing anything.
+
+**Files:** none modified — writes goldens to `/tmp/sp-golden/`.
+
+- [ ] **Step 1: Confirm you are on `gh-pages` with a clean tree**
+
+Run: `git -C /Users/matt/git/skill-patterns rev-parse --abbrev-ref HEAD && git -C /Users/matt/git/skill-patterns status --porcelain`
+Expected: prints `gh-pages` and shows only the untracked `docs/` (no other changes).
+
+- [ ] **Step 2: Build the live site to render `llms.txt` and `patterns.json`**
+
+Run:
+```bash
+cd /Users/matt/git/skill-patterns
+bundle exec jekyll build
+```
+Expected: `done in N.NNN seconds`, no errors. (`_site/llms.txt` and `_site/patterns.json` now exist.)
+
+- [ ] **Step 3: Save the three goldens**
+
+Run:
+```bash
+mkdir -p /tmp/sp-golden
+cp _site/llms.txt /tmp/sp-golden/llms.txt.golden
+cp _site/patterns.json /tmp/sp-golden/patterns.json.golden
+git show main:skills/skill-patterns/references/patterns.md > /tmp/sp-golden/snapshot.golden
+```
+Expected: all three files exist and are non-empty: `wc -c /tmp/sp-golden/*` shows three non-zero sizes.
+
+- [ ] **Step 4: Record the current pattern/category counts (sanity anchor)**
+
+Run: `ls _patterns/*.md | wc -l && grep -c '^- key:' _data/categories.yml`
+Expected: `38` and `6`. Note these — the generator must reproduce them.
+
+- [ ] **Step 5: Confirm snapshot vs llms.txt drift (informational)**
+
+Run: `diff /tmp/sp-golden/snapshot.golden /tmp/sp-golden/llms.txt.golden && echo IDENTICAL || echo "PRE-EXISTING DRIFT — note it"`
+Expected: `IDENTICAL` (the committed snapshot was curled from `llms.txt`). If it reports drift, note the diff — phase 1 must still match each golden to its own target.
+
+No commit (goldens live in `/tmp`).
+
+---
+
+## Task 1: Create the `main` work branch and seed the canonical source
+
+**Files:**
+- Create: `patterns/*.md` (38 files), `categories.yml`
+
+- [ ] **Step 1: Create the branch off `main`**
+
+Run:
+```bash
+cd /Users/matt/git/skill-patterns
+git switch -c catalog-source-on-main main
+```
+Expected: `Switched to a new branch 'catalog-source-on-main'`. Switching updates tracked files to `main`'s tree and leaves the untracked `docs/` in place — no stash needed, since `main` has no `docs/` to conflict.
+
+- [ ] **Step 2: Seed `patterns/` and `categories.yml` from `gh-pages` (verbatim)**
+
+Run:
+```bash
+git checkout gh-pages -- _patterns _data/categories.yml
+mkdir -p patterns
+git mv _patterns/*.md patterns/
+git mv _data/categories.yml categories.yml
+rmdir _data 2>/dev/null || true
+```
+Expected: `patterns/` holds 38 `.md` files; `categories.yml` at repo root. Verify: `ls patterns/*.md | wc -l` → `38`.
+
+- [ ] **Step 3: Confirm the seeded files are byte-identical to the source**
+
+Run: `git show gh-pages:_patterns/adversarial-pushback.md | diff - patterns/adversarial-pushback.md && echo OK`
+Expected: `OK` (no diff). Compares the `gh-pages` version directly against the moved file without touching the index (`git mv` preserves content; this is a sanity check).
+
+- [ ] **Step 4: Commit the seed**
+
+```bash
+git add patterns categories.yml
+# Use /commit (bork:commit). Intent:
+# feat: add canonical pattern catalog to main (patterns/ + categories.yml)
+```
+Run `/commit` and confirm the commit lands on `catalog-source-on-main`.
+
+---
+
+## Task 2: Add the Node package and `.gitignore`
+
+**Files:**
+- Create: `package.json`, `.gitignore`
+- Create (generated by npm): `package-lock.json`
+
+- [ ] **Step 1: Write `package.json`**
+
+Create `package.json`:
+```json
+{
+ "name": "skill-patterns-catalog",
+ "version": "1.0.0",
+ "private": true,
+ "type": "module",
+ "description": "Build tooling for the Skill Patterns catalog (generates the plugin snapshot, llms.txt, and patterns.json).",
+ "scripts": {
+ "build": "node scripts/build.mjs"
+ },
+ "devDependencies": {
+ "js-yaml": "^4.1.0"
+ }
+}
+```
+
+- [ ] **Step 2: Write `.gitignore`** (merge with any existing entries; do not drop existing lines)
+
+Ensure `.gitignore` contains:
+```
+node_modules/
+build/
+```
+
+- [ ] **Step 3: Install to generate the lockfile**
+
+Run: `npm install`
+Expected: creates `node_modules/` and `package-lock.json`; exit 0. (`js-yaml` resolved.)
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add package.json package-lock.json .gitignore
+# /commit intent: chore: add node build tooling (js-yaml) and gitignore
+```
+
+---
+
+## Task 3: Write the generator `scripts/build.mjs`
+
+**Files:**
+- Create: `scripts/build.mjs`
+
+- [ ] **Step 1: Write `scripts/build.mjs`**
+
+Create `scripts/build.mjs`:
+```js
+#!/usr/bin/env node
+// Generates the Skill Patterns catalog outputs from patterns/*.md + categories.yml.
+// skills/skill-patterns/references/patterns.md -> plugin snapshot (identical to llms.txt)
+// build/llms.txt -> live /llms.txt
+// build/patterns.json -> live /patterns.json
+// Do NOT hand-edit outputs. Edit patterns/ and run `npm run build`.
+// Flag: --no-related (omit related[] — used only for the phase-1 parity gate)
+
+import { readFileSync, writeFileSync, readdirSync, mkdirSync } from 'node:fs';
+import { join, dirname, basename } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import yaml from 'js-yaml';
+
+const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
+const SITE_URL = 'https://skillpatterns.ai';
+const INCLUDE_RELATED = !process.argv.includes('--no-related');
+const REQUIRED = ['title', 'slug', 'category', 'summary', 'adds', 'prompt'];
+
+function readFrontmatter(file) {
+ const raw = readFileSync(file, 'utf8');
+ const m = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
+ if (!m) throw new Error(`${basename(file)}: no YAML frontmatter`);
+ return yaml.load(m[1]);
+}
+
+const categories = yaml.load(readFileSync(join(ROOT, 'categories.yml'), 'utf8'));
+const sortedCats = [...categories].sort((a, b) => a.order - b.order);
+
+const dir = join(ROOT, 'patterns');
+const patterns = readdirSync(dir)
+ .filter((f) => f.endsWith('.md'))
+ .map((f) => {
+ const data = readFrontmatter(join(dir, f));
+ data._base = f.replace(/\.md$/, '');
+ return data;
+ });
+
+const titleBySlug = new Map(patterns.map((p) => [p.slug, p.title]));
+const catKeys = new Set(categories.map((c) => c.key));
+
+for (const p of patterns) {
+ for (const k of REQUIRED) {
+ if (p[k] == null) throw new Error(`${p._base}.md: missing required field '${k}'`);
+ }
+ if (!catKeys.has(p.category)) {
+ throw new Error(`${p._base}.md: unknown category '${p.category}'`);
+ }
+ for (const r of p.related ?? []) {
+ if (!titleBySlug.has(r.slug)) {
+ throw new Error(`${p._base}.md: related slug '${r.slug}' does not exist`);
+ }
+ }
+}
+
+const patternsIn = (catKey) =>
+ patterns
+ .filter((p) => p.category === catKey)
+ .sort((a, b) => a.title.toLowerCase().localeCompare(b.title.toLowerCase()));
+
+const stripNewlines = (s) => String(s).replace(/\r?\n/g, '');
+
+function buildLlms() {
+ let o = '';
+ o += `# Skill Patterns\n\n`;
+ o += `> Reusable, composable techniques for shaping how an AI agent behaves — ${patterns.length} patterns across ${categories.length} categories. When creating or improving a Skill, apply the patterns whose purpose matches the task; each entry includes an example prompt you can adapt. Most skills use 2–4 patterns — don't over-apply. Site: ${SITE_URL}/\n`;
+ for (const cat of sortedCats) {
+ o += `\n## ${cat.title}\n${cat.description}\n`;
+ for (const p of patternsIn(cat.key)) {
+ o += `\n### ${p.title}\n`;
+ o += `${p.summary}\n`;
+ o += `- What it adds: ${p.adds.join('; ')}.\n`;
+ o += `- Example prompt: ${stripNewlines(p.prompt)}\n`;
+ o += `- URL: ${SITE_URL}/patterns/${p._base}/\n`;
+ if (INCLUDE_RELATED && p.related?.length) {
+ const rel = p.related.map((r) => `${titleBySlug.get(r.slug)} — ${r.note}`).join('; ');
+ o += `- Related: ${rel}\n`;
+ }
+ }
+ }
+ o += `\n`;
+ return o;
+}
+
+function buildJson() {
+ const j = JSON.stringify;
+ const objs = [];
+ for (const cat of sortedCats) {
+ for (const p of patternsIn(cat.key)) {
+ let s =
+ `{"title":${j(p.title)},"slug":${j(p.slug)},"category":${j(cat.title)},` +
+ `"categoryKey":${j(p.category)},"summary":${j(p.summary)},"adds":${j(p.adds)},` +
+ `"prompt":${j(stripNewlines(p.prompt))},"url":${j(`${SITE_URL}/patterns/${p._base}/`)}`;
+ if (INCLUDE_RELATED && p.related?.length) {
+ s += `,"related":${j(p.related.map((r) => ({ slug: r.slug, note: r.note })))}`;
+ }
+ objs.push(s + `}`);
+ }
+ }
+ return `[${objs.join(',')}]\n`;
+}
+
+const llms = buildLlms();
+mkdirSync(join(ROOT, 'build'), { recursive: true });
+writeFileSync(join(ROOT, 'build', 'llms.txt'), llms);
+writeFileSync(join(ROOT, 'build', 'patterns.json'), buildJson());
+writeFileSync(join(ROOT, 'skills', 'skill-patterns', 'references', 'patterns.md'), llms);
+console.log(
+ `Generated ${patterns.length} patterns across ${categories.length} categories (related: ${INCLUDE_RELATED ? 'on' : 'off'}).`
+);
+```
+
+- [ ] **Step 2: Run it once to confirm it executes**
+
+Run: `npm run build`
+Expected: `Generated 38 patterns across 6 categories (related: on).` and `build/llms.txt`, `build/patterns.json`, and `skills/skill-patterns/references/patterns.md` are written. Do **not** commit yet — parity comes first.
+
+---
+
+## Task 4: Parity gate — phase 1 (faithful port, `related` disabled)
+
+**Goal:** Prove the Node port reproduces today's output exactly, ignoring the deliberate `related` addition.
+
+- [ ] **Step 1: Generate with `related` disabled**
+
+Run: `node scripts/build.mjs --no-related`
+Expected: `Generated 38 patterns across 6 categories (related: off).`
+
+- [ ] **Step 2: Diff `llms.txt` against golden**
+
+Run: `diff /tmp/sp-golden/llms.txt.golden build/llms.txt && echo PASS`
+Expected: `PASS` (empty diff).
+
+If not empty, the difference is almost certainly one of: trailing-newline count at EOF; `2–4` (en dash U+2013) vs `2-4`; `behaves —` / `don't` (em dash U+2014, straight apostrophe — copy from the golden, don't retype); category/pattern sort order (`localeCompare` case-insensitive); or the `Site: …/` trailing slash. Adjust `build.mjs` string literals to match the golden byte-for-byte and re-run Steps 1–2.
+
+- [ ] **Step 3: Diff `patterns.json` against golden**
+
+Run: `diff /tmp/sp-golden/patterns.json.golden build/patterns.json && echo PASS`
+Expected: `PASS`. Likely culprits if not: key order in each object; `adds`/`prompt` escaping (`JSON.stringify` vs Ruby `jsonify` — both leave UTF-8 unescaped, so em dashes should match); single trailing newline after `]`.
+
+- [ ] **Step 4: Diff the snapshot against golden**
+
+Run: `diff /tmp/sp-golden/snapshot.golden skills/skill-patterns/references/patterns.md && echo PASS`
+Expected: `PASS` (the snapshot is the same text as `llms.txt`).
+
+- [ ] **Step 5: Gate**
+
+All three diffs must print `PASS`. Do not proceed to Task 5 until phase 1 is clean. No commit yet.
+
+---
+
+## Task 5: Parity gate — phase 2 (enable `related`, verify only-additions)
+
+**Goal:** Turn `related` back on and confirm the *only* change from phase 1 is the added related content.
+
+- [ ] **Step 1: Regenerate with `related` on (default)**
+
+Run: `npm run build`
+Expected: `... (related: on).`
+
+- [ ] **Step 2: Confirm `llms.txt` differs from golden ONLY by `- Related:` lines**
+
+Run: `diff /tmp/sp-golden/llms.txt.golden build/llms.txt`
+Expected: every diff hunk is a pure **addition** (`>`) of a line beginning `- Related: `. No `<` (removed) or changed lines. Spot-check one: `grep -c '^- Related: ' build/llms.txt` should be > 0 and ≤ 38.
+
+- [ ] **Step 3: Confirm `patterns.json` differs ONLY by `related` keys**
+
+Run:
+```bash
+node -e '
+const fs = require("fs");
+const a = JSON.parse(fs.readFileSync("/tmp/sp-golden/patterns.json.golden", "utf8"));
+const b = JSON.parse(fs.readFileSync("./build/patterns.json", "utf8"));
+if (a.length !== b.length) { console.error("length mismatch", a.length, b.length); process.exit(1); }
+for (let i = 0; i < a.length; i++) {
+ const { related, ...rest } = b[i];
+ if (JSON.stringify(rest) !== JSON.stringify(a[i])) { console.error("MISMATCH at", i, a[i].slug); process.exit(1); }
+}
+console.log("PASS: only related[] added");'
+```
+Expected: `PASS: only related[] added`. Strips `related` from each new object and confirms the rest equals the golden object. (Reads + `JSON.parse`s the golden — its `.golden` extension means `require` won't auto-parse it.)
+
+- [ ] **Step 4: Confirm snapshot == llms.txt**
+
+Run: `diff build/llms.txt skills/skill-patterns/references/patterns.md && echo IDENTICAL`
+Expected: `IDENTICAL`.
+
+- [ ] **Step 5: Commit the generator + the generated snapshot**
+
+```bash
+git add scripts/build.mjs skills/skill-patterns/references/patterns.md
+# /commit intent:
+# feat: generate catalog outputs from main via scripts/build.mjs
+# - snapshot now includes related[] (composition hints)
+```
+Run `/commit`. (`build/` is git-ignored, so only the snapshot + script are staged.)
+
+---
+
+## Task 6: GitHub Actions workflow
+
+**Files:**
+- Create: `.github/workflows/sync-catalog.yml`
+
+- [ ] **Step 1: Write the workflow**
+
+Create `.github/workflows/sync-catalog.yml`:
+```yaml
+name: Sync catalog
+
+on:
+ pull_request:
+ branches: [main]
+ paths:
+ - 'patterns/**'
+ - 'categories.yml'
+ - 'scripts/build.mjs'
+ - 'package.json'
+ - 'package-lock.json'
+ push:
+ branches: [main]
+ paths:
+ - 'patterns/**'
+ - 'categories.yml'
+ - 'scripts/build.mjs'
+ - 'package.json'
+ - 'package-lock.json'
+
+permissions:
+ contents: write
+
+jobs:
+ snapshot-check:
+ if: github.event_name == 'pull_request'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: npm
+ - run: npm ci
+ - run: npm run build
+ - name: Verify the committed snapshot is up to date
+ run: |
+ if ! git diff --quiet -- skills/skill-patterns/references/patterns.md; then
+ echo "::error::Snapshot is stale. Run 'npm run build' and commit skills/skill-patterns/references/patterns.md."
+ git --no-pager diff -- skills/skill-patterns/references/patterns.md
+ exit 1
+ fi
+ echo "Snapshot is up to date."
+
+ sync-to-pages:
+ if: github.event_name == 'push'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out main
+ uses: actions/checkout@v4
+ with:
+ path: main
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: npm
+ cache-dependency-path: main/package-lock.json
+ - name: Build catalog outputs
+ working-directory: main
+ run: |
+ npm ci
+ npm run build
+ - name: Check out gh-pages
+ uses: actions/checkout@v4
+ with:
+ ref: gh-pages
+ path: pages
+ - name: Sync generated files into gh-pages
+ run: |
+ rm -rf pages/_patterns
+ mkdir -p pages/_patterns pages/_data
+ cp main/patterns/*.md pages/_patterns/
+ cp main/categories.yml pages/_data/categories.yml
+ cp main/build/llms.txt pages/llms.txt
+ cp main/build/patterns.json pages/patterns.json
+ - name: Commit and push to gh-pages
+ working-directory: pages
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ git add _patterns _data/categories.yml llms.txt patterns.json
+ if git diff --cached --quiet; then
+ echo "No catalog changes to sync."
+ else
+ git commit -m "chore: sync catalog from main@${GITHUB_SHA::7}"
+ git push
+ fi
+```
+
+- [ ] **Step 2: Validate the workflow YAML locally**
+
+Run: `node -e 'const fs=require("fs"),yaml=require("js-yaml");yaml.load(fs.readFileSync(".github/workflows/sync-catalog.yml","utf8"));console.log("valid YAML")'`
+Expected: `valid YAML`.
+
+> **Caveat:** GitHub Actions does **not** support YAML anchors/aliases in workflow files — the `paths` list is intentionally repeated for `pull_request` and `push`, not aliased. Also, if `gh-pages` has branch protection blocking the `github-actions[bot]` push, `sync-to-pages` will fail; grant the default token push access to `gh-pages` or use a PAT secret.
+
+- [ ] **Step 3: Commit**
+
+```bash
+git add .github/workflows/sync-catalog.yml
+# /commit intent: ci: sync catalog to gh-pages on push; verify snapshot freshness on PRs
+```
+
+---
+
+## Task 7: Update `main` docs (AGENTS.md / CLAUDE.md)
+
+**Files:**
+- Modify: `AGENTS.md`, `CLAUDE.md` (both currently say "update BOTH branches" with the old direction)
+
+- [ ] **Step 1: Read the current files**
+
+Run: `cat AGENTS.md` (and note `CLAUDE.md` is the same content per the repo convention).
+
+- [ ] **Step 2: Replace the "Two branches" + "On ANY catalog change" sections**
+
+Replace the catalog-workflow guidance with the new direction. The replacement text:
+```markdown
+## Two branches, two jobs
+
+- **`main`** (default) — the canonical home of the catalog **and** the installable plugin. Holds `patterns/*.md`, `categories.yml`, the generator (`scripts/build.mjs`), and the plugin under `skills/skill-patterns/`.
+- **`gh-pages`** — the **website** ([skillpatterns.ai](https://skillpatterns.ai), Jekyll). Its catalog inputs (`_patterns/`, `_data/categories.yml`, `llms.txt`, `patterns.json`) are **generated** — synced in by CI from `main`. Do not hand-edit them.
+
+## Adding or editing a pattern
+
+1. Edit (or add) one file in `patterns/` on `main`. Frontmatter: `title, slug, icon, category, summary, adds, related, prompt`.
+2. Run `npm run build` (regenerates `skills/skill-patterns/references/patterns.md`).
+3. Open one PR. The `snapshot-check` job fails if you forgot step 2. On merge, `sync-to-pages` regenerates and pushes the site's catalog files to `gh-pages`.
+
+Patterns sort **alphabetically by title** within their category (the `order` field is unused). `categories.yml` `order` sets category order.
+
+## Never hand-edit generated files
+
+`skills/skill-patterns/references/patterns.md` (on `main`) and `_patterns/`, `_data/categories.yml`, `llms.txt`, `patterns.json` (on `gh-pages`) are all generated by `scripts/build.mjs`. Edit `patterns/` + `categories.yml` and rebuild.
+```
+
+- [ ] **Step 3: Mirror the change into `CLAUDE.md`** (same content, matching the repo's existing AGENTS.md/CLAUDE.md parity).
+
+- [ ] **Step 4: Fix the generation note in `skills/skill-patterns/SKILL.md`**
+
+The last line currently reads: *"`references/patterns.md` is a generated snapshot of the live catalog (`skillpatterns.ai/llms.txt`); regenerate it when the catalog changes."* Replace it with:
+> `references/patterns.md` is generated from the canonical catalog on `main` (`patterns/*.md` + `categories.yml`) by `scripts/build.mjs` — run `npm run build` after editing a pattern. Never hand-edit it.
+
+Leave the rest of `SKILL.md` (including the "live source is `https://skillpatterns.ai/llms.txt`" tip) unchanged.
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add AGENTS.md CLAUDE.md skills/skill-patterns/SKILL.md
+# /commit intent: docs: rewrite catalog contribution flow (edit patterns/ on main, one PR)
+```
+
+- [ ] **Step 6: Push the branch and open the PR**
+
+```bash
+git push -u origin catalog-source-on-main
+gh pr create --base main --title "Move catalog source to main; generate downstream" \
+ --body "See docs/superpowers/plans/2026-05-27-catalog-source-on-main.md. Inverts the catalog source-of-truth to main; CI generates the snapshot and syncs the site."
+```
+Expected: PR opens; the `snapshot-check` job runs and **passes** (snapshot was committed in Task 5).
+
+---
+
+## Task 8: Verify the sync end-to-end locally (before merge)
+
+**Why:** Prove the `sync-to-pages` copy logic produces a working site that still renders today's output (plus related), without waiting on a live deploy.
+
+**Files:** none committed — uses a throwaway `gh-pages` worktree.
+
+- [ ] **Step 1: Create a gh-pages worktree**
+
+Run:
+```bash
+cd /Users/matt/git/skill-patterns
+git worktree add /tmp/sp-pages gh-pages
+```
+Expected: worktree created at `/tmp/sp-pages`.
+
+- [ ] **Step 2: Run the sync copy commands (mirror the workflow)**
+
+Run:
+```bash
+cd /Users/matt/git/skill-patterns # the catalog-source-on-main checkout
+npm run build
+rm -rf /tmp/sp-pages/_patterns && mkdir -p /tmp/sp-pages/_patterns /tmp/sp-pages/_data
+cp patterns/*.md /tmp/sp-pages/_patterns/
+cp categories.yml /tmp/sp-pages/_data/categories.yml
+cp build/llms.txt /tmp/sp-pages/llms.txt
+cp build/patterns.json /tmp/sp-pages/patterns.json
+```
+Expected: files copied; `ls /tmp/sp-pages/_patterns/*.md | wc -l` → `38`. The `cp` overwrites `gh-pages`'s Liquid `llms.txt`/`patterns.json` in the worktree with the static generated versions — exactly what the real sync does.
+
+- [ ] **Step 3: Build Jekyll in the worktree and confirm the static output wins**
+
+Run: `cd /tmp/sp-pages && bundle exec jekyll build && diff _site/llms.txt llms.txt && echo MATCH`
+Expected: `done`, no errors, then `MATCH`. Because Step 2's `cp` replaced the front-matter Liquid templates with front-matter-free static files, Jekyll copies them verbatim (no Liquid processing), so `_site/llms.txt` equals the generated `build/llms.txt`. This previews exactly what Task 10 makes permanent.
+
+- [ ] **Step 4: Confirm a pattern page renders and includes related**
+
+Run: `grep -l 'adversarial' /tmp/sp-pages/_site/patterns/adversarial-pushback/index.html && echo PAGE_OK`
+Expected: `PAGE_OK` (the per-pattern page still builds from the synced `_patterns/`).
+
+- [ ] **Step 5: Tear down the worktree**
+
+Run: `cd /Users/matt/git/skill-patterns && git worktree remove /tmp/sp-pages --force`
+Expected: worktree removed. No commit.
+
+---
+
+## Task 9: Merge `main` PR, then enable the real sync
+
+- [ ] **Step 1: Merge the PR** once `snapshot-check` is green and review is done.
+
+Run: `gh pr merge catalog-source-on-main --squash` (or via UI).
+Expected: merged to `main`; the `sync-to-pages` job triggers on the push.
+
+- [ ] **Step 2: Watch the sync job**
+
+Run: `gh run watch` (or `gh run list --workflow sync-catalog.yml`).
+Expected: `sync-to-pages` succeeds and pushes a `chore: sync catalog from main@…` commit to `gh-pages`.
+
+- [ ] **Step 3: Confirm `gh-pages` received the generated files**
+
+Run: `git fetch origin gh-pages && git show origin/gh-pages:llms.txt | head -3`
+Expected: the intro line with `38 patterns across 6 categories`. (`_patterns/` and `patterns.json` updated too.)
+
+---
+
+## Task 10: Mark generated files and update `gh-pages` docs
+
+**Why:** After Task 9's first sync, the committed `llms.txt`/`patterns.json` on `gh-pages` are **already** the static, front-matter-free generated files — the sync `cp` overwrote the old Liquid templates in place. The remaining work is to mark the catalog files as generated and document the new flow so no one hand-edits them.
+
+**Files (on a branch off `gh-pages`):**
+- Create: `.gitattributes`
+- Modify: `AGENTS.md` (gh-pages copy)
+- Verify (no change expected): `llms.txt`, `patterns.json` are static
+
+- [ ] **Step 1: Branch off the synced `gh-pages`**
+
+Run:
+```bash
+cd /Users/matt/git/skill-patterns
+git fetch origin gh-pages
+git switch -c retire-liquid-templates origin/gh-pages
+```
+
+- [ ] **Step 2: Confirm the catalog files are now static (Liquid retired by the sync)**
+
+Run: `head -1 llms.txt; head -c 2 patterns.json; echo`
+Expected: `# Skill Patterns` and `[{` — i.e. **no** `---`/`permalink` front matter. If either still begins with `---`, the sync didn't overwrite it: copy the generated file from `main`'s `build/` output over it and `git add` it before continuing.
+
+- [ ] **Step 3: Add `.gitattributes` marking the generated files**
+
+Create `.gitattributes`:
+```
+_patterns/** linguist-generated=true
+_data/categories.yml linguist-generated=true
+llms.txt linguist-generated=true
+patterns.json linguist-generated=true
+```
+
+- [ ] **Step 4: Update `gh-pages` `AGENTS.md`**
+
+Replace the catalog-workflow section with a pointer to `main`:
+```markdown
+## The catalog is generated — edit it on `main`
+
+`_patterns/`, `_data/categories.yml`, `llms.txt`, and `patterns.json` are **generated** by `scripts/build.mjs` on `main` and synced here by the `Sync catalog` workflow. **Do not hand-edit them.** To change a pattern, edit `patterns/.md` on `main` and open a PR.
+
+Hand-editable on `gh-pages`: layouts, `index`, `install.md`, styles, `_config.yml`, `CNAME` — the site chrome only.
+```
+
+- [ ] **Step 5: Build to confirm the site still renders**
+
+Run: `bundle exec jekyll build && diff _site/llms.txt llms.txt && echo MATCH && test -f _site/patterns/adversarial-pushback/index.html && echo PAGE_OK`
+Expected: `done`, no errors, then `MATCH` and `PAGE_OK`.
+
+- [ ] **Step 6: Commit and open the PR**
+
+```bash
+git add -A
+# /commit intent: chore: mark catalog files generated; document edit-on-main flow
+git push -u origin retire-liquid-templates
+gh pr create --base gh-pages --title "Mark catalog files generated; document edit-on-main flow" \
+ --body "Catalog files are generated by main's build + Sync catalog workflow. See docs/superpowers/plans/2026-05-27-catalog-source-on-main.md."
+```
+
+- [ ] **Step 7: Merge and verify the live site**
+
+After merge, confirm `https://skillpatterns.ai/llms.txt` shows the `- Related:` lines and the pattern count is unchanged (38).
+
+---
+
+## Done criteria
+
+- Editing `patterns/.md` on `main` + `npm run build` + one PR is the entire contribution flow.
+- `snapshot-check` fails a PR that forgot `npm run build`.
+- On merge, `sync-to-pages` regenerates and pushes `_patterns/`, `_data/categories.yml`, `llms.txt`, `patterns.json` to `gh-pages`.
+- `llms.txt`/`patterns.json`/snapshot match today's output except for the added `related[]` content (proven by the two-phase parity gate).
+- No file on `gh-pages` is hand-edited for catalog content; `llms.txt`/`patterns.json` are static generated files (Liquid templates retired by the sync) and marked `linguist-generated`.
+- `AGENTS.md`/`CLAUDE.md` on both branches describe the new flow.
diff --git a/docs/superpowers/specs/2026-05-23-skill-patterns-site-design.md b/docs/superpowers/specs/2026-05-23-skill-patterns-site-design.md
new file mode 100644
index 0000000..980370f
--- /dev/null
+++ b/docs/superpowers/specs/2026-05-23-skill-patterns-site-design.md
@@ -0,0 +1,375 @@
+# Skill Patterns Site — Design Spec
+
+**Date:** 2026-05-23
+**Status:** Implemented (hybrid redesign — see Update below)
+
+> **Update (post-implementation):** Shipped as a **hybrid**, not the original single-page-with-anchors model: a scannable card **index** links to a **page per pattern** (`/patterns//`) for SEO. Adds per-page meta (description, canonical, Open Graph), `sitemap.xml` + `robots.txt`, FontAwesome Free icons per pattern, and **alphabetical ordering by title** within each category (the `order` field is no longer used for sorting). Three titles were shortened: "Trusted sources", "Clarification gate", "Progressive disclosure". Sections below that describe the single-page model, scroll-spy, or per-pattern pages as out-of-scope are superseded by this update.
+**Source material:** An original set of 14 skill patterns (each with a definition, "what it adds", and an example prompt partial) and a curated list of external references and reference skills, plus later additions (clarification gate, failure-mode preloading, progressive disclosure, convention wrapper, graceful degradation, and a set adapted from the gstack review and discernment skills, plus decomposition, long-term memory, scope guardrails, schema-locked output, and self-tuning) — 34 patterns total. `_patterns/*.md` is the source of truth for the current set.
+
+## Overview
+
+A clean, public GitHub Pages site that documents common **skill patterns** — reusable techniques people can compose into Claude/agent Skills to bake in specific interactions, flows, and behaviors. The heart of the site is a browsable, searchable catalog of 34 patterns (an original set of 14 plus later additions), each with a definition, what it adds, and a copyable example prompt partial.
+
+## Goals
+
+- Make the 34 patterns easy to **browse, scan, and search**.
+- Let people **copy each pattern's example prompt partial** in one click.
+- Look **clean and polished** in both light and dark themes.
+- Be **low-maintenance**: native Jekyll build on GitHub Pages, no CI workflow.
+- Stay **product-neutral and public-friendly**, with light Automattic credit.
+
+## Non-goals (out of scope for v1)
+
+- Per-pattern detail pages (we use a single page + anchors).
+- A build-time search index library (lunr/Pagefind) — client-side DOM filtering is enough for 14 items.
+- Broader narrative material (what Skills are, the improvement lifecycle, evals, finding/sharing). Patterns-first only.
+- The canonical 01–14 numbering (dropped in favor of purpose-based grouping).
+- Analytics, comments, CMS.
+
+## Audience
+
+Anyone building skills for Claude Code / Cowork or other agents. Tone and content are product-neutral. Automattic gets a light credit in the footer; no internal-only links (e.g. `mc.a8c.com`) on the public site.
+
+## Locked decisions
+
+| Decision | Choice |
+|---|---|
+| Scope | Patterns-first catalog |
+| Audience | Public & general, product-neutral |
+| Organization | Grouped by purpose, **no numbers**, searchable |
+| Tooling | Jekyll (GitHub Pages native build) |
+| Layout | Sidebar nav + content (Layout B) |
+| Page model | Single page + anchor nav, scroll-spy |
+| Theme | Light + dark, toggle, defaults to system preference |
+| Publishing | Custom apex domain `skillpatterns.ai` (`baseurl: ""`) |
+
+## Information architecture
+
+- **Home (`/`)** — the single catalog page:
+ - Header: logo ("SkillPatterns"), theme toggle, GitHub link.
+ - Sidebar: search box (focusable with `/`) + category nav listing each category and its patterns.
+ - Main content: a short intro ("what skill patterns are / how to use these") followed by all 14 patterns grouped by category, each with an anchor (`#slug`).
+- **Resources (`/resources/`)** — a small separate page with curated external links and a set of reference skills.
+- **Footer** — Automattic credit line, license, GitHub link. Present on both pages.
+
+## Content model
+
+Each pattern is one Markdown file in a `_patterns/` Jekyll collection. The collection has `output: false` — we do **not** generate per-pattern pages; the home page iterates `site.patterns`. Structured fields live in frontmatter so rendering and the copy button are exact:
+
+```yaml
+---
+title: "Trusted sources / grounding"
+slug: trusted-sources # anchor id; also derivable from filename
+category: grounding # key into _data/categories.yml
+order: 1 # sort order within the category
+summary: "Anchors the agent in specific authoritative references so it stops improvising from training data."
+adds:
+ - "Cites which source supports each claim"
+ - "Defers to specified sources when they conflict with general knowledge"
+ - "Flags gaps instead of filling them silently"
+prompt: |
+ Ground this Skill in the following authoritative sources: [URLs / paths / docs]. When the task touches this area, consult these first. If your training contradicts these sources, the sources win. Cite which source each claim comes from. If a source is missing or ambiguous, flag the gap rather than filling it from prior knowledge.
+---
+
+
+```
+
+Categories are defined once in `_data/categories.yml` (key, title, description, order) so the taxonomy and its ordering are editable in one place.
+
+```yaml
+- key: grounding
+ title: "Grounding & accuracy"
+ description: "Keep the agent tethered to truth and honest about what it knows."
+ order: 1
+- key: critique
+ title: "Critique & stress-testing"
+ description: "Find weaknesses before the work ships."
+ order: 2
+- key: decision
+ title: "Decision-making"
+ description: "Structure how choices get made and recorded."
+ order: 3
+- key: output
+ title: "Output shaping"
+ description: "Control the form and structure of what comes out."
+ order: 4
+- key: control
+ title: "Control & composition"
+ description: "Govern flow, stance, and how Skills combine."
+ order: 5
+```
+
+## Category taxonomy
+
+| Category | Patterns (in order) |
+|---|---|
+| **Grounding & accuracy** | Trusted sources · Exemplars over instruction · Confidence calibration · Convention wrapper · Graceful degradation · Signal vs. noise |
+| **Decision-making** | Bounded option generation · Decision capture · Question sharpening · Stakes-scaled rigor |
+| **Output shaping** | Format projection · Artifact creation · Schema-locked output |
+| **Critique & stress-testing** | Encoded reasoning · Self-critique · Adversarial push back · Premortem · Failure mode preloading · Prove it works · Disconfirmation · Gap-to-target scoring · Self-tuning |
+| **Control** | Clarification gate · Human in the loop · Circuit breaker · Codified judgment · Anti-sycophancy · Role priming · Scope guardrails |
+| **Composition** | Workflows as superset · Externalized working state · Progressive disclosure · Decomposition · Long-term memory |
+
+## Pattern content (original transcription — `_patterns/*.md` is the source of truth for all 34 patterns)
+
+Each entry maps directly to one `_patterns/*.md` file.
+
+### Grounding & accuracy
+
+**Trusted sources** (`trusted-sources`, order 1)
+- Summary: Anchors the agent in specific authoritative references so it stops improvising from training data.
+- What it adds:
+ - Cites which source supports each claim
+ - Defers to specified sources when they conflict with general knowledge
+ - Flags gaps instead of filling them silently
+- Prompt: Ground this Skill in the following authoritative sources: [URLs / paths / docs]. When the task touches this area, consult these first. If your training contradicts these sources, the sources win. Cite which source each claim comes from. If a source is missing or ambiguous, flag the gap rather than filling it from prior knowledge.
+
+**Exemplars over instruction** (`exemplars-over-instruction`, order 2)
+- Summary: Anchors the Skill's output in concrete examples of "good" rather than describing it in rules.
+- What it adds:
+ - Matches the shape, voice, and structure of provided examples
+ - Surfaces which exemplar it drew from when the choice is ambiguous
+ - Asks for a new exemplar when the work falls outside the set
+- Prompt: Here are exemplars of [strong outputs / preferred voice / target format]: [paste 2-4 examples]. Match the shape and voice of these rather than following rules I might write down. When the task falls outside what the exemplars cover, say so and ask for a new exemplar instead of guessing. Cite which exemplar most influenced the output.
+
+**Confidence calibration** (`confidence-calibration`, order 3)
+- Summary: Requires the agent to mark which parts of its output it's confident about and which are guesses.
+- What it adds:
+ - Tags claims by certainty so high-risk pieces are visible at a glance
+ - Distinguishes what's verified against sources from what's inferred or assumed
+ - Tells you where to spend your verification time and where you can move fast
+- Prompt: As you produce [output], mark each substantive claim with a confidence level: high (verified against a source or directly observable), medium (inferred from pattern or adjacent evidence), low (filling a gap, best guess, please verify). For low-confidence claims, briefly note what would raise the confidence — a source to check, a test to run, a person to ask. Don't smooth out uncertainty in the final wording; if it's a guess, it should read like one.
+
+**Convention wrapper** (`convention-wrapper`) — *later addition (adopted from the ADK "Tool Wrapper" pattern)*
+- Summary: Packages a specific tool, library, or domain's conventions as on-demand knowledge the Skill applies only when that area is in play.
+- What it adds:
+ - Encodes the right way to use a specific tool or library, not generic advice
+ - Activates only when the task actually touches that area
+ - Keeps the detailed reference out of context until it's needed
+- Prompt: When the task involves [tool / library / domain], follow these conventions: [rules, or point to a reference doc]. Use this specific guidance rather than generic best practices, and only pull in the detailed reference when the task actually touches [area]. If a convention here conflicts with your default approach, this guidance wins. If the task is outside [area], ignore this.
+
+**Graceful degradation** (`graceful-degradation`) — *later addition*
+- Summary: When an input or source is unavailable, the Skill produces the best partial result and flags what was missing, instead of blocking or guessing.
+- What it adds:
+ - Continues with available inputs when a source fails
+ - Names which sources were unavailable and what they'd have affected
+ - Marks the result as partial rather than presenting it as complete
+- Prompt: If a required input or source is unavailable or errors out, don't block or silently fill the gap. Proceed with what you have, clearly mark the result as partial, and list which sources were missing and what they affected. Only hard-stop if a missing input makes the whole task meaningless — and say which one.
+
+### Critique & stress-testing
+
+**Encoded reasoning** (`encoded-reasoning`, order 1)
+- Summary: Bakes review rubrics, validation steps, and quality checks into how the Skill operates.
+- What it adds:
+ - Runs outputs against a defined rubric before returning them
+ - Surfaces which criteria passed, failed, or are uncertain
+ - Catches predictable failure modes the team has seen before
+- Prompt: Before returning output, check the work against these criteria: [rubric items]. Report which criteria passed, failed, or are uncertain. Don't return work that fails [hard criteria] — revise and retry. Surface the rubric results alongside the output so I can see the reasoning.
+
+**Self-critique** (`self-critique`, order 2)
+- Summary: Has the agent review its own output against criteria, identify weaknesses, and revise before returning.
+- What it adds:
+ - Produces a first draft, then critiques it against the brief
+ - Names the weakest reasoning and the most fragile assumption
+ - Returns the revised output with a note on what changed and why
+- Prompt: After producing [output], step back and critique your own work against [criteria: the original brief, the rubric, what a strong reviewer would notice]. Identify the weakest reasoning, the most fragile assumption, and the part most likely to be wrong. Revise. Return the revised output along with a brief note on what changed and why.
+
+**Adversarial push back** (`adversarial-push-back`, order 3)
+- Summary: Pits a challenger persona or parallel agent against the work to expose weaknesses before it ships.
+- What it adds:
+ - Argues the strongest case against the proposal, with reasoning
+ - Surfaces assumptions that wouldn't survive scrutiny
+ - Forces defense of choices instead of quiet acceptance
+- Prompt: Before finalizing [output], take the role of [adversary: skeptical reviewer, hostile architect, opposing counsel, competitor's CTO]. Argue the strongest case against the proposal. Identify the assumptions most likely to fail, the evidence that's missing, and the decisions that would look wrong in hindsight. Return the pushback and the original work side by side.
+
+**Premortem** (`premortem`, order 4)
+- Summary: Skill imagines the work has already failed and reasons backward to why.
+- What it adds:
+ - Generates the most plausible failure stories before the work ships
+ - Surfaces risks that wouldn't appear in a forward-looking review
+ - Names which current assumptions, if wrong, cause the failure
+- Prompt: Before finalizing [the plan / the decision / the proposal], run a premortem. Imagine it's [6 months / a year / one quarter] from now and this work has clearly failed. Generate the 3 most plausible failure stories — what went wrong, in what order, and why it wasn't caught in time. For each, name the assumption in the current plan that, if wrong, made the failure inevitable. Return the failure stories alongside the original work, with the riskiest assumptions called out.
+
+**Failure mode preloading** (`failure-mode-preloading`, order 5) — *later addition*
+- Summary: Names the specific ways this kind of work tends to go wrong, so the agent watches for them.
+- What it adds:
+ - Lists the known failure modes for this kind of task up front
+ - Watches for each one while working, not only at the end
+ - Flags when the work starts drifting toward a named failure mode
+- Prompt: Before starting [task], name the specific ways this kind of work usually goes wrong — [known failure modes, or ask me for them]. Keep that list in view as you work and check against it as you go, not only at the end. If the work starts drifting toward one of these failure modes, stop and flag it rather than pushing through. In the result, note which failure modes you actively guarded against.
+
+### Decision-making
+
+**Bounded option generation** (`bounded-option-generation`, order 1)
+- Summary: Forces a fixed number of distinct alternatives with trade-offs before converging on a recommendation.
+- What it adds:
+ - Generates options that are genuinely different, not variations
+ - Names what each option optimizes for and what it gives up
+ - Recommends one, addressing why not the others
+- Prompt: Before recommending [a decision / an approach], generate [3] meaningfully different options. Each must take a different bet — not variations of the same shape. For each, name what it's optimizing for and what it's giving up. Then recommend one, including why the other options were rejected rather than only why this one wins.
+
+**Decision capture** (`decision-capture`, order 2)
+- Summary: Surfaces the assumptions, alternatives considered, and reasoning trail alongside the output so the decision is auditable.
+- What it adds:
+ - Records what was assumed and what was uncertain
+ - Lists alternatives considered and why they were rejected
+ - Writes the reasoning trail for a reader who wasn't in the room
+- Prompt: Alongside [the output / the recommendation], capture: the assumptions you made, the alternatives you considered, the reasoning that led to this choice, and the conditions under which you'd revisit it. Write it for a reader who wasn't in the room. Keep it short — enough that someone three months from now can tell whether the decision still holds.
+
+### Output shaping
+
+**Format projection** (`format-projection`, order 1)
+- Summary: Renders one canonical artifact into multiple downstream forms while preserving the underlying content.
+- What it adds:
+ - Produces the source artifact once, then derives variants from it
+ - Each variant matches its channel's conventions (length, tone, format)
+ - Surfaces what was cut or compressed in each derivation
+- Prompt: Produce the canonical [artifact: decision doc, spec, research summary] first. Then derive these variants from it: [list: P2 post, Slack summary, exec brief, email update]. Each variant should match the conventions of its channel. Don't re-reason — derive. Note what was cut or compressed in each variant so I can spot if something important got lost.
+
+**Artifact creation** (`artifact-creation`, order 2)
+- Summary: Directs the Skill to produce a concrete, standalone deliverable rather than a conversational response.
+- What it adds:
+ - Returns a finished artifact (doc, deck outline, spec, mockup, dataset) you can lift out and use
+ - Matches a defined structure or template so the output is predictable
+ - Separates the artifact from the surrounding chatter — you know what to keep
+- Prompt: Produce a standalone [artifact type: brief, spec, one-pager, dashboard outline, draft P2 post] rather than answering conversationally. Follow this structure: [sections / template / required fields]. Return the artifact as a self-contained block I can copy out. Keep commentary about the artifact separate from the artifact itself — if you need to flag assumptions or open questions, put them after, not inside.
+
+### Control & composition
+
+**Human in the loop** (`human-in-the-loop`, order 1)
+- Summary: Inserts explicit checkpoints where the agent pauses for discernment before proceeding.
+- What it adds:
+ - Stops before destructive, irreversible, or high-stakes steps
+ - Surfaces what it's about to do and waits for confirmation
+ - Distinguishes routine steps (proceed) from judgment calls (pause)
+- Prompt: Before [specific actions: deploying, sending, deleting, committing, finalizing], pause and summarize what you're about to do and why. Wait for my confirmation, redirect, or override before proceeding. Routine steps can run without checkpoints; judgment calls always pause. [When presenting me with options, allow me to keep the default, give me two more, and let me enter my own.]
+
+**Role priming** (`role-priming`, order 2)
+- Summary: Puts the agent in a specific stance for the duration of the Skill so its reasoning carries that perspective.
+- What it adds:
+ - Approaches the work from the named role's priorities and constraints
+ - Uses the vocabulary and reference points of that role
+ - Stays in role across follow-ups within the same task
+- Prompt: Approach this work as [role: staff engineer reviewing a PR, finance partner reviewing a forecast, support lead reviewing a flow]. Use the priorities, vocabulary, and constraints that role brings. Stay in role across follow-up questions within this task. If you'd break role to be more helpful, say so and ask before switching.
+
+**Workflows as superset** (`workflows-as-superset`, order 3)
+- Summary: Composes this Skill with others into a sequenced flow.
+- What it adds:
+ - Triggers other Skills in a defined order
+ - Passes outputs from one stage as inputs to the next
+ - Surfaces workflow state so you can see where you are in the chain
+- Prompt: Run this as a workflow: [Skill 1] → [Skill 2] → [Skill 3]. Pass the output of each stage as input to the next. After each stage, summarize what was produced and confirm before moving on. If a stage fails its checks, stop and surface the issue rather than continuing.
+
+**Clarification gate** (`clarification-gate`, order 4) — *later addition*
+- Summary: Makes the agent ask clarifying questions before producing output when the brief is ambiguous.
+- What it adds:
+ - Detects ambiguity or missing constraints before starting work
+ - Asks only the questions whose answers would change the output
+ - Holds off on producing until the brief is clear enough to commit to
+- Prompt: Before producing [output], check whether the brief is clear enough to commit to. If anything ambiguous would change the result — scope, audience, constraints, definition of done — ask me those questions first, as one short batch, and wait. Only ask what you genuinely can't proceed without; don't ask things the brief already answers. If it's already clear, say so and proceed without stalling.
+
+**Progressive disclosure** (`progressive-disclosure`, order 5) — *later addition*
+- Summary: Loads only the context needed for the current sub-task, expanding as the work deepens.
+- What it adds:
+ - Starts with the minimum context the current step requires
+ - Pulls in more detail only when the work actually reaches it
+ - Keeps unrelated material out of the way until it's relevant
+- Prompt: Work through [task] in stages, loading only the context each stage needs. Start with the high-level [overview / index / table of contents]; pull in the detailed [files / sections / data] only when a step actually requires them. Don't front-load everything. When you move to a new sub-task, say what additional context you're bringing in and why, so the scope stays visible.
+
+## Visual design
+
+- **Themes:** light and dark, implemented with CSS custom properties on `:root` and `[data-theme="dark"]`. A no-flash inline script in `` sets `data-theme` from `localStorage` (falling back to `prefers-color-scheme`) before first paint. The header toggle flips and persists the value.
+- **Accent:** Automattic blue `#3858E9` (light); a brighter `#6B8AFF` for accents/links in dark mode.
+- **Typography:** system sans-serif stack for UI/prose; monospace for the prompt partial body.
+- **Pattern block:** category eyebrow (uppercase, accent) → title (`h2`/`h3`, bold) → summary → "What it adds" list (custom `+` bullets in accent) → example prompt partial.
+- **Example prompt partial component:** a bordered amber panel for the example prompt. Header row with the label "EXAMPLE PROMPT PARTIAL" and a **Copy** button; monospace body. In dark mode the panel becomes a dark amber surface. The Copy button copies the exact `prompt` text and shows a transient "Copied!" state.
+- **Accessibility:** semantic landmarks (`header`/`nav`/`main`/`footer`), labeled theme toggle, visible focus styles, sufficient contrast in both themes, `prefers-reduced-motion` respected for any scroll/transition.
+
+## Search & interactions (vanilla JS, no dependencies)
+
+- **Live search:** typing in the box filters patterns by title, summary, and "what it adds" text (case-insensitive substring). Non-matching pattern blocks hide; categories with zero visible patterns collapse (both in the sidebar and the main content). Clearing the box restores everything. `/` focuses the search box; `Esc` clears it.
+- **Anchor nav + scroll-spy:** each sidebar pattern link targets `#slug`. An `IntersectionObserver` highlights the active pattern as the reader scrolls. Direct links to `#slug` scroll to and highlight the pattern.
+- **Copy:** each prompt partial's Copy button writes `prompt` text to the clipboard via the async Clipboard API, with a fallback, and shows "Copied!" for ~1.5s.
+
+## Build & deploy
+
+- **Jekyll**, served by GitHub Pages' native **Deploy from branch** (Settings → Pages → Source: `main`, folder `/` root). No GitHub Action.
+- `_config.yml` highlights:
+ - `title: "Skill Patterns"`, `url: "https://skillpatterns.ai"`, `baseurl: ""`.
+ - `collections.patterns.output: false`.
+ - `markdown: kramdown`.
+ - Sort patterns by `category` order then `order`.
+- `CNAME` file containing `skillpatterns.ai`.
+- `Gemfile` pinning the `github-pages` gem for faithful local preview (`bundle exec jekyll serve`).
+- **DNS (apex domain) the user must configure** at the registrar:
+ - A records → `185.199.108.153`, `185.199.109.153`, `185.199.110.153`, `185.199.111.153`
+ - AAAA records → `2606:50c0:8000::153`, `2606:50c0:8001::153`, `2606:50c0:8002::153`, `2606:50c0:8003::153`
+ - Optional `www` CNAME → `.github.io`
+ - Enable "Enforce HTTPS" in Pages settings once the cert provisions.
+
+## Proposed file structure
+
+```
+/
+├── _config.yml
+├── CNAME # skillpatterns.ai
+├── Gemfile
+├── index.html # layout: home — the catalog page
+├── resources.md # layout: default — resources page
+├── _data/
+│ └── categories.yml
+├── _patterns/ # 17 Markdown files (collection, output: false)
+│ ├── trusted-sources.md
+│ ├── exemplars-over-instruction.md
+│ ├── confidence-calibration.md
+│ ├── convention-wrapper.md
+│ ├── graceful-degradation.md
+│ ├── encoded-reasoning.md
+│ ├── self-critique.md
+│ ├── adversarial-push-back.md
+│ ├── premortem.md
+│ ├── bounded-option-generation.md
+│ ├── decision-capture.md
+│ ├── format-projection.md
+│ ├── artifact-creation.md
+│ ├── human-in-the-loop.md
+│ ├── role-priming.md
+│ ├── workflows-as-superset.md
+│ ├── clarification-gate.md
+│ ├── failure-mode-preloading.md
+│ └── progressive-disclosure.md
+├── _layouts/
+│ ├── default.html # head, header, footer wrapper
+│ └── home.html # sidebar + content composition
+├── _includes/
+│ ├── head.html # meta, theme no-flash script, asset links
+│ ├── header.html # logo, theme toggle, GitHub link
+│ ├── sidebar.html # search + category/pattern nav
+│ ├── pattern.html # one rendered pattern block
+│ └── footer.html # credit, license, links
+└── assets/
+ ├── css/style.css # tokens + light/dark themes + layout
+ └── js/app.js # search, scroll-spy, copy, theme toggle
+```
+
+## Resources page content
+
+External links (public, product-neutral):
+- **Agent Skills open standard** — agentskills.io
+- **Anthropic Skills repo** — github.com/anthropics/skills
+- **Claude Code / Skills docs** — docs.anthropic.com/en/docs/claude-code
+- **Engineering blog** — anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills
+- **skills.sh** — the open agent skills ecosystem (searchable, ratings); `npx skills find `
+- **WordPress agent skills** — github.com/WordPress/agent-skills
+- **Automattic design skills** — github.com/Automattic/design-skills
+
+Reference skills to study — present as a short annotated list; the implementer verifies/links each repo where public:
+- caveman · council · grill-with-docs · humanize · prototype · red-pen (skills)
+- voiceprint · frontend-designer · last30days · superpowers · borkweb/skills (plugins)
+
+Footer: a neutral tagline ("Reusable patterns for composing AI Skills.") plus the GitHub source link. Repo license: MIT (existing `LICENSE`).
+
+## Open items / future
+
+- Confirm exact repo URLs for the reference skills during implementation; omit any that aren't publicly linkable.
+- Future (not v1): per-pattern pages, a "copy all patterns" export, contribution guide for adding patterns, broader narrative material.
diff --git a/docs/superpowers/specs/2026-05-27-catalog-source-on-main-design.md b/docs/superpowers/specs/2026-05-27-catalog-source-on-main-design.md
new file mode 100644
index 0000000..7a56f12
--- /dev/null
+++ b/docs/superpowers/specs/2026-05-27-catalog-source-on-main-design.md
@@ -0,0 +1,172 @@
+# Catalog Source on `main` — Design Spec
+
+**Date:** 2026-05-27
+**Status:** Approved (brainstorm) — pending implementation plan
+
+## Overview
+
+Today the canonical pattern catalog lives on the **`gh-pages`** branch (`_patterns/*.md`), and the plugin on **`main`** carries a generated snapshot. To add or edit a pattern, a contributor must work on a *non-default* branch, learn Jekyll frontmatter, run Ruby/Jekyll to verify, and then make a *second* commit on `main` to regenerate the snapshot ("update BOTH branches").
+
+This redesign **inverts the source-of-truth direction**: the canonical catalog moves to **`main`** (the default branch), and everything downstream — the plugin snapshot and the live site's `_patterns/`, `llms.txt`, and `patterns.json` — is **generated**. A contributor edits one markdown file on the default branch and opens one PR; CI handles the rest.
+
+## Goals
+
+- Make the catalog **contributable from the default branch** (`main`) with a single PR.
+- Eliminate the **two-branch authoring dance** — patterns are authored in exactly one place.
+- Preserve today's published output exactly through the port (**byte-for-byte parity** checkpoint), then layer on `related[]` as the one intentional enrichment — verifying nothing else moved.
+- **One renderer** owns the output format — no duplicated template logic.
+- Keep the plugin self-contained: it still ships a committed snapshot, regenerated automatically.
+
+## Non-goals
+
+- Collapsing to a single branch / moving the Jekyll site source onto `main` (considered and rejected for now — see Alternatives). `gh-pages` stays a Jekyll branch.
+- Changing the pattern **format** — frontmatter is unchanged; only its home moves.
+- Changing the site's visual design, layouts, or per-pattern page URLs.
+- A bot that auto-commits the regenerated snapshot (considered — see Alternatives).
+
+## Locked decisions
+
+| Decision | Choice |
+|---|---|
+| Source of truth | `main` (default branch) holds the canonical catalog |
+| Sync model | Reverse-sync: CI pushes generated files to `gh-pages`; `gh-pages` stays a Jekyll branch |
+| Generator | One **Node** script (`scripts/build.mjs`) on `main` owns the format |
+| Generator deps | `js-yaml` (one dep — parses both pattern frontmatter via a `---` split and `categories.yml`) via `package.json` + lockfile on `main` |
+| Generated artifacts | plugin snapshot, `llms.txt`, `patterns.json` (Liquid templates retired) |
+| Catalog content | Outputs **add `related[]`** — the one intentional change beyond today's format. Rendered as related-pattern **titles** + notes in the snapshot/`llms.txt`, and a `{slug, note}` array in `patterns.json` |
+| Snapshot freshness | Failing PR check (`npm run build` + `git diff --exit-code`) — contributor runs `npm run build` |
+| Skill read model | Skill reads the **generated snapshot** in one cheap Read (per-file direct-read and progressive-disclosure index both considered and rejected — see Alternatives) |
+| Pattern format | Unchanged (`title, slug, icon, category, summary, adds, related[], prompt`) |
+
+## Architecture
+
+### Canonical source on `main`
+
+```
+main/
+├── patterns/ ← CANONICAL catalog, one file per pattern (today's _patterns frontmatter, verbatim)
+│ ├── adversarial-pushback.md
+│ └── … (38)
+├── categories.yml ← CANONICAL category metadata (today's _data/categories.yml)
+├── scripts/
+│ └── build.mjs ← the one generator (Node ESM)
+├── package.json ← "build": "node scripts/build.mjs"; devDep: js-yaml
+├── package-lock.json
+├── skills/skill-patterns/
+│ ├── SKILL.md (hand-written)
+│ └── references/
+│ ├── choosing-patterns.md (hand-written)
+│ └── patterns.md ← GENERATED snapshot — committed, never hand-edited
+├── .github/workflows/
+│ └── sync-catalog.yml
+└── .claude-plugin/ …
+```
+
+The pattern files move **verbatim** — same frontmatter they have on `gh-pages` today. The canonical files *are* the full record; the snapshot is a distilled view that still omits site-only fields (`icon`, `order`, layout) but now carries `related[]` for composition hints.
+
+### `scripts/build.mjs` — the single format owner
+
+A Node (ESM) script, run via `npm run build`, that:
+
+1. Reads every `patterns/*.md` (frontmatter via a `---` split + `js-yaml`) and `categories.yml`.
+2. Sorts **categories by `order`**, **patterns `sort_natural` by title** within each category — matching the current Liquid behavior. (The `order` field on patterns remains unused.)
+3. Resolves each pattern's `related[]` slugs to the related pattern's **title** (building a slug→title map across the catalog first), so output names the paired pattern rather than a bare slug.
+4. Emits three artifacts from one format definition:
+ - `skills/skill-patterns/references/patterns.md` — the plugin snapshot (identical to `llms.txt`).
+ - `build/llms.txt` — for the live `/llms.txt` endpoint.
+ - `build/patterns.json` — for the live `/patterns.json` endpoint.
+
+The format **ports the two existing Liquid templates** (`llms.txt`, `patterns.json` on `gh-pages`), including the `https://skillpatterns.ai` base URL Liquid derives from `site.url`, plus **one intentional addition**: each entry gains `related[]` — a `Related: — ; …` line in the snapshot/`llms.txt`, and a `"related": [{ "slug", "note" }]` array in `patterns.json`. Patterns with no `related` omit it. This **retires** the Liquid templates. Resolving `related[]` also makes the build **validate referential integrity** — an unknown related slug fails the build (see Edge cases).
+
+### What `gh-pages` becomes
+
+Still a normal Jekyll branch serving the site. Its catalog inputs become **generated, not authored** — CI writes them in:
+
+| File on `gh-pages` | Origin | How |
+|---|---|---|
+| `_patterns/*.md` | `main:patterns/*.md` | copied verbatim |
+| `_data/categories.yml` | `main:categories.yml` | copied verbatim |
+| `llms.txt` (root, static) | `build/llms.txt` | generated, replaces the Liquid template |
+| `patterns.json` (root, static) | `build/patterns.json` | generated, replaces the Liquid template |
+
+Generated files are marked via `.gitattributes` (`linguist-generated`) and a note in `gh-pages` `AGENTS.md`/README — **not** inline headers, which in `llms.txt`/`patterns.json`/`_patterns` would break the byte-parity gate. Jekyll still renders the per-pattern pages (`/patterns/:slug/`) and category indexes from the `_patterns` collection + `_layouts/pattern` — those are unchanged.
+
+Hand-authored site chrome (`_layouts/`, `index`, `install.md`, `CNAME`, analytics, `_config.yml`) **stays on `gh-pages`** and is edited there as before — maintainer-only and rare.
+
+### CI + contributor flow (`.github/workflows/sync-catalog.yml`)
+
+**On pull request to `main`** (paths: `patterns/**`, `categories.yml`, `scripts/build.mjs`, `package*.json`):
+1. `actions/setup-node` + `npm ci`.
+2. `npm run build`.
+3. `git diff --exit-code skills/skill-patterns/references/patterns.md` — fails if the committed snapshot is stale, with a message: *"Run `npm run build` and commit the updated snapshot."*
+
+This keeps the snapshot a **reviewable part of the PR** and avoids any post-merge writeback to `main`.
+
+**On push to `main`** (post-merge, same paths):
+1. `npm ci && npm run build`.
+2. Check out `gh-pages`, copy in the four generated/synced files (table above), commit, push.
+3. GitHub Pages rebuilds the site.
+
+No `main → main` writeback occurs: the snapshot already landed via the PR.
+
+### Contributor experience (target)
+
+1. Edit (or add) one file in `patterns/` on `main`.
+2. Run `npm run build` (rebuilds the committed snapshot).
+3. Open one PR. CI verifies snapshot freshness; on merge, the site syncs automatically.
+
+No Jekyll, no Ruby, no second branch.
+
+## Data flow
+
+```
+ edit one file
+contributor ─────────────────────────────▶ main:patterns/*.md + categories.yml
+ │
+ npm run build (scripts/build.mjs)
+ │
+ ┌────────────────────────────────────┼─────────────────────────────────┐
+ ▼ ▼ ▼
+ skills/.../references/patterns.md build/llms.txt build/patterns.json
+ (committed on main, │ │
+ verified by PR check) │ on push to main, CI syncs ──────┤
+ ▼ ▼
+ gh-pages: llms.txt, patterns.json (static),
+ _patterns/*.md + _data/categories.yml (copied verbatim)
+ │
+ GitHub Pages rebuild → skillpatterns.ai
+```
+
+## Migration (one-time), with a parity gate
+
+1. Seed `main`: `git checkout gh-pages -- _patterns _data/categories.yml`; move into `main:patterns/` and `main:categories.yml`.
+2. Add `package.json`, `package-lock.json`, `scripts/build.mjs`.
+3. Run `npm run build`.
+4. **Parity gate, phase 1 — faithful port (must pass before anything else):** with `related[]` output temporarily disabled, generated `build/llms.txt`, `build/patterns.json`, and `references/patterns.md` must be **byte-identical** to today's published/committed outputs. Empty diff proves the Node port reproduces the Liquid templates exactly.
+5. **Parity gate, phase 2 — enrichment:** enable `related[]` output and confirm the *only* differences from phase 1 are the added `Related:` lines (snapshot/`llms.txt`) and `related` arrays (`patterns.json`) — nothing else moved.
+6. Add `.github/workflows/sync-catalog.yml`; run one real end-to-end sync; confirm the live site renders correctly (now including related info on `/llms.txt` and `/patterns.json`).
+7. On `gh-pages`: delete the Liquid `llms.txt` and `patterns.json` source templates (now generated and synced as static files). Add DO-NOT-EDIT headers to the synced files via the generator/sync step.
+8. Rewrite `AGENTS.md` / `CLAUDE.md` on both branches: replace the "update BOTH branches" rule with the new flow — "edit `patterns/` on `main`, run `npm run build`, open one PR; everything downstream is generated."
+
+## Error handling & edge cases
+
+- **Stale snapshot in a PR** → PR check fails with a clear remediation message; nothing merges out of sync.
+- **Malformed pattern frontmatter** (bad YAML, missing required field) → `build.mjs` exits non-zero with the offending filename; the PR check surfaces it.
+- **Category referenced by a pattern but absent from `categories.yml`** → build error naming the pattern and missing category key.
+- **Unknown `related` slug** (a pattern points at a related slug that doesn't exist) → `build.mjs` fails, naming the source pattern and the bad slug; caught by the PR check. A free integrity benefit of resolving `related[]`.
+- **Site-only edits** (layouts, index, install) → made directly on `gh-pages`; never overwritten by the sync (the sync touches only the four catalog files).
+- **Sync race / partial failure** → the sync is idempotent (deterministic regenerate + copy); re-running reconciles. A failed sync leaves `gh-pages` on its last good commit.
+
+## Alternatives considered
+
+- **Collapse to one branch** (move Jekyll source onto `main`, `gh-pages` becomes a pure CI build artifact or is replaced by Actions Pages deploy). Cleanest end-state, but relocates and re-tests the whole site + deploy pipeline. Deferred; the reverse-sync gets us the contribution win at far lower risk and remains a stepping stone to this.
+- **Manual reversed script** (no CI; maintainer runs a local script to build the snapshot and push `_patterns/`). Lowest tech, but preserves the two-step maintainer ritual. Rejected.
+- **Reuse Jekyll's Liquid templates** for the snapshot (sync patterns to `gh-pages`, let Pages rebuild, fetch the built `llms.txt` back into `main`). No duplicated format logic, but the snapshot would depend on a successful deploy (timing/race) and keep a `main → gh-pages → main` round trip. Rejected in favor of one self-contained generator.
+- **Ruby generator** (parity with Jekyll). Rejected: Node has lower CI/contributor overhead (`actions/setup-node` + `npm ci`, no rbenv/bundle), at the cost of one small YAML dependency.
+- **Bot auto-commits the snapshot** to the PR branch (zero local steps for contributors). Smoother, but more CI machinery and fork-permission nuance (`pull_request_target`). Deferred in favor of the simpler failing PR check.
+- **Skill reads per-file sources directly** (no committed snapshot, no freshness check — lightest contributor flow). Rejected: the runtime path runs far more often than contributions, and Claude Code reads one file per tool call, so grounding in the full catalog would cost ~38 Reads *per invocation* plus site-only frontmatter noise. The snapshot pays that cost once, at contribution time. (Shipping was *not* a factor — `marketplace.json` `source: "./"` means the whole repo installs, so a top-level `patterns/` would ship regardless.)
+- **Progressive-disclosure index** (skill reads a small generated index, then only the 2–4 selected patterns in full). Best token economics at large scale; more moving parts than justified at 38 patterns. Revisit if the catalog grows into the hundreds.
+
+## Open questions
+
+None blocking. (Resolved during planning: generator dependency is `js-yaml` with a manual `---` frontmatter split — `categories.yml` needs standalone YAML parsing anyway, making `gray-matter` redundant.)
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..ac180a5
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,35 @@
+{
+ "name": "skill-patterns-catalog",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "skill-patterns-catalog",
+ "version": "1.0.0",
+ "devDependencies": {
+ "js-yaml": "^4.1.0"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..9230090
--- /dev/null
+++ b/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "skill-patterns-catalog",
+ "version": "1.0.0",
+ "private": true,
+ "type": "module",
+ "description": "Build tooling for the Skill Patterns catalog (generates the plugin snapshot, llms.txt, and patterns.json).",
+ "scripts": {
+ "build": "node scripts/build.mjs"
+ },
+ "devDependencies": {
+ "js-yaml": "^4.1.0"
+ }
+}
diff --git a/patterns/adversarial-pushback.md b/patterns/adversarial-pushback.md
new file mode 100644
index 0000000..66979cf
--- /dev/null
+++ b/patterns/adversarial-pushback.md
@@ -0,0 +1,22 @@
+---
+title: "Adversarial pushback"
+slug: adversarial-pushback
+icon: "fa-solid fa-gavel"
+category: critique
+order: 3
+summary: "Pits a challenger persona or parallel agent against the work to expose weaknesses before it ships."
+adds:
+ - "Argues the strongest case against the proposal, with reasoning"
+ - "Surfaces assumptions that wouldn't survive scrutiny"
+ - "Forces defense of choices instead of quiet acceptance"
+ - "Can run blind — the challenger sees only the artifact, not your reasoning, removing the pull to agree"
+related:
+ - slug: premortem
+ note: "Premortem imagines it already failed and works backward; pushback argues against it in the present."
+ - slug: disconfirmation
+ note: "Disconfirmation hunts evidence that falsifies one claim; pushback attacks the whole proposal from an adversary's role."
+ - slug: specialist-fan-out
+ note: "Several narrow critics in parallel is a fan-out of this single-challenger move."
+prompt: |
+ Before finalizing [output], take the role of [adversary: skeptical reviewer, hostile architect, opposing counsel, competitor's CTO]. Argue the strongest case against the proposal. Identify the assumptions most likely to fail, the evidence that's missing, and the decisions that would look wrong in hindsight. For a sharper check, run it blind: give the challenger only the finished artifact and the task — not your reasoning or how you got here — so it judges the work cold, the way a reader with none of your context would. Return the pushback and the original work side by side.
+---
diff --git a/patterns/anti-sycophancy.md b/patterns/anti-sycophancy.md
new file mode 100644
index 0000000..2ff5c36
--- /dev/null
+++ b/patterns/anti-sycophancy.md
@@ -0,0 +1,13 @@
+---
+title: "Anti-sycophancy"
+slug: anti-sycophancy
+icon: "fa-solid fa-comment-slash"
+category: control
+summary: "Bans hedging and hollow agreement — the agent commits to a position, names the weakest point plainly, and pushes past the first polished answer."
+adds:
+ - "Cuts filler agreement ('great question', 'that could work')"
+ - "Commits to a recommendation and says what would change it"
+ - "Names the weakest part of the work plainly instead of smoothing it over"
+prompt: |
+ Don't hedge or flatter. Skip "great question", "that's a good point", and "that could work". Take a clear position on [topic] and state what evidence would change it. If part of this is weak, say which part and why — plainly. If my idea has a real problem, tell me directly rather than softening it. Push past your first answer to a sharper one before you settle.
+---
diff --git a/patterns/artifact-creation.md b/patterns/artifact-creation.md
new file mode 100644
index 0000000..dd1511f
--- /dev/null
+++ b/patterns/artifact-creation.md
@@ -0,0 +1,14 @@
+---
+title: "Artifact creation"
+slug: artifact-creation
+icon: "fa-solid fa-cube"
+category: output
+order: 2
+summary: "Directs the Skill to produce a concrete, standalone deliverable rather than a conversational response."
+adds:
+ - "Returns a finished artifact (doc, deck outline, spec, mockup, dataset) you can lift out and use"
+ - "Matches a defined structure or template so the output is predictable"
+ - "Separates the artifact from the surrounding chatter — you know what to keep"
+prompt: |
+ Produce a standalone [artifact type: brief, spec, one-pager, dashboard outline, draft P2 post] rather than answering conversationally. Follow this structure: [sections / template / required fields]. Return the artifact as a self-contained block I can copy out. Keep commentary about the artifact separate from the artifact itself — if you need to flag assumptions or open questions, put them after, not inside.
+---
diff --git a/patterns/best-of-n.md b/patterns/best-of-n.md
new file mode 100644
index 0000000..a27dac7
--- /dev/null
+++ b/patterns/best-of-n.md
@@ -0,0 +1,18 @@
+---
+title: "Best-of-N"
+slug: best-of-n
+icon: "fa-solid fa-check-to-slot"
+category: critique
+summary: "Runs the same problem several times independently and converges on the consensus — a majority vote, or the verified top candidate — so a single bad sample can't decide the answer."
+adds:
+ - "Attacks one problem with several independent passes — varied angles, no shared reasoning between runs"
+ - "Converges by majority vote, or by ranking the attempts and re-verifying the strongest"
+ - "Aggregates for reliability — it isn't generating options for you to choose between"
+related:
+ - slug: specialist-fan-out
+ note: "Fan-out runs different lenses and merges for coverage; Best-of-N runs the same problem and votes for reliability."
+ - slug: bounded-option-generation
+ note: "Bounded options surface distinct choices for you to pick; Best-of-N aggregates internally to a single answer."
+prompt: |
+ For [a high-stakes or error-prone task] where a single attempt can quietly be wrong, run it [N] times independently — varied starting angles, no shared reasoning between runs — rather than trusting one pass. Then aggregate: for a definite answer, take the majority vote; for open-ended work, rank the candidates and verify the strongest one. Treat convergence across independent attempts as the real signal and a lone dissent as likely noise. If the attempts don't converge, say so and surface the disagreement instead of quietly picking one and moving on.
+---
diff --git a/patterns/bounded-option-generation.md b/patterns/bounded-option-generation.md
new file mode 100644
index 0000000..a90b948
--- /dev/null
+++ b/patterns/bounded-option-generation.md
@@ -0,0 +1,14 @@
+---
+title: "Bounded option generation"
+slug: bounded-option-generation
+icon: "fa-solid fa-code-branch"
+category: decision
+order: 1
+summary: "Forces a fixed number of distinct alternatives with trade-offs before converging on a recommendation."
+adds:
+ - "Generates options that are genuinely different, not variations"
+ - "Names what each option optimizes for and what it gives up"
+ - "Recommends one, addressing why not the others"
+prompt: |
+ Before recommending [a decision / an approach], generate [3] meaningfully different options. Each must take a different bet — not variations of the same shape. For each, name what it's optimizing for and what it's giving up. Then recommend one, including why the other options were rejected rather than only why this one wins.
+---
diff --git a/patterns/capability-detection.md b/patterns/capability-detection.md
new file mode 100644
index 0000000..fb2e18e
--- /dev/null
+++ b/patterns/capability-detection.md
@@ -0,0 +1,16 @@
+---
+title: "Capability detection"
+slug: capability-detection
+icon: "fa-solid fa-plug"
+category: composition
+summary: "Probes what the runtime actually offers — subagents, a browser, the project's language, specific tools — and takes the path that fits, instead of assuming one environment."
+adds:
+ - "Checks which tools, integrations, and capabilities are present before committing to an approach"
+ - "Branches to the path that fits what's available rather than failing or assuming a default environment"
+ - "Falls back to a sensible default — and says which path it took — when the environment can't be determined"
+related:
+ - slug: graceful-degradation
+ note: "Graceful-degradation handles a missing input with a partial result; capability-detection probes the environment and picks a different full path."
+prompt: |
+ Before committing to an approach for [task], detect what this environment actually provides — [e.g. subagents, a display or browser, the project's language, a particular integration or MCP server] — rather than assuming. Then take the path that fits: [if X is available, do A; otherwise do B]. State which capabilities you found and which path you're taking, so the choice is visible and I can redirect it. If you can't tell what's available, pick the safe default, name it, and proceed rather than stalling or guessing wrong.
+---
diff --git a/patterns/characterization-baseline.md b/patterns/characterization-baseline.md
new file mode 100644
index 0000000..9635b66
--- /dev/null
+++ b/patterns/characterization-baseline.md
@@ -0,0 +1,16 @@
+---
+title: "Characterization baseline"
+slug: characterization-baseline
+icon: "fa-solid fa-thumbtack"
+category: composition
+summary: "Before changing existing behavior, pins it down as a test contract — concrete input→output pairs captured from the current code — then makes the change and proves every pin still passes."
+adds:
+ - "Captures the current observable behavior as a runnable baseline before touching anything"
+ - "Treats those captured cases as the definition of done for the change"
+ - "Proves equivalence after — the change passes the baseline, or each difference is deliberate and named"
+related:
+ - slug: prove-it-works
+ note: "Prove-it-works verifies at the end that the work works; this captures the current behavior up front, then proves the change preserved it."
+prompt: |
+ Before you change [existing code or behavior — a refactor, rename, migration, optimization, or dependency upgrade], pin down what it does now. First, capture the current observable behavior as a baseline: characterization tests (concrete input → expected-output pairs read off the existing code — what it actually does, not what you think it should do), or a golden-master snapshot of its outputs. Treat that baseline as the definition of done. Then make the change and run the baseline against the new version — it must pass unchanged. If some output legitimately should differ, call out each deviation and why it's intended; don't quietly update the baseline to match the new behavior. The goal is to change the form while proving the behavior held.
+---
diff --git a/patterns/circuit-breaker.md b/patterns/circuit-breaker.md
new file mode 100644
index 0000000..3bee5cd
--- /dev/null
+++ b/patterns/circuit-breaker.md
@@ -0,0 +1,13 @@
+---
+title: "Circuit breaker"
+slug: circuit-breaker
+icon: "fa-solid fa-circle-stop"
+category: control
+summary: "Tracks an accumulating 'am I thrashing?' signal during a loop and forces a stop-and-ask before the agent flails."
+adds:
+ - "Counts warning signs — reverts, edits to unrelated files, repeated failed attempts"
+ - "Trips a hard stop after a set budget instead of grinding on"
+ - "Surfaces what it tried and why it's stuck, rather than continuing silently"
+prompt: |
+ While working [task] in a loop, watch for signs you're thrashing: reverting your own changes, touching files unrelated to the goal, or the same fix failing more than [N] times. Keep a running count. When you hit [the budget — e.g., 3 failed attempts or 5 unrelated files], stop and surface what you've tried, what's still failing, and your best guess at why — then ask me before continuing. Don't grind past the limit.
+---
diff --git a/patterns/clarification-gate.md b/patterns/clarification-gate.md
new file mode 100644
index 0000000..91431c0
--- /dev/null
+++ b/patterns/clarification-gate.md
@@ -0,0 +1,14 @@
+---
+title: "Clarification gate"
+slug: clarification-gate
+icon: "fa-solid fa-circle-question"
+category: control
+order: 4
+summary: "Makes the agent ask clarifying questions before producing output when the brief is ambiguous."
+adds:
+ - "Detects ambiguity or missing constraints before starting work"
+ - "Asks only the questions whose answers would change the output"
+ - "Holds off on producing until the brief is clear enough to commit to"
+prompt: |
+ Before producing [output], check whether the brief is clear enough to commit to. If anything ambiguous would change the result — scope, audience, constraints, definition of done — ask me those questions first, as one short batch, and wait. Only ask what you genuinely can't proceed without; don't ask things the brief already answers. If it's already clear, say so and proceed without stalling.
+---
diff --git a/patterns/confidence-calibration.md b/patterns/confidence-calibration.md
new file mode 100644
index 0000000..a4dee76
--- /dev/null
+++ b/patterns/confidence-calibration.md
@@ -0,0 +1,15 @@
+---
+title: "Confidence calibration"
+slug: confidence-calibration
+icon: "fa-solid fa-gauge"
+category: grounding
+order: 3
+summary: "Requires the agent to mark which parts of its output it's confident about and which are guesses."
+adds:
+ - "Tags claims by certainty so high-risk pieces are visible at a glance"
+ - "Distinguishes what's verified against sources from what's inferred or assumed"
+ - "Tells you where to spend your verification time and where you can move fast"
+ - "Declines outright when overall confidence is too low — an honest abstention beats a confident guess"
+prompt: |
+ As you produce [output], mark each substantive claim with a confidence level: high (verified against a source or directly observable), medium (inferred from pattern or adjacent evidence), low (filling a gap, best guess, please verify). For low-confidence claims, briefly note what would raise the confidence — a source to check, a test to run, a person to ask. Don't smooth out uncertainty in the final wording; if it's a guess, it should read like one. And if your confidence in the answer as a whole is too low to stand behind it, say so and decline rather than dressing up a guess — an honest "I can't answer this confidently, here's what I'd need" beats a confident wrong answer.
+---
diff --git a/patterns/decision-capture.md b/patterns/decision-capture.md
new file mode 100644
index 0000000..d6858c5
--- /dev/null
+++ b/patterns/decision-capture.md
@@ -0,0 +1,14 @@
+---
+title: "Decision capture"
+slug: decision-capture
+icon: "fa-solid fa-clipboard-check"
+category: decision
+order: 2
+summary: "Surfaces the assumptions, alternatives considered, and reasoning trail alongside the output so the decision is auditable."
+adds:
+ - "Records what was assumed and what was uncertain"
+ - "Lists alternatives considered and why they were rejected"
+ - "Writes the reasoning trail for a reader who wasn't in the room"
+prompt: |
+ Alongside [the output / the recommendation], capture: the assumptions you made, the alternatives you considered, the reasoning that led to this choice, and the conditions under which you'd revisit it. Write it for a reader who wasn't in the room. Keep it short — enough that someone three months from now can tell whether the decision still holds.
+---
diff --git a/patterns/decomposition.md b/patterns/decomposition.md
new file mode 100644
index 0000000..2b7d896
--- /dev/null
+++ b/patterns/decomposition.md
@@ -0,0 +1,13 @@
+---
+title: "Decomposition"
+slug: decomposition
+icon: "fa-solid fa-object-ungroup"
+category: composition
+summary: "Breaks a complex task into smaller, well-scoped sub-tasks and tackles them one at a time."
+adds:
+ - "Splits the problem into parts before attempting any of it"
+ - "Defines each sub-task's input and output so the pieces fit back together"
+ - "Surfaces the breakdown so you can correct the plan before work starts"
+prompt: |
+ Before working on [task], break it into a short list of smaller, well-scoped sub-tasks. For each, note what it needs as input and what it should produce. Show me the breakdown and let me adjust it before you start. Then work through the sub-tasks one at a time, keeping each self-contained, and assemble the results at the end.
+---
diff --git a/patterns/disconfirmation.md b/patterns/disconfirmation.md
new file mode 100644
index 0000000..600bb0c
--- /dev/null
+++ b/patterns/disconfirmation.md
@@ -0,0 +1,18 @@
+---
+title: "Disconfirmation"
+slug: disconfirmation
+icon: "fa-solid fa-flask"
+category: critique
+summary: "Actively hunts for the evidence that would falsify the current hypothesis — and names the one observation that would change the conclusion."
+adds:
+ - "Looks for the evidence that would falsify the current belief, not just confirm it"
+ - "States explicitly what observation would change the conclusion"
+ - "Treats a belief with no disconfirming test as an assumption, not a finding"
+related:
+ - slug: adversarial-pushback
+ note: "Pushback role-plays an adversary against the whole proposal; disconfirmation tests one hypothesis for what would falsify it."
+ - slug: premortem
+ note: "Premortem imagines a finished failure and works backward; disconfirmation seeks a falsifying observation now."
+prompt: |
+ For [hypothesis / conclusion], don't just gather support for it — actively look for the evidence that would prove it wrong. State, in one line, what observation or result would change your mind. If nothing could, say so and flag it as an assumption rather than a finding. Report the disconfirming checks you ran alongside the conclusion.
+---
diff --git a/patterns/encoded-reasoning.md b/patterns/encoded-reasoning.md
new file mode 100644
index 0000000..44c3810
--- /dev/null
+++ b/patterns/encoded-reasoning.md
@@ -0,0 +1,17 @@
+---
+title: "Encoded reasoning"
+slug: encoded-reasoning
+icon: "fa-solid fa-list-check"
+category: critique
+order: 1
+summary: "Bakes the review rubric and quality gates into the Skill — it drafts, checks its own work against the criteria, and revises before returning."
+adds:
+ - "Runs output against a defined rubric — or, absent one, the brief and what a strong reviewer would notice"
+ - "Reports which criteria passed, failed, or are uncertain, and names the weakest reasoning and most fragile assumption"
+ - "Holds back work that fails a hard criterion — revises, retries, and returns a note on what changed"
+related:
+ - slug: gap-to-target-scoring
+ note: "Gap-to-target is the numeric variant — score 0–10, define the 10, re-score; encoded-reasoning gates on a pass/fail rubric."
+prompt: |
+ Before returning [output], check your own work against these criteria: [rubric items — or, absent a rubric, the original brief and what a strong reviewer would notice]. Report which criteria passed, failed, or are uncertain, and name the weakest reasoning and the most fragile assumption. Don't return work that fails a hard criterion — revise and retry. Return the revised output with a brief note on what changed and why.
+---
diff --git a/patterns/exemplars-over-instruction.md b/patterns/exemplars-over-instruction.md
new file mode 100644
index 0000000..a159627
--- /dev/null
+++ b/patterns/exemplars-over-instruction.md
@@ -0,0 +1,14 @@
+---
+title: "Exemplars over instruction"
+slug: exemplars-over-instruction
+icon: "fa-solid fa-star"
+category: grounding
+order: 2
+summary: "Anchors the Skill's output in concrete examples of \"good\" rather than describing it in rules."
+adds:
+ - "Matches the shape, voice, and structure of provided examples"
+ - "Surfaces which exemplar it drew from when the choice is ambiguous"
+ - "Asks for a new exemplar when the work falls outside the set"
+prompt: |
+ Here are exemplars of [strong outputs / preferred voice / target format]: [paste 2-4 examples]. Match the shape and voice of these rather than following rules I might write down. When the task falls outside what the exemplars cover, say so and ask for a new exemplar instead of guessing. Cite which exemplar most influenced the output.
+---
diff --git a/patterns/externalized-working-state.md b/patterns/externalized-working-state.md
new file mode 100644
index 0000000..f06e282
--- /dev/null
+++ b/patterns/externalized-working-state.md
@@ -0,0 +1,13 @@
+---
+title: "Externalized working state"
+slug: externalized-working-state
+icon: "fa-solid fa-table-list"
+category: composition
+summary: "Keeps a live, structured state file — a running ledger of what's been checked or decided — that survives across steps and skills instead of relying on chat memory."
+adds:
+ - "Writes progress and findings to a file, not just the conversation"
+ - "Tracks what's been ruled out, not only what's confirmed"
+ - "Lets separate steps or skills coordinate through a shared, structured record"
+prompt: |
+ For [multi-step work], maintain a structured state file at [path] rather than holding everything in this conversation. After each step, update it: what you checked, what you confirmed, what you ruled out, and what's still open. Read it back at the start of each step. Write it so a fresh session — or a different skill — could pick up exactly where this left off.
+---
diff --git a/patterns/failure-mode-preloading.md b/patterns/failure-mode-preloading.md
new file mode 100644
index 0000000..05e18f0
--- /dev/null
+++ b/patterns/failure-mode-preloading.md
@@ -0,0 +1,17 @@
+---
+title: "Failure mode preloading"
+slug: failure-mode-preloading
+icon: "fa-solid fa-triangle-exclamation"
+category: critique
+order: 5
+summary: "Names the specific ways this kind of work tends to go wrong, so the agent watches for them."
+adds:
+ - "Lists the known failure modes for this kind of task up front"
+ - "Watches for each one while working, not only at the end"
+ - "Flags when the work starts drifting toward a named failure mode"
+related:
+ - slug: premortem
+ note: "Premortem invents specific failure stories for this work; this loads the known, recurring failure types up front to watch for."
+prompt: |
+ Before starting [task], name the specific ways this kind of work usually goes wrong — [known failure modes, or ask me for them]. Keep that list in view as you work and check against it as you go, not only at the end. If the work starts drifting toward one of these failure modes, stop and flag it rather than pushing through. In the result, note which failure modes you actively guarded against.
+---
diff --git a/patterns/format-projection.md b/patterns/format-projection.md
new file mode 100644
index 0000000..412012e
--- /dev/null
+++ b/patterns/format-projection.md
@@ -0,0 +1,14 @@
+---
+title: "Format projection"
+slug: format-projection
+icon: "fa-solid fa-shapes"
+category: output
+order: 1
+summary: "Renders one canonical artifact into multiple downstream forms while preserving the underlying content."
+adds:
+ - "Produces the source artifact once, then derives variants from it"
+ - "Each variant matches its channel's conventions (length, tone, format)"
+ - "Surfaces what was cut or compressed in each derivation"
+prompt: |
+ Produce the canonical [artifact: decision doc, spec, research summary] first. Then derive these variants from it: [list: P2 post, Slack summary, exec brief, email update]. Each variant should match the conventions of its channel. Don't re-reason — derive. Note what was cut or compressed in each variant so I can spot if something important got lost.
+---
diff --git a/patterns/gap-to-target-scoring.md b/patterns/gap-to-target-scoring.md
new file mode 100644
index 0000000..19ed7d3
--- /dev/null
+++ b/patterns/gap-to-target-scoring.md
@@ -0,0 +1,16 @@
+---
+title: "Gap-to-target scoring"
+slug: gap-to-target-scoring
+icon: "fa-solid fa-ranking-star"
+category: critique
+summary: "Scores each dimension on a 0–10 scale, describes concretely what a 10 would look like, closes the gap, then re-scores to show the movement."
+adds:
+ - "Rates each dimension numerically instead of a vague pass/fail"
+ - "Spells out what a perfect 10 looks like for this specific work"
+ - "Re-scores after improvements so the gain is visible"
+related:
+ - slug: encoded-reasoning
+ note: "Encoded-reasoning gates on a pass/fail rubric and revises; gap-to-target scores 0–10 and shows the before→after movement."
+prompt: |
+ Evaluate [work] by scoring each of these dimensions 0–10: [dimensions]. For any score below 10, describe concretely what a 10 would look like for this specific case, then do the work to close the gap. Re-score afterward and show the before → after for each dimension. Keep the final verdict consistent with the scores.
+---
diff --git a/patterns/graceful-degradation.md b/patterns/graceful-degradation.md
new file mode 100644
index 0000000..7853c6a
--- /dev/null
+++ b/patterns/graceful-degradation.md
@@ -0,0 +1,13 @@
+---
+title: "Graceful degradation"
+slug: graceful-degradation
+icon: "fa-solid fa-life-ring"
+category: grounding
+summary: "When an input or source is unavailable, the Skill produces the best partial result and flags what was missing, instead of blocking or guessing."
+adds:
+ - "Continues with available inputs when a source fails"
+ - "Names which sources were unavailable and what they'd have affected"
+ - "Marks the result as partial rather than presenting it as complete"
+prompt: |
+ If a required input or source is unavailable or errors out, don't block or silently fill the gap. Proceed with what you have, clearly mark the result as partial, and list which sources were missing and what they affected. Only hard-stop if a missing input makes the whole task meaningless — and say which one.
+---
diff --git a/patterns/human-in-the-loop.md b/patterns/human-in-the-loop.md
new file mode 100644
index 0000000..6917bf7
--- /dev/null
+++ b/patterns/human-in-the-loop.md
@@ -0,0 +1,19 @@
+---
+title: "Human in the loop"
+slug: human-in-the-loop
+icon: "fa-solid fa-hand"
+category: control
+order: 1
+summary: "Draws the line between what the agent settles on its own and what it pauses to confirm — routine, reversible work proceeds (and gets logged); irreversible or high-stakes steps wait for a human."
+adds:
+ - "Stops before destructive, irreversible, or high-stakes steps and waits for confirmation"
+ - "Decides routine, reversible choices on its own instead of asking about every fork"
+ - "Keeps a short log of the calls it made autonomously, so they can be reviewed after"
+related:
+ - slug: scope-guardrails
+ note: "Scope-guardrails declines out-of-scope or unsafe requests outright; this pauses on in-scope but high-stakes steps."
+ - slug: clarification-gate
+ note: "Clarification-gate pauses before starting when the brief is ambiguous; this pauses before acting on a risky step."
+prompt: |
+ Draw a clear line between what you decide on your own and what you bring to me. Decide routine, reversible, low-stakes choices yourself — using these principles: [principles] — and keep a short running log of those calls and why, so I can review them later. Before anything destructive, irreversible, or high-stakes — [deploying, sending, deleting, committing, finalizing, taste-defining choices] — pause, summarize what you're about to do and why, and wait for my confirmation, redirect, or override. When you're unsure which side a step falls on, treat it as a judgment call and ask. [When presenting options, let me keep the default, give me two more, and enter my own.]
+---
diff --git a/patterns/interactive-playground.md b/patterns/interactive-playground.md
new file mode 100644
index 0000000..507b756
--- /dev/null
+++ b/patterns/interactive-playground.md
@@ -0,0 +1,13 @@
+---
+title: "Interactive playground"
+slug: interactive-playground
+icon: "fa-solid fa-sliders"
+category: output
+summary: "When the input space is visual or hard to put into words, builds a small self-contained interactive tool that lets you explore the options and hand back structured choices."
+adds:
+ - "Builds a throwaway interactive artifact instead of asking a long list of text questions"
+ - "Lets you explore a large, visual, or structural space directly and see choices update live"
+ - "Returns a structured result — chosen settings, a generated prompt — you can hand straight back"
+prompt: |
+ When [the decision space for this task] is large, visual, or hard to pin down in words, don't interrogate me with a long list of questions — build a small self-contained interactive tool (for example, a single HTML file with controls, a live preview, and a copy-out result) that lets me explore the options directly and see them update as I adjust. Give it sensible defaults and a few named presets so it's useful the moment it opens, and have it emit a structured result — the settings I chose, or a ready-to-paste prompt — that I can hand straight back to you. Keep it dependency-free so it works offline.
+---
diff --git a/patterns/long-term-memory.md b/patterns/long-term-memory.md
new file mode 100644
index 0000000..25c3b9c
--- /dev/null
+++ b/patterns/long-term-memory.md
@@ -0,0 +1,13 @@
+---
+title: "Long-term memory"
+slug: long-term-memory
+icon: "fa-solid fa-brain"
+category: composition
+summary: "Persists learnings, preferences, and decisions across sessions and recalls them next time, instead of starting cold."
+adds:
+ - "Records durable facts, preferences, and decisions to a store that outlives the session"
+ - "Recalls the relevant ones at the start of related work"
+ - "Updates or retires memories when they're superseded, rather than hoarding"
+prompt: |
+ Keep a durable memory across sessions for [domain]. When something is worth remembering — a preference, a decision and its rationale, a recurring fact — write it to [memory store / file]. At the start of related work, recall the relevant entries and apply them instead of asking again. When a memory is contradicted or out of date, update or remove it rather than letting it pile up. Tell me what you stored or recalled.
+---
diff --git a/patterns/premortem.md b/patterns/premortem.md
new file mode 100644
index 0000000..1829e58
--- /dev/null
+++ b/patterns/premortem.md
@@ -0,0 +1,19 @@
+---
+title: "Premortem"
+slug: premortem
+icon: "fa-solid fa-skull"
+category: critique
+order: 4
+summary: "Imagines the work has already shipped and failed, then reasons backward to the cause — and the assumption behind it."
+adds:
+ - "Generates the most plausible failure stories before the work ships"
+ - "Surfaces risks that wouldn't appear in a forward-looking review"
+ - "Names which current assumptions, if wrong, cause the failure"
+related:
+ - slug: adversarial-pushback
+ note: "Pushback argues against the work in the present; premortem imagines it already failed and traces why."
+ - slug: failure-mode-preloading
+ note: "Failure-mode-preloading lists known, recurring failure types up front; premortem invents specific failure stories for this work."
+prompt: |
+ Before finalizing [the plan / the decision / the proposal], run a premortem. Imagine it's [6 months / a year / one quarter] from now and this work has clearly failed. Generate the 3 most plausible failure stories — what went wrong, in what order, and why it wasn't caught in time. For each, name the assumption in the current plan that, if wrong, made the failure inevitable. Return the failure stories alongside the original work, with the riskiest assumptions called out.
+---
diff --git a/patterns/progressive-disclosure.md b/patterns/progressive-disclosure.md
new file mode 100644
index 0000000..1d0dd7d
--- /dev/null
+++ b/patterns/progressive-disclosure.md
@@ -0,0 +1,14 @@
+---
+title: "Progressive disclosure"
+slug: progressive-disclosure
+icon: "fa-solid fa-layer-group"
+category: composition
+order: 5
+summary: "Loads only the context needed for the current sub-task, expanding as the work deepens."
+adds:
+ - "Starts with the minimum context the current step requires"
+ - "Pulls in more detail only when the work actually reaches it"
+ - "Keeps unrelated material out of the way until it's relevant"
+prompt: |
+ Work through [task] in stages, loading only the context each stage needs. Start with the high-level [overview / index / table of contents]; pull in the detailed [files / sections / data] only when a step actually requires them. Don't front-load everything. When you move to a new sub-task, say what additional context you're bringing in and why, so the scope stays visible.
+---
diff --git a/patterns/prove-it-works.md b/patterns/prove-it-works.md
new file mode 100644
index 0000000..0ecfa10
--- /dev/null
+++ b/patterns/prove-it-works.md
@@ -0,0 +1,16 @@
+---
+title: "Prove it works"
+slug: prove-it-works
+icon: "fa-solid fa-circle-check"
+category: critique
+summary: "Before claiming the work is done, the Skill proves it actually happened — running it, checking output, showing evidence — instead of asserting completion."
+adds:
+ - "Runs the verification before saying 'done', not after"
+ - "Shows the evidence (output, test result, screenshot) behind any success claim"
+ - "Treats 'this looks finished' as a prompt to test, not to stop"
+related:
+ - slug: characterization-baseline
+ note: "For behavior-preserving changes, characterization baseline pins the current behavior up front; prove-it-works is the general end-of-task evidence check."
+prompt: |
+ Before you claim [task] is complete, actually verify it: run it, check the output, and show me the evidence. Don't say "done", "fixed", or "working" without the result that proves it. If you can't verify a claim, mark it unverified rather than asserting it. Treat "this looks finished" as a signal to test, not to stop.
+---
diff --git a/patterns/question-sharpening.md b/patterns/question-sharpening.md
new file mode 100644
index 0000000..05c4892
--- /dev/null
+++ b/patterns/question-sharpening.md
@@ -0,0 +1,13 @@
+---
+title: "Question sharpening"
+slug: question-sharpening
+icon: "fa-solid fa-bullseye"
+category: decision
+summary: "Challenges and sharpens the question itself before answering — naming the premise and pushing past the generic framing."
+adds:
+ - "Surfaces the assumptions baked into the question as asked"
+ - "Voices the consensus, average answer as a foil to push past it"
+ - "Steers toward the sharper question without drafting your framing for you"
+prompt: |
+ Before answering [question], interrogate the question itself. Name the premise it assumes. Say plainly what the generic, consensus answer would be — then treat that as the floor to beat, not the answer. Ask me the one or two questions that would sharpen this into the version only I would ask. Don't write my framing for me; supplying it would just anchor us to the average.
+---
diff --git a/patterns/role-priming.md b/patterns/role-priming.md
new file mode 100644
index 0000000..e02a9b6
--- /dev/null
+++ b/patterns/role-priming.md
@@ -0,0 +1,14 @@
+---
+title: "Role priming"
+slug: role-priming
+icon: "fa-solid fa-masks-theater"
+category: control
+order: 2
+summary: "Puts the agent in a specific stance for the duration of the Skill so its reasoning carries that perspective."
+adds:
+ - "Approaches the work from the named role's priorities and constraints"
+ - "Uses the vocabulary and reference points of that role"
+ - "Stays in role across follow-ups within the same task"
+prompt: |
+ Approach this work as [role: staff engineer reviewing a PR, finance partner reviewing a forecast, support lead reviewing a flow]. Use the priorities, vocabulary, and constraints that role brings. Stay in role across follow-up questions within this task. If you'd break role to be more helpful, say so and ask before switching.
+---
diff --git a/patterns/schema-locked-output.md b/patterns/schema-locked-output.md
new file mode 100644
index 0000000..8ce1066
--- /dev/null
+++ b/patterns/schema-locked-output.md
@@ -0,0 +1,13 @@
+---
+title: "Schema-locked output"
+slug: schema-locked-output
+icon: "fa-solid fa-code"
+category: output
+summary: "Forces output into a strict, validated structure and repairs or rejects anything that doesn't conform."
+adds:
+ - "Emits output that matches a defined schema or field set exactly"
+ - "Validates against the schema before returning, and repairs what doesn't fit"
+ - "Fails loudly when the content can't be made to conform, instead of bending the format"
+prompt: |
+ Return [output] strictly as [schema / field set / JSON shape]: [fields and their types]. Include every required field, use exactly these names, and add nothing outside the schema. Before returning, validate against it — if something doesn't conform, fix it. If the content genuinely can't fit the schema, say so explicitly rather than bending the format or inventing fields.
+---
diff --git a/patterns/scope-guardrails.md b/patterns/scope-guardrails.md
new file mode 100644
index 0000000..9277d21
--- /dev/null
+++ b/patterns/scope-guardrails.md
@@ -0,0 +1,13 @@
+---
+title: "Scope guardrails"
+slug: scope-guardrails
+icon: "fa-solid fa-vector-square"
+category: control
+summary: "Defines what the Skill should not do and declines or escalates out-of-scope or unsafe requests instead of attempting them."
+adds:
+ - "States the boundaries of what's in and out of scope up front"
+ - "Declines or flags requests that fall outside them, with a reason"
+ - "Routes genuinely out-of-scope or risky asks to a human instead of improvising"
+prompt: |
+ Operate within these boundaries for [task]: in scope — [what it should do]; out of scope — [what it must not do]. If a request falls outside the in-scope list, don't attempt it — say it's out of scope, explain why in a line, and suggest where it should go instead. If something looks unsafe or irreversible beyond your remit, stop and escalate to me rather than improvising.
+---
diff --git a/patterns/scoped-conventions.md b/patterns/scoped-conventions.md
new file mode 100644
index 0000000..0901b65
--- /dev/null
+++ b/patterns/scoped-conventions.md
@@ -0,0 +1,16 @@
+---
+title: "Scoped conventions"
+slug: scoped-conventions
+icon: "fa-solid fa-screwdriver-wrench"
+category: grounding
+summary: "Packages a specific tool, library, or domain's conventions as on-demand knowledge the Skill applies only when that area is in play."
+adds:
+ - "Encodes the right way to use a specific tool or library, not generic advice"
+ - "Activates only when the task actually touches that area"
+ - "Keeps the detailed reference out of context until it's needed"
+related:
+ - slug: trusted-sources
+ note: "Scoped-conventions encodes procedures for a tool or domain; trusted-sources anchors facts in cited authoritative references."
+prompt: |
+ When the task involves [tool / library / domain], follow these conventions: [rules, or point to a reference doc]. Use this specific guidance rather than generic best practices, and only pull in the detailed reference when the task actually touches [area]. If a convention here conflicts with your default approach, this guidance wins. If the task is outside [area], ignore this.
+---
diff --git a/patterns/self-tuning.md b/patterns/self-tuning.md
new file mode 100644
index 0000000..5138e05
--- /dev/null
+++ b/patterns/self-tuning.md
@@ -0,0 +1,13 @@
+---
+title: "Self-tuning"
+slug: self-tuning
+icon: "fa-solid fa-arrows-rotate"
+category: critique
+summary: "After a run, the Skill proposes concrete edits to its own instructions when they were unclear or incomplete — and stays silent when nothing needs changing."
+adds:
+ - "Notices where its own instructions were unclear, incomplete, or forced a workaround"
+ - "Proposes a specific edit — quotes the line and gives the replacement — not a vague 'could be better'"
+ - "Stays silent on a clean run; speaks up only when there's a real improvement to make"
+prompt: |
+ After completing [task], reflect on the instructions you just followed. Only speak up if something was ambiguous, missing, or forced a workaround — and then propose a specific edit to this Skill: quote the line and give the replacement. If the run was clean and nothing needs changing, say nothing at all about tuning — don't announce that it went fine. Don't edit the skill yourself; surface the proposal for review.
+---
diff --git a/patterns/signal-noise-pre-commitment.md b/patterns/signal-noise-pre-commitment.md
new file mode 100644
index 0000000..489eccd
--- /dev/null
+++ b/patterns/signal-noise-pre-commitment.md
@@ -0,0 +1,13 @@
+---
+title: "Signal vs. noise"
+slug: signal-noise-pre-commitment
+icon: "fa-solid fa-filter"
+category: grounding
+summary: "Forces an explicit list of which sources count as signal versus noise before analysis — including the noise you're most tempted to lean on anyway."
+adds:
+ - "Names the signal sources to weight and the noise to exclude up front"
+ - "Calls out the tempting-but-noisy source you'd otherwise over-rely on"
+ - "Lets you instruct the agent to actively discount that source"
+prompt: |
+ Before analyzing [topic], list your sources in two columns: signal (what should drive the conclusion) and noise (what to discount). Then name the one noisy source you're most likely to lean on anyway — vanity metrics, a loud stakeholder, recency — and treat it as noise on purpose. Weight the analysis toward signal, and flag any place noise is creeping back in.
+---
diff --git a/patterns/skill-chaining.md b/patterns/skill-chaining.md
new file mode 100644
index 0000000..0f23b16
--- /dev/null
+++ b/patterns/skill-chaining.md
@@ -0,0 +1,14 @@
+---
+title: "Skill chaining"
+slug: skill-chaining
+icon: "fa-solid fa-link"
+category: composition
+order: 3
+summary: "Composes this Skill with others into a sequenced flow."
+adds:
+ - "Triggers other Skills in a defined order"
+ - "Passes outputs from one stage as inputs to the next"
+ - "Surfaces workflow state so you can see where you are in the chain"
+prompt: |
+ Run this as a workflow: [Skill 1] → [Skill 2] → [Skill 3]. Pass the output of each stage as input to the next. After each stage, summarize what was produced and confirm before moving on. If a stage fails its checks, stop and surface the issue rather than continuing.
+---
diff --git a/patterns/specialist-fan-out.md b/patterns/specialist-fan-out.md
new file mode 100644
index 0000000..8a724f8
--- /dev/null
+++ b/patterns/specialist-fan-out.md
@@ -0,0 +1,20 @@
+---
+title: "Specialist fan-out"
+slug: specialist-fan-out
+icon: "fa-solid fa-sitemap"
+category: composition
+summary: "Splits a review or analysis across several agents running in parallel, each with a different lens, then merges their complementary findings into one synthesis."
+adds:
+ - "Runs several specialists at once — each owning a distinct aspect — instead of one generalist pass"
+ - "Dispatches only the lenses the work actually calls for"
+ - "Merges and de-duplicates complementary findings into one ranked result — coverage, not a vote"
+related:
+ - slug: best-of-n
+ note: "Best-of-N runs the same problem redundantly and votes for reliability; fan-out runs different lenses and merges for coverage."
+ - slug: decomposition
+ note: "Decomposition splits work into sequential sub-tasks for one worker; fan-out runs specialists in parallel, then synthesizes."
+ - slug: adversarial-pushback
+ note: "A panel of narrow critics is a fan-out aimed at review; adversarial-pushback is the single-challenger case."
+prompt: |
+ For [reviewing / analyzing / mapping] [target] where several distinct concerns matter, don't make one pass try to cover everything. Fan out: launch a separate agent per lens — [e.g. correctness, security, performance, test coverage, type design] — running in parallel, each focused only on its aspect and returning findings with specific evidence ([file:line], quotes). Dispatch only the lenses the work actually calls for. Then merge: collect every agent's findings, de-duplicate the overlaps, and synthesize one ranked result. The point is coverage — each agent catches what the others miss — not running the same check several times to vote on it.
+---
diff --git a/patterns/stakes-scaled-rigor.md b/patterns/stakes-scaled-rigor.md
new file mode 100644
index 0000000..c9917ce
--- /dev/null
+++ b/patterns/stakes-scaled-rigor.md
@@ -0,0 +1,13 @@
+---
+title: "Stakes-scaled rigor"
+slug: stakes-scaled-rigor
+icon: "fa-solid fa-weight-hanging"
+category: decision
+summary: "Tunes how much verification effort to spend to the stakes — a glance for low-risk reversible work, a full interrogation for high-impact irreversible calls."
+adds:
+ - "Judges reversibility and impact before deciding how hard to check"
+ - "Spends minimal effort on cheap, reversible steps"
+ - "Reserves deep verification for high-stakes, hard-to-undo decisions"
+prompt: |
+ Before verifying [output / decision], size the stakes: how reversible is it, and how big is the blast radius if it's wrong? Match your rigor to that — a quick sanity check for low-risk, easily-undone work; a thorough interrogation for high-impact or irreversible calls. Say which level you chose and why, so I can push for more if I disagree.
+---
diff --git a/patterns/tool-offloading.md b/patterns/tool-offloading.md
new file mode 100644
index 0000000..b95fa43
--- /dev/null
+++ b/patterns/tool-offloading.md
@@ -0,0 +1,16 @@
+---
+title: "Tool offloading"
+slug: tool-offloading
+icon: "fa-solid fa-gears"
+category: composition
+summary: "Hands deterministic, repetitive, or error-prone work to a bundled script the agent runs but never reads — keeping the logic reliable and out of the context window."
+adds:
+ - "Delegates fiddly, deterministic steps to a script instead of re-deriving them in prose each run"
+ - "Calls the script as a black box — runs it, reads its output, never loads its source into context"
+ - "Reserves the context window for judgment, not boilerplate the same code can do identically every time"
+related:
+ - slug: progressive-disclosure
+ note: "Progressive-disclosure loads reference docs in stages; tool-offloading runs scripts as black boxes and never loads their source."
+prompt: |
+ For [the deterministic, repetitive, or error-prone part of this task — e.g. validating a file, transforming data, assembling a document], use the bundled script at [path] rather than writing the logic inline or re-deriving it each time. Run it with `--help` first to learn its usage, then call it directly and work from its output. Don't read the script's source into context unless it actually fails and you need to debug it — it exists to be run, not ingested, and loading it just burns the window on code that already works. If no such script exists yet but you keep writing the same helper across runs, that's the signal to create one and reuse it.
+---
diff --git a/patterns/trusted-sources.md b/patterns/trusted-sources.md
new file mode 100644
index 0000000..3622191
--- /dev/null
+++ b/patterns/trusted-sources.md
@@ -0,0 +1,17 @@
+---
+title: "Trusted sources"
+slug: trusted-sources
+icon: "fa-solid fa-anchor"
+category: grounding
+order: 1
+summary: "Anchors the agent in specific authoritative references so it stops improvising from training data."
+adds:
+ - "Cites which source supports each claim"
+ - "Defers to specified sources when they conflict with general knowledge"
+ - "Flags gaps instead of filling them silently"
+related:
+ - slug: scoped-conventions
+ note: "Trusted-sources anchors facts in authoritative references; scoped-conventions packages how-to conventions for a tool or domain."
+prompt: |
+ Ground this Skill in the following authoritative sources: [URLs / paths / docs]. When the task touches this area, consult these first. If your training contradicts these sources, the sources win. Cite which source each claim comes from. If a source is missing or ambiguous, flag the gap rather than filling it from prior knowledge.
+---
diff --git a/scripts/build.mjs b/scripts/build.mjs
new file mode 100644
index 0000000..37aeefd
--- /dev/null
+++ b/scripts/build.mjs
@@ -0,0 +1,135 @@
+#!/usr/bin/env node
+// Generates the Skill Patterns catalog outputs from patterns/*.md + categories.yml.
+// skills/skill-patterns/references/patterns.md -> plugin snapshot (identical to llms.txt)
+// build/llms.txt -> live /llms.txt
+// build/patterns.json -> live /patterns.json
+// Do NOT hand-edit outputs. Edit patterns/ and run `npm run build`.
+// Flag: --no-related (omit related[] — used only for the phase-1 parity gate)
+
+import { readFileSync, writeFileSync, readdirSync, mkdirSync } from 'node:fs';
+import { join, dirname, basename } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import yaml from 'js-yaml';
+
+const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
+const SITE_URL = 'https://skillpatterns.ai';
+const INCLUDE_RELATED = !process.argv.includes('--no-related');
+const REQUIRED = ['title', 'slug', 'category', 'summary', 'adds', 'prompt'];
+
+function readFrontmatter(file) {
+ const raw = readFileSync(file, 'utf8');
+ const m = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
+ if (!m) throw new Error(`${basename(file)}: no YAML frontmatter`);
+ return yaml.load(m[1]);
+}
+
+const categories = yaml.load(readFileSync(join(ROOT, 'categories.yml'), 'utf8'));
+for (const c of categories) {
+ if (typeof c.order !== 'number') {
+ throw new Error(`categories.yml: category '${c.key}' is missing a numeric 'order'`);
+ }
+}
+const sortedCats = [...categories].sort((a, b) => a.order - b.order);
+
+const dir = join(ROOT, 'patterns');
+const patterns = readdirSync(dir)
+ .filter((f) => f.endsWith('.md'))
+ .map((f) => {
+ const data = readFrontmatter(join(dir, f));
+ data._base = f.replace(/\.md$/, '');
+ return data;
+ });
+
+const slugToFile = new Map();
+for (const p of patterns) {
+ if (slugToFile.has(p.slug)) {
+ throw new Error(
+ `${p._base}.md: duplicate slug '${p.slug}' (also used by ${slugToFile.get(p.slug)}.md)`
+ );
+ }
+ slugToFile.set(p.slug, p._base);
+}
+
+const titleBySlug = new Map(patterns.map((p) => [p.slug, p.title]));
+const catKeys = new Set(categories.map((c) => c.key));
+
+for (const p of patterns) {
+ for (const k of REQUIRED) {
+ if (p[k] == null) throw new Error(`${p._base}.md: missing required field '${k}'`);
+ }
+ if (p.slug !== p._base) {
+ throw new Error(`${p._base}.md: slug '${p.slug}' must match the filename`);
+ }
+ if (!Array.isArray(p.adds)) {
+ throw new Error(`${p._base}.md: 'adds' must be a list`);
+ }
+ if (!catKeys.has(p.category)) {
+ throw new Error(`${p._base}.md: unknown category '${p.category}'`);
+ }
+ for (const r of p.related ?? []) {
+ if (typeof r.slug !== 'string' || r.slug === '') {
+ throw new Error(`${p._base}.md: related entry missing 'slug'`);
+ }
+ if (typeof r.note !== 'string' || r.note === '') {
+ throw new Error(`${p._base}.md: related entry missing 'note'`);
+ }
+ if (!titleBySlug.has(r.slug)) {
+ throw new Error(`${p._base}.md: related slug '${r.slug}' does not exist`);
+ }
+ }
+}
+
+const patternsIn = (catKey) =>
+ patterns
+ .filter((p) => p.category === catKey)
+ .sort((a, b) => a.title.toLowerCase().localeCompare(b.title.toLowerCase()));
+
+const stripNewlines = (s) => String(s).replace(/\r?\n/g, '');
+
+function buildLlms() {
+ let o = '';
+ o += `# Skill Patterns\n\n`;
+ o += `> Reusable, composable techniques for shaping how an AI agent behaves — ${patterns.length} patterns across ${categories.length} categories. When creating or improving a Skill, apply the patterns whose purpose matches the task; each entry includes an example prompt you can adapt. Most skills use 2–4 patterns — don't over-apply. Site: ${SITE_URL}/\n`;
+ for (const cat of sortedCats) {
+ o += `\n## ${cat.title}\n${cat.description}\n`;
+ for (const p of patternsIn(cat.key)) {
+ o += `\n### ${p.title}\n`;
+ o += `${p.summary}\n`;
+ o += `- What it adds: ${p.adds.join('; ')}.\n`;
+ o += `- Example prompt: ${stripNewlines(p.prompt)}\n`;
+ o += `- URL: ${SITE_URL}/patterns/${p._base}/\n`;
+ if (INCLUDE_RELATED && p.related?.length) {
+ const rel = p.related.map((r) => `${titleBySlug.get(r.slug)} — ${r.note}`).join('; ');
+ o += `- Related: ${rel}\n`;
+ }
+ }
+ }
+ return o;
+}
+
+function buildJson() {
+ const j = JSON.stringify;
+ const objs = [];
+ for (const cat of sortedCats) {
+ for (const p of patternsIn(cat.key)) {
+ let s =
+ `{"title":${j(p.title)},"slug":${j(p.slug)},"category":${j(cat.title)},` +
+ `"categoryKey":${j(p.category)},"summary":${j(p.summary)},"adds":${j(p.adds)},` +
+ `"prompt":${j(stripNewlines(p.prompt))},"url":${j(`${SITE_URL}/patterns/${p._base}/`)}`;
+ if (INCLUDE_RELATED && p.related?.length) {
+ s += `,"related":${j(p.related.map((r) => ({ slug: r.slug, note: r.note })))}`;
+ }
+ objs.push(s + `}`);
+ }
+ }
+ return `[${objs.join(',')}]\n`;
+}
+
+const llms = buildLlms();
+mkdirSync(join(ROOT, 'build'), { recursive: true });
+writeFileSync(join(ROOT, 'build', 'llms.txt'), llms);
+writeFileSync(join(ROOT, 'build', 'patterns.json'), buildJson());
+writeFileSync(join(ROOT, 'skills', 'skill-patterns', 'references', 'patterns.md'), llms);
+console.log(
+ `Generated ${patterns.length} patterns across ${categories.length} categories (related: ${INCLUDE_RELATED ? 'on' : 'off'}).`
+);
diff --git a/skills/skill-patterns/SKILL.md b/skills/skill-patterns/SKILL.md
index 422c632..1fcfb1d 100644
--- a/skills/skill-patterns/SKILL.md
+++ b/skills/skill-patterns/SKILL.md
@@ -38,4 +38,4 @@ Whenever you're authoring or revising a Skill's instructions: drafting a new `SK
This skill is itself a composition of its own catalog: it grounds in an authoritative source (Trusted sources), generates bounded candidates (Bounded option generation), decides what to apply vs. surface (Decision delegation), exposes its choices for override (Clarification gate), and loads detail only when needed (Progressive disclosure).
-`references/patterns.md` is a generated snapshot of the live catalog (`skillpatterns.ai/llms.txt`); regenerate it when the catalog changes.
+`references/patterns.md` is generated from the canonical catalog on `main` (`patterns/*.md` + `categories.yml`) by `scripts/build.mjs` — run `npm run build` after editing a pattern. Never hand-edit it.
diff --git a/skills/skill-patterns/references/patterns.md b/skills/skill-patterns/references/patterns.md
index 2f8941a..052b41c 100644
--- a/skills/skill-patterns/references/patterns.md
+++ b/skills/skill-patterns/references/patterns.md
@@ -28,6 +28,7 @@ Packages a specific tool, library, or domain's conventions as on-demand knowledg
- What it adds: Encodes the right way to use a specific tool or library, not generic advice; Activates only when the task actually touches that area; Keeps the detailed reference out of context until it's needed.
- Example prompt: When the task involves [tool / library / domain], follow these conventions: [rules, or point to a reference doc]. Use this specific guidance rather than generic best practices, and only pull in the detailed reference when the task actually touches [area]. If a convention here conflicts with your default approach, this guidance wins. If the task is outside [area], ignore this.
- URL: https://skillpatterns.ai/patterns/scoped-conventions/
+- Related: Trusted sources — Scoped-conventions encodes procedures for a tool or domain; trusted-sources anchors facts in cited authoritative references.
### Signal vs. noise
Forces an explicit list of which sources count as signal versus noise before analysis — including the noise you're most tempted to lean on anyway.
@@ -40,6 +41,7 @@ Anchors the agent in specific authoritative references so it stops improvising f
- What it adds: Cites which source supports each claim; Defers to specified sources when they conflict with general knowledge; Flags gaps instead of filling them silently.
- Example prompt: Ground this Skill in the following authoritative sources: [URLs / paths / docs]. When the task touches this area, consult these first. If your training contradicts these sources, the sources win. Cite which source each claim comes from. If a source is missing or ambiguous, flag the gap rather than filling it from prior knowledge.
- URL: https://skillpatterns.ai/patterns/trusted-sources/
+- Related: Scoped conventions — Trusted-sources anchors facts in authoritative references; scoped-conventions packages how-to conventions for a tool or domain.
## Decision-making
Structure how choices get made and recorded.
@@ -103,48 +105,56 @@ Pits a challenger persona or parallel agent against the work to expose weaknesse
- What it adds: Argues the strongest case against the proposal, with reasoning; Surfaces assumptions that wouldn't survive scrutiny; Forces defense of choices instead of quiet acceptance; Can run blind — the challenger sees only the artifact, not your reasoning, removing the pull to agree.
- Example prompt: Before finalizing [output], take the role of [adversary: skeptical reviewer, hostile architect, opposing counsel, competitor's CTO]. Argue the strongest case against the proposal. Identify the assumptions most likely to fail, the evidence that's missing, and the decisions that would look wrong in hindsight. For a sharper check, run it blind: give the challenger only the finished artifact and the task — not your reasoning or how you got here — so it judges the work cold, the way a reader with none of your context would. Return the pushback and the original work side by side.
- URL: https://skillpatterns.ai/patterns/adversarial-pushback/
+- Related: Premortem — Premortem imagines it already failed and works backward; pushback argues against it in the present.; Disconfirmation — Disconfirmation hunts evidence that falsifies one claim; pushback attacks the whole proposal from an adversary's role.; Specialist fan-out — Several narrow critics in parallel is a fan-out of this single-challenger move.
### Best-of-N
Runs the same problem several times independently and converges on the consensus — a majority vote, or the verified top candidate — so a single bad sample can't decide the answer.
- What it adds: Attacks one problem with several independent passes — varied angles, no shared reasoning between runs; Converges by majority vote, or by ranking the attempts and re-verifying the strongest; Aggregates for reliability — it isn't generating options for you to choose between.
- Example prompt: For [a high-stakes or error-prone task] where a single attempt can quietly be wrong, run it [N] times independently — varied starting angles, no shared reasoning between runs — rather than trusting one pass. Then aggregate: for a definite answer, take the majority vote; for open-ended work, rank the candidates and verify the strongest one. Treat convergence across independent attempts as the real signal and a lone dissent as likely noise. If the attempts don't converge, say so and surface the disagreement instead of quietly picking one and moving on.
- URL: https://skillpatterns.ai/patterns/best-of-n/
+- Related: Specialist fan-out — Fan-out runs different lenses and merges for coverage; Best-of-N runs the same problem and votes for reliability.; Bounded option generation — Bounded options surface distinct choices for you to pick; Best-of-N aggregates internally to a single answer.
### Disconfirmation
Actively hunts for the evidence that would falsify the current hypothesis — and names the one observation that would change the conclusion.
- What it adds: Looks for the evidence that would falsify the current belief, not just confirm it; States explicitly what observation would change the conclusion; Treats a belief with no disconfirming test as an assumption, not a finding.
- Example prompt: For [hypothesis / conclusion], don't just gather support for it — actively look for the evidence that would prove it wrong. State, in one line, what observation or result would change your mind. If nothing could, say so and flag it as an assumption rather than a finding. Report the disconfirming checks you ran alongside the conclusion.
- URL: https://skillpatterns.ai/patterns/disconfirmation/
+- Related: Adversarial pushback — Pushback role-plays an adversary against the whole proposal; disconfirmation tests one hypothesis for what would falsify it.; Premortem — Premortem imagines a finished failure and works backward; disconfirmation seeks a falsifying observation now.
### Encoded reasoning
Bakes the review rubric and quality gates into the Skill — it drafts, checks its own work against the criteria, and revises before returning.
- What it adds: Runs output against a defined rubric — or, absent one, the brief and what a strong reviewer would notice; Reports which criteria passed, failed, or are uncertain, and names the weakest reasoning and most fragile assumption; Holds back work that fails a hard criterion — revises, retries, and returns a note on what changed.
- Example prompt: Before returning [output], check your own work against these criteria: [rubric items — or, absent a rubric, the original brief and what a strong reviewer would notice]. Report which criteria passed, failed, or are uncertain, and name the weakest reasoning and the most fragile assumption. Don't return work that fails a hard criterion — revise and retry. Return the revised output with a brief note on what changed and why.
- URL: https://skillpatterns.ai/patterns/encoded-reasoning/
+- Related: Gap-to-target scoring — Gap-to-target is the numeric variant — score 0–10, define the 10, re-score; encoded-reasoning gates on a pass/fail rubric.
### Failure mode preloading
Names the specific ways this kind of work tends to go wrong, so the agent watches for them.
- What it adds: Lists the known failure modes for this kind of task up front; Watches for each one while working, not only at the end; Flags when the work starts drifting toward a named failure mode.
- Example prompt: Before starting [task], name the specific ways this kind of work usually goes wrong — [known failure modes, or ask me for them]. Keep that list in view as you work and check against it as you go, not only at the end. If the work starts drifting toward one of these failure modes, stop and flag it rather than pushing through. In the result, note which failure modes you actively guarded against.
- URL: https://skillpatterns.ai/patterns/failure-mode-preloading/
+- Related: Premortem — Premortem invents specific failure stories for this work; this loads the known, recurring failure types up front to watch for.
### Gap-to-target scoring
Scores each dimension on a 0–10 scale, describes concretely what a 10 would look like, closes the gap, then re-scores to show the movement.
- What it adds: Rates each dimension numerically instead of a vague pass/fail; Spells out what a perfect 10 looks like for this specific work; Re-scores after improvements so the gain is visible.
- Example prompt: Evaluate [work] by scoring each of these dimensions 0–10: [dimensions]. For any score below 10, describe concretely what a 10 would look like for this specific case, then do the work to close the gap. Re-score afterward and show the before → after for each dimension. Keep the final verdict consistent with the scores.
- URL: https://skillpatterns.ai/patterns/gap-to-target-scoring/
+- Related: Encoded reasoning — Encoded-reasoning gates on a pass/fail rubric and revises; gap-to-target scores 0–10 and shows the before→after movement.
### Premortem
Imagines the work has already shipped and failed, then reasons backward to the cause — and the assumption behind it.
- What it adds: Generates the most plausible failure stories before the work ships; Surfaces risks that wouldn't appear in a forward-looking review; Names which current assumptions, if wrong, cause the failure.
- Example prompt: Before finalizing [the plan / the decision / the proposal], run a premortem. Imagine it's [6 months / a year / one quarter] from now and this work has clearly failed. Generate the 3 most plausible failure stories — what went wrong, in what order, and why it wasn't caught in time. For each, name the assumption in the current plan that, if wrong, made the failure inevitable. Return the failure stories alongside the original work, with the riskiest assumptions called out.
- URL: https://skillpatterns.ai/patterns/premortem/
+- Related: Adversarial pushback — Pushback argues against the work in the present; premortem imagines it already failed and traces why.; Failure mode preloading — Failure-mode-preloading lists known, recurring failure types up front; premortem invents specific failure stories for this work.
### Prove it works
Before claiming the work is done, the Skill proves it actually happened — running it, checking output, showing evidence — instead of asserting completion.
- What it adds: Runs the verification before saying 'done', not after; Shows the evidence (output, test result, screenshot) behind any success claim; Treats 'this looks finished' as a prompt to test, not to stop.
- Example prompt: Before you claim [task] is complete, actually verify it: run it, check the output, and show me the evidence. Don't say "done", "fixed", or "working" without the result that proves it. If you can't verify a claim, mark it unverified rather than asserting it. Treat "this looks finished" as a signal to test, not to stop.
- URL: https://skillpatterns.ai/patterns/prove-it-works/
+- Related: Characterization baseline — For behavior-preserving changes, characterization baseline pins the current behavior up front; prove-it-works is the general end-of-task evidence check.
### Self-tuning
After a run, the Skill proposes concrete edits to its own instructions when they were unclear or incomplete — and stays silent when nothing needs changing.
@@ -178,6 +188,7 @@ Draws the line between what the agent settles on its own and what it pauses to c
- What it adds: Stops before destructive, irreversible, or high-stakes steps and waits for confirmation; Decides routine, reversible choices on its own instead of asking about every fork; Keeps a short log of the calls it made autonomously, so they can be reviewed after.
- Example prompt: Draw a clear line between what you decide on your own and what you bring to me. Decide routine, reversible, low-stakes choices yourself — using these principles: [principles] — and keep a short running log of those calls and why, so I can review them later. Before anything destructive, irreversible, or high-stakes — [deploying, sending, deleting, committing, finalizing, taste-defining choices] — pause, summarize what you're about to do and why, and wait for my confirmation, redirect, or override. When you're unsure which side a step falls on, treat it as a judgment call and ask. [When presenting options, let me keep the default, give me two more, and enter my own.]
- URL: https://skillpatterns.ai/patterns/human-in-the-loop/
+- Related: Scope guardrails — Scope-guardrails declines out-of-scope or unsafe requests outright; this pauses on in-scope but high-stakes steps.; Clarification gate — Clarification-gate pauses before starting when the brief is ambiguous; this pauses before acting on a risky step.
### Role priming
Puts the agent in a specific stance for the duration of the Skill so its reasoning carries that perspective.
@@ -199,12 +210,14 @@ Probes what the runtime actually offers — subagents, a browser, the project's
- What it adds: Checks which tools, integrations, and capabilities are present before committing to an approach; Branches to the path that fits what's available rather than failing or assuming a default environment; Falls back to a sensible default — and says which path it took — when the environment can't be determined.
- Example prompt: Before committing to an approach for [task], detect what this environment actually provides — [e.g. subagents, a display or browser, the project's language, a particular integration or MCP server] — rather than assuming. Then take the path that fits: [if X is available, do A; otherwise do B]. State which capabilities you found and which path you're taking, so the choice is visible and I can redirect it. If you can't tell what's available, pick the safe default, name it, and proceed rather than stalling or guessing wrong.
- URL: https://skillpatterns.ai/patterns/capability-detection/
+- Related: Graceful degradation — Graceful-degradation handles a missing input with a partial result; capability-detection probes the environment and picks a different full path.
### Characterization baseline
Before changing existing behavior, pins it down as a test contract — concrete input→output pairs captured from the current code — then makes the change and proves every pin still passes.
- What it adds: Captures the current observable behavior as a runnable baseline before touching anything; Treats those captured cases as the definition of done for the change; Proves equivalence after — the change passes the baseline, or each difference is deliberate and named.
- Example prompt: Before you change [existing code or behavior — a refactor, rename, migration, optimization, or dependency upgrade], pin down what it does now. First, capture the current observable behavior as a baseline: characterization tests (concrete input → expected-output pairs read off the existing code — what it actually does, not what you think it should do), or a golden-master snapshot of its outputs. Treat that baseline as the definition of done. Then make the change and run the baseline against the new version — it must pass unchanged. If some output legitimately should differ, call out each deviation and why it's intended; don't quietly update the baseline to match the new behavior. The goal is to change the form while proving the behavior held.
- URL: https://skillpatterns.ai/patterns/characterization-baseline/
+- Related: Prove it works — Prove-it-works verifies at the end that the work works; this captures the current behavior up front, then proves the change preserved it.
### Decomposition
Breaks a complex task into smaller, well-scoped sub-tasks and tackles them one at a time.
@@ -241,9 +254,11 @@ Splits a review or analysis across several agents running in parallel, each with
- What it adds: Runs several specialists at once — each owning a distinct aspect — instead of one generalist pass; Dispatches only the lenses the work actually calls for; Merges and de-duplicates complementary findings into one ranked result — coverage, not a vote.
- Example prompt: For [reviewing / analyzing / mapping] [target] where several distinct concerns matter, don't make one pass try to cover everything. Fan out: launch a separate agent per lens — [e.g. correctness, security, performance, test coverage, type design] — running in parallel, each focused only on its aspect and returning findings with specific evidence ([file:line], quotes). Dispatch only the lenses the work actually calls for. Then merge: collect every agent's findings, de-duplicate the overlaps, and synthesize one ranked result. The point is coverage — each agent catches what the others miss — not running the same check several times to vote on it.
- URL: https://skillpatterns.ai/patterns/specialist-fan-out/
+- Related: Best-of-N — Best-of-N runs the same problem redundantly and votes for reliability; fan-out runs different lenses and merges for coverage.; Decomposition — Decomposition splits work into sequential sub-tasks for one worker; fan-out runs specialists in parallel, then synthesizes.; Adversarial pushback — A panel of narrow critics is a fan-out aimed at review; adversarial-pushback is the single-challenger case.
### Tool offloading
Hands deterministic, repetitive, or error-prone work to a bundled script the agent runs but never reads — keeping the logic reliable and out of the context window.
- What it adds: Delegates fiddly, deterministic steps to a script instead of re-deriving them in prose each run; Calls the script as a black box — runs it, reads its output, never loads its source into context; Reserves the context window for judgment, not boilerplate the same code can do identically every time.
- Example prompt: For [the deterministic, repetitive, or error-prone part of this task — e.g. validating a file, transforming data, assembling a document], use the bundled script at [path] rather than writing the logic inline or re-deriving it each time. Run it with `--help` first to learn its usage, then call it directly and work from its output. Don't read the script's source into context unless it actually fails and you need to debug it — it exists to be run, not ingested, and loading it just burns the window on code that already works. If no such script exists yet but you keep writing the same helper across runs, that's the signal to create one and reuse it.
- URL: https://skillpatterns.ai/patterns/tool-offloading/
+- Related: Progressive disclosure — Progressive-disclosure loads reference docs in stages; tool-offloading runs scripts as black boxes and never loads their source.