← back to Cli Printing Press
feat(skill): v2 overhaul - 14 changes from Notion + Linear post-mortems
854ff6014fb5292f804fce41c7856552e805f704 · 2026-03-27 17:22:37 -0700 · Matt Van Horn
Three root problems fixed:
1. Scorecard-driven development: demoted scorecard to Priority 4,
added anti-gaming rules. Table stakes features now Priority 1.
2. Discrawl trap: added Phase 0.6 Feature Parity Audit so every CLI
matches competitor features before adding novel data-layer commands.
gogcli + discrawl stay as quality/architecture references.
3. Names nobody asked for: default to <api>-pp-cli naming convention.
New phases: 0.6 (Feature Parity Audit), 5.9 (Offer Emboss)
New priorities: P1 Table Stakes, P3 Name Normalization, P5 Tests, P6 Distribution
New validations: module path (2.0b), API version (2.7), pipeline smoke test (5.5g)
New anti-shortcuts: 8 rules covering naming, testing, gaming, and competition
Emboss: now opt-in only, offered at end of run
Three-benchmark gate: architecture (discrawl) + quality (gogcli) + features (competitor)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Files touched
A docs/plans/2026-03-27-docs-lz-cli-honest-quality-assessment.mdA docs/plans/2026-03-27-fix-printing-press-comprehensive-overhaul-plan.mdA docs/plans/2026-03-27-fix-printing-press-post-mortem-notion-run-plan.mdM skills/printing-press/SKILL.md
Diff
commit 854ff6014fb5292f804fce41c7856552e805f704
Author: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Date: Fri Mar 27 17:22:37 2026 -0700
feat(skill): v2 overhaul - 14 changes from Notion + Linear post-mortems
Three root problems fixed:
1. Scorecard-driven development: demoted scorecard to Priority 4,
added anti-gaming rules. Table stakes features now Priority 1.
2. Discrawl trap: added Phase 0.6 Feature Parity Audit so every CLI
matches competitor features before adding novel data-layer commands.
gogcli + discrawl stay as quality/architecture references.
3. Names nobody asked for: default to <api>-pp-cli naming convention.
New phases: 0.6 (Feature Parity Audit), 5.9 (Offer Emboss)
New priorities: P1 Table Stakes, P3 Name Normalization, P5 Tests, P6 Distribution
New validations: module path (2.0b), API version (2.7), pipeline smoke test (5.5g)
New anti-shortcuts: 8 rules covering naming, testing, gaming, and competition
Emboss: now opt-in only, offered at end of run
Three-benchmark gate: architecture (discrawl) + quality (gogcli) + features (competitor)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
...-03-27-docs-lz-cli-honest-quality-assessment.md | 251 +++++++++
...x-printing-press-comprehensive-overhaul-plan.md | 625 +++++++++++++++++++++
...x-printing-press-post-mortem-notion-run-plan.md | 286 ++++++++++
skills/printing-press/SKILL.md | 370 +++++++++---
4 files changed, 1469 insertions(+), 63 deletions(-)
diff --git a/docs/plans/2026-03-27-docs-lz-cli-honest-quality-assessment.md b/docs/plans/2026-03-27-docs-lz-cli-honest-quality-assessment.md
new file mode 100644
index 00000000..0da5a235
--- /dev/null
+++ b/docs/plans/2026-03-27-docs-lz-cli-honest-quality-assessment.md
@@ -0,0 +1,251 @@
+---
+title: "Honest Quality Assessment: Is lz the Best Linear CLI?"
+type: docs
+status: active
+date: 2026-03-27
+---
+
+# Honest Quality Assessment: Is lz the Best Linear CLI?
+
+## The Short Answer
+
+**No.** lz is not the best Linear CLI in existence. It's the best Linear CLI *for one specific job* - offline analytics and backlog intelligence. For the job most developers actually hire a Linear CLI to do (issue management while coding), schpet/linear-cli is better.
+
+## The Longer Answer
+
+### What lz genuinely does well (things nobody else offers)
+
+1. **Local SQLite with offline queries.** This is real and it works. 500 issues sync in 4 seconds, then every query is instant with zero API calls. No other Linear CLI has this.
+
+2. **FTS5 full-text search.** Search across 50k issues in milliseconds. The competitors hit the API on every search, which is rate-limited and slow.
+
+3. **Raw SQL access.** `lz sql "SELECT ..."` against your entire issue database. Cross-entity joins, aggregations, custom reports. This is genuinely powerful and unique.
+
+4. **Sprint analytics commands.** velocity, health, bottleneck, trends, stale, orphans, duplicates, sla - these are EM/PM workflow commands that don't exist anywhere else as CLI tools.
+
+5. **Code quality is solid.** The audit found: proper GraphQL pagination, parameterized SQL (no injection), correct FTS5 triggers, real error handling with typed exit codes, all 29 commands functional (no stubs).
+
+### What lz genuinely lacks (honest weaknesses)
+
+1. **Zero tests.** No `*_test.go` files anywhere. This is the biggest quality gap. Every refactor could silently break SQL queries. Not production-trustworthy without tests.
+
+2. **No git/VCS integration.** The #1 reason developers install a Linear CLI - creating branches from issues, linking PRs - is completely missing. schpet/linear-cli's killer feature.
+
+3. **No comment/document write operations.** Can create and update issues, but can't add comments, manage documents, upload files, or handle labels.
+
+4. **Single installation method.** `go install` only. No Homebrew, no pre-built binaries, no npm. Most PMs don't have Go installed.
+
+5. **Data staleness.** Every query depends on `lz sync` having been run recently. A standup report showing an issue as "In Progress" when it was completed 5 minutes ago is misleading.
+
+6. **No agent/AI integration.** Both competitors ship MCP wrappers or Claude skills. lz has nothing here.
+
+7. **6 scorecard-gaming type aliases.** `type staleDB = store.Store` in 6 files - harmless but exists only to match scorecard string patterns. Not dead code technically, but not real engineering either.
+
+8. **CSV export inconsistency.** export.go uses naive string formatting while sql_cmd.go uses proper encoding/csv.
+
+### The Competitive Reality
+
+| Job to Be Done | Best Tool | Why |
+|----------------|-----------|-----|
+| "Work on issues while coding" | schpet/linear-cli (524 stars) | Git branch integration, PR generation, interactive mode |
+| "Query issues for agents" | linearis (164 stars) | JSON-first, 1k token self-description, smart ID parsing |
+| "Analyze my backlog offline" | **lz** | SQLite, FTS5, SQL, velocity, health, stale, orphans |
+| "Create/update issues from scripts" | schpet or linearis | More write operations, better error handling for mutations |
+
+### If I were rating lz honestly
+
+**As a complete Linear CLI: 6/10.** Missing too many write operations, no git integration, no tests, single install method.
+
+**As a Linear analytics/intelligence tool: 8.5/10.** Genuinely novel capabilities (SQLite, FTS5, SQL, workflow commands). Well-engineered sync and query layer. Would be 9.5 with tests.
+
+**Scorecard score (76/100) is misleading.** The scorecard measures code patterns, not product-market fit. A CLI that scores 76 but can't create a git branch from an issue is less useful than one that scores 50 but has `linear start ENG-123`.
+
+### What would make lz the best Linear CLI?
+
+1. **Add unit tests** - especially for sync cursors, SQL composition, FTS5
+2. **Add `lz start <issue>` with git branch creation** - this is the #1 feature
+3. **Add comment write operations** - `lz comment ENG-123 "Done"`
+4. **Ship Homebrew formula** - `brew install mvanhorn/tap/lz`
+5. **Add pre-built binaries** via goreleaser
+6. **Add MCP wrapper** - make lz accessible to Claude/agents
+7. **Remove scorecard-gaming patterns** - delete the 6 type aliases, earn scores through real code
+8. **Fix CSV export** - use encoding/csv consistently
+9. **Add `--watch` to sync** - auto-resync on interval to reduce staleness
+
+---
+
+## What the Printing Press Should Do Differently
+
+This section is a post-mortem on the process, not the CLI. These are structural failures in the printing-press skill that caused lz to ship as a niche analytics tool instead of the GOAT Linear CLI.
+
+### Root Cause: The Scorecard Drives Behavior, Not Product Thinking
+
+The printing-press skill spends Phase 0 doing excellent competitive research - we catalogued every competitor, counted their stars, read their issues, identified their weaknesses. Then Phase 4 says **"Focus on changes that RAISE THE SCORECARD NUMBER."** That single instruction overrides everything the research discovered.
+
+We knew schpet/linear-cli's killer feature was `linear start` (git branch creation). We knew linearis had comment writes and label management. We wrote it all down. Then we spent 35% of our time budget chasing scorecard dimensions (adding type aliases for `store.Store`, creating `formatErrorWithHint` wrappers, writing `outputFormat()` functions) instead of building `lz start ENG-123`.
+
+**The fix:** The scorecard should be a health check, not the objective function. The objective function should be: "Would a user of the top competitor switch to this CLI?"
+
+### Process Failures and Proposed Fixes
+
+#### 1. NO "TABLE STAKES" PHASE
+
+**The problem:** There's no phase between research and generation that says: "Before building novel features, list every feature the top competitor has and decide which ones are table stakes." The Phase 0.5 workflows are additive-only - they brainstorm new compound commands but never check if we can do what the incumbent already does.
+
+**The fix - add Phase 0.6: Feature Parity Audit:**
+
+```
+For the top 2 competitors by stars:
+ 1. List every command they offer
+ 2. Classify each as: TABLE STAKES / NICE-TO-HAVE / ANTI-SCOPE
+ 3. Table stakes = features that >50% of users would expect any CLI for this API to have
+ 4. Any TABLE STAKES feature MUST be built in Phase 4, alongside workflow commands
+ 5. Anti-scope decisions require explicit justification ("we skip X because Y")
+```
+
+For Linear, this would have caught:
+- `start` (create git branch from issue) = TABLE STAKES
+- `comment` (add comment to issue) = TABLE STAKES
+- `label add/remove` = TABLE STAKES
+- PR generation = NICE-TO-HAVE (requires gh CLI)
+- Interactive prompts = NICE-TO-HAVE
+
+#### 2. "ANTI-SCOPE" IS DECIDED TOO EARLY
+
+**The problem:** Phase 0.8 asks "What's the anti-scope?" and we wrote: "Not a git integration tool. Complements schpet, doesn't replace it." This was decided BEFORE we understood that git integration isn't a differentiator - it's the minimum viable feature set. We drew a lane boundary that excluded the #1 feature users want.
+
+**The fix:** Anti-scope should only exclude things that are genuinely out of scope (e.g., "not a TUI", "not a Jira migration tool"). Features that the top competitor offers should NEVER be in anti-scope unless there's a strong technical reason. Rename the question from "What's the anti-scope?" to:
+
+```
+"What do we deliberately NOT build, and what's the cost of that decision?"
+
+For each anti-scope item, answer:
+ - What % of potential users need this feature?
+ - Does any competitor with >100 stars offer it?
+ - If yes: this is NOT anti-scope, it's a backlog item. Move it to Phase 4.
+```
+
+#### 3. THE SCORECARD INCENTIVIZES GAMING
+
+**The problem:** Phase 4 Priority 2 says "Run the scorecard and fix dimensions below 10/10." This led directly to:
+- 6 type aliases (`type staleDB = store.Store`) to match `store.` patterns
+- `readCache`/`writeCache`/`cacheDir` functions in client.go for string matching
+- `outputFormat()` returning `"plain"` and `"ndjson"` strings nobody uses
+- `formatErrorWithHint()` wrapper function that got inlined when dead code was detected
+- Hours spent going from 69 -> 76 on the scorecard instead of building `lz start`
+
+**The fix - restructure Phase 4 priorities:**
+
+```
+Priority 0: Data Layer Foundation (unchanged - this is the product)
+Priority 1: Table Stakes Features (NEW - from Phase 0.6 parity audit)
+Priority 2: Power User Workflows (from Phase 0.5 - currently Priority 1)
+Priority 3: Scorecard Gap Fixes (demoted from Priority 2)
+Priority 4: Polish (unchanged)
+```
+
+And add an anti-gaming rule:
+
+```
+ANTI-GAMING: Every code change must serve a user need.
+ - If a function exists only because the scorecard checks for a string pattern, DELETE IT.
+ - If a flag is registered but never checked in any RunE, DELETE IT.
+ - If an import exists only to put "store." in the file, DELETE IT.
+ - The scorecard measures proxies for quality. Optimize for actual quality.
+ - A CLI that scores 60 but has every table-stakes feature beats one that scores 80 with type aliases.
+```
+
+#### 4. NO TEST PHASE
+
+**The problem:** The printing-press skill has 8 phases (0 through 5.7). NONE of them write tests. Phase 4.5 "dogfoods" against spec-derived mocks, and Phase 4.8 runs `printing-press verify`, but nobody writes `*_test.go` files. A CLI with 29 commands and 0 tests is not shippable to a team.
+
+**The fix - add Phase 4.3: Write Tests:**
+
+```
+For each Primary entity in the data layer:
+ 1. Test UpsertX with valid data -> verify row in DB
+ 2. Test UpsertX with missing fields -> verify graceful handling
+ 3. Test SearchX with FTS5 -> verify results match
+
+For each workflow command:
+ 1. Seed DB with test fixtures
+ 2. Run the command's core SQL query
+ 3. Verify result shape and counts
+
+For the sync layer:
+ 1. Test cursor get/set round-trip
+ 2. Test pagination with mock GraphQL responses
+ 3. Test retry with backoff timing
+
+Minimum: 1 test file per package (store, client, cli).
+Use table-driven tests matching the project's convention.
+```
+
+#### 5. NO DISTRIBUTION PHASE
+
+**The problem:** We build a Go binary that only installs via `go install`. Most engineering managers and PMs don't have the Go toolchain. schpet/linear-cli has Homebrew, npm, pre-built binaries. We have none.
+
+**The fix - add Phase 5.3: Distribution:**
+
+```
+1. Add goreleaser.yaml for cross-platform binary builds
+2. Add Homebrew formula (or tap)
+3. Verify `brew install` or download-and-run works
+4. Add install instructions for non-Go users to README
+
+If this API's ecosystem has conventions (npm for JS APIs, pip for Python APIs),
+follow those conventions. Go install is the fallback, not the primary channel.
+```
+
+#### 6. PHASE 3 SCORES AGAINST GOGCLI, NOT THE ACTUAL COMPETITOR
+
+**The problem:** The Non-Obvious Insight Review scores against Peter Steinberger's gogcli as the 10/10 reference. But gogcli is a GitHub CLI - its quality dimensions don't map to what makes a Linear CLI good. We should be scoring against schpet/linear-cli's actual feature set.
+
+**The fix:** Phase 3 should include a head-to-head feature matrix:
+
+```
+For the top competitor:
+ | Feature | Competitor | Ours | Gap |
+ |---------|-----------|------|-----|
+ List every command they have and mark: HAVE / MISSING / BETTER
+
+ "MISSING" items with >50% user need become Phase 4 Priority 1 work items.
+ "BETTER" items are our differentiators - highlight in README.
+```
+
+#### 7. THE "DISCRAWL BENCHMARK" IS A TRAP
+
+**The problem:** The skill says: "After Phase 4, ask: Would a discrawl user switch to this CLI?" This is the wrong question for most APIs. discrawl is a data archival tool for Discord - a communication platform with millions of messages. Linear is a project management tool with thousands of issues. The discrawl pattern (SQLite + FTS5 + sync) is valuable for Linear, but it's not sufficient. The skill's benchmarking against discrawl pushed us toward data features and away from workflow features.
+
+**The fix:** The benchmark question should be:
+
+```
+"Would a user of [top competitor] switch to this CLI?"
+If no: "What's the one feature that would flip them?" Build that feature.
+If yes: "What's our unique feature they can't get elsewhere?" Highlight that.
+```
+
+### Summary: The 7 Skill Changes
+
+| # | Change | Where in Skill | Impact |
+|---|--------|---------------|--------|
+| 1 | Add Phase 0.6: Feature Parity Audit | After Phase 0.5 | Prevents shipping without table stakes |
+| 2 | Anti-scope requires cost analysis | Phase 0.8 | Prevents premature lane narrowing |
+| 3 | Demote scorecard fixes + add anti-gaming rule | Phase 4 priorities | Stops optimizing for proxy metrics |
+| 4 | Add Phase 4.3: Write Tests | After Phase 4 Priority 1 | Ensures shippable quality |
+| 5 | Add Phase 5.3: Distribution | After Phase 5 | Ensures installability |
+| 6 | Score against actual competitor, not gogcli | Phase 3 | Grounds quality in real competition |
+| 7 | Replace discrawl benchmark with competitor switch question | Phase 4 gate | Grounds features in real user needs |
+
+### The Meta-Lesson
+
+The printing-press skill is optimized for generating impressive-looking CLIs that score well on automated quality checks. It is NOT optimized for generating CLIs that people would actually choose over existing tools. The research phases are excellent - Phase 0 through 1 produce genuine competitive intelligence. But the build phases (3-5) ignore that intelligence in favor of chasing scorecard numbers.
+
+The fix is simple: **make the competitor feature matrix the primary objective, and the scorecard the secondary health check.** Build what users need first, then polish the code patterns.
+
+## Sources
+
+- Code audit: ~/cli-printing-press/lz-cli/ (full codebase read)
+- schpet/linear-cli: https://github.com/schpet/linear-cli (524 stars)
+- linearis: https://github.com/czottmann/linearis (164 stars)
+- Live API testing: 11/11 commands pass with real Linear workspace
diff --git a/docs/plans/2026-03-27-fix-printing-press-comprehensive-overhaul-plan.md b/docs/plans/2026-03-27-fix-printing-press-comprehensive-overhaul-plan.md
new file mode 100644
index 00000000..1c885150
--- /dev/null
+++ b/docs/plans/2026-03-27-fix-printing-press-comprehensive-overhaul-plan.md
@@ -0,0 +1,625 @@
+---
+title: "Comprehensive Overhaul: Printing Press Skill v2"
+type: fix
+status: completed
+date: 2026-03-27
+origin: synthesis of 2026-03-27-fix-printing-press-post-mortem-notion-run-plan.md + 2026-03-27-docs-lz-cli-honest-quality-assessment.md
+---
+
+# Comprehensive Overhaul: Printing Press Skill v2
+
+## Overview
+
+Two independent post-mortems (Notion run, Linear/lz run) converged on the same diagnosis: the printing-press skill does excellent research (Phases 0-1) then throws it away to chase scorecard numbers (Phases 3-4). It produces discrawl clones for every API instead of purpose-built CLIs that beat the actual competition. It invents cute names nobody asked for. It has no test phase. It has no distribution phase. Emboss triggers confusingly.
+
+This plan synthesizes both post-mortems plus the user's direct feedback into 14 concrete changes to SKILL.md.
+
+## The Three Root Problems
+
+### 1. Scorecard-Driven Development
+
+Both runs exhibit the same pattern:
+- Phase 0 discovers what competitors do well (schpet/linear-cli has `start`, 4ier/notion-cli has clean names)
+- Phase 4 Priority 2 says "Focus on changes that RAISE THE SCORECARD NUMBER"
+- The rest of Phase 4 is spent gaming scorecard string patterns instead of building what users need
+- Result: type aliases, dead flags, wrapper functions that exist only to match scorecard regexes
+
+**Evidence:**
+- lz run: 6 type aliases (`type staleDB = store.Store`) to match `store.` patterns. Hours going from 69->76 instead of building `lz start ENG-123`
+- Notion run: `rateLimitErr` wired to `_ = rateLimitErr` to avoid dead code detection. `printPlain` created just because `flags.plain` was "dead"
+
+### 2. The Discrawl Trap
+
+Every CLI gets the same architecture: SQLite + FTS5 + sync + search + stale + health + trends + patterns + similar + forecast + bottleneck. This is fine for communication APIs (Discord) where the data layer IS the product. It's wrong for project management (Linear) where git integration is the product. It's wrong for content platforms (Notion) where markdown export and clean command names are the product.
+
+The skill's vision dimension benchmarks against discrawl. The anti-shortcut rules say "316 commands is worse than 12 commands." This pushes EVERY run toward the same discrawl-shaped output.
+
+**Evidence:**
+- lz has 8 insight commands (stale, health, velocity, trends, patterns, bottleneck, orphans, duplicates) and 0 git commands. schpet/linear-cli has `start` (create git branch from issue) with 524 stars.
+- Notion noto has 12 insight/workflow commands and ugly command names. 4ier/notion-cli has clean names and human-friendly filters with 91 stars.
+
+### 3. Names Nobody Asked For
+
+Phase 0.8 says "Do NOT default to `<api>-cli`." This forces creative names: noto (Notion), lz (Linear). These are:
+- Confusing ("what the hell is noto?")
+- Not discoverable (`brew search notion` won't find `notion-pp-cli`)
+- Unnecessary (nobody asked for a creative name)
+
+The generator should produce `<api>-pp-cli` by default (e.g., `notion-pp-cli`, `linear-pp-cli`, `stripe-pp-cli`). The `-pp-` identifies it as a printing press product. If the user wants a different name, they can rename it.
+
+---
+
+## The 14 Changes
+
+### Change 1: Naming - Default to `<api>-pp-cli`
+
+**File:** SKILL.md Phase 0.8 (line ~789)
+
+**Current (broken):**
+```markdown
+4. **What's the name?** (short, memorable, not confused with the incumbent)
+ - Consider: trademark risk, existing tools with that name, domain clarity
+ - Test: can you `brew install <name>` without collision?
+ - The generator will use this name. Do NOT default to `<api>-cli`.
+```
+
+**Proposed:**
+```markdown
+4. **What's the name?**
+ - DEFAULT: `<api>-pp-cli` (e.g., `notion-pp-cli`, `linear-pp-cli`, `stripe-pp-cli`)
+ - The `-pp-` identifies it as a printing press product.
+ - This is discoverable (`brew search notion` finds `notion-pp-cli`).
+ - Creative names are allowed ONLY if the user explicitly requests one.
+ - The printing press is a code generator, not a branding agency.
+```
+
+Also update the PHASE GATE 0.8 check:
+```markdown
+3. Name set to `<api>-pp-cli` (default) unless user specified otherwise
+```
+
+---
+
+### Change 2: Add Phase 0.6 - Feature Parity Audit (NEW)
+
+**Insert after Phase 0.5 (line ~625).**
+
+This is the missing link between research and build. Currently the skill brainstorms novel features (Phase 0.5) without first checking if we can do what the incumbent already does.
+
+```markdown
+# PHASE 0.6: FEATURE PARITY AUDIT
+
+## THIS PHASE IS MANDATORY. DO NOT SKIP IT.
+
+Before brainstorming novel features, catalog what the competition already ships.
+
+### Step 0.6a: Feature Matrix
+
+For the top 2 competitors by stars (from Phase 0/1 research):
+
+| Feature | Competitor A | Competitor B | Ours | Classification |
+|---------|-------------|-------------|------|----------------|
+
+List EVERY command and feature they offer.
+
+### Step 0.6b: Classify Each Feature
+
+- **TABLE STAKES**: >50% of users expect any CLI for this API to have it.
+ Examples: `issue create`, `page get`, git branch from issue, clean CRUD names
+- **NICE-TO-HAVE**: Useful but not expected. Won't lose users if missing.
+ Examples: interactive prompts, TUI mode, plugins
+- **ANTI-SCOPE**: Genuinely out of scope with justification.
+ Examples: full TUI, mobile app, GUI
+
+**Classification rules:**
+- If ANY competitor with >100 stars has it, it's TABLE STAKES unless you
+ provide an explicit reason it's anti-scope.
+- If users mention it in issues/Reddit with >10 upvotes, it's TABLE STAKES.
+- "Complements the incumbent" is NOT a reason to skip a feature. Users
+ don't want to install two CLIs.
+
+### Step 0.6c: Table Stakes Become Phase 4 Mandatory Work
+
+Every TABLE STAKES feature becomes a Phase 4 Priority 1 work item.
+They are built ALONGSIDE the data layer, not instead of it.
+
+### PHASE GATE 0.6
+
+**STOP.** Verify:
+1. Feature matrix complete for top 2 competitors
+2. Every feature classified as TABLE STAKES / NICE-TO-HAVE / ANTI-SCOPE
+3. TABLE STAKES list has at least 3 items
+4. Anti-scope items have explicit cost analysis
+
+Tell the user: "Feature parity audit: [N] table-stakes features identified
+from [competitor names]. Top gaps: [list]. These will be built in Phase 4."
+```
+
+---
+
+### Change 3: Anti-Scope Requires Cost Analysis
+
+**File:** SKILL.md Phase 0.8 (line ~797)
+
+**Current:**
+```markdown
+5. **What's the anti-scope?** (what we deliberately do NOT build)
+ - Example: "Not a TUI. Not a git replacement. Complements gh, doesn't replace it."
+```
+
+**Proposed:**
+```markdown
+5. **What's the anti-scope and what does it cost?**
+
+ For each anti-scope item, answer:
+ - What % of potential users need this feature?
+ - Does any competitor with >100 stars offer it?
+ - If yes: this is NOT anti-scope, it's a backlog item. Move to Phase 4.
+
+ VALID anti-scope: "Not a TUI" (no competitor offers one either)
+ INVALID anti-scope: "Not a git integration" (the top competitor's killer
+ feature is git integration - you just excluded the #1 reason people install it)
+```
+
+---
+
+### Change 4: Restructure Phase 4 Priorities
+
+**File:** SKILL.md Phase 4 (line ~1226)
+
+**Current order:**
+```
+Priority 0: Data Layer Foundation
+Priority 1: Power User Workflows (from Phase 0.5)
+Priority 2: Scorecard-Gap Fixes <-- THE PROBLEM
+Priority 3: Polish
+```
+
+**Proposed order:**
+```
+Priority 0: Data Layer Foundation (unchanged)
+Priority 1: Table Stakes Features (NEW - from Phase 0.6 parity audit)
+Priority 2: Power User Workflows (from Phase 0.5 - demoted from Priority 1)
+Priority 3: Command Name Normalization + Binary Naming (NEW)
+Priority 4: Scorecard Gap Fixes (demoted, with anti-gaming rules)
+Priority 5: Tests (NEW)
+Priority 6: Distribution Scaffold (NEW)
+Priority 7: Polish (README cookbook, FAQ)
+```
+
+### Priority 1: Table Stakes Features (NEW)
+
+```markdown
+### Priority 1: Table Stakes Features (from Phase 0.6)
+
+Build every feature classified as TABLE STAKES in Phase 0.6. These are
+features that the top competitor has and that >50% of users expect.
+
+For each table-stakes feature:
+1. Read how the competitor implements it (from Phase 1 research)
+2. Implement it - don't just match the competitor, make it BETTER
+3. Better means: works with --json, supports --dry-run, has --stdin,
+ composes with our data layer where possible
+
+**Gate:** Every TABLE STAKES feature from Phase 0.6 must be implemented
+before proceeding to Priority 2. No exceptions.
+```
+
+### Priority 3: Command Name Normalization + Binary Naming (NEW)
+
+```markdown
+### Priority 3: Command Name Normalization + Apply Product Name
+
+**Step 3a: Normalize generated command names**
+
+The generator produces ugly operationId-derived names. Fix them:
+
+| Generated | Normalized | Rule |
+|-----------|-----------|------|
+| `retrieve-a*` | `get` | Strip "Retrieve a" prefix |
+| `delete-a*` | `delete` | Strip "Delete a" prefix |
+| `create-a*` | `create` | Strip "Create a" prefix |
+| `update-a*` | `update` | Strip "Update a" prefix |
+| `post` | `create` | HTTP method -> action |
+| `patch` | `update` | HTTP method -> action |
+| `get-self` | `me` | Special case |
+| `list-*` | `list` | Strip resource suffix |
+
+For each rename:
+1. Update the `Use:` field in the command file
+2. Rename the file to match
+3. Verify `go build` passes
+
+**Step 3b: Apply the product name everywhere**
+
+1. Rename `cmd/<generated-name>/` to `cmd/<product-name>/`
+2. Update root.go Use field and version template
+3. Update go.mod module path
+4. Update client.go User-Agent header
+5. `grep -r "<old-name>" . | grep -v "Generated by"` must return 0 hits
+6. Update README examples
+
+**Step 3c: Validate API version header**
+
+1. Check what API version the spec uses
+2. Check what the generated client sends
+3. If they don't match, update client.go
+4. If the API uses date-based versions (Notion, Stripe), use the LATEST
+```
+
+### Priority 4: Scorecard Gap Fixes (with anti-gaming rule)
+
+```markdown
+### Priority 4: Scorecard Gap Fixes (DEMOTED + ANTI-GAMING)
+
+Run the scorecard. Fix real gaps. DO NOT GAME IT.
+
+**ANTI-GAMING RULES:**
+- If a function exists only because the scorecard checks for a string
+ pattern, DELETE IT.
+- If a flag is registered but never checked in any RunE, DELETE IT.
+- If an import exists only to put "store." in the file, DELETE IT.
+- A CLI that scores 60 but has every table-stakes feature beats one
+ that scores 80 with type aliases.
+- The scorecard measures proxies for quality. Optimize for actual quality.
+```
+
+### Priority 5: Tests (NEW)
+
+```markdown
+### Priority 5: Write Tests
+
+A CLI with 0 test files is not shippable.
+
+For each Primary entity in the data layer:
+1. Test UpsertX with valid data -> verify row in DB
+2. Test UpsertX with missing fields -> verify graceful handling
+3. Test SearchX with FTS5 -> verify results match
+
+For each workflow command:
+1. Seed DB with test fixtures
+2. Run the command's core query
+3. Verify result shape and counts
+
+Minimum: 1 test file per package (store, cli).
+Use table-driven tests matching Go conventions.
+```
+
+### Priority 6: Distribution Scaffold (NEW)
+
+```markdown
+### Priority 6: Distribution Scaffold
+
+1. Add `.goreleaser.yaml` for cross-platform binary builds
+2. Add Homebrew formula or tap
+3. Add install instructions for non-Go users to README
+4. Add `.github/workflows/ci.yml` (go test, go vet, goreleaser on tag)
+
+A CLI that can only be installed via `go install` is not a real CLI.
+```
+
+---
+
+### Change 5: Fix Emboss Mode UX
+
+**File:** SKILL.md Emboss section (line ~30)
+
+**Current problem:** Emboss can trigger unexpectedly or confusingly. The user said "What the hell is Emboss?" It should be an opt-in follow-up, not something that runs unless requested.
+
+**Proposed changes:**
+
+1. Emboss should NEVER run automatically. It only runs when the user types `emboss` explicitly.
+2. After the main run completes (Phase 5 final report), offer emboss as an option:
+
+Add to the end of Phase 5:
+
+```markdown
+### Phase 5.9: Offer Emboss
+
+After presenting the final report, ask the user:
+
+"The CLI scored [X]/100 (Grade [Y]). Want me to run an emboss pass
+to improve it further? This re-researches the landscape, finds the
+top 5 improvements, builds them, and re-scores."
+
+Options:
+- "Yes, run emboss" -> proceed to Emboss Mode
+- "No, I'm done" -> end the run
+- "I'll emboss later" -> tell user they can run `/printing-press emboss ./<api>-cli`
+
+Emboss is a FOLLOW-UP, not an automatic step. The user decides.
+```
+
+3. In the Emboss section at the top, add a guard:
+
+```markdown
+## Emboss Mode (Second Pass)
+
+**Emboss is opt-in.** It NEVER runs automatically. It runs when:
+1. The user explicitly types `/printing-press emboss <dir>`
+2. The user selects "Yes, run emboss" from the Phase 5.9 prompt
+
+If the user did NOT request emboss, do NOT mention it, do NOT run it,
+do NOT show emboss reports.
+```
+
+---
+
+### Change 6: Add Competitor Switch Question (Keep Discrawl as Architecture Reference)
+
+**File:** SKILL.md Phase 4 gate (line ~1331) and anti-shortcut rules
+
+**The printing press has three benchmarks, not one. All three stay:**
+
+1. **gogcli** = "What does quality CLI code look like?" (scoring reference for output modes, auth, error handling, agent-native design). KEEP as the 10/10 reference for code quality dimensions.
+
+2. **discrawl** = "What does a data-layer CLI look like?" (architecture reference for SQLite + FTS5 + sync + domain tables + workflow commands). KEEP as the architecture reference. This is the printing press's moat - most generators produce thin API wrappers. Ours produces discrawl-quality data layers.
+
+3. **Top competitor** = "What do users actually expect?" (feature reference). ADD as the third benchmark. This is what's missing today.
+
+**Current Phase 4 gate:**
+```markdown
+After Phase 4, ask: "Would a discrawl user switch to this CLI?"
+```
+
+**Proposed Phase 4 gate (additive, not replacing):**
+```markdown
+After Phase 4, ask THREE questions:
+
+1. ARCHITECTURE (discrawl benchmark): "Does this CLI have a real data
+ layer - domain-specific SQLite tables, FTS5 search, incremental sync,
+ workflow commands that query local data?" If no, Priority 0 isn't done.
+
+2. QUALITY (gogcli benchmark): "Does the code have proper output modes,
+ typed errors, agent-native flags, doctor command, README with cookbook?"
+ If gaps, Priority 4 scorecard fixes address them.
+
+3. FEATURES (competitor benchmark): "Would a user of [top competitor]
+ switch to this CLI?" If no: "What's the ONE feature that would flip
+ them?" Build it now before proceeding.
+
+All three must pass. Architecture without features is a toy.
+Features without architecture is a thin wrapper. Quality without
+either is polished nothing.
+```
+
+Update the discrawl-specific anti-shortcut rule to be more nuanced:
+- **Current:** `"316 commands is better than 12" (discrawl has 12 commands...)`
+- **Proposed:** `"316 commands is better than 12" (Depth beats breadth - discrawl proves this. But depth means building the RIGHT 12 commands, not the same 12 commands for every API. Check the competitor feature matrix.)`
+
+---
+
+### Change 7: Add Competitor Feature Matrix to Phase 3 (Keep gogcli Scoring)
+
+**File:** SKILL.md Phase 3 (line ~1121)
+
+**Keep the existing 10-dimension gogcli scoring table.** It measures real code quality dimensions (output modes, auth, error handling, etc.) that apply to every CLI. Don't touch it.
+
+**Add a SECOND evaluation after the gogcli scoring - the competitor feature matrix:**
+
+```markdown
+### Step 3.7b: Head-to-Head Competitor Feature Matrix
+
+The 10-dimension score (above) measures code quality against gogcli.
+This step measures feature completeness against the ACTUAL competition.
+
+For the top 2 competitors (from Phase 1):
+
+| Feature | Competitor A | Competitor B | Ours | Status |
+|---------|-------------|-------------|------|--------|
+| (list every command they have) | Y/N | Y/N | Y/N | HAVE / MISSING / BETTER |
+
+MISSING features with >50% user need become Phase 4 Priority 1 work items.
+BETTER features are our differentiators - highlight in README comparison table.
+
+**The gogcli score tells you if the code is good.**
+**The competitor matrix tells you if the product is good.**
+**You need both.** A CLI that scores 10/10 on output modes but can't
+do what the top competitor does is a well-polished toy.
+```
+
+---
+
+### Change 8: Phase 5.5 Data Pipeline Smoke Test
+
+**File:** SKILL.md Phase 5.5 (line ~1744)
+
+Add after the live API test sequence:
+
+```markdown
+### Step 5.5g: Data Pipeline Smoke Test
+
+After sync, verify data actually flowed through:
+
+1. Query entity counts: pages, blocks, users, etc.
+2. **If ANY primary entity has 0 rows:**
+ - Verdict: WARN (not PASS)
+ - Report the likely cause (permissions, empty workspace, sync bug)
+ - Suggest: share a test resource with the integration and re-run
+3. **If primary entities have rows, test the read path:**
+ - search, stale, health must return non-empty results
+4. **If search returns 0 results but rows exist:**
+ - FTS5 indexing is broken. Verdict: FAIL.
+
+"0 rows synced" is NEVER a PASS. It's WARN at best, FAIL if the
+API token had access.
+```
+
+---
+
+### Change 9: Validate Module Path
+
+**File:** SKILL.md Phase 2 (after line ~963)
+
+```markdown
+### Step 2.0b: Validate Module Path
+
+Before generation, check the module path:
+1. `git config user.name` - this becomes the org
+2. If it doesn't match your GitHub username, export the correct one
+3. After generation, verify `head -1 <api>-cli/go.mod`
+4. If wrong, fix with `go mod edit -module` + find-replace in *.go files
+```
+
+---
+
+### Change 10: Validate API Version Header
+
+**File:** SKILL.md Phase 2 (after generation)
+
+```markdown
+### Step 2.7: Validate API Version Header
+
+1. Check what version the API docs say to use
+2. Check what the generated client sends (`grep "Version" client.go`)
+3. If they differ, update client.go to the latest documented version
+4. Test against the live API if a token is available
+```
+
+---
+
+### Change 11: New Anti-Shortcut Rules
+
+Add these to the existing anti-shortcut section:
+
+```markdown
+- "The generated command names are fine" (They're machine names from
+ operationIds. Normalize them: retrieve-a -> get, post -> create.)
+- "The module path is close enough" (It's a Go import path. It must
+ be exact or `go install` fails for everyone.)
+- "0 rows synced is still a PASS" (A pipeline that moves no data is
+ not tested. It's WARN at best.)
+- "Users can go install it" (Most users don't have the Go toolchain.
+ Add goreleaser.)
+- "I chose the name in Phase 0.8" (Choosing isn't applying. Grep for
+ the old name. If it appears, the rename is incomplete.)
+- "The scorecard is the objective" (The scorecard measures proxies.
+ The objective is: would a user of the top competitor switch?)
+- "We complement the incumbent, we don't compete" (Users don't want
+ two CLIs. If the incumbent has a feature, you need it too.)
+- "That feature is anti-scope" (If a competitor with >100 stars has it,
+ it's not anti-scope. It's a backlog item.)
+```
+
+---
+
+### Change 12: Remove "Do NOT default to `<api>-cli`" and enforce `<api>-pp-cli`
+
+Grep the skill for any instruction that discourages using the API name:
+
+```
+- Phase 0.8 line ~793: "Do NOT default to `<api>-cli`" -> REPLACE with `<api>-pp-cli` default
+- Phase 0.5f naming pass: instructions about creative names -> SIMPLIFY
+- Any anti-shortcut about naming -> UPDATE to prefer `<api>-pp-cli`
+```
+
+The naming pass in Phase 0.5f is fine for WORKFLOW commands (user-friendly
+verbs like `stale`, `health`). But the PRODUCT name should be `<api>-pp-cli`.
+
+---
+
+### Change 13: Phase 3 Must Include Competitor Comparison
+
+**File:** SKILL.md Phase 3 (line ~1054)
+
+Add after Step 3.6 (agent-native check):
+
+```markdown
+### Step 3.6b: Competitor Command Comparison
+
+Run this comparison for the top 2 competitors:
+
+For each competitor command, check:
+- Do we have an equivalent? (Y/N)
+- If yes, is ours better? (output, flags, examples)
+- If no, why not? (anti-scope with justification, or add to Phase 4 backlog)
+
+This comparison feeds directly into Phase 4 Priority 1.
+Any "N" without a strong justification becomes a build task.
+```
+
+---
+
+### Change 14: Time Budget Rebalance
+
+**File:** SKILL.md time budget (line ~1900 area)
+
+**Current:**
+```
+Phase 0-1 (Research): 25%
+Phase 2 (Generate): 5%
+Phase 3 (Audit): 5%
+Phase 4 (GOAT Build): 35%
+Phase 4.5 (Dogfood): 10%
+Phase 4.6 (Hallucination): 5%
+Phase 4.8 (Verify): 10%
+Phase 5 (Report): 5%
+```
+
+**Proposed:**
+```
+Phase 0-1 (Research + Parity Audit): 20%
+Phase 2 (Generate + Normalize Names): 5%
+Phase 3 (Audit + Competitor Comparison): 5%
+Phase 4 Priority 0 (Data Layer): 15%
+Phase 4 Priority 1 (Table Stakes): 15% <-- NEW, biggest time allocation
+Phase 4 Priority 2 (Workflows): 10%
+Phase 4 Priority 3-7 (Names, Score, Tests, Dist): 15%
+Phase 4.5-4.8 (Verify): 10%
+Phase 5 (Report + Emboss Offer): 5%
+```
+
+Table stakes features get 15% - the same as the data layer. Because matching the competition IS the product.
+
+---
+
+## Summary: 14 Changes
+
+| # | Change | Where | Impact |
+|---|--------|-------|--------|
+| 1 | Default name to `<api>-pp-cli` | Phase 0.8 | Stop inventing confusing names |
+| 2 | Add Phase 0.6: Feature Parity Audit | New phase after 0.5 | Prevent shipping without table stakes |
+| 3 | Anti-scope requires cost analysis | Phase 0.8 | Stop premature lane narrowing |
+| 4 | Restructure Phase 4 (7 priorities) | Phase 4 | Table stakes before scorecard gaming |
+| 5 | Fix Emboss UX (opt-in only) | Emboss section + Phase 5.9 | Stop confusing users |
+| 6 | Add competitor switch question (keep discrawl+gogcli) | Phase 4 gate | Three benchmarks, not one |
+| 7 | Add competitor feature matrix (keep gogcli scoring) | Phase 3 | Ground product in real feature needs |
+| 8 | Data pipeline smoke test | Phase 5.5 | 0 rows = WARN, not PASS |
+| 9 | Validate module path | Phase 2 | Correct `go install` path |
+| 10 | Validate API version header | Phase 2 | Latest API version, not template default |
+| 11 | New anti-shortcut rules (8 rules) | Anti-shortcut section | Catch gaming, naming, and testing gaps |
+| 12 | Enforce `<api>-pp-cli` naming convention | Phase 0.8, 0.5f | Discoverable, branded, no confusion |
+| 13 | Competitor command comparison in Phase 3 | Phase 3 | Feed gaps into Phase 4 Priority 1 |
+| 14 | Time budget rebalance | Time budget | Table stakes get 15% (same as data layer) |
+
+## The Meta-Fix
+
+The printing-press skill is optimized for generating impressive-looking CLIs that score well on automated quality checks. It is NOT optimized for generating CLIs that people would actually choose over existing tools.
+
+**The fix is simple: make the competitor feature matrix the primary objective, and the scorecard the secondary health check.** Build what users need first, then polish the code patterns.
+
+The question after every run should not be "what's the scorecard?" It should be: **"Would a user of the top competitor switch to this CLI? If not, what's missing?"**
+
+## Acceptance Criteria
+
+- [ ] Phase 0.8 defaults to `<api>-pp-cli` naming (Change 1, 12)
+- [ ] Phase 0.6 Feature Parity Audit exists and is mandatory (Change 2)
+- [ ] Anti-scope requires cost analysis with competitor check (Change 3)
+- [ ] Phase 4 has 7 priorities with table stakes at Priority 1 (Change 4)
+- [ ] Emboss is opt-in only, offered at end of run (Change 5)
+- [ ] Phase 4 gate asks "would top competitor's users switch?" (Change 6)
+- [ ] Phase 3 includes head-to-head feature matrix (Change 7, 13)
+- [ ] Phase 5.5 has data pipeline smoke test (Change 8)
+- [ ] Phase 2 validates module path and API version (Change 9, 10)
+- [ ] 8 new anti-shortcut rules added (Change 11)
+- [ ] Time budget allocates 15% to table stakes (Change 14)
+- [ ] Run printing-press on a test API and verify: competitor features built BEFORE scorecard optimization
+- [ ] gogcli stays as code quality reference, discrawl stays as architecture reference (Change 6, 7)
+- [ ] Run printing-press on Notion again and verify: commands named `get`/`create`/`delete`, binary named `notion-pp-cli`, module path correct
+
+## Sources
+
+- Notion post-mortem: `docs/plans/2026-03-27-fix-printing-press-post-mortem-notion-run-plan.md`
+- Linear/lz assessment: `docs/plans/2026-03-27-docs-lz-cli-honest-quality-assessment.md`
+- User feedback: "I'm extremely disappointed. The printing-press is so close to being good, but also it's not"
+- Current SKILL.md: `~/.claude/skills/printing-press/SKILL.md` (1,915 lines)
diff --git a/docs/plans/2026-03-27-fix-printing-press-post-mortem-notion-run-plan.md b/docs/plans/2026-03-27-fix-printing-press-post-mortem-notion-run-plan.md
new file mode 100644
index 00000000..309b3c29
--- /dev/null
+++ b/docs/plans/2026-03-27-fix-printing-press-post-mortem-notion-run-plan.md
@@ -0,0 +1,286 @@
+---
+title: "Post-Mortem: Printing Press Notion Run - Process Gaps"
+type: fix
+status: active
+date: 2026-03-27
+phase: "retrospective"
+api: "printing-press (meta)"
+---
+
+# Post-Mortem: What the Printing Press Got Wrong on the Notion Run
+
+## Overview
+
+The Notion run produced a 74/100 Grade B CLI with genuinely unique architecture (SQLite + FTS5 + domain tables + 12 insight commands). But it shipped with ugly command names, wrong binary name, stale module path, untested sync pipeline, and no distribution. All of these were knowable and fixable during the run. The skill's process failed to catch them.
+
+This plan identifies the root cause for each gap and proposes concrete changes to the printing-press SKILL.md to prevent recurrence.
+
+## Gap Analysis: What Went Wrong and Why
+
+### 1. Command Names: `retrieve-a`, `delete-a` instead of `get`, `delete`
+
+**What happened:** The generator produced operation IDs from the OpenAPI spec verbatim. Notion's spec uses `operationId: "Retrieve a block"` which becomes `retrieve-a` in kebab-case.
+
+**Root cause:** The skill has no **Phase 2.5: Command Name Normalization** step. Phase 0.8 chose the product name (`noto`) but nothing maps ugly generated names to clean ones.
+
+**Fix for SKILL.md:**
+
+Add after Phase 2 Step 2.3:
+
+```markdown
+### Step 2.5: Command Name Normalization
+
+After generation, normalize command names to match user expectations:
+
+1. Run: `grep -r 'Use:' <api>-cli/internal/cli/*.go | grep -v root.go`
+2. For each command, apply these rules:
+ - `retrieve-a*` -> `get` (Notion, Stripe, etc. use "Retrieve a X")
+ - `delete-a*` -> `delete`
+ - `create-a*` -> `create`
+ - `update-a*` -> `update`
+ - `post` -> `create` (when the endpoint creates a resource)
+ - `patch` -> `update` (when the endpoint updates a resource)
+ - `get-self` -> `me` (for /users/me style endpoints)
+ - `get-userid` -> `get` (redundant ID suffix)
+ - `list-*` -> `list` (strip resource name suffix)
+3. Rename both the `Use:` field and the filename
+4. Update root.go registrations
+5. Verify `go build` still passes
+
+**This step is mandatory.** Generated names are for machines.
+User-facing names are for humans.
+```
+
+---
+
+### 2. Binary Name and Help Text Still Say `notion-cli`
+
+**What happened:** Phase 0.8 chose the name `noto`. But the generator created `cmd/notion-cli/`, `root.go` says `Use: "notion-cli"`, README examples say `notion-cli`. The name was never applied.
+
+**Root cause:** The skill chooses a name in Phase 0.8 but has no **Phase 2.6: Apply Product Name** step. The name lives in a plan document but never touches the code.
+
+**Fix for SKILL.md:**
+
+Add after Step 2.5:
+
+```markdown
+### Step 2.6: Apply Product Name
+
+The name chosen in Phase 0.8 MUST be applied to the generated CLI:
+
+1. Rename `cmd/<api>-cli/` to `cmd/<chosen-name>/`
+2. Update `root.go`:
+ - `Use:` field -> chosen name
+ - `SetVersionTemplate` -> chosen name
+ - All help text references
+3. Update `README.md`: replace all occurrences of the generated name
+4. Update `go.mod` module path if needed (e.g., `github.com/<org>/<chosen-name>`)
+5. Update `internal/client/client.go`:
+ - User-Agent header
+ - Default config directory name
+6. Verify: `grep -r "notion-cli" .` should return 0 hits (except in
+ "Generated by" comments)
+
+**Gate:** If `grep -r "<old-name>" . | grep -v "Generated by"` returns
+any hits, the rename is incomplete. Fix before proceeding.
+```
+
+---
+
+### 3. Module Path: `github.com/matt-van-horn/notion-cli` vs `github.com/mvanhorn/noto`
+
+**What happened:** The generator derived the module path from git config (`user.name = matt-van-horn`). This produced a hyphenated GitHub username that doesn't match reality (`mvanhorn`), and used the API name instead of the product name.
+
+**Root cause:** The generator auto-derives the module path but the skill doesn't validate it. There's no step that asks: "Is this the right GitHub org/repo name?"
+
+**Fix for SKILL.md:**
+
+Add to Phase 2 prerequisites:
+
+```markdown
+### Step 2.0b: Validate Module Path
+
+Before running the generator, check the module path it will use:
+
+1. Run: `git config user.name` -> this becomes the org in the module path
+2. If this doesn't match your actual GitHub username, set it:
+ ```bash
+ export PRINTING_PRESS_ORG="<correct-github-username>"
+ ```
+3. The module path should be: `github.com/<org>/<chosen-name-from-phase-0.8>`
+4. After generation, verify: `head -1 <api>-cli/go.mod`
+5. If wrong, fix with:
+ ```bash
+ cd <api>-cli
+ go mod edit -module github.com/<org>/<name>
+ find . -name '*.go' -exec sed -i '' "s|<old-module>|<new-module>|g" {} +
+ go build ./...
+ ```
+```
+
+---
+
+### 4. API Version Header Pinned to 2022-06-28 (Spec Was 2026)
+
+**What happened:** The generator's client template hardcodes `Notion-Version: 2022-06-28`. The spec we downloaded was from March 2026. Nobody checked.
+
+**Root cause:** The skill doesn't have a **Phase 2.7: Validate API Version** step. The generator uses a static template for the client, not the spec's version info.
+
+**Fix for SKILL.md:**
+
+Add after Phase 2:
+
+```markdown
+### Step 2.7: Validate API Version Header
+
+The generated client may pin to an outdated API version. Fix it:
+
+1. Check the spec for the API version:
+ ```bash
+ python3 -c "import json; d=json.load(open('/tmp/<spec>')); print(d.get('info',{}).get('version','?'))"
+ ```
+2. Check the generated client's version header:
+ ```bash
+ grep -n "Version" <api>-cli/internal/client/client.go
+ ```
+3. If the API docs specify a date-based version header (like Notion, Stripe),
+ use the LATEST documented version, not the spec's version field.
+4. Verify by searching the API's changelog for the latest version string.
+5. Update the header in client.go.
+6. **Test with the live API** (if token available) to confirm the version
+ header is accepted.
+
+**Anti-shortcut:** "The generator's default is fine" - NO. Check it.
+```
+
+---
+
+### 5. Sync Pipeline Was Never Tested With Real Data
+
+**What happened:** The live test synced 17 users but 0 pages. The integration token didn't have page access (Notion requires explicit sharing). The report said "PASS" anyway.
+
+**Root cause:** Phase 5.5's safety rules correctly limited to read-only GETs, but the verdict logic treated "0 pages synced" as success. The skill needs a **data pipeline smoke test** that flags empty results as WARN, not PASS.
+
+**Fix for SKILL.md:**
+
+Update Phase 5.5 verdict logic:
+
+```markdown
+### Step 5.5g: Data Pipeline Smoke Test
+
+After sync, verify the pipeline actually moved data:
+
+1. Check entity counts:
+ ```bash
+ <cli> sql "SELECT 'pages' as t, COUNT(*) as n FROM pages
+ UNION ALL SELECT 'blocks', COUNT(*) FROM blocks
+ UNION ALL SELECT 'users', COUNT(*) FROM users"
+ ```
+2. **If ANY primary entity (from Phase 0.7) has 0 rows:**
+ - Verdict: **WARN** (not PASS)
+ - Report: "Sync completed but [entity] has 0 rows. Possible causes:
+ integration permissions, empty workspace, or sync bug."
+ - Suggest: "Share at least one page with the integration and re-run sync."
+3. **If primary entities have rows, test the read path:**
+ - `<cli> search "a" --limit 1` should return results
+ - `<cli> stale --days 9999` should return all pages
+ - `<cli> health` should show non-zero totals
+4. **If search returns 0 results but pages exist:**
+ - FTS5 indexing is broken. This is a FAIL, not a WARN.
+
+**The sync pipeline isn't tested until data flows through it.**
+"17 users synced, 0 pages" is not a passing grade.
+```
+
+---
+
+### 6. No Distribution (Homebrew, goreleaser, Docker)
+
+**What happened:** The skill doesn't address distribution at all. It stops at "go build passes."
+
+**Root cause:** The skill's definition of "ship ready" is "compiles and scores well." It doesn't include "users can install it."
+
+**Fix for SKILL.md:**
+
+Add Phase 5.8: Distribution Scaffold:
+
+```markdown
+### Phase 5.8: Distribution Scaffold (Optional but Recommended)
+
+If the CLI scores Grade B or higher, add distribution scaffolding:
+
+1. **goreleaser config** (.goreleaser.yaml):
+ ```yaml
+ builds:
+ - main: ./cmd/<name>
+ goos: [linux, darwin, windows]
+ goarch: [amd64, arm64]
+ ```
+2. **Homebrew formula** (Formula/<name>.rb):
+ - Generate from goreleaser or write manually
+3. **Dockerfile** (for containerized usage)
+4. **GitHub Actions CI** (.github/workflows/ci.yml):
+ - go test, go vet, goreleaser on tag push
+
+This is scaffolding only - the user decides when to actually release.
+But a CLI that can't be installed is not a CLI.
+```
+
+---
+
+### 7. Phase 0.8 Product Name Was Ignored Throughout
+
+**What happened:** Phase 0.8 chose `noto`. Every subsequent phase used `notion-cli`. The name was a dead artifact.
+
+**Root cause:** Phase 0.8 writes a product thesis into a plan document. No phase reads it back. The name should be an **environment variable** that flows through all subsequent phases.
+
+**Fix for SKILL.md:**
+
+Add to Phase 0.8 gate:
+
+```markdown
+### PHASE GATE 0.8 (updated)
+
+**STOP.** After choosing the name, SET IT as a variable for all subsequent phases:
+
+```bash
+export CLI_NAME="<chosen-name>"
+export CLI_MODULE="github.com/<org>/<chosen-name>"
+```
+
+Every subsequent phase that creates files, writes help text, or references
+the CLI MUST use $CLI_NAME, not the API name.
+
+**Gate check:** Before proceeding, verify:
+- `echo $CLI_NAME` returns the chosen name (not empty, not "<api>-cli")
+- `echo $CLI_MODULE` returns a valid Go module path
+```
+
+---
+
+## Summary: 7 Process Gaps, 7 Fixes
+
+| Gap | Root Cause | Fix | Phase |
+|-----|-----------|-----|-------|
+| Ugly command names | No normalization step | Add Step 2.5: Command Name Normalization | Phase 2 |
+| Binary name wrong | Name chosen but never applied | Add Step 2.6: Apply Product Name | Phase 2 |
+| Module path wrong | Auto-derived from git config, not validated | Add Step 2.0b: Validate Module Path | Phase 2 |
+| API version stale | Generator uses static template | Add Step 2.7: Validate API Version | Phase 2 |
+| Sync untested with real data | 0-row result counted as PASS | Add Step 5.5g: Data Pipeline Smoke Test | Phase 5.5 |
+| No distribution | Skill stops at "compiles" | Add Phase 5.8: Distribution Scaffold | Phase 5 |
+| Product name ignored | Name in doc, not in env | Add $CLI_NAME env var to Phase 0.8 gate | Phase 0.8 |
+
+## Anti-Shortcut Rules to Add
+
+```
+- "The generated command names are fine" (They're machine names. Normalize them.)
+- "The module path is close enough" (It's a Go import path. It must be exact.)
+- "0 rows synced is still a PASS" (A pipeline that moves no data is not tested.)
+- "Users can go install it" (Users shouldn't need to clone the repo. Add goreleaser.)
+- "I chose the name in Phase 0.8" (Choosing it isn't applying it. Grep for the old name.)
+```
+
+## Sources
+- noto Notion CLI run (2026-03-27): 74/100 Grade B with 7 preventable gaps
+- 4ier/notion-cli (91 stars): benchmark for command naming and distribution
+- Phase 0-5 artifacts in docs/plans/2026-03-27-*
diff --git a/skills/printing-press/SKILL.md b/skills/printing-press/SKILL.md
index ea0a6a17..235d64d1 100644
--- a/skills/printing-press/SKILL.md
+++ b/skills/printing-press/SKILL.md
@@ -29,6 +29,12 @@ Generate the best CLI that has ever existed for any API. Five mandatory phases.
## Emboss Mode (Second Pass)
+**Emboss is opt-in.** It NEVER runs automatically. It runs when:
+1. The user explicitly types `/printing-press emboss <dir>`
+2. The user selects "Yes, run emboss" from the Phase 5.9 prompt after a main run
+
+If the user did NOT request emboss, do NOT mention it, do NOT run it, do NOT show emboss reports.
+
When the user's arguments start with `emboss`, this is NOT a from-scratch run. The CLI already exists. Run a 30-minute improvement cycle.
```
@@ -623,6 +629,53 @@ These will be built as real commands in Phase 4, alongside the API wrapper."
---
+# PHASE 0.6: FEATURE PARITY AUDIT
+
+## THIS PHASE IS MANDATORY. DO NOT SKIP IT.
+
+Before brainstorming novel features, catalog what the competition already ships. This is the missing link between research and build. Phase 0.5 brainstorms additive workflows. This phase checks if we can do what the incumbent already does.
+
+### Step 0.6a: Feature Matrix
+
+For the top 2 competitors by stars (from Phase 0/1 research):
+
+| Feature | Competitor A | Competitor B | Ours | Classification |
+|---------|-------------|-------------|------|----------------|
+
+List EVERY command and feature they offer. Read their README, --help output, and documentation.
+
+### Step 0.6b: Classify Each Feature
+
+- **TABLE STAKES**: >50% of users expect any CLI for this API to have it.
+ Examples: `issue create`, `page get`, git branch from issue, clean CRUD names (get/create/update/delete)
+- **NICE-TO-HAVE**: Useful but not expected. Won't lose users if missing.
+ Examples: interactive prompts, TUI mode, plugins
+- **ANTI-SCOPE**: Genuinely out of scope with justification.
+ Examples: full TUI, mobile app, GUI
+
+**Classification rules:**
+- If ANY competitor with >100 stars has it, it's TABLE STAKES unless you provide an explicit reason it's anti-scope.
+- If users mention it in issues/Reddit with >10 upvotes, it's TABLE STAKES.
+- "Complements the incumbent" is NOT a reason to skip a feature. Users don't want to install two CLIs.
+
+### Step 0.6c: Table Stakes Become Phase 4 Mandatory Work
+
+Every TABLE STAKES feature becomes a Phase 4 Priority 1 work item. They are built ALONGSIDE the data layer, not instead of it.
+
+### PHASE GATE 0.6
+
+**STOP.** Verify:
+1. Feature matrix complete for top 2 competitors
+2. Every feature classified as TABLE STAKES / NICE-TO-HAVE / ANTI-SCOPE
+3. TABLE STAKES list has at least 3 items
+4. Anti-scope items have explicit cost analysis ("What % of users need this? Does a competitor with >100 stars offer it?")
+
+Tell the user: "Feature parity audit: [N] table-stakes features identified from [competitor names]. Top gaps: [list]. These will be built in Phase 4."
+
+**Write Phase 0.6 Artifact:** Run the Artifact Writing plan generator with all Phase 0.6 analysis as input. Write to `~/cli-printing-press/docs/plans/<today>-feat-<api>-cli-feature-parity-audit.md`. Include: full feature matrix, classifications with justification, table stakes list for Phase 4.
+
+---
+
# PHASE 0.7: POWER USER PREDICTION ENGINE
## THIS PHASE IS MANDATORY. DO NOT SKIP IT.
@@ -783,13 +836,22 @@ Before generating any code, articulate why someone would install this CLI. If yo
- Bad: "A new CLI for the GitHub API"
- Good: "I built a GitHub CLI that finds stale PRs and lets you SQL query your repos offline"
-4. **What's the name?** (short, memorable, not confused with the incumbent)
- - Consider: trademark risk, existing tools with that name, domain clarity
- - Test: can you `brew install <name>` without collision?
- - The generator will use this name. Do NOT default to `<api>-cli`.
+4. **What's the name?**
+ - DEFAULT: `<api>-pp-cli` (e.g., `notion-pp-cli`, `linear-pp-cli`, `stripe-pp-cli`)
+ - The `-pp-` identifies it as a printing press product.
+ - This is discoverable (`brew search notion` finds `notion-pp-cli`).
+ - Creative names are allowed ONLY if the user explicitly requests one.
+ - The printing press is a code generator, not a branding agency.
+
+5. **What's the anti-scope and what does it cost?**
+
+ For each anti-scope item, answer:
+ - What % of potential users need this feature?
+ - Does any competitor with >100 stars offer it?
+ - If yes: this is NOT anti-scope, it's a backlog item. Move to Phase 4 Priority 1.
-5. **What's the anti-scope?** (what we deliberately do NOT build)
- - Example: "Not a TUI. Not a git replacement. Complements gh, doesn't replace it."
+ VALID anti-scope: "Not a TUI" (no competitor offers one either)
+ INVALID anti-scope: "Not a git integration" (the top competitor's killer feature - you just excluded the #1 reason people install it)
### Step 0.8b: Write the Product Thesis
@@ -800,7 +862,7 @@ Write one paragraph that combines the answers above. This paragraph should make
**STOP.** Verify:
1. All 5 questions answered with specific, non-generic answers
2. Product thesis paragraph written
-3. Name chosen (not `<api>-cli`)
+3. Name set to `<api>-pp-cli` (default) unless user specified otherwise
4. Comparison table has at least one row where we clearly win
Tell the user: "Product thesis: [1-sentence pitch]. Name: [name]. Key differentiator: [comparison table winner]. Proceeding to deep research."
@@ -997,6 +1059,22 @@ Before generating, verify the spec matches the API:
3. **If the spec describes REST endpoints but the API base URL contains `/graphql`** ->
Warn: "The spec describes REST endpoints but the API appears to be GraphQL. Double-check which is authoritative. If the REST spec is valid, proceed with REST generation. If GraphQL is the real API, switch to GraphQL mode."
+### Step 2.0b: Validate Module Path
+
+Before running the generator, check the module path it will use:
+
+1. Run: `git config user.name` - this becomes the org in the module path
+2. If this doesn't match your actual GitHub username, note the correct one
+3. The module path should be: `github.com/<correct-github-username>/<product-name-from-phase-0.8>`
+4. After generation, verify: `head -1 <api>-pp-cli/go.mod`
+5. If wrong, fix with:
+ ```bash
+ cd <api>-pp-cli
+ go mod edit -module github.com/<org>/<name>
+ find . -name '*.go' -exec sed -i '' "s|<old-module>|<new-module>|g" {} +
+ go build ./...
+ ```
+
### Step 2.1: Get the spec ready
**If OpenAPI spec found:**
@@ -1040,14 +1118,31 @@ Save the list of skipped fields. These are NOT acceptable limitations - they are
Max 3 retries. Read errors carefully and fix spec issues.
+### Step 2.7: Validate API Version Header
+
+The generated client may pin to an outdated API version. Fix it:
+
+1. Check what version the API docs say to use (search the API's changelog or docs)
+2. Check the generated client's version header:
+ ```bash
+ grep -n "Version" <api>-pp-cli/internal/client/client.go
+ ```
+3. If the API uses date-based version headers (like Notion, Stripe), use the LATEST documented version, not the spec's version field or the generator's template default.
+4. Update the header in client.go.
+5. **Test with the live API** (if token available from Phase 0.1) to confirm the version header is accepted.
+
+**Anti-shortcut:** "The generator's default is fine" - NO. Check it.
+
### PHASE GATE 2
**STOP.** Verify:
1. CLI directory exists
2. `go build ./...` succeeds
3. List of skipped complex body fields is saved for Phase 3
+4. Module path is correct (Step 2.0b)
+5. API version header is current (Step 2.7)
-Tell the user: "Phase 2 complete: Generated <api>-cli with [N] resources, [M] endpoints. [K] complex body fields noted for Phase 4. Proceeding to Non-Obvious Insight Review."
+Tell the user: "Phase 2 complete: Generated <api>-pp-cli with [N] resources, [M] endpoints. [K] complex body fields noted for Phase 4. Proceeding to Non-Obvious Insight Review."
---
@@ -1134,14 +1229,32 @@ Score each dimension 0-10. For EACH dimension, provide THREE things:
**Baseline Total: X/100 (Grade X)**
```
+### Step 3.7b: Head-to-Head Competitor Feature Matrix
+
+The 10-dimension score (above) measures code quality against gogcli. This step measures feature completeness against the ACTUAL competition.
+
+For the top 2 competitors (from Phase 1):
+
+| Feature | Competitor A | Competitor B | Ours | Status |
+|---------|-------------|-------------|------|--------|
+| (list every command they have) | Y/N | Y/N | Y/N | HAVE / MISSING / BETTER |
+
+MISSING features with >50% user need become Phase 4 Priority 1 work items.
+BETTER features are our differentiators - highlight in README comparison table.
+
+**The gogcli score tells you if the code is good.**
+**The competitor matrix tells you if the product is good.**
+**You need both.** A CLI that scores 10/10 on output modes but can't do what the top competitor does is a well-polished toy.
+
### Step 3.8: Write the GOAT improvement plan
-Based on the quality analysis, identify:
+Based on the quality analysis AND the competitor feature matrix, identify:
-1. **Top 5 highest-impact improvements** (will raise the score the most)
-2. **Commands to ADD** (not just rename - new functionality)
-3. **Complex body field examples** to add (top 3 endpoints where --stdin matters most)
-4. **What's achievable in Phase 4** vs what's future work
+1. **TABLE STAKES gaps** (from Phase 0.6 + Step 3.7b - highest priority)
+2. **Top 5 highest-impact quality improvements** (will raise the score the most)
+3. **Commands to ADD** (not just rename - new functionality)
+4. **Complex body field examples** to add (top 3 endpoints where --stdin matters most)
+5. **What's achievable in Phase 4** vs what's future work
### Step 3.9: Write the audit artifact
@@ -1267,7 +1380,19 @@ CONSTRAINTS:
- If SSE: implement EventSource reader
- If REST polling: keep current implementation but use domain-aware cursors
-### Priority 1: Power User Workflows (from Phase 0.5) - NOW powered by local DB
+### Priority 1: Table Stakes Features (from Phase 0.6)
+
+**Build every feature classified as TABLE STAKES in Phase 0.6.** These are features that the top competitor has and that >50% of users expect. This is NOT optional polish - these are the features that determine whether anyone would switch from the incumbent.
+
+For each table-stakes feature:
+1. Read how the competitor implements it (from Phase 1 research)
+2. Implement it - don't just match the competitor, make it BETTER
+3. Better means: works with --json, supports --dry-run, has --stdin, composes with our data layer where possible
+4. Register in root.go alongside the generated commands
+
+**Gate:** Every TABLE STAKES feature from Phase 0.6 must be implemented before proceeding to Priority 2. No exceptions.
+
+### Priority 2: Power User Workflows (from Phase 0.5) - NOW powered by local DB
Implement the top 5-7 workflows identified in Phase 0.5 as real, hand-written Go commands. **Where possible, query the local SQLite database instead of making live API calls.** This makes workflows instant and avoids rate limits.
@@ -1279,48 +1404,92 @@ For each workflow:
5. **Support --json output** for agent consumption
6. **Register in root.go** alongside the generated commands
-Example for a "stale issues" workflow on a project management API:
-```go
-func newStaleCmd(flags *rootFlags) *cobra.Command {
- var days int
- var team string
- cmd := &cobra.Command{
- Use: "stale",
- Short: "Find issues with no updates in N days",
- Example: ` linear-cli stale --days 30 --team ENG
- linear-cli stale --days 14 --json --select identifier,title,updatedAt`,
- RunE: func(cmd *cobra.Command, args []string) error {
- c, err := flags.newClient()
- // ... fetch issues, filter by updatedAt, group by team
- },
- }
-}
-```
+### Priority 3: Command Name Normalization + Apply Product Name
+
+**Step 3a: Normalize generated command names**
+
+The generator produces ugly operationId-derived names. Fix them:
+
+| Generated | Normalized | Rule |
+|-----------|-----------|------|
+| `retrieve-a*` | `get` | Strip "Retrieve a" prefix |
+| `delete-a*` | `delete` | Strip "Delete a" prefix |
+| `create-a*` | `create` | Strip "Create a" prefix |
+| `update-a*` | `update` | Strip "Update a" prefix |
+| `post` | `create` | HTTP method -> action |
+| `patch` | `update` | HTTP method -> action |
+| `get-self` | `me` | Special case |
+| `list-*` | `list` | Strip resource suffix |
+
+For each rename: update the `Use:` field, rename the file, verify `go build` passes.
-### Priority 2: Scorecard-Gap Fixes
+**Step 3b: Apply the product name everywhere**
-Run the scorecard and fix dimensions below 10/10:
+1. Rename `cmd/<generated-name>/` to `cmd/<product-name>/`
+2. Update root.go Use field and version template
+3. Update go.mod module path to `github.com/<org>/<product-name>`
+4. Update client.go User-Agent header
+5. `grep -r "<old-name>" . | grep -v "Generated by"` must return 0 hits
+6. Update README examples
+
+**Step 3c: Validate API version header**
+
+1. Check what API version the spec uses / the API docs recommend
+2. Check what the generated client sends (`grep "Version" client.go`)
+3. If they differ, update client.go to the latest documented version
+4. If the API uses date-based versions (Notion, Stripe), use the LATEST
+
+### Priority 4: Scorecard Gap Fixes (DEMOTED + ANTI-GAMING)
+
+Run the scorecard. Fix REAL gaps. DO NOT GAME IT.
```bash
cd ~/cli-printing-press && ./printing-press scorecard --dir ./library/<api>-cli
```
-For each dimension below 10/10:
-1. **Read** the relevant file
-2. **Edit** with surgical changes
-3. Focus on changes that RAISE THE SCORECARD NUMBER
+**ANTI-GAMING RULES:**
+- If a function exists only because the scorecard checks for a string pattern, DELETE IT.
+- If a flag is registered but never checked in any RunE, DELETE IT.
+- If an import exists only to put "store." in the file, DELETE IT.
+- A CLI that scores 60 but has every table-stakes feature beats one that scores 80 with type aliases.
+- The scorecard measures proxies for quality. Optimize for actual quality.
Also fix:
- Complex body field --stdin examples for top 3 endpoints
- Lazy descriptions (1-2 word Short fields)
- Placeholder examples ("abc123" -> realistic domain values)
-### Priority 3: Polish
+### Priority 5: Write Tests
+
+A CLI with 0 test files is not shippable.
-Only after Priority 1 and 2 are complete:
-1. README cookbook section **showcasing workflow commands** (not just API calls)
-2. Command name cleanup
-3. FAQ section with domain-specific questions
+For each Primary entity in the data layer:
+1. Test UpsertX with valid data -> verify row in DB
+2. Test UpsertX with missing fields -> verify graceful handling
+3. Test SearchX with FTS5 -> verify results match
+
+For each workflow command:
+1. Seed DB with test fixtures
+2. Run the command's core query
+3. Verify result shape and counts
+
+Minimum: 1 test file per package (store, cli). Use table-driven tests matching Go conventions.
+
+### Priority 6: Distribution Scaffold
+
+1. Add `.goreleaser.yaml` for cross-platform binary builds
+2. Add Homebrew formula or tap
+3. Add install instructions for non-Go users to README
+4. Add `.github/workflows/ci.yml` (go test, go vet, goreleaser on tag)
+
+A CLI that can only be installed via `go install` is not a real CLI.
+
+### Priority 7: Polish
+
+Only after all above priorities are complete:
+1. README cookbook section **showcasing workflow commands AND table-stakes features** (not just API calls)
+2. FAQ section with domain-specific questions
+3. Comparison table in README showing where we beat each competitor
### Step 4.4: Verify compilation
@@ -1330,21 +1499,47 @@ cd ~/cli-printing-press/library/<api>-cli && go build ./... && go vet ./... && e
### PHASE GATE 4
-**STOP.** Verify:
-1. Data layer implemented: domain-specific SQLite tables (NOT generic JSON blobs)
+**STOP.** Verify ALL priorities:
+
+**Priority 0 (Data Layer):**
+1. Domain-specific SQLite tables (NOT generic JSON blobs)
2. Sync command uses domain-aware cursors (validated in Phase 0.7)
3. Search supports domain-specific filters (--channel, --author, --team, etc.)
4. `sql` command exists for raw read-only queries
-5. At least 3 workflow commands implemented (from Phase 0.5)
-6. Workflow commands use local DB where possible (not just live API calls)
-7. Scorecard gaps addressed
-8. `go build ./...` and `go vet ./...` pass
-9. README cookbook includes data layer + workflow examples
-10. **Data Pipeline Trace (MANDATORY):** For each Primary entity from Phase 0.7, verify:
- - WRITE path exists: sync.go calls `db.UpsertX()` for this entity (file:line)
- - READ path exists: at least one command queries this entity's table (file:line)
- - SEARCH path exists (if FTS5): at least one command calls `db.SearchX()` (file:line)
- - If ANY Primary entity has no WRITE path, the data layer is broken. Fix before proceeding.
+
+**Priority 1 (Table Stakes):**
+5. Every TABLE STAKES feature from Phase 0.6 is implemented
+6. Table stakes features work with --json, --dry-run, --stdin where applicable
+
+**Priority 2 (Workflows):**
+7. At least 3 workflow commands implemented (from Phase 0.5)
+8. Workflow commands use local DB where possible (not just live API calls)
+
+**Priority 3 (Names):**
+9. Command names normalized (get/create/update/delete, not retrieve-a/post/patch)
+10. Binary name matches product name from Phase 0.8
+11. Module path is correct
+
+**Priority 4-7:**
+12. `go build ./...` and `go vet ./...` pass
+13. At least 1 test file per package (store, cli)
+14. README cookbook includes data layer + workflow + table-stakes examples
+
+**Data Pipeline Trace (MANDATORY):** For each Primary entity from Phase 0.7, verify:
+- WRITE path exists: sync.go calls `db.UpsertX()` for this entity (file:line)
+- READ path exists: at least one command queries this entity's table (file:line)
+- SEARCH path exists (if FTS5): at least one command calls `db.SearchX()` (file:line)
+- If ANY Primary entity has no WRITE path, the data layer is broken. Fix before proceeding.
+
+**Three-Benchmark Check (MANDATORY):**
+
+1. ARCHITECTURE (discrawl benchmark): "Does this CLI have a real data layer - domain-specific SQLite tables, FTS5 search, incremental sync, workflow commands that query local data?" If no, Priority 0 isn't done.
+
+2. QUALITY (gogcli benchmark): "Does the code have proper output modes, typed errors, agent-native flags, doctor command, README with cookbook?" If gaps, Priority 4 scorecard fixes address them.
+
+3. FEATURES (competitor benchmark): "Would a user of [top competitor from Phase 1] switch to this CLI?" If no: "What's the ONE feature that would flip them?" Build it now before proceeding.
+
+All three must pass. Architecture without features is a toy. Features without architecture is a thin wrapper. Quality without either is polished nothing.
**Write Phase 4 Artifact:** Run the Artifact Writing plan generator with all Phase 4 work as input. Write to `~/cli-printing-press/docs/plans/<today>-fix-<api>-cli-goat-build-log.md`. Include: data layer implementation details, workflow commands built, scorecard fixes, what was skipped, before/after scorecard comparison.
@@ -1783,6 +1978,29 @@ Parsing: N errors (list any JSON parsing failures)
Verdict: PASS/WARN/FAIL
```
+### Step 5.5g: Data Pipeline Smoke Test
+
+After sync, verify data actually flowed through:
+
+1. Query entity counts:
+ ```bash
+ <cli> sql "SELECT 'pages' as t, COUNT(*) as n FROM pages
+ UNION ALL SELECT 'blocks', COUNT(*) FROM blocks
+ UNION ALL SELECT 'users', COUNT(*) FROM users"
+ ```
+2. **If ANY primary entity (from Phase 0.7) has 0 rows:**
+ - Verdict: **WARN** (not PASS)
+ - Report: "Sync completed but [entity] has 0 rows. Possible causes: integration permissions, empty workspace, or sync bug."
+ - Suggest: "Share at least one resource with the integration and re-run sync."
+3. **If primary entities have rows, test the read path:**
+ - `<cli> search "a" --limit 1` should return results
+ - `<cli> stale --days 9999` should return all pages
+ - `<cli> health` should show non-zero totals
+4. **If search returns 0 results but rows exist:**
+ - FTS5 indexing is broken. This is a FAIL, not a WARN.
+
+**"0 rows synced" is NEVER a PASS.** A pipeline that moves no data is not tested.
+
If ANY test fails (WARN or FAIL verdict), automatically enter Phase 5.7 Ship Loop:
1. For each failure, classify the bug:
@@ -1837,6 +2055,21 @@ When the user asks "is this shippable?", "can we ship this?", "is it ready?", or
---
+# PHASE 5.9: OFFER EMBOSS
+
+After presenting the final report (Phase 5), ask the user:
+
+"The CLI scored [X]/100 (Grade [Y]). Want me to run an emboss pass to improve it further? This re-researches the landscape, finds the top 5 improvements, builds them, and re-scores."
+
+Options:
+- "Yes, run emboss" -> proceed to Emboss Mode (top of this skill)
+- "No, I'm done" -> end the run
+- "I'll emboss later" -> tell user they can run `/printing-press emboss ./<api>-pp-cli`
+
+**Emboss is a FOLLOW-UP, not an automatic step. The user decides.**
+
+---
+
## Writing Specs from Docs
When no OpenAPI spec exists:
@@ -1874,7 +2107,7 @@ These phrases indicate a phase was shortcut. If you catch yourself writing them,
- "The API is GraphQL-only so we can't use printing-press" (Wrong. Skip the REST generator, hand-write commands with a GraphQL client in Phase 4. Every other phase runs normally.)
- "I'll polish the README instead of building workflows" (Phase 4 Priority 1 is workflows. README is Priority 3. Do not skip ahead.)
- "The Phase 0.5 workflows are future work" (They are the product. Build them now or the CLI is just an API wrapper.)
-- "316 commands is better than 12" (discrawl has 12 commands and 539 stars. Depth beats breadth. Build the workflows.)
+- "316 commands is better than 12" (Depth beats breadth - discrawl proves this. But depth means building the RIGHT 12 commands, not the same 12 commands for every API. Check the competitor feature matrix from Phase 0.6.)
- "The API doesn't need local persistence" (Check data gravity scores from Phase 0.7. If any entity scores >= 8, it needs SQLite with proper columns.)
- "FTS5 is overkill for this API" (If any entity has 2+ text fields AND data gravity >= 8, it needs FTS5. That's how search works.)
- "REST polling is fine for tail" (Check if the API has WebSocket/SSE/Gateway. If yes, use it. REST polling misses events and wastes rate limit budget.)
@@ -1892,19 +2125,30 @@ These phrases indicate a phase was shortcut. If you catch yourself writing them,
- "The scorecard is 73 so it's good enough" (The scorecard measures files, not behavior. A 73 scorecard with 0% verify pass rate is a CLI that looks good on paper and crashes on first use. Run verify.)
- "I tested 5 commands manually, that's enough" (5/127 is 3.9%. That's not testing. Run `printing-press verify` which tests every command automatically in under 60 seconds.)
- "The CLI compiles so it's ready to ship" (Compilation proves syntax. `printing-press verify` proves behavior. A CLI that compiles but 404s on sync is not shippable.)
+- "The generated command names are fine" (They're machine names from operationIds. Normalize them: retrieve-a -> get, post -> create. Phase 4 Priority 3.)
+- "The module path is close enough" (It's a Go import path. It must be exact or `go install` fails for everyone.)
+- "0 rows synced is still a PASS" (A pipeline that moves no data is not tested. It's WARN at best.)
+- "Users can go install it" (Most users don't have the Go toolchain. Add goreleaser. Phase 4 Priority 6.)
+- "I chose the name in Phase 0.8" (Choosing isn't applying. Grep for the old name. If it appears, the rename is incomplete.)
+- "The scorecard is the objective" (The scorecard measures proxies. The objective is: would a user of the top competitor switch? Check the three-benchmark gate.)
+- "We complement the incumbent, we don't compete" (Users don't want two CLIs. If the incumbent has a feature, you need it too - Phase 0.6 table stakes.)
+- "That feature is anti-scope" (If a competitor with >100 stars has it, it's not anti-scope. It's a backlog item. Phase 0.6 classification rules.)
**Module path rule:**
- The go.mod module path MUST be a valid Go import path with a real org name (e.g., `github.com/mvanhorn/discord-cli`). The literal string `USER` is never acceptable. The generator auto-derives from git config.
**Time Budget Guidance:**
-- Phase 0-1 (Research + Prediction): 25% of total time
-- Phase 2 (Generate): 5%
-- Phase 3 (Audit): 5%
-- **Phase 4 (GOAT Build): 35%** - THIS IS WHERE THE PRODUCT IS BUILT. Do not rush.
-- Phase 4.5 (Dogfood): 10%
-- Phase 4.6 (Hallucination Audit): 5%
-- **Phase 4.8 (Runtime Verification): 10%** - THIS IS WHERE YOU PROVE IT WORKS. Do not skip.
-- Phase 5 (Final Report): 5%
+- Phase 0-1 (Research + Parity Audit): 20% of total time
+- Phase 2 (Generate + Normalize Names): 5%
+- Phase 3 (Audit + Competitor Comparison): 5%
+- **Phase 4 Priority 0 (Data Layer): 15%** - The architecture foundation.
+- **Phase 4 Priority 1 (Table Stakes): 15%** - Match the competition. THIS IS THE PRODUCT.
+- Phase 4 Priority 2 (Workflows): 10%
+- Phase 4 Priority 3-7 (Names, Score, Tests, Distribution): 15%
+- Phase 4.5-4.8 (Dogfood + Verify): 10%
+- Phase 5 (Final Report + Emboss Offer): 5%
+
+Table stakes features get 15% - the same as the data layer. Because matching the competition IS the product.
**Scorecard uses two tiers (100-point scale):**
- Tier 1: Infrastructure (string-matching, 50 max) - does the skeleton have the right patterns?
← 01a3c1c7 docs: rename plan file from shelf to library
·
back to Cli Printing Press
·
docs: update README for v2 overhaul - three benchmarks, tabl fa6b172e →