← back to Cli Printing Press
feat(press): v2 - depth over breadth, creativity over mechanical
13860ec01423bbca4e1495dcbb81c68cccd1484b · 2026-03-25 23:31:06 -0700 · Matt Van Horn
Plan A (Creativity Engine):
- SKILL.md: Added Phase 0.5 "Power User Workflows" - classifies API
archetype, generates 10-15 workflow ideas, validates against API,
ranks by impact, selects top 5-7 as mandatory Phase 4 work items
- SKILL.md: Rewrote Phase 4 from "GOAT FIX" (polish) to "GOAT BUILD"
(workflows first, scorecard second, polish third)
- Added 4 anti-shortcut rules: no faking GraphQL specs, no skipping
workflows for README polish, no treating workflows as future work
Plan B (API Type Detection):
- profiler/apitype.go: DetectAPIType() identifies REST/GraphQL/gRPC
from file content, extensions, URL patterns. 5 tests.
- SKILL.md: Added Step 2.0 API Type Check - refuses to generate REST
CLIs for GraphQL APIs, prevents garbage generation
- scorecard: Added "Workflows" dimension (0-10) measuring compound
commands that combine 2+ API calls. Rewards depth over breadth.
- scorecard: Updated to 11 dimensions (110 max), percentage recalculated
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Files touched
M internal/cli/scorecard.goM internal/pipeline/scorecard.goA internal/profiler/apitype.goA internal/profiler/apitype_test.goM skills/printing-press/SKILL.md
Diff
commit 13860ec01423bbca4e1495dcbb81c68cccd1484b
Author: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Date: Wed Mar 25 23:31:06 2026 -0700
feat(press): v2 - depth over breadth, creativity over mechanical
Plan A (Creativity Engine):
- SKILL.md: Added Phase 0.5 "Power User Workflows" - classifies API
archetype, generates 10-15 workflow ideas, validates against API,
ranks by impact, selects top 5-7 as mandatory Phase 4 work items
- SKILL.md: Rewrote Phase 4 from "GOAT FIX" (polish) to "GOAT BUILD"
(workflows first, scorecard second, polish third)
- Added 4 anti-shortcut rules: no faking GraphQL specs, no skipping
workflows for README polish, no treating workflows as future work
Plan B (API Type Detection):
- profiler/apitype.go: DetectAPIType() identifies REST/GraphQL/gRPC
from file content, extensions, URL patterns. 5 tests.
- SKILL.md: Added Step 2.0 API Type Check - refuses to generate REST
CLIs for GraphQL APIs, prevents garbage generation
- scorecard: Added "Workflows" dimension (0-10) measuring compound
commands that combine 2+ API calls. Rewards depth over breadth.
- scorecard: Updated to 11 dimensions (110 max), percentage recalculated
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
internal/cli/scorecard.go | 3 +-
internal/pipeline/scorecard.go | 91 ++++++++++++++++----
internal/profiler/apitype.go | 72 ++++++++++++++++
internal/profiler/apitype_test.go | 59 +++++++++++++
skills/printing-press/SKILL.md | 169 ++++++++++++++++++++++++++++++--------
5 files changed, 341 insertions(+), 53 deletions(-)
diff --git a/internal/cli/scorecard.go b/internal/cli/scorecard.go
index 875a663a..415d3acc 100644
--- a/internal/cli/scorecard.go
+++ b/internal/cli/scorecard.go
@@ -52,7 +52,8 @@ func newScorecardCmd() *cobra.Command {
fmt.Printf(" Local Cache %d/10\n", s.LocalCache)
fmt.Printf(" Breadth %d/10\n", s.Breadth)
fmt.Printf(" Vision %d/10\n", s.Vision)
- fmt.Printf("\n Total: %d/100 (%d%%) - Grade %s\n", s.Total, s.Percentage, sc.OverallGrade)
+ fmt.Printf(" Workflows %d/10\n", s.Workflows)
+ fmt.Printf("\n Total: %d/110 (%d%%) - Grade %s\n", s.Total, s.Percentage, sc.OverallGrade)
if len(sc.GapReport) > 0 {
fmt.Printf("\nGaps:\n")
diff --git a/internal/pipeline/scorecard.go b/internal/pipeline/scorecard.go
index 33814a27..7795268b 100644
--- a/internal/pipeline/scorecard.go
+++ b/internal/pipeline/scorecard.go
@@ -17,20 +17,21 @@ type Scorecard struct {
GapReport []string `json:"gap_report"`
}
-// SteinerScore breaks down the Steinberger bar into 10 dimensions, each 0-10.
+// SteinerScore breaks down the Steinberger bar into 11 dimensions, each 0-10.
type SteinerScore struct {
- OutputModes int `json:"output_modes"` // 0-10
- Auth int `json:"auth"` // 0-10
- ErrorHandling int `json:"error_handling"` // 0-10
- TerminalUX int `json:"terminal_ux"` // 0-10
- README int `json:"readme"` // 0-10
- Doctor int `json:"doctor"` // 0-10
- AgentNative int `json:"agent_native"` // 0-10
- LocalCache int `json:"local_cache"` // 0-10
- Breadth int `json:"breadth"` // 0-10: how many commands (penalizes empty CLIs)
- Vision int `json:"vision"` // 0-10
- Total int `json:"total"` // 0-100
- Percentage int `json:"percentage"` // 0-100
+ OutputModes int `json:"output_modes"` // 0-10
+ Auth int `json:"auth"` // 0-10
+ ErrorHandling int `json:"error_handling"` // 0-10
+ TerminalUX int `json:"terminal_ux"` // 0-10
+ README int `json:"readme"` // 0-10
+ Doctor int `json:"doctor"` // 0-10
+ AgentNative int `json:"agent_native"` // 0-10
+ LocalCache int `json:"local_cache"` // 0-10
+ Breadth int `json:"breadth"` // 0-10: how many commands (penalizes empty CLIs)
+ Vision int `json:"vision"` // 0-10
+ Workflows int `json:"workflows"` // 0-10
+ Total int `json:"total"` // 0-110
+ Percentage int `json:"percentage"` // 0-100
}
// CompScore compares our score against a competitor on a single dimension.
@@ -59,6 +60,7 @@ func RunScorecard(outputDir, pipelineDir string) (*Scorecard, error) {
sc.Steinberger.LocalCache = scoreLocalCache(outputDir)
sc.Steinberger.Breadth = scoreBreadth(outputDir)
sc.Steinberger.Vision = scoreVision(outputDir)
+ sc.Steinberger.Workflows = scoreWorkflows(outputDir)
sc.Steinberger.Total = sc.Steinberger.OutputModes +
sc.Steinberger.Auth +
@@ -69,10 +71,11 @@ func RunScorecard(outputDir, pipelineDir string) (*Scorecard, error) {
sc.Steinberger.AgentNative +
sc.Steinberger.LocalCache +
sc.Steinberger.Breadth +
- sc.Steinberger.Vision
+ sc.Steinberger.Vision +
+ sc.Steinberger.Workflows
if sc.Steinberger.Total > 0 {
- sc.Steinberger.Percentage = (sc.Steinberger.Total * 100) / 100
+ sc.Steinberger.Percentage = (sc.Steinberger.Total * 100) / 110
}
// Grade
@@ -598,6 +601,60 @@ func scoreVision(dir string) int {
return score
}
+func scoreWorkflows(dir string) int {
+ cliDir := filepath.Join(dir, "internal", "cli")
+ entries, err := os.ReadDir(cliDir)
+ if err != nil {
+ return 0
+ }
+
+ compoundCommands := 0
+ for _, e := range entries {
+ if e.IsDir() || !strings.HasSuffix(e.Name(), ".go") {
+ continue
+ }
+
+ content := readFileContent(filepath.Join(cliDir, e.Name()))
+
+ // Count files that make 2+ different API calls in a single RunE.
+ apiCalls := 0
+ if strings.Contains(content, "c.Get(") || strings.Contains(content, "c.Get (") {
+ apiCalls++
+ }
+ if strings.Contains(content, "c.Post(") || strings.Contains(content, "c.Post (") {
+ apiCalls++
+ }
+ if strings.Contains(content, "c.Put(") || strings.Contains(content, "c.Put (") {
+ apiCalls++
+ }
+ if strings.Contains(content, "c.Delete(") || strings.Contains(content, "c.Delete (") {
+ apiCalls++
+ }
+ // Also count store operations as compound behavior.
+ if strings.Contains(content, "store.") || strings.Contains(content, "/store") {
+ apiCalls++
+ }
+ if apiCalls >= 2 {
+ compoundCommands++
+ }
+ }
+
+ switch {
+ case compoundCommands >= 7:
+ return 10
+ case compoundCommands >= 5:
+ return 8
+ case compoundCommands >= 3:
+ return 6
+ case compoundCommands >= 2:
+ return 4
+ case compoundCommands >= 1:
+ return 2
+ default:
+ return 0
+ }
+}
+
// sampleCommandFiles reads up to n command files from internal/cli/.
// If n <= 0, reads all command files.
func sampleCommandFiles(dir string, n int) []string {
@@ -728,6 +785,7 @@ func buildGapReport(s SteinerScore) []string {
{"local_cache", s.LocalCache},
{"breadth", s.Breadth},
{"vision", s.Vision},
+ {"workflows", s.Workflows},
}
for _, d := range dimensions {
if d.score < 5 {
@@ -804,12 +862,13 @@ func writeScorecardMD(sc *Scorecard, pipelineDir string) error {
{"Local Cache", s.LocalCache},
{"Breadth", s.Breadth},
{"Vision", s.Vision},
+ {"Workflows", s.Workflows},
}
for _, d := range dimensions {
bar := strings.Repeat("#", d.score) + strings.Repeat(".", 10-d.score)
b.WriteString(fmt.Sprintf("| %s | %d/10 %s |\n", d.name, d.score, bar))
}
- b.WriteString(fmt.Sprintf("| **Total** | **%d/100** |\n\n", s.Total))
+ b.WriteString(fmt.Sprintf("| **Total** | **%d/110** |\n\n", s.Total))
// Competitor comparison
if len(sc.CompetitorScores) > 0 {
diff --git a/internal/profiler/apitype.go b/internal/profiler/apitype.go
new file mode 100644
index 00000000..4f7b7d88
--- /dev/null
+++ b/internal/profiler/apitype.go
@@ -0,0 +1,72 @@
+package profiler
+
+import (
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+type APIType string
+
+const (
+ APITypeREST APIType = "rest"
+ APITypeGraphQL APIType = "graphql"
+ APITypeGRPC APIType = "grpc"
+ APITypeUnknown APIType = "unknown"
+)
+
+// DetectAPIType determines the API type from a spec file path or URL.
+func DetectAPIType(specPath string) APIType {
+ lower := strings.ToLower(specPath)
+ ext := strings.ToLower(filepath.Ext(specPath))
+
+ // URL-based detection
+ if strings.Contains(lower, "/graphql") || strings.HasSuffix(lower, "/graphql") {
+ return APITypeGraphQL
+ }
+
+ // Extension-based detection
+ switch ext {
+ case ".graphql", ".gql":
+ return APITypeGraphQL
+ case ".proto":
+ return APITypeGRPC
+ }
+
+ // Content-based detection (read first 1000 bytes)
+ if data, err := readHead(specPath, 1000); err == nil {
+ content := string(data)
+ if strings.Contains(content, "openapi") || strings.Contains(content, "swagger") {
+ return APITypeREST
+ }
+ if strings.Contains(content, "type Query") || strings.Contains(content, "type Mutation") || strings.Contains(content, "schema {") {
+ return APITypeGraphQL
+ }
+ if strings.Contains(content, `syntax = "proto`) {
+ return APITypeGRPC
+ }
+ }
+
+ // YAML/JSON specs are typically REST
+ if ext == ".yaml" || ext == ".yml" || ext == ".json" {
+ return APITypeREST
+ }
+
+ return APITypeUnknown
+}
+
+func readHead(path string, n int) ([]byte, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ buf := make([]byte, n)
+ nr, err := f.Read(buf)
+ if err != nil && err != io.EOF {
+ return nil, err
+ }
+ return buf[:nr], nil
+}
diff --git a/internal/profiler/apitype_test.go b/internal/profiler/apitype_test.go
new file mode 100644
index 00000000..5049fafe
--- /dev/null
+++ b/internal/profiler/apitype_test.go
@@ -0,0 +1,59 @@
+package profiler
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestDetectAPITypeREST(t *testing.T) {
+ path := writeTempSpec(t, "spec.json", `{"openapi": "3.0.0"}`)
+
+ if got := DetectAPIType(path); got != APITypeREST {
+ t.Fatalf("DetectAPIType(%q) = %q, want %q", path, got, APITypeREST)
+ }
+}
+
+func TestDetectAPITypeGraphQL(t *testing.T) {
+ path := writeTempSpec(t, "schema.graphql", `type Query { users: [User] }`)
+
+ if got := DetectAPIType(path); got != APITypeGraphQL {
+ t.Fatalf("DetectAPIType(%q) = %q, want %q", path, got, APITypeGraphQL)
+ }
+}
+
+func TestDetectAPITypeGRPC(t *testing.T) {
+ path := writeTempSpec(t, "service.proto", `syntax = "proto3";`)
+
+ if got := DetectAPIType(path); got != APITypeGRPC {
+ t.Fatalf("DetectAPIType(%q) = %q, want %q", path, got, APITypeGRPC)
+ }
+}
+
+func TestDetectAPITypeURL(t *testing.T) {
+ path := "https://api.example.com/graphql"
+
+ if got := DetectAPIType(path); got != APITypeGraphQL {
+ t.Fatalf("DetectAPIType(%q) = %q, want %q", path, got, APITypeGraphQL)
+ }
+}
+
+func TestDetectAPITypeYAMLFallback(t *testing.T) {
+ path := writeTempSpec(t, "spec.yaml", "title: Example API\nversion: v1\n")
+
+ if got := DetectAPIType(path); got != APITypeREST {
+ t.Fatalf("DetectAPIType(%q) = %q, want %q", path, got, APITypeREST)
+ }
+}
+
+func writeTempSpec(t *testing.T, name, content string) string {
+ t.Helper()
+
+ dir := t.TempDir()
+ path := filepath.Join(dir, name)
+ if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
+ t.Fatalf("write temp spec: %v", err)
+ }
+
+ return path
+}
diff --git a/skills/printing-press/SKILL.md b/skills/printing-press/SKILL.md
index f54e4363..d90466d5 100644
--- a/skills/printing-press/SKILL.md
+++ b/skills/printing-press/SKILL.md
@@ -36,11 +36,11 @@ Generate the best CLI that has ever existed for any API. Five mandatory phases.
Every run produces the GOAT CLI through 6 mandatory phases:
```
-PHASE 0: VISIONARY RESEARCH -> PHASE 1: DEEP RESEARCH -> PHASE 2: GENERATE -> PHASE 3: STEINBERGER AUDIT -> PHASE 4: GOAT FIX -> PHASE 5: FINAL STEINBERGER
- (3-5 min) (5-8 min) (1-2 min) (5-8 min) (3-5 min) (2-3 min)
+PHASE 0: VISIONARY RESEARCH -> PHASE 0.5: POWER USER WORKFLOWS -> PHASE 1: DEEP RESEARCH -> PHASE 2: GENERATE -> PHASE 3: STEINBERGER AUDIT -> PHASE 4: GOAT BUILD -> PHASE 5: FINAL STEINBERGER
+ (3-5 min) (2-3 min) (5-8 min) (1-2 min) (5-8 min) (5-10 min) (2-3 min)
```
-Total expected time: 18-30 minutes. If a run completes in under 12 minutes, phases were shortcut.
+Total expected time: 20-40 minutes. Phase 4 is longer now because it builds real workflow commands, not just polishes READMEs.
**The Steinberger bar:** Peter Steinberger's gogcli is the 10/10 reference. Every generated CLI is scored against it TWICE - once during audit to find gaps, once after fixes to prove improvement. The delta is the proof of work.
@@ -244,6 +244,70 @@ Tell the user: "Phase 0 complete: Domain: [category]. Data profile: [volume]/[re
---
+# PHASE 0.5: POWER USER WORKFLOWS
+
+## THIS PHASE IS MANDATORY. DO NOT SKIP IT.
+
+The generator produces API wrappers. Power users want workflow tools. This phase predicts what compound commands would make the CLI genuinely useful - the kind of features that make discrawl (12 commands) more valuable than a 316-command API wrapper.
+
+### Step 0.5a: Classify the API Archetype
+
+Based on Phase 0 research, classify the API:
+
+| Archetype | Signal | Example Workflows |
+|---|---|---|
+| **Communication** | Messages, channels, threads | Archive, offline search, monitor keywords, export conversations |
+| **Project Management** | Issues, tasks, sprints, states | Stale issues, orphan detection, velocity, burndown, standup, triage |
+| **Payments** | Charges, subscriptions, invoices | Reconciliation, webhook replay, fixture flows, revenue reports |
+| **Infrastructure** | Servers, deployments, logs | State sync, log tailing, deploy orchestration, health dashboards |
+| **Content** | Documents, pages, blocks, media | Backup to local files, diff, template management, publish workflows |
+| **CRM** | Contacts, deals, pipelines | Pipeline reports, stale deal alerts, activity timelines, bulk updates |
+| **Developer Platform** | Repos, PRs, CI runs | PR triage, CI monitoring, release management, dependency audit |
+
+### Step 0.5b: Generate 10-15 Workflow Ideas
+
+For the identified archetype, brainstorm compound workflows. Ask:
+- "What does a power user of this API wish they could do in one command?"
+- "What multi-step task do people automate with scripts today?"
+- "What reporting/hygiene/monitoring task requires manual effort?"
+- "What would make an engineering manager's life easier?"
+
+Each workflow should:
+- Combine 2+ API calls into one operation
+- Solve a real recurring problem
+- Be expressible as a single CLI command with flags
+
+### Step 0.5c: Validate Against API Capabilities
+
+For each workflow idea, check:
+1. Does the API have the required endpoints/fields?
+2. Can the required data be queried/filtered?
+3. Are write operations available (for mutation workflows)?
+4. For GraphQL APIs: does the schema have the required types?
+
+Drop workflows the API can't support.
+
+### Step 0.5d: Rank by Impact
+
+Score each workflow on:
+- **Frequency**: How often would users run this? (daily=3, weekly=2, monthly=1)
+- **Pain**: How painful is the manual alternative? (high=3, medium=2, low=1)
+- **Feasibility**: How hard to implement? (easy=3, medium=2, hard=1)
+- **Uniqueness**: Does any existing tool do this? (no=3, partial=2, yes=0)
+
+### Step 0.5e: Select Top 5-7 for Implementation
+
+These become **mandatory Phase 4 work items**. They are NOT optional polish. They are the PRODUCT.
+
+### PHASE GATE 0.5
+
+**STOP.** Tell the user: "Identified [N] power-user workflows for [API name]. Top 5:
+1. [name] - [one-line description] (score [X]/12)
+2. ...
+These will be built as real commands in Phase 4, alongside the API wrapper."
+
+---
+
# PHASE 1: DEEP RESEARCH
## THIS PHASE IS MANDATORY. DO NOT SKIP IT.
@@ -372,6 +436,21 @@ Tell the user: "Phase 1 complete: Found [spec/no spec], [N] competitors. Best: [
## THIS PHASE IS MANDATORY. DO NOT SKIP IT.
+### Step 2.0: API Type Check
+
+Before generating, verify the spec matches the API:
+
+1. **If spec is OpenAPI/Swagger** -> proceed to REST generation (Step 2.1)
+2. **If spec is a GraphQL schema** -> STOP. Tell the user:
+ "This API is GraphQL-only. The printing press generates REST CLIs. Options:
+ a) I'll build the Phase 0.5 workflow commands directly using a GraphQL client (recommended)
+ b) Pick a different REST API for generation"
+3. **If no spec and API is GraphQL-only** -> same as #2
+4. **If the spec describes REST endpoints but the API base URL contains `/graphql`** -> STOP.
+ "The spec describes REST endpoints but the API is GraphQL. Generating would produce commands that can't make successful API calls."
+
+**NEVER generate a CLI that can't make a single successful API call.**
+
### Step 2.1: Get the spec ready
**If OpenAPI spec found:**
@@ -544,20 +623,45 @@ Tell the user: "Phase 3 complete: Baseline Steinberger Score: [X]/100 (Grade [X]
---
-# PHASE 4: GOAT FIX
+# PHASE 4: GOAT BUILD
## THIS PHASE IS MANDATORY.
-Execute fixes in priority order:
+**The generator output is scaffolding, not the product. The workflows are the product.**
-1. **Scorecard-gap fixes** - run scorecard, identify dimensions below 10/10, fix patterns the scorecard measures
-2. **Complex body field --stdin examples** (useful for agents, visible in help text)
-3. **Command name cleanup** (UX quality, not scored by automated scorecard)
-4. **Description/README polish** (UX quality, not scored)
+Execute in this priority order. Do NOT skip Priority 1 to polish the README.
-Scorecard-measured improvements first. UX polish second. If the scorecard says 10/10 for a dimension, do not spend time improving it further.
+### Priority 1: Power User Workflows (from Phase 0.5)
-### Step 4.1: Apply scorecard-gap fixes
+This is the most important work in the entire pipeline. Implement the top 5-7 workflows identified in Phase 0.5 as real, hand-written Go commands.
+
+For each workflow:
+1. **Create a dedicated command file** (e.g., `internal/cli/stale.go`, `internal/cli/velocity.go`)
+2. **Use the generated client** to make real API calls
+3. **Combine 2+ API calls** into one user-facing operation
+4. **Add realistic examples** in --help that show the actual 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 2: Scorecard-Gap Fixes
Run the scorecard and fix dimensions below 10/10:
@@ -570,28 +674,17 @@ For each dimension below 10/10:
2. **Edit** with surgical changes
3. Focus on changes that RAISE THE SCORECARD NUMBER
-### Step 4.2: Add complex body field examples
-
-For the top 3 endpoints with complex body fields (identified in Phase 3 Step 3.6):
-
-1. **Read** the command file
-2. **Edit** the Example field to include a `--stdin` example with realistic JSON:
-
-```go
-Example: ` # Get a page
- <api>-cli pages get d9824bdc-8445-4327-be8b-5b47f462e1b0
-
- # Create a page with complex properties (pipe JSON via stdin)
- echo '{"parent":{"database_id":"..."},"properties":{"Name":{"title":[{"text":{"content":"My Page"}}]}}}' | <api>-cli pages create --stdin`,
-```
+Also fix:
+- Complex body field --stdin examples for top 3 endpoints
+- Lazy descriptions (1-2 word Short fields)
+- Placeholder examples ("abc123" -> realistic domain values)
-### Step 4.3: Command name cleanup and description/README polish
+### Priority 3: Polish
-Only if time remains after scorecard-gap fixes:
-1. Fix command names -> clean, intuitive names (get/list/create/update/delete)
-2. Fix help text jargon -> developer-friendly descriptions
-3. Fix examples -> realistic values (real UUIDs, real API objects, not "abc123")
-4. Fix README -> compelling, useful documentation
+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
### Step 4.4: Verify compilation
@@ -602,13 +695,13 @@ cd ~/cli-printing-press/<api>-cli && go build ./... && go vet ./... && echo "ALL
### PHASE GATE 4
**STOP.** Verify:
-1. All GOAT improvements applied
-2. All tactical fixes applied
-3. Complex body field examples added for at least 2 endpoints
+1. At least 3 workflow commands implemented (from Phase 0.5)
+2. Workflow commands combine 2+ API calls each
+3. Scorecard gaps addressed
4. `go build ./...` and `go vet ./...` pass
-5. Count changed files: `cd <api>-cli && git diff --stat 2>/dev/null | tail -1` (if git tracked) or `find . -newer /tmp/printing-press-spec-<api>.json -name "*.go" | wc -l`
+5. README cookbook includes workflow examples
-Tell the user: "Phase 4 complete: Applied [N] improvements, [M] tactical fixes, [K] complex body field examples. Compilation verified. Proceeding to final Steinberger scoring."
+Tell the user: "Phase 4 complete: Built [N] workflow commands, applied [M] scorecard fixes. Top workflow: [name]. Compilation verified. Proceeding to final scoring."
---
@@ -739,3 +832,7 @@ These phrases indicate a phase was shortcut. If you catch yourself writing them,
- "Let's wrap up" (are all 5 phases complete with artifacts?)
- "This API doesn't need local persistence" (Did you run Phase 0? Check the data profile. If search need is high, it needs persistence.)
- "This is just an API wrapper" (Run Phase 0 again. What would a thoughtful developer build?)
+- "The API is GraphQL-only but I'll write a REST spec anyway" (STOP. This produces garbage. Use Phase 0.5 workflows or build a GraphQL client.)
+- "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.)
← d51d1e89 feat(generator): add compound workflow template with archive
·
back to Cli Printing Press
·
feat(press): add Phase 0.7 prediction engine, Discord CLI, 6 6775a862 →