← back to Cli Printing Press
feat(skills): make printing-press-retro a public skill (#129) (#131)
c2076e02461816c849805c016a02c9508fc6d72c · 2026-04-05 12:17:04 -0700 · Trevin Chow
* feat(skills): make printing-press-retro a public skill with GitHub issue output (#129)
Move the retro skill from .claude/skills/ (private) to skills/ (public plugin).
The skill now creates GitHub issues on mvanhorn/cli-printing-press with scrubbed
artifact uploads via catbox.moe, so external users can contribute machine
improvement findings without repo access.
Key changes:
- Modified setup contract (path-only, no binary check) for external users
- Layered secrets scrub (exact-value + pattern-based) before public upload
- User confirmation gate before anything leaves the machine
- Graceful degradation when gh auth or catbox upload fails
- Context-aware: in-repo gets local save + offer-to-plan; external gets issue-only
- Reference file pattern applied to keep SKILL.md lean
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(skills): address correctness issues in public retro skill
- Add API_SLUG and RETRO_PROOF_PATH variable definitions (were undefined)
- Fix HAR loop to use space-safe find -print0 pattern
- Fix "Six Questions" → "seven questions" (lists 7)
- Tighten env var regex to suffix-match only (avoids CACHE_KEY false positives)
- Replace commented rsync fallback with real if/else
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(skills): use "the Printing Press" in user-facing output, add issue gate
Skills run as a plugin without AGENTS.md context, so "the machine" is
meaningless to external users. Replace with "the Printing Press" as the
system name across all skills. Subsystem names (generator, scorer, skills,
binary) are preserved in diagnostic output where developers need to know
what to fix.
Also adds Phase 5.6 issue gate to retro skill — skips GitHub issue
creation when all findings are printed-CLI-specific with nothing
actionable for the Printing Press.
- Add Terminology section to retro skill with subsystem breakdown
- Update AGENTS.md with skill-facing terminology guidance
- Update voice.md, polish, publish, and main skill references
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Files touched
D .claude/skills/printing-press-retro/SKILL.mdM AGENTS.mdA docs/brainstorms/2026-04-04-public-retro-skill-requirements.mdA docs/plans/2026-04-05-001-feat-public-retro-skill-plan.mdM skills/printing-press-polish/SKILL.mdM skills/printing-press-publish/SKILL.mdA skills/printing-press-retro/SKILL.mdA skills/printing-press-retro/references/artifact-packaging.mdA skills/printing-press-retro/references/issue-template.mdA skills/printing-press-retro/references/secret-scrubbing.mdM skills/printing-press/SKILL.mdM skills/printing-press/references/voice.md
Diff
commit c2076e02461816c849805c016a02c9508fc6d72c
Author: Trevin Chow <trevin@trevinchow.com>
Date: Sun Apr 5 12:17:04 2026 -0700
feat(skills): make printing-press-retro a public skill (#129) (#131)
* feat(skills): make printing-press-retro a public skill with GitHub issue output (#129)
Move the retro skill from .claude/skills/ (private) to skills/ (public plugin).
The skill now creates GitHub issues on mvanhorn/cli-printing-press with scrubbed
artifact uploads via catbox.moe, so external users can contribute machine
improvement findings without repo access.
Key changes:
- Modified setup contract (path-only, no binary check) for external users
- Layered secrets scrub (exact-value + pattern-based) before public upload
- User confirmation gate before anything leaves the machine
- Graceful degradation when gh auth or catbox upload fails
- Context-aware: in-repo gets local save + offer-to-plan; external gets issue-only
- Reference file pattern applied to keep SKILL.md lean
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(skills): address correctness issues in public retro skill
- Add API_SLUG and RETRO_PROOF_PATH variable definitions (were undefined)
- Fix HAR loop to use space-safe find -print0 pattern
- Fix "Six Questions" → "seven questions" (lists 7)
- Tighten env var regex to suffix-match only (avoids CACHE_KEY false positives)
- Replace commented rsync fallback with real if/else
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(skills): use "the Printing Press" in user-facing output, add issue gate
Skills run as a plugin without AGENTS.md context, so "the machine" is
meaningless to external users. Replace with "the Printing Press" as the
system name across all skills. Subsystem names (generator, scorer, skills,
binary) are preserved in diagnostic output where developers need to know
what to fix.
Also adds Phase 5.6 issue gate to retro skill — skips GitHub issue
creation when all findings are printed-CLI-specific with nothing
actionable for the Printing Press.
- Add Terminology section to retro skill with subsystem breakdown
- Update AGENTS.md with skill-facing terminology guidance
- Update voice.md, polish, publish, and main skill references
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
.claude/skills/printing-press-retro/SKILL.md | 605 ---------------------
AGENTS.md | 4 +
.../2026-04-04-public-retro-skill-requirements.md | 88 +++
.../2026-04-05-001-feat-public-retro-skill-plan.md | 326 +++++++++++
skills/printing-press-polish/SKILL.md | 2 +-
skills/printing-press-publish/SKILL.md | 4 +-
skills/printing-press-retro/SKILL.md | 565 +++++++++++++++++++
.../references/artifact-packaging.md | 165 ++++++
.../references/issue-template.md | 170 ++++++
.../references/secret-scrubbing.md | 152 ++++++
skills/printing-press/SKILL.md | 10 +-
skills/printing-press/references/voice.md | 2 +-
12 files changed, 1479 insertions(+), 614 deletions(-)
diff --git a/.claude/skills/printing-press-retro/SKILL.md b/.claude/skills/printing-press-retro/SKILL.md
deleted file mode 100644
index cb8e6466..00000000
--- a/.claude/skills/printing-press-retro/SKILL.md
+++ /dev/null
@@ -1,605 +0,0 @@
----
-name: printing-press-retro
-description: >
- Run a retrospective after generating a CLI with the printing press. Identifies
- systemic improvements to the machine — generator templates, Go binary, skill
- instructions, catalog — not patches to the specific CLI. Covers bugs, but also
- recurring friction (like dead code), features that had to be built manually,
- and optimizations discovered during the session. Use after any /printing-press
- run. Trigger phrases: "retro", "retrospective", "what went wrong", "improve
- the press", "post-mortem", "lessons learned", "what can we improve".
-allowed-tools:
- - Bash
- - Read
- - Glob
- - Grep
- - Write
- - Agent
- - AskUserQuestion
----
-
-# /printing-press-retro
-
-Analyze a printing press session to find ways to make the *machine* better. Not
-fixes to the CLI that was just printed — improvements to the generator, binary,
-skill, and catalog so the *next* CLI comes out stronger with less manual effort.
-
-This goes beyond bugs. The most valuable findings are often the work that *succeeded
-but shouldn't have been necessary* — features you built by hand that the generator
-should have emitted, friction that recurs on every generation, and optimizations you
-discovered that should become defaults.
-
-## When to run
-
-Run in the same conversation where the CLI was generated (post-shipcheck). The retro
-needs the full conversation history — every error, retry, manual edit, and discovery.
-
-If running in a fresh conversation, point it at the manuscripts directory, but know
-you'll miss the in-conversation debugging context.
-
-## Setup
-
-```bash
-PRESS_HOME="$HOME/printing-press"
-PRESS_MANUSCRIPTS="$PRESS_HOME/manuscripts"
-
-# Find the most recent run across all APIs
-LATEST_RUN=$(find "$PRESS_MANUSCRIPTS" -name "*shipcheck*" -type f -exec stat -f "%m %N" {} \; | sort -rn | head -1 | awk '{print $2}')
-
-if [ -z "$LATEST_RUN" ]; then
- echo "No shipcheck proofs found. Run /printing-press first."
- exit 1
-fi
-
-API_NAME=$(echo "$LATEST_RUN" | sed "s|$PRESS_MANUSCRIPTS/||" | cut -d'/' -f1)
-RUN_ID=$(echo "$LATEST_RUN" | sed "s|$PRESS_MANUSCRIPTS/||" | cut -d'/' -f2)
-RUN_DIR="$PRESS_MANUSCRIPTS/$API_NAME/$RUN_ID"
-
-echo "Retro for: $API_NAME (run $RUN_ID)"
-echo "Manuscripts: $RUN_DIR"
-```
-
-If the user passed an API name as an argument, use that instead of auto-detecting.
-
-## Phase 1: Gather evidence
-
-Read all artifacts from the run:
-
-1. **Research brief** — `$RUN_DIR/research/*brief*`
-2. **Absorb manifest** — `$RUN_DIR/research/*absorb*`
-3. **Shipcheck proof** — `$RUN_DIR/proofs/*shipcheck*`
-4. **Build log** — `$RUN_DIR/proofs/*build-log*` (if exists)
-5. **Live smoke log** — `$RUN_DIR/proofs/*live-smoke*` (if exists)
-6. **The generated CLI** — `$PRESS_HOME/library/<api>-pp-cli/`
-
-Also gather the scorecard, verify pass rate, and dogfood report (from the shipcheck
-proof or by re-running the tools).
-
-## Phase 2: Mine the session
-
-Scan the full conversation history for five categories of signal. Every finding
-becomes a row in Phase 3 — don't filter yet, just collect.
-
-### 2a. Errors and retries
-
-Any time a command failed and was re-run, a build broke, or the generator produced
-code that didn't compile. What broke and what fixed it?
-
-### 2b. Manual code edits
-
-Every hand-edit to generated code is a signal. Each one means the generator *should
-have* gotten it right but didn't. These are the highest-value findings because they
-point directly at template gaps.
-
-Examples from real sessions:
-- Rewriting the root command `Short:` description from API-speak to user-speak
-- Adding top-level commands to wrap deeply-nested generated commands
-- Fixing `serviceForPath` routing for proxy-envelope APIs
-- Rewriting the sync command for offset-based pagination
-- Adding entity-specific store tables the generator didn't create
-
-### 2c. Features built from scratch
-
-Features in the absorb manifest or transcendence list that had to be written entirely
-by hand during Phase 3. The generator produced no scaffolding for them. Ask: is this
-a feature class the generator could reasonably emit, or is it genuinely custom?
-
-For example: if every CLI needs a `trending` command that queries local SQLite, maybe
-the generator should emit a trending template when it detects time-series metrics in
-the spec.
-
-### 2d. Recurring friction
-
-Work that happens on *every* generation, not just this one. The key question for each:
-**is this inherent to the approach, or can the machine eliminate it?**
-
-Examples:
-- **Dead code** — The generator emits generic helpers (CSV, delete-classify, etc.) and
- some are never called. Is the fix to stop emitting them (risk: some CLIs need them)?
- Or to add a post-generation dead-code sweep? Or to make the generator smarter about
- which helpers each API actually needs?
-- **Default resource mismatch** — `defaultSyncResources()` always returns a placeholder.
- Could the generator derive the right resources from the spec's entity types?
-- **DB path inconsistency** — Different generated commands use different default paths.
- Could the generator emit a single `defaultDBPath()` and reference it everywhere?
-
-For each piece of friction, propose at least two possible fixes at different levels
-(generator, binary post-processing, skill instruction) and assess which is most durable.
-
-### 2e. Discovered optimizations
-
-Improvements noticed during the session that weren't fixing a problem — they were
-making something better. These might be UX ideas, performance improvements, new
-command patterns, or output format improvements that emerged from actually using the
-CLI.
-
-Ask: could this optimization be detected automatically and applied by the generator?
-
-### 2f. Scorer accuracy audit
-
-Before proposing machine fixes to improve scores, check whether the scoring itself
-is correct. A low verify score might mean the CLI is bad, or it might mean verify
-has a bug. Same for dogfood and scorecard. **Changing the generator to satisfy a
-broken scorer is worse than doing nothing** — it adds complexity to work around a
-tool defect, and the workaround becomes load-bearing debt.
-
-For each score penalty from dogfood, verify, and scorecard:
-
-1. **Trace the scorer's logic.** Read the scoring tool's source code to understand
- exactly what it checks and how it derives the score. Don't guess.
-2. **Test the scorer's assumption against reality.** Does the CLI actually have
- the problem the scorer claims? Run the relevant command, read the code, verify.
-3. **Classify the penalty:**
- - **Scorer is correct** — the CLI genuinely has this problem. Fix the generator
- or the CLI code.
- - **Scorer is wrong** — the CLI is fine but the scorer can't detect it correctly
- (e.g., verify looks for the wrong command name, dogfood skips the file where
- the flag is used). Fix the scoring tool.
- - **Scorer is partially right** — the CLI could be better AND the scorer's
- approach is flawed. Fix both, but distinguish which is primary.
-
-Common scorer bugs to watch for:
-- **Name derivation mismatches** — the tool derives expected names differently
- than the generator creates them (e.g., from Go function names vs cobra `Use:`)
-- **Grep-based detection missing patterns** — simple string search fails when
- code uses the feature through indirection (struct fields, interface methods)
-- **File exclusions too broad** — the tool skips files it shouldn't (like
- dogfood skipping root.go for flag usage)
-- **Section-counting heuristics** — scorecard checks for named sections rather
- than content quality (README with all sections but bad content scores higher
- than a well-organized README missing one heading)
-
-The scorer audit is not optional. Every finding that comes from a score penalty
-must have a "Scorer correct?" assessment before proposing a fix direction.
-
-## Phase 3: Classify findings
-
-For each finding from Phase 2, answer these questions. Skip findings that only
-affect this specific API and wouldn't recur.
-
-### The Six Questions
-
-**1. What happened?**
-One sentence. Describe the symptom or the work that was done, not the fix.
-
-**2. Is the scorer correct?** (mandatory for any finding surfaced by a score penalty)
-
-Before classifying the finding, determine whether the tool that flagged it is
-measuring correctly. Read the tool's source to understand the detection logic.
-Test the claim against reality. Classify as one of:
-
-- **Scorer correct** — the CLI genuinely has this problem. Proceed to fix the
- generator, template, or CLI code.
-- **Scorer wrong** — the CLI is fine; the scoring tool has a bug. The fix goes
- in the scoring tool (verify, dogfood, or scorecard), not the generator.
-- **Both** — the CLI could be better AND the scorer's approach is flawed. Fix
- both, but label which is primary.
-
-If the scorer is wrong, the finding's category is **Scorer bug**, the component
-is the scoring tool, and the durable fix targets the tool — not the generator.
-Do not propose generator workarounds for scorer bugs.
-
-**3. What category is this?**
-
-| Category | Description | Example |
-|----------|-------------|---------|
-| **Bug** | Generated code is wrong | serviceForPath returns wrong service |
-| **Scorer bug** | Scoring tool reports a false positive or mis-measures | Verify derives command name from Go function instead of cobra Use field |
-| **Template gap** | Generator has no template for a common pattern | No top-level command aliases |
-| **Assumption mismatch** | Generator assumes X but API uses Y | Cursor pagination vs offset |
-| **Recurring friction** | Happens every generation, might be inherent | Dead code cleanup |
-| **Missing scaffolding** | Feature class the generator could emit but doesn't | Entity-specific store tables |
-| **Default gap** | Generator emits a wrong or placeholder default | Sync resources list, DB path |
-| **Discovered optimization** | Improvement found during use | Compact number formatting |
-| **Skill instruction gap** | Skill told Claude wrong thing or missed a step | Phase ordering issue |
-
-**4. Where in the machine does this originate?**
-
-| Component | Path | Controls |
-|-----------|------|----------|
-| Generator templates | `internal/generator/` | Go code emitted for commands, store, client |
-| Spec parser | `internal/spec/` | Internal YAML spec parsing |
-| OpenAPI parser | `internal/openapi/` | OpenAPI 3.0+ parsing |
-| Catalog | `catalog/` | API entries and metadata |
-| Main skill | `skills/printing-press/SKILL.md` | Orchestration instructions |
-| Verify/dogfood/scorecard | CLI commands | Quality checking tools |
-
-**5. Blast radius and fallback cost — should the machine handle this?**
-
-This is the most important question and the easiest to get wrong. The retro runs
-right after a session with one API, and pattern-matching from a single example is
-unreliable. A finding that felt universal during the Postman Explore session might
-be specific to proxy-envelope APIs, or to sniffed specs, or to APIs with entity-type
-enum params.
-
-**Step A: Cross-API stress test.** Test across both API shapes and input methods
-since the printing press handles all combinations:
-
-API shapes:
-- A standard REST API with clean resources (e.g., Stripe, GitHub)
-- A non-standard or minimal API (proxy-envelope, RPC-style, etc.)
-
-Input methods:
-- OpenAPI spec (well-documented, machine-readable)
-- Crowd-sniffed (derived from npm/GitHub SDKs, may have gaps)
-- HAR-sniffed (derived from captured traffic)
-- No spec (Claude researches and builds from scratch)
-
-For each relevant combination, ask: "Would this exact problem occur? Would the
-proposed fix help, be irrelevant, or actively hurt?"
-
-**Step B: Estimate frequency.** Based on the stress test, assign a blast radius:
-
-- **Every API** — occurs regardless of API shape or input method.
-- **Most APIs** — affects common patterns. Name the triggering condition.
-- **API subclass** — affects a specific pattern. Name the subclass precisely:
- proxy-envelope, GraphQL, sniffed-only, offset-paginated, etc.
-- **This API only** — isolated quirk.
-
-**Step C: Assess fallback cost.** This is what happens if the machine does NOT have
-the fix. The cost is NOT measured in time — Claude does the implementation. The cost
-is about **reliability and quality degradation**:
-
-| Fallback | Cost | Why it's costly |
-|----------|------|-----------------|
-| **Claude rewrites from scratch** | High — error-prone, may produce inconsistent code | Claude might forget, get it wrong, or produce code that doesn't match the generator's patterns |
-| **Claude makes targeted edits** | Medium — usually succeeds but adds friction | Claude generally catches it, but each manual edit is a chance for the CLI to diverge from machine quality |
-| **Claude deletes/tweaks one thing** | Low — mechanical, reliable | Claude catches it consistently, fix is trivial and deterministic |
-| **CLI ships broken** | Critical — user hits the bug at runtime | Defect reaches the user. No amount of Claude effort during generation prevents this if the machine emits wrong code |
-
-The key question: **how reliably will Claude catch and fix this every time, across
-every future API?** A "simple" edit that Claude forgets 30% of the time is actually
-high cost because those 30% ship with the defect.
-
-**Step D: Make the tradeoff.** The default is to **fix it in the machine**. The
-retro exists to feed an improvement loop — if findings get punted to Skip by
-default, the loop stalls and CLIs don't get better. Every finding left out of the
-machine is a bet that Claude will catch it every time, and Claude won't.
-
-The burden of proof is on *not* fixing, not on fixing.
-
-**Skip** when the behavior is unlikely to occur with other APIs or services.
-
-For each finding, ask: **"If I'm building CLIs for 50 different APIs — big
-enterprise platforms, small indie services, legacy systems, modern startups — is
-this something I'd plausibly encounter again, or is it truly this one vendor's
-idiosyncratic choice?"**
-
-Use your knowledge of the API landscape to make this judgment. You know how APIs
-are built, what conventions exist across the industry, and what patterns different
-vendors converge on independently. Trust that judgment rather than trying to apply
-a mechanical rule.
-
-Examples of findings that were correctly skipped:
-- **Valve's `input_json` wrapping** — Steam's "Service" interfaces require all params
- encoded as `input_json={"steamid":"xxx"}`. Valve invented this for their internal
- service RPC layer. Across 50 APIs, you wouldn't see this convention again.
-
-Examples of findings that LOOK isolated but should NOT be skipped:
-- "This API uses API keys in query params instead of headers" — many older APIs
- do this. You'd see it again.
-- "This API returns 200 for errors with an error field in the body" — common
- anti-pattern across many APIs.
-- "This API has no pagination and returns everything in one call" — a pagination
- variant (none/single-page), not a quirk.
-
-**Do** when you'd plausibly encounter the behavior again — even if this is the
-first API to trigger it.
-
-The printing press handles multiple input paths — OpenAPI specs, crowd-sniffed
-specs, HAR-sniffed specs, and no-spec APIs. Findings can surface from any path.
-Examples that cut across input methods:
-- Offset pagination (vs cursor) — fundamental pagination approach, surfaces whether
- you have an OpenAPI spec or are sniffing traffic
-- Response envelope wrapping — most APIs do this regardless of how the spec was
- obtained
-- Incomplete parameter discovery — happens with crowd-sniff (SDK gaps), HAR sniff
- (limited traffic capture), and even OpenAPI specs (undocumented params)
-- Auth pattern detection — needed whether auth info comes from an OpenAPI
- `securitySchemes`, an SDK constructor, or HAR request headers
-- Resource naming mismatches — the generator's command structure vs user-friendly
- names is independent of spec source
-
-With the diversity of APIs and input methods the printing press targets, **true
-vendor quirks are rarer than they seem.** When in doubt, lean toward Do with a
-guard rather than Skip.
-
-When the finding applies to a subclass, include conditional logic so it doesn't
-regress the simple case.
-
-When the finding applies to an API subclass, the recommendation must include:
-- **Condition:** When to activate (e.g., "spec has `x-proxy-routes`")
-- **Guard:** When to skip (e.g., "standard REST APIs without proxy pattern")
-- **Frequency estimate:** How common is this subclass? If it's >20% of APIs the
- printing press targets, the conditional logic is likely worth the complexity.
-
-**6. Is this inherent or fixable?**
-This question matters most for recurring friction. Some friction is structural — code
-generation will always produce some unused code because templates are generic. But
-"inherent" shouldn't be the default answer. Push hard on whether a smarter generator,
-a post-processing step, or better spec analysis could eliminate the friction.
-
-If inherent: propose the cheapest mitigation (e.g., "dogfood auto-deletes dead helpers
-as a post-generation step").
-
-If fixable: propose the fix at the right level.
-
-**7. What is the durable fix?**
-A concrete change to the machine. Prefer this hierarchy:
-
-1. **Generator template fix** — Code is emitted correctly from the start. Zero manual work.
-2. **Binary post-processing** — A printing-press command that auto-fixes after generation
- (like a `printing-press polish` that removes dead code and aligns paths).
-3. **Skill instruction** — Tell Claude to do it during generation. Last resort because
- Claude might forget or get it wrong. Every instruction is a tax on every future run.
-
-Describe what test would verify the fix: "Generate a CLI for an API with offset
-pagination and verify sync terminates after fetching all pages."
-
-## Phase 4: Prioritize
-
-Group findings into three buckets using judgment, not a formula. No "backlog" —
-backlog is where findings go to die. Either it's worth doing or it's not.
-
-- **Fix the scorer** — the scoring tool is wrong and penalizing a correct CLI.
- The fix goes in the quality tool (verify, dogfood, or scorecard), not the
- generator. These are the highest-priority fixes because a wrong scorer
- distorts every future retro and leads to wasted effort "fixing" things that
- aren't broken. Include the scorer's buggy code path in the work unit.
-- **Do** — the score is correct and a machine fix is warranted. This is the
- default for legitimate penalties. Split into "Do now" (scoped cleanly, can
- implement immediately) and "Do next" (needs design work or careful guards —
- plan before implementing).
-- **Skip** — unlikely to encounter again across other APIs. State why.
-
-Do NOT use numerical scoring formulas. The inputs (frequency=3, fallback=4) are
-ordinal gut-feels, and multiplying them produces fake precision that obscures
-judgment. State the reasoning in words instead.
-
-## Phase 5: Write the retro
-
-```markdown
-# Printing Press Retro: <API name>
-
-## Session Stats
-- API: <name>
-- Spec source: <catalog/sniffed/docs/HAR>
-- Scorecard: <before> -> <after> (if applicable)
-- Verify pass rate: <X>%
-- Fix loops: <N>
-- Manual code edits: <N>
-- Features built from scratch: <N>
-
-## Findings
-
-### 1. <Title> (<category>)
-- **What happened:** ...
-- **Scorer correct?** (required if surfaced by a score penalty) Yes / No / Partially.
- If no: what is the scorer's bug? Trace the detection logic in the tool's source,
- explain why it produces a false result, and cite the specific code path (file:line).
- The fix goes in the scoring tool, not the generator. If partially: explain what
- part of the penalty is legitimate vs what part is a detection bug.
-- **Root cause:** Component + what's specifically wrong
-- **Cross-API check:** Would this recur across other APIs and input methods?
-- **Frequency:** every API / most / subclass:<name> / this API only
-- **Fallback if machine doesn't fix it:** What Claude has to do dynamically and how
- reliably Claude catches it (always / usually / sometimes / never). If "sometimes"
- or "never", the CLI ships with the defect — that's the real cost.
-- **Worth a machine fix?** Default is yes. Only no if you'd be unlikely to encounter
- this across other APIs. State the reasoning in plain language.
-- **Inherent or fixable:** ...
-- **Durable fix:** Concrete machine change. If subclass-scoped, include:
- - Condition: when to activate
- - Guard: when to skip
- - Frequency estimate: how common is this subclass?
-- **Test:** How to verify, including a negative test for APIs that should NOT be affected
-- **Evidence:** Session moment that surfaced this
-
-### 2. ...
-
-## Prioritized Improvements
-
-### Fix the Scorer (scoring tool bugs — highest priority)
-| # | Scorer | Bug | Impact (false failures/points) | Fix target |
-|---|--------|-----|-------------------------------|------------|
-
-### Do Now
-| # | Fix | Component | Frequency | Fallback Reliability | Complexity | Guards |
-|---|-----|-----------|-----------|---------------------|------------|--------|
-
-### Do Next (needs design/planning)
-| # | Fix | Component | Frequency | Fallback Reliability | Complexity | Guards |
-|---|-----|-----------|-----------|---------------------|------------|--------|
-
-### Skip
-| # | Fix | Why unlikely to recur |
-|---|-----|----------------------|
-
-## Work Units
-
-### WU-1: <Title> (findings #N, #M)
-- **Goal:** ...
-- **Target files:** actual paths from Glob/Grep
-- **Acceptance criteria:**
- - positive test: ...
- - negative test: ...
-- **Scope boundary:** ...
-- **Complexity:** small / medium / large
-
-### WU-2: ...
-
-## Anti-patterns
-
-Patterns that looked right but led to problems. These should become warnings in
-AGENTS.md or the relevant skill:
-- ...
-
-## What the Machine Got Right
-
-Patterns to preserve and extend — things that worked well and should not be
-accidentally degraded by future changes:
-- ...
-```
-
-## Phase 5.5: Plannable work units
-
-The retro's findings are analytical. To bridge to implementation planning (e.g.,
-via `/compound-engineering:ce-plan`), group related findings into coherent work units that a planner
-could pick up directly.
-
-For each "Do now" or "Do next" group, produce a work unit block:
-
-```markdown
-## Work Units
-
-### WU-1: <Title> (from findings #N, #M, ...)
-- **Goal:** One sentence describing the outcome
-- **Target files:** Specific file paths in the printing-press repo to modify
- (use Glob/Grep to resolve component names to actual files)
-- **Acceptance criteria:** 2-3 concrete, testable scenarios:
- - "Generate from postman-explore spec → sync terminates without manual fix"
- - "Generate from Stripe spec → sync still uses cursor-based pagination (negative test)"
-- **Scope boundary:** What this does NOT include
-- **Dependencies:** Other work units that must complete first (if any)
-- **Complexity:** small (1-2 files, straightforward) / medium (3-5 files, needs design) / large (new capability, multiple subsystems)
-```
-
-To resolve target files, actually look at the printing-press repo:
-
-```bash
-# Find generator template files
-find <repo>/internal/generator -name "*.go" -o -name "*.tmpl" | head -20
-
-# Find where sync code is generated
-grep -rl "syncResource\|defaultSyncResources\|determinePaginationDefaults" <repo>/internal/
-```
-
-Group related findings into work units when they touch the same files or when
-one fix enables another. For example:
-- Response envelope unwrapping + pagination detection + sync resource derivation
- → "WU: Data layer generation pipeline"
-- Entity-specific store tables + FTS index generation + typed columns
- → "WU: Schema-driven store generation"
-
-A good work unit is scoped to a single implementable chunk with a clear definition
-of done. If it touches more than ~5 files across multiple subsystems, split it.
-
-## Phase 6: Save and present
-
-### Save locations
-
-Save the retro to two places:
-
-1. **Manuscripts** (ephemeral, tied to the run):
- ```
- $PRESS_MANUSCRIPTS/<api>/<run-id>/proofs/<stamp>-retro-<api>-pp-cli.md
- ```
-
-2. **Repo** (durable, checkable-into-git, readable by future sessions):
- ```bash
- REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")"
- RETRO_DIR="$REPO_ROOT/docs/retros"
- mkdir -p "$RETRO_DIR"
-
- # Filename: YYYY-MM-DD-<api>-retro.md
- RETRO_FILE="$RETRO_DIR/$(date +%Y-%m-%d)-<api>-retro.md"
- ```
-
- The repo copy is the canonical one. It accumulates over time so future retros
- can reference past findings ("this was also flagged in the notion retro on 2026-03-15").
-
-### Present summary
-
-Show the user: the "Do now" table and the work units.
-
-### Offer to plan
-
-Check whether `/compound-engineering:ce-plan` is available (the compound-engineering plugin is in
-`.claude/settings.json` as a dependency, so it should be — but might not be for
-standalone installs). Use `AskUserQuestion` to offer next steps:
-
-> "Retro saved to `docs/retros/<date>-<api>-retro.md`. Found <N> findings across
-> <M> work units. Want to plan implementation?"
->
-> 1. **Plan "Do now" work units** — invoke `/compound-engineering:ce-plan` with the retro's Do now work
-> units as input
-> 2. **Plan a specific work unit** — pick one WU to plan
-> 3. **Done for now** — retro is saved, plan later
-
-If the user picks option 1 or 2, invoke the `compound-engineering:ce:plan` skill
-(if that name doesn't resolve, try `compound-engineering:ce-plan` as a fallback)
-with a prompt like:
-
-```
-Create a plan to improve the printing-press CLI generation system in this repo.
-We just generated a CLI for <API> and encountered systemic problems and
-opportunities documented in the retro. The retro includes prioritized work units
-with target files, acceptance criteria, and scope boundaries:
-docs/retros/<date>-<api>-retro.md
-[If option 2: Focus on work unit WU-<N>: <title>.]
-
-Note: the retro is advisory, not declarative. During planning you may discover
-valid reasons to adjust scope — combining work units, dropping items that turn out
-to be impractical once you read the code, or adding items the retro missed. That's
-expected. Use the retro as a starting point, not a spec.
-```
-
-If neither skill name resolves, fall back to:
-- Tell the user the retro is saved and they can invoke it manually
-- Print the prompt they'd use:
- `/compound-engineering:ce-plan Create a plan to improve the printing-press system given the retro at docs/retros/<file>`
-
-## Rules
-
-- The retro is about the machine, not the CLI. Do not propose fixes to the generated
- CLI.
-- **Never work around a scorer bug in the generator.** If a scoring tool (verify,
- dogfood, scorecard) penalizes something incorrectly, the fix goes in the scoring
- tool. Changing the generator to satisfy a broken scorer adds complexity to work
- around a tool defect, and the workaround becomes load-bearing debt that makes
- future changes harder. Trace the scorer's logic, prove it's wrong, and fix the
- tool.
-- Do not add more phases, documents, or gates to the main skill. It's already long.
- Propose making existing phases smarter or the generator emit better defaults.
-- Prefer automatic fixes (generator, binary) over instructional fixes (skill).
-- For recurring friction, always answer "inherent or fixable?" honestly. Don't
- dismiss friction as inherent without considering alternatives.
-- Be honest about what went well. Protecting good patterns is as important as
- fixing bad ones.
-- **Bias toward fixing.** The retro feeds an improvement loop. If the loop is too
- conservative, CLIs don't get better. When in doubt, fix it — scope narrowly with
- conditional logic if needed. A guarded fix for a rare case is better than no fix
- at all. Future retros can widen the scope when the pattern recurs.
-- **Look for broader patterns.** Before skipping a finding as API-specific, consider
- whether it's the first sighting of a behavior you'd encounter again. Offset
- pagination was first seen on one API — but it's clearly a pattern across many.
-- When a fix only applies to a subclass of APIs, the recommendation must include the
- condition (when to activate) AND the guard (when to skip). A generator change
- without a guard is a blanket change, and blanket changes break simple cases.
-- **No time estimates.** Claude does the implementation. Hours/days/weeks are
- meaningless. Use complexity sizing (small/medium/large) based on number of files
- touched and design work needed.
-- Be thorough. The retro document is a reference for future planning — include
- enough detail that someone reading it months later can understand the finding,
- the tradeoff reasoning, and the proposed fix without needing the original
- conversation.
diff --git a/AGENTS.md b/AGENTS.md
index db1a0775..880b7a96 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -47,6 +47,10 @@ Key terms used throughout this repo. Several have overloaded meanings — the gl
**Use the canonical term** (left column) in your own responses so intent stays unambiguous. If the user's phrasing is ambiguous and the distinction affects what action to take — e.g., "publish it" could mean the pipeline step or pushing to the public library repo — ask before acting.
+**In skills and user-facing output** (GitHub issues, retro documents, confirmation prompts), use **"the Printing Press"** as the system name — never "the machine." Skills run as a plugin without AGENTS.md loaded, so readers won't have this glossary. "The machine" is fine in AGENTS.md, code comments, and developer conversation within this repo.
+
+**Subsystem names are fine alongside the Printing Press name.** When skills produce diagnostic output (retro findings, issue tables, work units), use component names — generator, scorer, skills, binary — to tell developers *where* to fix something. "Fix the Printing Press" is useless as an action item; "fix the scorer — it penalizes cookie auth" is actionable. The Printing Press is the system; the subsystems are how you navigate within it.
+
| Canonical term | Meaning |
|----------------|---------|
| **the printing press** / **the machine** | This repo's generator system — the Go binary, templates, skills, and catalog that together produce CLIs. |
diff --git a/docs/brainstorms/2026-04-04-public-retro-skill-requirements.md b/docs/brainstorms/2026-04-04-public-retro-skill-requirements.md
new file mode 100644
index 00000000..2224ddcf
--- /dev/null
+++ b/docs/brainstorms/2026-04-04-public-retro-skill-requirements.md
@@ -0,0 +1,88 @@
+---
+date: 2026-04-04
+topic: public-retro-skill
+---
+
+# Public Retro Skill
+
+## Problem Frame
+
+The `/printing-press-retro` skill captures high-value machine improvement signals -- bugs, template gaps, recurring friction, scorer issues -- but it's private (`.claude/skills/`). Only repo maintainers can run it. External users who generate CLIs via the plugin discover the same issues but have no structured way to feed those findings back. Making the skill public turns every external user's generation run into a potential machine improvement contribution.
+
+The output target changes fundamentally: instead of saving findings to `docs/retros/` in the repo (which external users can't access), the skill creates a GitHub issue on `mvanhorn/cli-printing-press` with enough information -- including manuscript and source artifacts -- for someone (human or AI agent) to fix the problem using only what's in the issue.
+
+## Requirements
+
+**Analysis**
+
+- R1. The skill runs the full retro methodology (evidence gathering, session mining, classification with cross-API stress tests, scorer accuracy audits, prioritization, work unit creation). Same analytical depth as the current private skill -- findings are pre-analyzed, not raw symptoms. Phases that have repo-local dependencies (e.g., Phase 5.5 work units resolving target file paths via `find`/`grep` in the printing-press repo) must adapt: when the repo is not available, work units describe target components and acceptance criteria without resolved file paths.
+- R2. The retro document is distilled into a well-structured GitHub issue body with prioritized findings, work units, and enough context for an AI agent or human to act on it without additional information.
+
+**Artifact Packaging**
+
+- R3. The skill zips the manuscript run directory (`~/printing-press/manuscripts/<api-slug>/<run-id>/`) and uploads it to catbox.moe via their curl API (`curl -F "reqtype=fileupload" -F "fileToUpload=@file.zip" https://catbox.moe/user/api.php`). The returned URL is linked from the GitHub issue body. Manuscripts are typically 24-268KB per run.
+- R4. The skill zips the generated CLI source code (`~/printing-press/library/<cli-name>/`) excluding the compiled binary, `vendor/`, and `go.sum`, and uploads it to catbox.moe. The returned URL is linked from the issue body. Source is ~2.2MB uncompressed; zipped Go source compresses well (~200-400KB).
+- R5. Before zipping, a defensive secrets/PII scrub runs on both the manuscript and CLI source. This includes: (a) exact-value scanning for the session API key (existing pattern from `secret-protection.md`), and (b) pattern-based scanning for common secret formats: `sk_live_*`, `sk_test_*`, `ghp_*`, `Bearer` tokens in code, JWT-shaped strings (`eyJ...`), and env var assignments containing `SECRET`, `TOKEN`, `KEY`, `PASSWORD`. Conservative patterns with low false-positive risk.
+
+**Output Routing**
+
+- R6. The skill creates a GitHub issue on `mvanhorn/cli-printing-press` via `gh issue create`. The issue body contains the distilled retro analysis with links to the catbox-hosted artifact zips.
+- R7. If the current working directory is inside the `cli-printing-press` repo (detected by checking for a known marker file like `cmd/printing-press/main.go`), also save the retro document to `docs/retros/YYYY-MM-DD-<api>-retro.md`. When running from inside the repo, the "Offer to plan" handoff (invoking `/ce:plan`) is retained. For external users, this step is skipped.
+- R8. The retro document is always saved to the manuscript proofs directory (`~/printing-press/manuscripts/<api-slug>/<run-id>/proofs/`), regardless of context.
+
+**Graceful Degradation**
+
+- R9. The skill refuses to run if `~/printing-press/manuscripts/` is empty or doesn't exist. Clear message: "No manuscripts found. Run `/printing-press` first to generate a CLI."
+- R10. If multiple APIs exist in manuscripts and the user didn't specify which one, the skill asks for clarification (listing available APIs with their most recent run dates).
+- R11. If an API has multiple runs, the skill defaults to the most recent run but lets the user choose if they specify a run ID.
+- R14. If `gh` is not authenticated or `gh issue create` fails, the skill saves the retro document and artifact zips locally (next to the manuscript proofs), prints the catbox URLs if upload succeeded, and tells the user to file the issue manually with the generated content.
+- R15. If catbox.moe upload fails (service down, network issue), the skill still creates the GitHub issue with the retro analysis in the body but notes that artifacts could not be uploaded. The local zips are preserved for the user to attach manually.
+
+**Skill Distribution**
+
+- R12. Move the skill from `.claude/skills/printing-press-retro/` (private) to `skills/printing-press-retro/` (public, packaged with the plugin). Apply the reference file pattern from AGENTS.md to keep the SKILL.md lean -- extract conditional content (issue templates, scrub patterns, work unit formatting) into `references/` files.
+- R13. The current private skill is removed after the public skill is verified working. No duplication.
+
+## Success Criteria
+
+- An external user (not a repo contributor) can run `/printing-press-retro` after generating a CLI, and a GitHub issue is created on `mvanhorn/cli-printing-press` with the retro analysis and links to artifact zips hosted on catbox.moe.
+- A maintainer or AI agent can read the issue and download the artifacts, understand the findings, and implement fixes using only the information in the issue.
+- When run from inside the `cli-printing-press` repo, the retro also saves to `docs/retros/` and offers to plan implementation.
+- No secrets or PII appear in the issue body or uploaded artifacts.
+- When `gh` auth or catbox upload fails, the skill degrades gracefully with clear instructions for manual filing.
+
+## Scope Boundaries
+
+- The retro methodology's analytical framework (classification, scorer audit protocol, cross-API stress tests) is not being redesigned -- it's being adapted for two contexts (in-repo with file path resolution, external without).
+- The skill does not implement fixes. It analyzes and reports.
+- The skill does not modify the generation pipeline or the printing-press binary.
+- Issue labels, milestones, or project board assignment are out of scope -- just create the issue with a clear title and structured body.
+- The skill does not create separate child issues per finding -- one issue per retro run.
+
+## Key Decisions
+
+- **Full analysis on user's side**: The skill runs the complete retro methodology before distilling into an issue. The fixer gets pre-analyzed findings, not raw symptoms.
+- **Catbox.moe for artifact hosting**: Zip manuscripts and CLI source, upload via catbox's curl API, link from issue body. No GitHub auth needed for uploads, no file size concerns, simple implementation. Third-party dependency accepted since artifacts are intentionally public.
+- **One issue per retro run**: All findings go into one well-structured issue. Work units serve as splitting points.
+- **Context-aware behavior**: In-repo runs get local save + offer-to-plan. External runs get issue-only output. Detected via marker file, not origin URL parsing.
+- **Layered secrets scrub**: Exact-value scanning (session key) plus conservative pattern matching (sk_live_*, JWT, etc.) before any public upload. Defense in depth for public artifacts.
+- **Graceful degradation over hard failures**: If gh or catbox fails, save locally and guide the user to file manually. The retro analysis is never lost.
+
+## Dependencies / Assumptions
+
+- `gh` CLI is authenticated and can create issues on `mvanhorn/cli-printing-press`. Any authenticated GitHub user can create issues on public repos. If auth fails, R14 handles the fallback.
+- catbox.moe's API (`https://catbox.moe/user/api.php`) is available. If it fails, R15 handles the fallback.
+- `curl` is available on the user's system (standard on macOS/Linux, available on modern Windows).
+
+## Outstanding Questions
+
+### Deferred to Planning
+
+- [Affects R2][Technical] What's the exact GitHub issue body template? The retro markdown format is comprehensive but may need trimming for issue readability. Planning should determine which sections go in the issue body vs the attached retro document.
+- [Affects R12][Technical] What adjustments are needed to the skill frontmatter and description for marketplace discovery? The trigger phrases need to work for external users, not just maintainers.
+- [Affects R5][Technical] Exact regex patterns for the secret scanner. Planning should define the pattern list and test against real manuscripts for false-positive rate.
+- [Affects R1][Technical] Which phases need conditional logic for in-repo vs external context? Phase 5.5 (work units with file path resolution) is identified; planning should audit all 6 phases.
+
+## Next Steps
+
+--> `/ce:plan` for structured implementation planning
diff --git a/docs/plans/2026-04-05-001-feat-public-retro-skill-plan.md b/docs/plans/2026-04-05-001-feat-public-retro-skill-plan.md
new file mode 100644
index 00000000..eee98b09
--- /dev/null
+++ b/docs/plans/2026-04-05-001-feat-public-retro-skill-plan.md
@@ -0,0 +1,326 @@
+---
+title: "feat: Make printing-press-retro a public skill with GitHub issue output"
+type: feat
+status: complete
+date: 2026-04-05
+origin: docs/brainstorms/2026-04-04-public-retro-skill-requirements.md
+---
+
+# feat: Make printing-press-retro a public skill with GitHub issue output
+
+## Overview
+
+Move the `/printing-press-retro` skill from private (`.claude/skills/`) to public (`skills/`), change its output from local `docs/retros/` files to GitHub issues on `mvanhorn/cli-printing-press` with scrubbed artifact uploads via catbox.moe, and adapt the methodology for external users who don't have the repo checked out.
+
+## Problem Frame
+
+The retro skill captures high-value machine improvement signals but is only available to repo maintainers. External plugin users discover the same issues but have no structured way to contribute findings back. Making it public turns every generation run into a potential machine improvement. (see origin: `docs/brainstorms/2026-04-04-public-retro-skill-requirements.md`)
+
+## Requirements Trace
+
+- R1. Full retro methodology adapted for dual context (in-repo vs external)
+- R2. Retro distilled into well-structured GitHub issue body
+- R3. Manuscript zip uploaded to catbox.moe, linked from issue
+- R4. CLI source zip (excluding binary, vendor/, go.sum) uploaded to catbox.moe
+- R5. Layered secrets scrub: exact-value + pattern-based scanning before upload
+- R6. GitHub issue creation via `gh issue create --repo mvanhorn/cli-printing-press`
+- R7. Context-aware: in-repo gets local save + offer-to-plan; external gets issue-only
+- R8. Retro always saved to manuscript proofs
+- R9. Refuse if no manuscripts exist
+- R10. Clarify which API if ambiguous
+- R11. Default to most recent run
+- R12. Move to `skills/`, apply reference file pattern
+- R13. Remove private skill after verification
+- R14. Graceful degradation when `gh` auth fails
+- R15. Graceful degradation when catbox upload fails
+
+## Scope Boundaries
+
+- The analytical methodology (classification, scorer audit, cross-API stress tests) is adapted for two contexts, not redesigned
+- No Go code changes. No manifest changes (skills auto-discovered)
+- No issue labels, milestones, or project board assignment
+- One issue per retro run (not per finding)
+
+## Context & Research
+
+### Relevant Code and Patterns
+
+- **Setup contract**: `<!-- PRESS_SETUP_CONTRACT_START -->` block used by 4/5 public skills — sets `PRESS_HOME`, `PRESS_MANUSCRIPTS`, `PRESS_LIBRARY`, detects repo vs standalone
+- **Reference file pattern**: Main skill has 11 reference files. Inline pointers like `Read [references/foo.md](references/foo.md) when X`
+- **Secret protection**: `skills/printing-press/references/secret-protection.md` — exact-value scanning with `grep -F`, python3 literal replacement, HAR auth stripping
+- **Public skill frontmatter**: `name`, `description` (with trigger phrases), `version`, `min-binary-version`, `allowed-tools`
+- **Publish skill**: Best analog for `gh` CLI usage — `gh auth status`, `gh pr create` with HEREDOC body, `--repo` targeting, full https:// URLs
+
+### Institutional Learnings
+
+- **Never mutate source directory** (`docs/solutions/best-practices/validation-must-not-mutate-source-directory-2026-03-29.md`): Scrub copies in a temp directory, not originals. Zip the temp copy, upload that.
+- **Path traversal protection** (`docs/solutions/security-issues/filepath-join-traversal-with-user-input-2026-03-29.md`): Validate user-provided API names for traversal characters, verify resolved paths stay under `~/printing-press/`.
+- **Skill instruction reliability ~70-90%** (`docs/retros/2026-04-01-steam-run5-retro.md`): The secrets scrub must use deterministic bash commands in reference files, not vague prose instructions.
+- **Shared setup contract** (`docs/retros/2026-04-03-dominos-retro.md`): Use the standard `PRESS_SETUP_CONTRACT` block to inherit binary detection fixes. **However**: the standard contract exits early if the printing-press binary isn't found. The retro skill doesn't need the binary — it only needs the path variables. A modified contract that skips the binary check is required.
+- **Output layout contract** (`docs/solutions/best-practices/checkout-scoped-printing-press-output-layout-2026-03-28.md`): Canonical paths at `~/printing-press/manuscripts/<api-slug>/<run-id>/` and `~/printing-press/library/<api-slug>-pp-cli/`.
+
+## Key Technical Decisions
+
+- **Modified setup contract (no binary check)**: The standard `PRESS_SETUP_CONTRACT` exits early if the printing-press binary isn't found. The retro skill only needs path variables (`PRESS_HOME`, `PRESS_MANUSCRIPTS`, `PRESS_LIBRARY`), not the binary. Use a slimmed-down contract that resolves paths and detects repo context but skips binary detection entirely. This avoids aborting for external users who installed the plugin but not the Go binary.
+- **Repo detection via marker file, not origin URL**: Check for `cmd/printing-press/main.go` relative to `_scope_dir`. More reliable than parsing `git remote get-url origin` which breaks on forks and SSH vs HTTPS.
+- **Three reference files extracted from SKILL.md**: `references/secret-scrubbing.md` (deterministic scrub commands), `references/issue-template.md` (GitHub issue body format), `references/artifact-packaging.md` (zip + catbox upload). Keeps SKILL.md focused on the analytical methodology.
+- **Scrub-on-copy pattern**: Copy artifacts to a temp directory, scrub the copies, zip the scrubbed copies, upload. Never modify `~/printing-press/manuscripts/` or `~/printing-press/library/` in place.
+- **Phase 5.5 work units adapt to context**: In-repo runs use Glob/Grep tool invocations (not bash `find`/`grep`) to resolve target file paths. External runs describe target components by name and acceptance criteria without file paths.
+- **Phase 6 bifurcates on context**: In-repo: save to `docs/retros/` + manuscript proofs + issue + offer `/ce:plan` (best-effort — guarded by checking skill availability). External: save to manuscript proofs + issue only.
+- **`gh issue create` modeled on publish skill's `gh pr create`**: Check `gh auth status`, build body via HEREDOC, use `--repo mvanhorn/cli-printing-press`, return full `https://` URLs.
+- **Catbox upload via curl**: `curl -F "reqtype=fileupload" -F "fileToUpload=@file.zip" https://catbox.moe/user/api.php` returns a direct URL. No auth needed.
+
+## Open Questions
+
+### Resolved During Planning
+
+- **Which phases need conditional logic?** Phase 5.5 (work units: file path resolution) and Phase 6 (save/present: output routing). Phases 1-5 work on manuscripts which are always available. Phase 2 "mine the session" is best-effort — if no conversation history exists, note it and proceed with manuscript evidence only.
+- **GitHub issue body template**: Full retro goes to manuscript proofs and as a linked artifact. Issue body contains a distilled summary: session stats, priority tables (Do Now / Do Next / Skip), work unit summaries, and artifact download links. Not the full 6-question classification per finding — that's in the attached retro document.
+- **Skill frontmatter**: Add `version: 0.1.0`. No `min-binary-version` needed — the retro skill does not invoke the printing-press binary directly (it reads manuscripts and runs `gh`). Update description and trigger phrases for external users.
+- **Do we need `min-binary-version`?**: No. The retro skill reads manuscript files and invokes `gh`/`curl`. It does not call the printing-press binary. The setup contract is still useful for `PRESS_HOME`/`PRESS_MANUSCRIPTS` path resolution, but no binary version check is needed.
+
+- **Secret scanner regex patterns (pinned)**: The following patterns are specified for the pattern-based scanner. Implementation may tune thresholds but the pattern list is fixed:
+ - `sk_live_[A-Za-z0-9]{20,}` — Stripe live keys
+ - `sk_test_[A-Za-z0-9]{20,}` — Stripe test keys
+ - `ghp_[A-Za-z0-9]{36,}` — GitHub personal access tokens
+ - `gho_[A-Za-z0-9]{36,}` — GitHub OAuth tokens
+ - `Bearer [A-Za-z0-9._~+/=-]{20,}` — Bearer tokens in code
+ - `eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}` — JWT-shaped strings
+ - `(SECRET|TOKEN|KEY|PASSWORD)\s*[:=]\s*["'][^"']{16,}["']` — env var assignments with secret-like values
+ - Redaction format: `<REDACTED:pattern-name>` (e.g., `<REDACTED:stripe-live-key>`)
+
+### Deferred to Implementation
+
+- **False-positive tuning**: Run the pinned regex patterns against real manuscripts to verify false-positive rate. Adjust match thresholds if needed but do not drop pattern categories.
+- **Issue body character limits**: GitHub issue bodies have a practical limit around 65KB. If the distilled retro exceeds this (unlikely for a single API retro), truncate with "Full retro in attached artifact" and retry. This is a distinct error path from R14 (auth failure) — handle it separately.
+
+## Implementation Units
+
+- [ ] **Unit 1: Create reference files**
+
+**Goal:** Write the three reference files that contain conditional implementation details extracted from the main SKILL.md.
+
+**Requirements:** R5, R3, R4, R2, R12
+
+**Dependencies:** None
+
+**Files:**
+- Create: `skills/printing-press-retro/references/secret-scrubbing.md`
+- Create: `skills/printing-press-retro/references/artifact-packaging.md`
+- Create: `skills/printing-press-retro/references/issue-template.md`
+
+**Approach:**
+
+`references/secret-scrubbing.md`:
+- Header: "Read this file during Phase 6 before zipping and uploading artifacts."
+- Layer 1: Exact-value scanning adapted from `skills/printing-press/references/secret-protection.md`. `grep -F` for session API key value, python3 literal replacement. 16-char minimum guard.
+- Layer 2: Pattern-based scanning with deterministic bash commands (not prose instructions). Use the pinned regex patterns from the "Resolved During Planning" section above. Each pattern gets a concrete `grep -E` command block the agent copies and runs.
+- Redaction: Replace matched values with `<REDACTED:pattern-name>` to preserve debugging context.
+- HAR stripping: Include the `jq` pipeline from `secret-protection.md` for any HAR files in manuscripts.
+- **Critical**: All scrub operations work on the temp copy, never originals.
+
+`references/artifact-packaging.md`:
+- Header: "Read this file during Phase 6 when packaging artifacts for upload."
+- Step 1: Create temp staging directory (`mktemp -d`)
+- Step 2: Copy manuscript run directory and CLI source to staging (excluding binary, vendor/, go.sum, .git/)
+- Step 3: Read and apply `references/secret-scrubbing.md` on the staging copies
+- Step 4: Zip each into named archives: `<api-slug>-manuscripts.zip`, `<api-slug>-cli-source.zip`
+- Step 5: Upload each to catbox.moe via curl, capture returned URLs
+- Step 6: Clean up temp directory
+- Include fallback behavior: if catbox upload fails, preserve local zips and return empty URLs with error message
+
+`references/issue-template.md`:
+- Header: "Read this file during Phase 6 when creating the GitHub issue."
+- Defines the issue title format: `Retro: <API name> — <N> findings, <M> work units`
+- Defines the issue body structure as a markdown template:
+ - Session stats table (API, spec source, scorecard, verify rate, fix loops, manual edits)
+ - Priority summary tables (Do Now, Do Next, Skip — one-line per finding)
+ - Work unit summaries (goal, component, acceptance criteria — no file paths for external users)
+ - Artifact links section (catbox URLs for manuscripts and CLI source zips)
+ - "Generated by `/printing-press-retro`" footer
+- Not the full retro — that's attached as a separate artifact
+
+**Patterns to follow:**
+- `skills/printing-press/references/secret-protection.md` — deterministic bash commands, not prose
+- `skills/printing-press/references/sniff-capture.md` — header format with load condition
+
+**Test scenarios:**
+- Happy path: Reference files load correctly when the skill reaches Phase 6
+- Edge case: Manuscript with no HAR files — HAR stripping step skips cleanly
+- Edge case: No API key in session (exact-value scan layer skips, pattern scan still runs)
+- Error path: catbox curl returns non-200 — packaging preserves local zips, returns empty URLs with error
+
+**Verification:**
+- All three files exist under `skills/printing-press-retro/references/`
+- Each has a header stating when to load it
+- Secret scrubbing uses concrete bash commands, not instructional prose
+- No references to absolute paths or user-specific directories
+
+---
+
+- [ ] **Unit 2: Create public SKILL.md**
+
+**Goal:** Write the public retro skill SKILL.md that adapts the 6-phase methodology for dual context (in-repo and external), integrates the reference files, and handles the full lifecycle from guard rails through issue creation.
+
+**Requirements:** R1, R6, R7, R8, R9, R10, R11, R12, R14, R15
+
+**Dependencies:** Unit 1 (reference files must exist for inline pointers)
+
+**Files:**
+- Create: `skills/printing-press-retro/SKILL.md`
+
+**Approach:**
+
+Structure of the new SKILL.md (~350-400 lines estimated, down from 606 + new output logic, because conditional content is extracted to references):
+
+**Frontmatter:**
+```yaml
+name: printing-press-retro
+description: >
+ Run a retrospective after generating a CLI. Identifies systemic improvements
+ to the printing press machine — generator templates, Go binary, skill
+ instructions, catalog. Creates a GitHub issue with findings and artifacts
+ so anyone can fix the machine. Use after any /printing-press run.
+ Trigger phrases: "retro", "retrospective", "what went wrong", "improve
+ the press", "post-mortem", "lessons learned", "what can we improve",
+ "file a retro", "submit findings".
+version: 0.1.0
+allowed-tools:
+ - Bash
+ - Read
+ - Glob
+ - Grep
+ - Write
+ - Agent
+ - AskUserQuestion
+```
+
+No `min-binary-version` — skill reads manuscripts and runs `gh`/`curl`, not the binary.
+
+**Modified setup contract (path-only, no binary check):**
+- Use a slimmed-down version of the `PRESS_SETUP_CONTRACT` that resolves `_scope_dir`, `PRESS_HOME`, `PRESS_MANUSCRIPTS`, `PRESS_LIBRARY` and creates directories — but **omits the binary detection and early-exit guard**. The standard contract exits with `return 1 || exit 1` if the binary isn't found, which would abort for external users who don't have it installed. The retro skill never invokes the binary.
+- After path resolution, detect context: `IN_REPO=false; if [ -f "$_scope_dir/cmd/printing-press/main.go" ]; then IN_REPO=true; fi`
+- Mark the contract block with `<!-- RETRO_SETUP_START -->` / `<!-- RETRO_SETUP_END -->` comments to distinguish from the standard binary-requiring contract
+
+**Guard rails (after setup, using resolved paths):**
+- Check `$PRESS_MANUSCRIPTS` exists and is non-empty (R9)
+- If user provided an API name argument, validate for path traversal (no `/`, `\`, `..`), verify resolved path stays under `$PRESS_MANUSCRIPTS`
+- If no API name and multiple APIs exist, list them with most recent run dates, ask user to choose (R10)
+- If API has multiple runs, default to most recent, allow user to specify run ID (R11)
+
+**Phases 1-4 (analytical methodology):**
+- Carry forward from current private skill with minimal changes
+- Phase 1 (Gather evidence): uses `$PRESS_MANUSCRIPTS` and `$PRESS_LIBRARY` paths from setup contract
+- Phase 2 (Mine the session): Add note: "If running in a fresh conversation without generation history, note this and proceed with manuscript evidence only. Mark session-dependent findings as 'evidence: manuscripts only'."
+- Phase 3 (Classify findings): Unchanged — the six questions framework works in both contexts
+- Phase 4 (Prioritize): Unchanged
+
+**Phase 5 (Write the retro):**
+- Same template as current skill
+- Save to `$PRESS_MANUSCRIPTS/<api>/<run-id>/proofs/<stamp>-retro-<api>-pp-cli.md` (R8, always)
+
+**Phase 5.5 (Work units):**
+- Conditional on `IN_REPO`:
+ - In-repo: resolve target file paths via `find`/`grep` on `$_scope_dir` (current behavior)
+ - External: describe components by name (e.g., "Generator templates in `internal/generator/`"), acceptance criteria, and complexity — skip file path resolution
+
+**Phase 6 (Package, upload, and present):**
+- Read and apply `references/artifact-packaging.md` — copy, scrub, zip, upload to catbox
+- Read and apply `references/issue-template.md` — build the issue body from retro findings
+- Check `gh auth status`: if authenticated, create issue via `gh issue create --repo mvanhorn/cli-printing-press --title "..." --body "$(cat <<'EOF' ... EOF)"`. Print full issue URL.
+- If `gh` fails (R14): save retro document and zips locally, print catbox URLs if available, tell user to file manually
+- If catbox failed (R15): create issue without artifact links, note artifacts couldn't be uploaded, tell user local zips are at `<path>`
+- If `gh issue create` fails due to body size: truncate the issue body to summary tables + artifact links, add "Full retro analysis in attached artifacts", retry
+- Conditional on `IN_REPO`: also save to `docs/retros/YYYY-MM-DD-<api>-retro.md` (R7)
+- Conditional on `IN_REPO`: offer to plan via `/ce:plan` — best-effort, guarded by checking if the compound-engineering plugin is available. If not available, skip silently (this is existing behavior being carried forward, not a new capability)
+- External: show issue URL and done
+
+**Cardinal rules (inline, always loaded):**
+- Never upload un-scrubbed artifacts
+- Never modify source manuscripts or library directories
+- Never skip the secrets scrub, even if the pipeline already ran one
+- The retro is about the machine, not the CLI
+
+**Patterns to follow:**
+- `skills/printing-press-score/SKILL.md` — frontmatter structure, setup contract placement, CLI resolution logic
+- `skills/printing-press-publish/SKILL.md` — `gh auth status` checking, `gh pr create` HEREDOC pattern (adapt for `gh issue create`)
+- `.claude/skills/printing-press-retro/SKILL.md` — analytical methodology (Phases 1-5.5), classification framework, scorer audit protocol
+
+**Test scenarios:**
+- Happy path: External user runs `/printing-press-retro` with one API in manuscripts → retro analysis runs, artifacts uploaded to catbox, issue created on repo, full URL displayed
+- Happy path: In-repo user runs retro → same as above plus local save to `docs/retros/` and offer-to-plan
+- Edge case: Multiple APIs in manuscripts, no argument → skill lists APIs with dates, asks user to choose
+- Edge case: Fresh conversation (no generation history) → Phase 2 notes limited evidence, proceeds with manuscripts only
+- Error path: `gh auth status` fails → retro saved locally, catbox URLs printed if available, manual filing instructions
+- Error path: catbox upload fails → issue created without artifact links, local zips preserved
+- Error path: Both `gh` and catbox fail → retro saved to manuscripts only, all local paths printed
+- Edge case: User provides API name with path traversal (`../../etc`) → rejected with clear error
+- Edge case: No manuscripts → refuses to run with clear message (R9)
+
+**Verification:**
+- Skill discovered as `cli-printing-press:printing-press-retro` in Claude Code skill list
+- Reference files loaded conditionally (only during Phase 6)
+- Setup contract resolves `PRESS_HOME`/`PRESS_MANUSCRIPTS` correctly
+- Guard rails trigger before any analysis work
+- In-repo detection works via marker file check
+
+---
+
+- [ ] **Unit 3: Remove private skill and verify**
+
+**Goal:** Delete the private retro skill and verify the public one is discovered correctly.
+
+**Requirements:** R13
+
+**Dependencies:** Unit 2
+
+**Files:**
+- Delete: `.claude/skills/printing-press-retro/SKILL.md`
+
+**Approach:**
+- Remove `.claude/skills/printing-press-retro/` directory entirely
+- Verify `skills/printing-press-retro/SKILL.md` exists with correct frontmatter
+- Start a new Claude Code session from the repo to verify `cli-printing-press:printing-press-retro` appears in the skill list
+- Verify the old private skill no longer appears
+- Check that `.claude/scripts/install-internal-skills.sh` no longer picks up the retro (it iterates `.claude/skills/` — removing the directory is sufficient)
+- **Migration note**: Users who previously ran `install-internal-skills.sh` will have a stale copy at `~/.claude/skills/printing-press-retro/`. Both the stale private skill and the new public skill would be visible. Add a note in the skill description or a one-time migration hint that old copies at `~/.claude/skills/printing-press-retro/` should be removed
+
+**Patterns to follow:**
+- Verify via the same discovery mechanism other public skills use — check skill list output
+
+**Test expectation: none** — this is a delete + verify step with no behavioral code
+
+**Verification:**
+- `.claude/skills/printing-press-retro/` no longer exists
+- `skills/printing-press-retro/SKILL.md` exists with valid frontmatter
+- `skills/printing-press-retro/references/` contains three reference files
+- New Claude Code session shows `cli-printing-press:printing-press-retro` in available skills
+
+## System-Wide Impact
+
+- **Interaction graph**: The retro skill calls `gh issue create` (new pattern in this plugin), `curl` to catbox.moe (new external dependency), and conditionally invokes `/ce:plan` (existing pattern from compound-engineering plugin)
+- **Error propagation**: Failures in catbox/gh degrade gracefully to local-only output. The retro analysis is never lost — worst case it's saved to manuscript proofs only.
+- **State lifecycle risks**: Scrub-on-copy pattern prevents accidental mutation of user's manuscripts/library. Temp directory cleanup handles partial failures.
+- **API surface parity**: No other skill creates GitHub issues — this establishes a new pattern. Future skills that need issue creation should follow this pattern.
+- **Unchanged invariants**: The analytical methodology (Phases 1-5.5) is preserved. The setup contract is the standard shared block. The manuscript layout contract is unchanged.
+
+## Risks & Dependencies
+
+| Risk | Mitigation |
+|------|------------|
+| catbox.moe goes down or changes API | Graceful degradation (R15): issue created without artifacts, local zips preserved. catbox is simple enough to swap for another anonymous upload service if needed. |
+| Secrets leak through pattern-matching gaps | Defense in depth: exact-value scan catches session key, pattern scan catches common formats, HAR stripping catches auth headers. Manual review of first few retro issues recommended. |
+| Large manuscripts exceed catbox upload limit | catbox supports 200MB uploads. Largest observed manuscript is 268KB. Even with CLI source (~2MB), well within limits. |
+| External users don't have `gh` installed | R14 fallback: save locally, print instructions. `gh` is widely installed by Claude Code users since it's recommended for GitHub workflows. |
+| Phase 2 quality degrades without conversation history | Documented limitation. Manuscripts provide strong signal for Phases 1/3/4/5. Phase 2 "mine the session" is explicitly marked as best-effort for fresh conversations. |
+
+## Sources & References
+
+- **Origin document:** [docs/brainstorms/2026-04-04-public-retro-skill-requirements.md](docs/brainstorms/2026-04-04-public-retro-skill-requirements.md)
+- Current private skill: `.claude/skills/printing-press-retro/SKILL.md`
+- Setup contract pattern: `skills/printing-press-score/SKILL.md` (lines 36-73)
+- Secret protection: `skills/printing-press/references/secret-protection.md`
+- Publish skill gh pattern: `skills/printing-press-publish/SKILL.md`
+- Validation-must-not-mutate: `docs/solutions/best-practices/validation-must-not-mutate-source-directory-2026-03-29.md`
+- Path traversal protection: `docs/solutions/security-issues/filepath-join-traversal-with-user-input-2026-03-29.md`
+- Related issue: [mvanhorn/cli-printing-press#129](https://github.com/mvanhorn/cli-printing-press/issues/129)
diff --git a/skills/printing-press-polish/SKILL.md b/skills/printing-press-polish/SKILL.md
index 884fc831..6ff53289 100644
--- a/skills/printing-press-polish/SKILL.md
+++ b/skills/printing-press-polish/SKILL.md
@@ -23,7 +23,7 @@ allowed-tools:
Polish a generated CLI so it passes verification and is ready to publish.
-The retro improves the generator. Polish improves the generated CLI. The actual
+The retro improves the Printing Press. Polish improves the generated CLI. The actual
fix protocol lives in the `polish-worker` agent — this skill resolves the CLI,
checks locks, dispatches the agent, and offers to publish.
diff --git a/skills/printing-press-publish/SKILL.md b/skills/printing-press-publish/SKILL.md
index 9974e422..6ac475c4 100644
--- a/skills/printing-press-publish/SKILL.md
+++ b/skills/printing-press-publish/SKILL.md
@@ -716,10 +716,10 @@ Before creating the PR, verify that no secrets leaked into the packaged CLI.
**This matters because the library repo is public.** A leaked API key in a PR is
a security incident — anyone can see it, even if the PR is later closed.
-### What the machine checks (deterministic)
+### What the Printing Press checks (deterministic)
The generation skill (`/printing-press`) runs an exact-value scan during Phase 5.5
-if the user provided an API key. By the time publish runs, the machine's own
+if the user provided an API key. By the time publish runs, the Printing Press's own
mistakes should already be caught. But the user may have edited files between
generation and publish.
diff --git a/skills/printing-press-retro/SKILL.md b/skills/printing-press-retro/SKILL.md
new file mode 100644
index 00000000..1d2862df
--- /dev/null
+++ b/skills/printing-press-retro/SKILL.md
@@ -0,0 +1,565 @@
+---
+name: printing-press-retro
+description: >
+ Run a retrospective after generating a CLI. Identifies systemic improvements
+ to the Printing Press — templates, Go binary, skill instructions, catalog —
+ so the next CLI comes out better. Creates a GitHub issue with actionable
+ findings when there are Printing Press fixes to make.
+ Use after any /printing-press run.
+ Trigger phrases: "retro", "retrospective", "what went wrong", "improve
+ the press", "post-mortem", "lessons learned", "what can we improve",
+ "file a retro", "submit findings".
+version: 0.1.0
+allowed-tools:
+ - Bash
+ - Read
+ - Glob
+ - Grep
+ - Write
+ - Agent
+ - AskUserQuestion
+---
+
+# /printing-press-retro
+
+Analyze a Printing Press session to find ways to improve the system that produces
+CLIs — the Go binary, templates, skills, and catalog. Not fixes to the specific CLI
+that was just printed, but improvements so the *next* CLI comes out stronger with
+less manual effort.
+
+This goes beyond bugs. The most valuable findings are often the work that *succeeded
+but shouldn't have been necessary* — features you built by hand that the Printing
+Press should have emitted, friction that recurs on every generation, and optimizations
+you discovered that should become defaults.
+
+The retro creates a GitHub issue on the printing-press repo with your findings and
+artifacts so maintainers (or an AI agent) can fix the Printing Press.
+
+## Terminology
+
+- **The Printing Press**: The whole system that produces CLIs. Use this name in all
+ user-facing output (issues, retros, prompts). It has four subsystems:
+ - **Generator** — templates that emit Go code (`internal/generator/`)
+ - **Scorer** — tools that grade the output: verify, dogfood, scorecard
+ - **Skills** — SKILL.md instructions that guide Claude during generation
+ - **Binary** — the Go CLI itself: commands, flags, parsers (`cmd/printing-press/`)
+- **Printed CLI**: A CLI produced by the Printing Press for a specific API (e.g.,
+ `notion-pp-cli`). Printed-CLI fixes only help that one CLI.
+
+Use "the Printing Press" when talking about the system. Use the subsystem name when
+pointing a developer at what to fix — "fix the scorer" and "fix the generator" are
+different PRs.
+
+## Cardinal rules
+
+- The retro is about the Printing Press, not the printed CLI. Do not propose fixes to one specific generated CLI.
+- **Never upload un-scrubbed artifacts.** All artifacts go through the secrets scrub before upload.
+- **Never modify source directories.** Manuscripts and library directories are read-only. Scrub operations work on temporary copies.
+- **Never skip the secrets scrub,** even if the generation pipeline already ran one. Defense in depth.
+- **Never work around a scorer bug in the Printing Press.** If a scoring tool penalizes something incorrectly, the fix goes in the scoring tool.
+
+## Setup
+
+<!-- RETRO_SETUP_START -->
+```bash
+# Path-only setup — no binary detection required.
+# The retro skill reads manuscripts and runs gh/curl. It does not invoke the
+# printing-press binary. This avoids aborting for users who installed the
+# plugin but not the Go binary.
+
+_scope_dir="$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")"
+_scope_dir="$(cd "$_scope_dir" && pwd -P)"
+
+PRESS_HOME="$HOME/printing-press"
+PRESS_MANUSCRIPTS="$PRESS_HOME/manuscripts"
+PRESS_LIBRARY="$PRESS_HOME/library"
+
+mkdir -p "$PRESS_MANUSCRIPTS" "$PRESS_LIBRARY"
+
+# Detect whether we're inside the printing-press repo
+IN_REPO=false
+if [ -f "$_scope_dir/cmd/printing-press/main.go" ]; then
+ IN_REPO=true
+ REPO_ROOT="$_scope_dir"
+ echo "Running from printing-press repo: $REPO_ROOT"
+fi
+```
+<!-- RETRO_SETUP_END -->
+
+## Guard rails
+
+### Nothing to retro
+
+```bash
+if [ ! -d "$PRESS_MANUSCRIPTS" ] || [ -z "$(ls -A "$PRESS_MANUSCRIPTS" 2>/dev/null)" ]; then
+ echo "No manuscripts found. Run /printing-press first to generate a CLI."
+ exit 1
+fi
+```
+
+### Resolve which API
+
+If the user passed an API name as an argument, use that. Validate for path traversal:
+
+```bash
+# Reject names with /, \, or ..
+if echo "$USER_API_NAME" | grep -qE '[/\\]|\.\.'; then
+ echo "Invalid API name: '$USER_API_NAME'. Names cannot contain path separators or '..'."
+ exit 1
+fi
+
+# Verify resolved path stays under PRESS_MANUSCRIPTS
+RESOLVED="$(cd "$PRESS_MANUSCRIPTS/$USER_API_NAME" 2>/dev/null && pwd -P)"
+case "$RESOLVED" in
+ "$PRESS_MANUSCRIPTS"/*) ;; # OK
+ *) echo "Invalid API name: path resolves outside manuscripts directory."; exit 1 ;;
+esac
+```
+
+If no API name was provided and multiple APIs exist, list them with their most recent
+run dates and ask the user to choose:
+
+```bash
+echo "Multiple APIs found in manuscripts:"
+for api_dir in "$PRESS_MANUSCRIPTS"/*/; do
+ api_name=$(basename "$api_dir")
+ latest=$(ls -t "$api_dir" 2>/dev/null | head -1)
+ echo " - $api_name (latest run: $latest)"
+done
+```
+
+Use `AskUserQuestion` to let the user pick.
+
+### Resolve which run
+
+If the API has multiple runs, default to the most recent. If the user specified a
+run ID, use that. Otherwise:
+
+```bash
+API_DIR="$PRESS_MANUSCRIPTS/$API_NAME"
+RUN_ID=$(ls -t "$API_DIR" 2>/dev/null | head -1)
+RUN_DIR="$API_DIR/$RUN_ID"
+
+echo "Retro for: $API_NAME (run $RUN_ID)"
+echo "Manuscripts: $RUN_DIR"
+```
+
+### Resolve CLI directory
+
+```bash
+API_SLUG="$API_NAME"
+CLI_NAME="${API_SLUG}-pp-cli"
+CLI_DIR="$PRESS_LIBRARY/$CLI_NAME"
+
+if [ ! -d "$CLI_DIR" ]; then
+ # Try without -pp-cli suffix (legacy naming)
+ CLI_DIR="$PRESS_LIBRARY/$API_NAME"
+fi
+
+if [ ! -d "$CLI_DIR" ]; then
+ echo "WARNING: CLI directory not found at $PRESS_LIBRARY/$CLI_NAME"
+ echo "Proceeding with manuscripts only — CLI source will not be included in artifacts."
+ CLI_DIR=""
+fi
+```
+
+## When to run
+
+Best results come from running in the same conversation where the CLI was generated
+(post-shipcheck) — the retro can mine the full conversation history for errors,
+retries, manual edits, and discoveries.
+
+If running in a fresh conversation, the retro proceeds with manuscript evidence only.
+Phase 2 marks session-dependent findings as "evidence: manuscripts only."
+
+## Phase 1: Gather evidence
+
+Read all artifacts from the run:
+
+1. **Research brief** — `$RUN_DIR/research/*brief*`
+2. **Absorb manifest** — `$RUN_DIR/research/*absorb*`
+3. **Shipcheck proof** — `$RUN_DIR/proofs/*shipcheck*`
+4. **Build log** — `$RUN_DIR/proofs/*build-log*` (if exists)
+5. **Live smoke log** — `$RUN_DIR/proofs/*live-smoke*` (if exists)
+6. **The generated CLI** — `$CLI_DIR/` (if available)
+
+Also gather the scorecard, verify pass rate, and dogfood report (from the shipcheck
+proof or by re-running the tools if `IN_REPO` is true and the binary is available).
+
+## Phase 2: Mine the session
+
+Scan the conversation history for six categories of signal. Every finding becomes a
+row in Phase 3 — don't filter yet, just collect.
+
+**If running in a fresh conversation without generation history:** Note this and
+proceed with manuscript evidence only. Focus on what the manuscripts reveal — scorecard
+gaps, verify failures, dogfood issues, and obvious template patterns in the CLI source.
+Mark session-dependent findings as "evidence: manuscripts only."
+
+### 2a. Errors and retries
+
+Any time a command failed and was re-run, a build broke, or the Printing Press produced
+code that didn't compile. What broke and what fixed it?
+
+### 2b. Manual code edits
+
+Every hand-edit to generated code is a signal — the Printing Press *should have* gotten
+it right but didn't. These are the highest-value findings because they point directly
+at template gaps.
+
+### 2c. Features built from scratch
+
+Features that had to be written entirely by hand. Ask: is this a feature class the
+Printing Press could reasonably emit, or is it genuinely custom?
+
+### 2d. Recurring friction
+
+Work that happens on *every* generation, not just this one. For each: **is this
+inherent to the approach, or can the Printing Press eliminate it?**
+
+Propose at least two possible fixes at different levels (generator templates, binary
+post-processing, skill instruction) and assess which is most durable.
+
+### 2e. Discovered optimizations
+
+Improvements noticed during the session — UX ideas, performance improvements, new
+command patterns, output format improvements. Could this optimization be detected
+automatically and applied by the Printing Press?
+
+### 2f. Scorer accuracy audit
+
+Before proposing Printing Press fixes to improve scores, check whether the scoring
+itself is correct. **Changing the Printing Press to satisfy a broken scorer is worse
+than doing nothing.**
+
+For each score penalty from dogfood, verify, and scorecard:
+
+1. **Trace the scorer's logic.** Read the scoring tool's source code to understand
+ exactly what it checks. Don't guess.
+2. **Test the scorer's assumption against reality.** Does the CLI actually have the
+ problem the scorer claims?
+3. **Classify the penalty:**
+ - **Scorer is correct** — the CLI genuinely has this problem.
+ - **Scorer is wrong** — the CLI is fine; the scoring tool has a bug.
+ - **Scorer is partially right** — both could be better.
+
+Common scorer bugs: name derivation mismatches, grep-based detection missing patterns,
+file exclusions too broad, section-counting heuristics.
+
+The scorer audit is not optional. Every finding from a score penalty must have a
+"Scorer correct?" assessment before proposing a fix direction.
+
+## Phase 3: Classify findings
+
+For each finding from Phase 2, answer these seven questions. Skip findings that only
+affect this specific API and wouldn't recur.
+
+**1. What happened?** One sentence — the symptom, not the fix.
+
+**2. Is the scorer correct?** (mandatory for score-penalty findings)
+- **Scorer correct** → fix the Printing Press (templates, binary, or skill)
+- **Scorer wrong** → fix the scoring tool, not the Printing Press
+- **Both** → fix both, label which is primary
+
+**3. What category?**
+
+| Category | Description |
+|----------|-------------|
+| **Bug** | Generated code is wrong |
+| **Scorer bug** | Scoring tool reports a false positive |
+| **Template gap** | No template for a common pattern |
+| **Assumption mismatch** | Printing Press assumes X but API uses Y |
+| **Recurring friction** | Happens every generation, might be inherent |
+| **Missing scaffolding** | Feature class the Printing Press could emit but doesn't |
+| **Default gap** | Printing Press emits a wrong or placeholder default |
+| **Discovered optimization** | Improvement found during use |
+| **Skill instruction gap** | Skill told Claude wrong thing or missed a step |
+
+**4. Where in the Printing Press does this originate?**
+
+| Component | Path |
+|-----------|------|
+| Generator templates | `internal/generator/` |
+| Spec parser | `internal/spec/` |
+| OpenAPI parser | `internal/openapi/` |
+| Catalog | `catalog/` |
+| Main skill | `skills/printing-press/SKILL.md` |
+| Verify/dogfood/scorecard | CLI commands |
+
+**5. Blast radius and fallback cost — should the Printing Press handle this?**
+
+**Step A: Cross-API stress test.** Test across API shapes (standard REST, proxy-envelope,
+RPC-style) and input methods (OpenAPI, crowd-sniffed, HAR-sniffed, no spec).
+
+**Step B: Estimate frequency.** Every API / Most APIs / API subclass (name it) / This API only.
+
+**Step C: Assess fallback cost.** How reliably will Claude catch and fix this across every
+future API? A "simple" edit Claude forgets 30% of the time means 30% ship with the defect.
+
+**Step D: Make the tradeoff.** Default is **fix it in the Printing Press**. The burden of
+proof is on *not* fixing. Skip only when the behavior is unlikely to recur across 50
+different APIs.
+
+When the finding applies to an API subclass, include: Condition (when to activate),
+Guard (when to skip), Frequency estimate.
+
+**6. Is this inherent or fixable?** Push hard on whether smarter templates, a
+post-processing step, or better spec analysis could eliminate the friction. If inherent,
+propose the cheapest mitigation.
+
+**7. What is the durable fix?** Prefer: template fix > binary post-processing > skill instruction.
+
+## Phase 4: Prioritize
+
+Group findings into three buckets using judgment, not a formula:
+
+- **Fix the scorer** — scoring tool is wrong. Highest priority because a wrong scorer
+ distorts every future retro.
+- **Do** — score is correct, Printing Press fix is warranted. Split into "Do now" (scoped,
+ immediate) and "Do next" (needs design/planning).
+- **Skip** — unlikely to recur. State why.
+
+No numerical scoring formulas. State the reasoning in words.
+
+## Phase 5: Write the retro
+
+Write the full retro document using this template:
+
+```markdown
+# Printing Press Retro: <API name>
+
+## Session Stats
+- API: <name>
+- Spec source: <catalog/sniffed/docs/HAR>
+- Scorecard: <score>/100 (<grade>)
+- Verify pass rate: <X>%
+- Fix loops: <N>
+- Manual code edits: <N>
+- Features built from scratch: <N>
+
+## Findings
+
+### 1. <Title> (<category>)
+- **What happened:** ...
+- **Scorer correct?** Yes / No / Partially. [details]
+- **Root cause:** Component + what's specifically wrong
+- **Cross-API check:** Would this recur?
+- **Frequency:** every API / most / subclass:<name> / this API only
+- **Fallback if the Printing Press doesn't fix it:** ...
+- **Worth a Printing Press fix?** ...
+- **Inherent or fixable:** ...
+- **Durable fix:** ...
+- **Test:** How to verify (positive + negative)
+- **Evidence:** Session moment that surfaced this
+
+## Prioritized Improvements
+
+### Fix the Scorer
+| # | Scorer | Bug | Impact | Fix target |
+|---|--------|-----|--------|------------|
+
+### Do Now
+| # | Fix | Component | Frequency | Fallback Reliability | Complexity | Guards |
+|---|-----|-----------|-----------|---------------------|------------|--------|
+
+### Do Next
+| # | Fix | Component | Frequency | Fallback Reliability | Complexity | Guards |
+|---|-----|-----------|-----------|---------------------|------------|--------|
+
+### Skip
+| # | Fix | Why unlikely to recur |
+|---|-----|----------------------|
+
+## Work Units
+(see Phase 5.5)
+
+## Anti-patterns
+- ...
+
+## What the Printing Press Got Right
+- ...
+```
+
+Save the retro to manuscript proofs (always):
+
+```bash
+RETRO_PROOF_PATH="$PRESS_MANUSCRIPTS/$API_NAME/$RUN_ID/proofs/$(date +%Y%m%d-%H%M%S)-retro-$CLI_NAME.md"
+```
+
+This must complete before Phase 6 Step 1 copies the manuscripts directory to staging.
+
+## Phase 5.5: Plannable work units
+
+Group related findings into coherent work units a planner could pick up directly.
+
+For each "Do now" or "Do next" group:
+
+```markdown
+### WU-1: <Title> (from findings #N, #M, ...)
+- **Goal:** One sentence describing the outcome
+- **Target:** <component and area, e.g., "Generator templates in internal/generator/">
+- **Acceptance criteria:**
+ - positive test: ...
+ - negative test: ...
+- **Scope boundary:** What this does NOT include
+- **Dependencies:** Other work units that must complete first
+- **Complexity:** small / medium / large
+```
+
+**If running from inside the printing-press repo (`IN_REPO=true`):**
+Resolve target file paths using Glob and Grep tool invocations on `$REPO_ROOT` to
+make work units more precise. E.g., use Glob to find `internal/generator/*.go` files,
+Grep to find where sync code is generated.
+
+**If running externally (`IN_REPO=false`):**
+Describe target components by name (e.g., "Generator templates in `internal/generator/`")
+and acceptance criteria without resolved file paths. The fixer will resolve paths when
+they pick up the work.
+
+## Phase 5.6: Issue gate — are there Printing Press improvements?
+
+After prioritization and work units are written, decide whether a GitHub issue is
+warranted. The purpose of the issue is to give someone (human or agent) something to
+fix in the Printing Press. If every finding is specific to this one printed CLI with
+nothing to change in the Printing Press, the issue is noise — there's nothing to act on.
+
+**Skip the GitHub issue if:**
+- Every finding landed in "Skip"
+- All findings are printed-CLI-specific (manual edits that only apply to this one API
+ and wouldn't recur across other CLIs)
+- The "Do Now" and "Do Next" tables are empty and there are no scorer bugs
+
+**Create the GitHub issue if:**
+- There is at least one "Fix the Scorer", "Do Now", or "Do Next" finding — i.e.,
+ something a maintainer or agent could act on in the Printing Press (templates, binary,
+ skills, or scoring tools)
+
+Use judgment. A retro that found three things but all three are "this API has a weird
+auth scheme no other API uses" is not worth an issue. A retro that found one small
+template gap that would help every future CLI *is* worth an issue.
+
+If the issue is skipped, still save the retro locally (manuscript proofs + `docs/retros/`
+if in-repo), present the findings to the user, then jump directly to Phase 6 Step 6
+(present results — adjusted to show local-only paths) and Step 8 (offer next steps).
+
+## Phase 6: Package, upload, and present
+
+### Step 1: Package artifacts into staging folder
+
+Read and apply [references/artifact-packaging.md](references/artifact-packaging.md)
+**through Step 4 only** (create staging dir, copy, scrub, zip). Do not upload or
+clean up yet — the staging folder stays alive until the end of Phase 6.
+
+The staging folder (`$STAGING_DIR`) now contains the scrubbed copies and the zips.
+This is both the review target and the upload source.
+
+### Step 2: Confirm before publishing
+
+*This step only runs if the Phase 5.6 issue gate passed (there are Printing Press findings to act on).*
+
+Before uploading anything, show the user a friendly summary and ask for confirmation
+via `AskUserQuestion`.
+
+> **Ready to submit your retro.**
+>
+> Here's what will happen:
+>
+> - A GitHub issue will be created on [mvanhorn/cli-printing-press](https://github.com/mvanhorn/cli-printing-press) with your **<N> findings** and **<M> work units**
+> - Scrubbed artifact zips will be uploaded to catbox.moe and linked from the issue:
+> - **Manuscripts** (<size>) — research brief, shipcheck proof, build logs
+> - **CLI source** (<size>) — the generated Go code (no binary, no vendor/) *(omit if not available)*
+>
+> **Top findings:**
+> - <1-3 sentence summary of the highest-priority Do Now items>
+>
+> Everything is staged at `<$STAGING_DIR>` if you'd like to inspect the files first.
+
+Options:
+1. **Submit** — upload artifacts and create the issue
+2. **Let me review the files first** — I'll check the staging folder, then come back
+3. **Save locally only** — skip the issue, just save to manuscripts
+
+If the user picks "Let me review the files first," acknowledge and wait. When they
+come back, re-ask with Submit / Save locally only.
+
+If the user picks "Save locally only," skip Steps 3 and 4 — save to manuscript
+proofs (and `docs/retros/` if in-repo), clean up the staging folder, then jump
+to Step 6.
+
+### Step 3: Upload artifacts
+
+Run artifact-packaging.md Step 5 (the catbox upload) using the zips already in
+`$STAGING_DIR`. This produces `$MANUSCRIPTS_URL` and `$CLI_SOURCE_URL`.
+
+### Step 4: Create GitHub issue
+
+Read and apply [references/issue-template.md](references/issue-template.md).
+
+Build the issue body from the retro findings (distilled summary — not the full retro
+document). Create the issue via `gh issue create --repo mvanhorn/cli-printing-press`.
+
+If `gh` is not authenticated or issue creation fails, follow the graceful degradation
+path in the issue-template reference: save locally and print manual filing instructions.
+
+### Step 5: Local save (conditional)
+
+If `IN_REPO=true`, also save the retro to the repo:
+
+```bash
+RETRO_DIR="$REPO_ROOT/docs/retros"
+mkdir -p "$RETRO_DIR"
+RETRO_FILE="$RETRO_DIR/$(date +%Y-%m-%d)-$API_NAME-retro.md"
+```
+
+### Step 6: Present results
+
+After the issue is created, show the user:
+
+> **Retro submitted!**
+>
+> Issue: <full https:// URL>
+>
+> Found <N> findings across <M> work units.
+> *(if artifacts uploaded)* Artifacts: [manuscripts](<URL>) · [CLI source](<URL>)
+
+If the issue wasn't created (user chose local-only, or gh failed), show the local
+save paths instead.
+
+### Step 7: Clean up staging folder
+
+Run artifact-packaging.md Step 7 to delete `$STAGING_DIR`.
+
+### Step 8: Offer next steps
+
+Use `AskUserQuestion`:
+
+**If `IN_REPO=true`:**
+
+> 1. **Plan "Do now" work units** — invoke `/compound-engineering:ce-plan`
+> 2. **Plan a specific work unit** — pick one WU
+> 3. **Done for now**
+
+If the user picks option 1 or 2, try to invoke `compound-engineering:ce-plan`. If
+it's not available, fall back to printing the prompt the user would run manually.
+
+**If `IN_REPO=false`:**
+
+> The printing-press maintainers will review your findings.
+>
+> 1. **Done**
+
+## Rules
+
+- Prefer automatic fixes (templates, binary) over instructional fixes (skill).
+- For recurring friction, always answer "inherent or fixable?" honestly.
+- Be honest about what went well. Protecting good patterns matters.
+- **Bias toward fixing.** When in doubt, fix it — scope narrowly with conditional
+ logic if needed.
+- **Look for broader patterns.** Before skipping, consider whether this is the first
+ sighting of a behavior you'd encounter again.
+- When a fix applies to an API subclass, include the condition AND the guard.
+- **No time estimates.** Use complexity sizing (small/medium/large).
+- Be thorough. Include enough detail that someone reading months later can understand
+ the finding, the reasoning, and the proposed fix without the original conversation.
+- Do not add more phases, documents, or gates to the main printing-press skill.
+ Propose making existing phases smarter or the Printing Press emit better defaults.
diff --git a/skills/printing-press-retro/references/artifact-packaging.md b/skills/printing-press-retro/references/artifact-packaging.md
new file mode 100644
index 00000000..437ffd76
--- /dev/null
+++ b/skills/printing-press-retro/references/artifact-packaging.md
@@ -0,0 +1,165 @@
+# Artifact Packaging and Upload
+
+Read this file during Phase 6, Step 1 (packaging) and Step 3 (uploading).
+
+Steps 1-4 run during Phase 6 Step 1 to prepare artifacts locally.
+Step 5 runs during Phase 6 Step 3 **after the user confirms** they want to submit.
+Step 6 (failure handling) runs if Step 5 encounters errors.
+Step 7 (cleanup) runs at the very end of Phase 6, after everything else is done.
+
+**Cardinal rule:** Never modify the user's source directories. All operations work on
+temporary copies. If anything fails, the user's manuscripts and library are untouched.
+
+## Step 1: Create staging directory
+
+```bash
+STAGING_DIR=$(mktemp -d)
+STAGING_MANUSCRIPTS="$STAGING_DIR/manuscripts"
+STAGING_CLI_SOURCE="$STAGING_DIR/cli-source"
+echo "Staging artifacts in $STAGING_DIR"
+```
+
+## Step 2: Copy artifacts to staging
+
+Copy the manuscript run directory:
+
+```bash
+mkdir -p "$STAGING_MANUSCRIPTS"
+cp -r "$RUN_DIR/." "$STAGING_MANUSCRIPTS/"
+```
+
+Copy the CLI source if available. Skip if `CLI_DIR` is empty (manuscripts-only mode):
+
+```bash
+if [ -n "$CLI_DIR" ] && [ -d "$CLI_DIR" ]; then
+ mkdir -p "$STAGING_CLI_SOURCE"
+ if command -v rsync >/dev/null 2>&1; then
+ rsync -a \
+ --exclude="$CLI_NAME" \
+ --exclude="vendor/" \
+ --exclude="go.sum" \
+ --exclude=".git/" \
+ --exclude="*.test" \
+ --exclude="*.exe" \
+ "$CLI_DIR/" "$STAGING_CLI_SOURCE/"
+ else
+ cp -r "$CLI_DIR/." "$STAGING_CLI_SOURCE/"
+ rm -f "$STAGING_CLI_SOURCE/$CLI_NAME"
+ rm -rf "$STAGING_CLI_SOURCE/vendor" "$STAGING_CLI_SOURCE/.git"
+ rm -f "$STAGING_CLI_SOURCE/go.sum"
+ find "$STAGING_CLI_SOURCE" \( -name "*.test" -o -name "*.exe" \) -delete 2>/dev/null
+ fi
+else
+ echo "No CLI source directory available. Packaging manuscripts only."
+ STAGING_CLI_SOURCE=""
+fi
+```
+
+## Step 3: Scrub secrets
+
+Read and apply [references/secret-scrubbing.md](references/secret-scrubbing.md) on
+the staging copies. The scrub file expects `$STAGING_MANUSCRIPTS` and
+`$STAGING_CLI_SOURCE` to be set.
+
+If the post-scrub verification reports unresolved secrets, **do not proceed with upload**.
+Save the zips locally and tell the user to review manually.
+
+## Step 4: Zip artifacts
+
+```bash
+MANUSCRIPTS_ZIP="$STAGING_DIR/$API_SLUG-manuscripts.zip"
+CLI_SOURCE_ZIP=""
+
+(cd "$STAGING_MANUSCRIPTS" && zip -r "$MANUSCRIPTS_ZIP" . -x "*.DS_Store") 2>/dev/null
+echo "Manuscripts zip: $(du -h "$MANUSCRIPTS_ZIP" | cut -f1)"
+
+if [ -n "$STAGING_CLI_SOURCE" ] && [ -d "$STAGING_CLI_SOURCE" ]; then
+ CLI_SOURCE_ZIP="$STAGING_DIR/$API_SLUG-cli-source.zip"
+ (cd "$STAGING_CLI_SOURCE" && zip -r "$CLI_SOURCE_ZIP" . -x "*.DS_Store") 2>/dev/null
+ echo "CLI source zip: $(du -h "$CLI_SOURCE_ZIP" | cut -f1)"
+fi
+```
+
+## Step 5: Upload to catbox.moe
+
+Upload each zip and capture the returned URL:
+
+```bash
+MANUSCRIPTS_URL=""
+CLI_SOURCE_URL=""
+UPLOAD_FAILED=false
+
+# Upload manuscripts
+RESPONSE=$(curl -s -F "reqtype=fileupload" -F "fileToUpload=@$MANUSCRIPTS_ZIP" https://catbox.moe/user/api.php 2>/dev/null)
+if echo "$RESPONSE" | grep -q "^https://"; then
+ MANUSCRIPTS_URL="$RESPONSE"
+ echo "Manuscripts uploaded: $MANUSCRIPTS_URL"
+else
+ echo "WARNING: Failed to upload manuscripts to catbox.moe. Response: $RESPONSE"
+ UPLOAD_FAILED=true
+fi
+
+# Upload CLI source (only if it was packaged)
+if [ -n "$CLI_SOURCE_ZIP" ] && [ -f "$CLI_SOURCE_ZIP" ]; then
+ RESPONSE=$(curl -s -F "reqtype=fileupload" -F "fileToUpload=@$CLI_SOURCE_ZIP" https://catbox.moe/user/api.php 2>/dev/null)
+ if echo "$RESPONSE" | grep -q "^https://"; then
+ CLI_SOURCE_URL="$RESPONSE"
+ echo "CLI source uploaded: $CLI_SOURCE_URL"
+ else
+ echo "WARNING: Failed to upload CLI source to catbox.moe. Response: $RESPONSE"
+ UPLOAD_FAILED=true
+ fi
+else
+ echo "No CLI source to upload (manuscripts-only mode)."
+fi
+```
+
+## Step 6: Handle upload failure (R15)
+
+If either upload failed:
+
+```bash
+if [ "$UPLOAD_FAILED" = true ]; then
+ # Preserve local zips for manual attachment
+ LOCAL_ZIP_DIR="$RUN_DIR/proofs"
+ cp "$MANUSCRIPTS_ZIP" "$LOCAL_ZIP_DIR/" 2>/dev/null
+ cp "$CLI_SOURCE_ZIP" "$LOCAL_ZIP_DIR/" 2>/dev/null
+ echo ""
+ echo "Some artifacts could not be uploaded to catbox.moe."
+ echo "Local copies saved to: $LOCAL_ZIP_DIR/"
+ echo "You can upload them manually or attach them to the GitHub issue."
+fi
+```
+
+## Step 7: Cleanup
+
+**Called by the SKILL.md at the end of Phase 6**, after issue creation, local saves,
+and presenting results are all complete. Do not call this immediately after zipping —
+the staging folder must stay alive for user review and upload.
+
+```bash
+rm -rf "$STAGING_DIR"
+```
+
+If cleanup fails (permissions, etc.), it's a temp directory — the OS will clean it up
+eventually. Do not let cleanup failure block the rest of the workflow.
+
+## Variables expected by this reference
+
+| Variable | Set by | Contains |
+|----------|--------|----------|
+| `$RUN_DIR` | SKILL.md Phase 1 | Full path to the manuscript run directory |
+| `$CLI_DIR` | SKILL.md Phase 1 | Full path to the CLI library directory |
+| `$CLI_NAME` | SKILL.md guard rails | Binary name (e.g., `cal-com-pp-cli`) |
+| `$API_SLUG` | SKILL.md guard rails | API slug (e.g., `cal-com`) |
+| `$API_KEY_VALUE` | User session (optional) | The API key if provided during generation |
+
+## Variables produced by this reference
+
+| Variable | Contains |
+|----------|----------|
+| `$MANUSCRIPTS_URL` | catbox URL for manuscripts zip, or empty if upload failed |
+| `$CLI_SOURCE_URL` | catbox URL for CLI source zip, or empty if upload failed |
+| `$UPLOAD_FAILED` | `true` if any upload failed, `false` otherwise |
+| `$MANUSCRIPTS_ZIP` | Local path to manuscripts zip (in staging, deleted after cleanup) |
+| `$CLI_SOURCE_ZIP` | Local path to CLI source zip (in staging, deleted after cleanup) |
diff --git a/skills/printing-press-retro/references/issue-template.md b/skills/printing-press-retro/references/issue-template.md
new file mode 100644
index 00000000..04d3d162
--- /dev/null
+++ b/skills/printing-press-retro/references/issue-template.md
@@ -0,0 +1,170 @@
+# GitHub Issue Template
+
+Read this file during Phase 6 when creating the GitHub issue from retro findings.
+
+## Issue title format
+
+```
+Retro: <API display name> — <N> findings, <M> work units
+```
+
+Example: `Retro: Cal.com — 7 findings, 3 work units`
+
+## Issue body structure
+
+Build the issue body using a HEREDOC. The body is a **distilled summary** of the
+retro — not the full retro document. The full retro is linked via catbox artifacts.
+
+```markdown
+## Session Stats
+
+| Metric | Value |
+|--------|-------|
+| API | <api-display-name> |
+| Spec source | <catalog / sniffed / docs / HAR> |
+| Scorecard | <score>/100 (<grade>) |
+| Verify pass rate | <X>% |
+| Fix loops | <N> |
+| Manual code edits | <N> |
+| Features built from scratch | <N> |
+
+## Priority: Fix the Scorer
+
+| # | Scorer | Bug summary | Impact |
+|---|--------|-------------|--------|
+| <n> | <verify/dogfood/scorecard> | <one-line summary> | <false failures or points affected> |
+
+*Omit this section if no scorer bugs were found.*
+
+## Priority: Do Now
+
+| # | Finding | Component | Frequency | Fix summary |
+|---|---------|-----------|-----------|-------------|
+| <n> | <one-line title> | <generator/binary/skill/scorer> | <every/most/subclass> | <one-line fix> |
+
+## Priority: Do Next
+
+| # | Finding | Component | Frequency | Fix summary |
+|---|---------|-----------|-----------|-------------|
+| <n> | <one-line title> | <generator/binary/skill/scorer> | <every/most/subclass> | <one-line fix> |
+
+## Priority: Skip
+
+| # | Finding | Why unlikely to recur |
+|---|---------|----------------------|
+| <n> | <one-line title> | <one-line reasoning> |
+
+*Omit this section if no findings were skipped.*
+
+## Work Units
+
+### WU-<N>: <Title>
+- **Goal:** <one sentence>
+- **Component:** <target area in printing-press, e.g., "Generator templates in internal/generator/">
+- **Findings:** #<n>, #<m>
+- **Acceptance criteria:**
+ - <concrete, testable scenario>
+ - <negative test if applicable>
+- **Complexity:** <small / medium / large>
+
+### WU-<N>: ...
+
+## Artifacts
+
+| Artifact | Link |
+|----------|------|
+| Full retro document + manuscripts | <$MANUSCRIPTS_URL or "Upload failed — see below"> |
+| Generated CLI source code | <$CLI_SOURCE_URL or "Upload failed — see below"> |
+
+*If uploads failed:* Artifacts could not be uploaded to catbox.moe. The retro author
+has local copies. Ask them to attach manually if needed.
+
+## What the Printing Press Got Right
+
+- <pattern to preserve>
+- <pattern to preserve>
+
+---
+
+*Generated by `/printing-press-retro` · [CLI Printing Press](https://github.com/mvanhorn/cli-printing-press)*
+```
+
+## Creating the issue
+
+Check `gh` auth first:
+
+```bash
+if ! gh auth status 2>/dev/null; then
+ echo "GitHub CLI is not authenticated. Cannot create issue."
+ echo "Run 'gh auth login' to authenticate, or file the issue manually."
+ # Set flag for graceful degradation
+ GH_AVAILABLE=false
+else
+ GH_AVAILABLE=true
+fi
+```
+
+Create the issue:
+
+```bash
+if [ "$GH_AVAILABLE" = true ]; then
+ ISSUE_URL=$(gh issue create \
+ --repo mvanhorn/cli-printing-press \
+ --title "$ISSUE_TITLE" \
+ --body "$(cat <<'EOF'
+<constructed issue body from template above>
+EOF
+)" 2>&1)
+
+ if echo "$ISSUE_URL" | grep -q "^https://"; then
+ echo ""
+ echo "Issue created: $ISSUE_URL"
+ else
+ echo "WARNING: Failed to create GitHub issue. Error: $ISSUE_URL"
+ GH_AVAILABLE=false
+ fi
+fi
+```
+
+## Handling gh failure (R14)
+
+If `gh` is not available or issue creation fails:
+
+```bash
+if [ "$GH_AVAILABLE" = false ]; then
+ echo ""
+ echo "Could not create GitHub issue automatically."
+ echo ""
+ echo "To file the retro manually:"
+ echo " 1. Go to: https://github.com/mvanhorn/cli-printing-press/issues/new"
+ echo " 2. Title: $ISSUE_TITLE"
+ echo " 3. Copy the retro content from: $RETRO_PROOF_PATH"
+ if [ -n "$MANUSCRIPTS_URL" ]; then
+ echo " 4. Manuscripts: $MANUSCRIPTS_URL"
+ fi
+ if [ -n "$CLI_SOURCE_URL" ]; then
+ echo " 5. CLI source: $CLI_SOURCE_URL"
+ fi
+ echo ""
+ echo "The retro document has been saved locally to:"
+ echo " $RETRO_PROOF_PATH"
+fi
+```
+
+## Handling body size
+
+GitHub issue bodies have a practical limit (~65KB). The distilled summary should be
+well under this for typical retros. If `gh issue create` fails with a body-size error:
+
+1. Truncate the issue body to: Session Stats + Priority tables + Artifact links
+2. Add: "Full retro analysis available in the manuscripts artifact linked above."
+3. Retry the `gh issue create` with the truncated body.
+
+## Variables expected
+
+| Variable | Set by | Contains |
+|----------|--------|----------|
+| `$MANUSCRIPTS_URL` | artifact-packaging.md | catbox URL or empty |
+| `$CLI_SOURCE_URL` | artifact-packaging.md | catbox URL or empty |
+| `$RETRO_PROOF_PATH` | SKILL.md Phase 5 | Path to saved retro in manuscript proofs |
+| All retro findings | SKILL.md Phase 4 | The prioritized findings to populate tables |
diff --git a/skills/printing-press-retro/references/secret-scrubbing.md b/skills/printing-press-retro/references/secret-scrubbing.md
new file mode 100644
index 00000000..1bc4914e
--- /dev/null
+++ b/skills/printing-press-retro/references/secret-scrubbing.md
@@ -0,0 +1,152 @@
+# Secret & PII Scrubbing for Public Artifacts
+
+Read this file during Phase 6 before zipping and uploading artifacts to catbox.moe.
+All scrub operations work on the **temp staging copy**, never on the user's original
+manuscripts or library directories.
+
+## Layer 1: Exact-value scanning
+
+If the user provided an API key during the generation session, scan for its literal
+value and redact it. This has zero false positives.
+
+Use `grep -F` (fixed string) — NOT bare `grep` or `sed` — because API keys often
+contain regex metacharacters (`+`, `/`, `.`, `=`).
+
+```bash
+# Guard: skip if key is empty or too short (< 16 chars)
+if [ -n "$API_KEY_VALUE" ] && [ ${#API_KEY_VALUE} -ge 16 ]; then
+ LEAK_FOUND=false
+ for dir in "$STAGING_MANUSCRIPTS" "$STAGING_CLI_SOURCE"; do
+ if [ -d "$dir" ] && grep -rF "$API_KEY_VALUE" "$dir" 2>/dev/null; then
+ LEAK_FOUND=true
+ fi
+ done
+ if [ "$LEAK_FOUND" = true ]; then
+ echo "BLOCKING: API key value found in staging artifacts. Auto-redacting."
+ REDACT_TO='<REDACTED:session-api-key>'
+ for dir in "$STAGING_MANUSCRIPTS" "$STAGING_CLI_SOURCE"; do
+ [ -d "$dir" ] || continue
+ find "$dir" -type f -print0 | while IFS= read -r -d '' f; do
+ if grep -qF "$API_KEY_VALUE" "$f" 2>/dev/null; then
+ REDACT_OLD="$API_KEY_VALUE" REDACT_NEW="$REDACT_TO" python3 -c "
+import sys, os
+old, new, path = os.environ['REDACT_OLD'], os.environ['REDACT_NEW'], sys.argv[1]
+with open(path) as f: content = f.read()
+with open(path, 'w') as f: f.write(content.replace(old, new))
+" "$f"
+ fi
+ done
+ done
+ echo "Auto-redacted session API key."
+ fi
+fi
+```
+
+## Layer 2: Pattern-based scanning
+
+Scan for common secret formats regardless of whether a session key was provided.
+Each pattern uses `grep -rE` with a concrete regex and a labeled redaction tag.
+
+Run each pattern scan independently. A false positive from one pattern does not
+affect other scans.
+
+```bash
+# Define patterns: name|regex|redaction-tag
+PATTERNS=(
+ 'stripe-live-key|sk_live_[A-Za-z0-9]{20,}|<REDACTED:stripe-live-key>'
+ 'stripe-test-key|sk_test_[A-Za-z0-9]{20,}|<REDACTED:stripe-test-key>'
+ 'github-pat|ghp_[A-Za-z0-9]{36,}|<REDACTED:github-pat>'
+ 'github-oauth|gho_[A-Za-z0-9]{36,}|<REDACTED:github-oauth>'
+ 'bearer-token|Bearer [A-Za-z0-9._~+/=-]{20,}|<REDACTED:bearer-token>'
+ 'jwt-token|eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}|<REDACTED:jwt-token>'
+)
+
+for entry in "${PATTERNS[@]}"; do
+ IFS='|' read -r name regex tag <<< "$entry"
+ for dir in "$STAGING_MANUSCRIPTS" "$STAGING_CLI_SOURCE"; do
+ [ -d "$dir" ] || continue
+ find "$dir" -type f -print0 | while IFS= read -r -d '' f; do
+ if grep -qE "$regex" "$f" 2>/dev/null; then
+ # Use perl for in-place regex replacement (more reliable than sed across platforms)
+ perl -i -pe "s/$regex/$tag/g" "$f" 2>/dev/null
+ echo "Redacted $name in $(basename "$f")"
+ fi
+ done
+ done
+done
+```
+
+### Env var assignment scanning
+
+Separately scan for hardcoded secret assignments in source code:
+
+```bash
+# Matches assignments where the variable name ENDS with a secret-like suffix:
+# API_SECRET = "value", AUTH_TOKEN: 'value', API_KEY="value", DB_PASSWORD='value'
+# Does NOT match: CACHE_KEY, PRIMARY_KEY, TOKEN_EXPIRY (keyword is not a suffix)
+# Only in .go, .env, .yaml, .yml, .json, .toml files
+SECRET_ASSIGN_REGEX='[A-Z_]+(SECRET|_TOKEN|_KEY|PASSWORD)\s*[:=]\s*["'"'"'][^"'"'"']{16,}["'"'"']'
+
+for dir in "$STAGING_MANUSCRIPTS" "$STAGING_CLI_SOURCE"; do
+ [ -d "$dir" ] || continue
+ find "$dir" -type f \( -name "*.go" -o -name "*.env" -o -name "*.yaml" -o -name "*.yml" -o -name "*.json" -o -name "*.toml" \) -print0 | while IFS= read -r -d '' f; do
+ if grep -qE "$SECRET_ASSIGN_REGEX" "$f" 2>/dev/null; then
+ perl -i -pe 's/[A-Z_]+(SECRET|_TOKEN|_KEY|PASSWORD)\s*[:=]\s*["\x27][^"\x27]{16,}["\x27]/$1=<REDACTED:env-assignment>/g' "$f" 2>/dev/null
+ echo "Redacted env assignment in $(basename "$f")"
+ fi
+ done
+done
+```
+
+## Layer 3: HAR auth stripping
+
+If the staging manuscripts contain HAR files, strip auth-bearing fields:
+
+```bash
+find "$STAGING_MANUSCRIPTS" -name "*.har" -type f -print0 2>/dev/null | while IFS= read -r -d '' har; do
+ jq 'del(.log.entries[].response.content.text) |
+ (.log.entries[].request.headers) |= [.[] |
+ select(.name | test("^(Authorization|Cookie|Set-Cookie|X-API-Key|X-Auth-Token)$"; "i") | not)
+ ] |
+ (.log.entries[].response.headers) |= [.[] |
+ select(.name | test("^(Set-Cookie)$"; "i") | not)
+ ] |
+ (.log.entries[].request.queryString) |= [.[] |
+ if (.name | test("^(key|api_key|apikey|token|secret|access_token|password)$"; "i"))
+ then .value = "<REDACTED>"
+ else . end
+ ] |
+ (.log.entries[].request.cookies) |= [] |
+ (.log.entries[].response.cookies) |= []
+ ' "$har" > "${har}.stripped" 2>/dev/null && mv "${har}.stripped" "$har"
+ echo "Stripped auth from $(basename "$har")"
+done
+```
+
+## Layer 4: Session state cleanup
+
+Remove any session state files that may contain cookies or tokens:
+
+```bash
+find "$STAGING_MANUSCRIPTS" -name "session-state.json" -type f -delete 2>/dev/null
+```
+
+## Post-scrub verification
+
+After all layers complete, do a final scan for obvious leaks:
+
+```bash
+FINAL_CHECK=false
+for dir in "$STAGING_MANUSCRIPTS" "$STAGING_CLI_SOURCE"; do
+ [ -d "$dir" ] || continue
+ MATCHES=$(grep -rEi '(sk_live_|sk_test_|ghp_|gho_|Bearer [A-Za-z0-9]{20})' "$dir" 2>/dev/null | grep -v 'REDACTED' | head -5)
+ if [ -n "$MATCHES" ]; then
+ echo "$MATCHES"
+ FINAL_CHECK=true
+ fi
+done
+if [ "$FINAL_CHECK" = true ]; then
+ echo "WARNING: Potential secrets still found after scrubbing. Review the matches above."
+ echo "Artifacts will NOT be uploaded until this is resolved."
+fi
+```
diff --git a/skills/printing-press/SKILL.md b/skills/printing-press/SKILL.md
index 8caff14a..492de959 100644
--- a/skills/printing-press/SKILL.md
+++ b/skills/printing-press/SKILL.md
@@ -415,8 +415,8 @@ Before new research:
If prior research was also found (step 2), include the research summary alongside the library info.
Then ask:
- 1. **"Generate a fresh CLI"** — Re-runs the generator into a working directory, overwrites generated code, then rebuilds transcendence features. Prior research is reused if recent. ~15-20 min.
- 2. **"Improve existing CLI"** — Keeps all current code, audits for quality gaps, implements top improvements. The generator is not re-run. ~10 min.
+ 1. **"Generate a fresh CLI"** — Re-runs the Printing Press into a working directory, overwrites generated code, then rebuilds transcendence features. Prior research is reused if recent. ~15-20 min.
+ 2. **"Improve existing CLI"** — Keeps all current code, audits for quality gaps, implements top improvements. The Printing Press is not re-run. ~10 min.
3. **"Review prior research first"** — Show the full research brief and absorb manifest before deciding.
If the user picks option 1, proceed to Phase 1 (research) and then Phase 2 (generate) as normal.
@@ -1347,7 +1347,7 @@ For each test, print the command and result in this format:
When a test fails, fix it immediately — do not accumulate failures. Tag each fix:
- **CLI fix** — specific to this printed CLI
-- **Machine issue** — should be fixed in the generator (note for retro)
+- **Printing Press issue** — should be fixed in the Printing Press (note for retro)
### Step 4: Report and gate
@@ -1362,7 +1362,7 @@ Acceptance Report: <cli-name>
- [command]: expected [X], got [Y]
Fixes applied: K
- [each fix]
- Machine issues: J
+ Printing Press issues: J
- [each issue for retro]
Gate: PASS / FAIL
```
@@ -1528,7 +1528,7 @@ Present via `AskUserQuestion`:
>
> 1. **Publish now** (validate, package, and open a PR)
> 2. **Polish first** (run `/printing-press-polish` to fix verify failures, dead code, and README before publishing)
-> 3. **Run retro** (analyze the session to find improvements for the generator)
+> 3. **Run retro** (analyze the session to find improvements for the Printing Press)
> 4. **Done for now**
If the verdict was `ship-with-gaps`, prepend: "Note: shipcheck found minor gaps (see the shipcheck report above)." and recommend the polish option.
diff --git a/skills/printing-press/references/voice.md b/skills/printing-press/references/voice.md
index dcaac2a4..a8ae6c36 100644
--- a/skills/printing-press/references/voice.md
+++ b/skills/printing-press/references/voice.md
@@ -27,7 +27,7 @@ type by hand, now running digital machinery with the same pride of craft.
| **Publish** | Push a Printed CLI to the public library repo as a PR. |
| **Scorecard** | Quantitative quality score out of 100 across 16+ dimensions. |
| **Spec** | The API contract that drives generation. |
-| **The Machine** | This whole system — binary, templates, skills, catalog. |
+| **The Printing Press** | This whole system — binary, templates, skills, catalog. |
| **Absorb Manifest** | The feature inventory from Phase 1.5. Everything to build. |
| **Sniff Gate** | Decision point on whether to capture live site traffic. |
| **Quality Gates** | The 7 static checks every Printed CLI must pass. |
← b5c91158 fix(cli): replace MarkFlagRequired with RunE validation, rem
·
back to Cli Printing Press
·
fix(skills): improve retro issue format — priority sections, eae73f44 →