← back to Cli Printing Press
fix(review): extract DefaultOutputDir helper, update main skill and docs
cf381bbb948bf71f874e68653c237002a3b40400 · 2026-03-27 16:46:05 -0700 · Trevin Chow
- Extract shared DefaultOutputDir() in pipeline package, used by all 4 call sites
- Update 13 filesystem path references in skills/printing-press/SKILL.md
- Update ONBOARDING.md path reference
- Add TestDefaultOutputDir unit test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Files touched
M ONBOARDING.mdM internal/cli/root.goM internal/cli/vision.goM internal/pipeline/pipeline.goM internal/pipeline/state_test.goM skills/printing-press/SKILL.md
Diff
commit cf381bbb948bf71f874e68653c237002a3b40400
Author: Trevin Chow <trevin@trevinchow.com>
Date: Fri Mar 27 16:46:05 2026 -0700
fix(review): extract DefaultOutputDir helper, update main skill and docs
- Extract shared DefaultOutputDir() in pipeline package, used by all 4 call sites
- Update 13 filesystem path references in skills/printing-press/SKILL.md
- Update ONBOARDING.md path reference
- Add TestDefaultOutputDir unit test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
ONBOARDING.md | 2 +-
internal/cli/root.go | 4 ++--
internal/cli/vision.go | 3 ++-
internal/pipeline/pipeline.go | 8 +++++++-
internal/pipeline/state_test.go | 16 ++++++++++++++++
skills/printing-press/SKILL.md | 26 +++++++++++++-------------
6 files changed, 41 insertions(+), 18 deletions(-)
diff --git a/ONBOARDING.md b/ONBOARDING.md
index b1fd9d50..4df03e7d 100644
--- a/ONBOARDING.md
+++ b/ONBOARDING.md
@@ -101,7 +101,7 @@ internal/generator/generator.go (New + Generate)
renders 30+ .tmpl files to output dir
|
v
-Generated CLI project at ./<name>-cli/
+Generated CLI project at ./shelf/<name>-cli/
cmd/<name>-cli/main.go
cmd/<name>-mcp/main.go
internal/cli/ (per-resource commands)
diff --git a/internal/cli/root.go b/internal/cli/root.go
index b7751e83..83aa6cc1 100644
--- a/internal/cli/root.go
+++ b/internal/cli/root.go
@@ -112,7 +112,7 @@ func newGenerateCmd() *cobra.Command {
}
if outputDir == "" {
- outputDir = filepath.Join("shelf", parsed.Name+"-cli")
+ outputDir = pipeline.DefaultOutputDir(parsed.Name)
}
absOut, err := filepath.Abs(outputDir)
if err != nil {
@@ -211,7 +211,7 @@ func newGenerateCmd() *cobra.Command {
}
if outputDir == "" {
- outputDir = filepath.Join("shelf", apiSpec.Name+"-cli")
+ outputDir = pipeline.DefaultOutputDir(apiSpec.Name)
}
absOut, err := filepath.Abs(outputDir)
diff --git a/internal/cli/vision.go b/internal/cli/vision.go
index fc6cc63b..2531c1c7 100644
--- a/internal/cli/vision.go
+++ b/internal/cli/vision.go
@@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
+ "github.com/mvanhorn/cli-printing-press/internal/pipeline"
"github.com/mvanhorn/cli-printing-press/internal/vision"
"github.com/spf13/cobra"
)
@@ -31,7 +32,7 @@ The vision command produces the structure; Phase 0 fills it with intelligence.`,
return &ExitError{Code: ExitInputError, Err: fmt.Errorf("--api is required")}
}
if outputDir == "" {
- outputDir = filepath.Join("shelf", apiName+"-cli")
+ outputDir = pipeline.DefaultOutputDir(apiName)
}
absOut, err := filepath.Abs(outputDir)
diff --git a/internal/pipeline/pipeline.go b/internal/pipeline/pipeline.go
index db9715e7..f382ebbe 100644
--- a/internal/pipeline/pipeline.go
+++ b/internal/pipeline/pipeline.go
@@ -6,6 +6,12 @@ import (
"path/filepath"
)
+// DefaultOutputDir returns the default output directory for a given API name.
+// All commands should use this when --output is not specified.
+func DefaultOutputDir(apiName string) string {
+ return filepath.Join("shelf", apiName+"-cli")
+}
+
// Options configures a pipeline run.
type Options struct {
OutputDir string
@@ -23,7 +29,7 @@ func Init(apiName string, opts Options) (*PipelineState, error) {
outputDir := opts.OutputDir
if outputDir == "" {
- outputDir = filepath.Join("shelf", apiName+"-cli")
+ outputDir = DefaultOutputDir(apiName)
}
absOutputDir, err := filepath.Abs(outputDir)
diff --git a/internal/pipeline/state_test.go b/internal/pipeline/state_test.go
index de52cc9a..6b5852a5 100644
--- a/internal/pipeline/state_test.go
+++ b/internal/pipeline/state_test.go
@@ -102,6 +102,22 @@ func TestIsSeedBackwardCompatible(t *testing.T) {
assert.False(t, s.IsSeed(PhasePreflight))
}
+func TestDefaultOutputDir(t *testing.T) {
+ tests := []struct {
+ name string
+ apiName string
+ expected string
+ }{
+ {"simple", "stripe", "shelf/stripe-cli"},
+ {"hyphenated", "my-api", "shelf/my-api-cli"},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equal(t, tt.expected, DefaultOutputDir(tt.apiName))
+ })
+ }
+}
+
func TestPhaseStateJSONIncludesPlanStatus(t *testing.T) {
state := PhaseState{
Status: StatusPlanned,
diff --git a/skills/printing-press/SKILL.md b/skills/printing-press/SKILL.md
index 528134e1..f3c7ee0d 100644
--- a/skills/printing-press/SKILL.md
+++ b/skills/printing-press/SKILL.md
@@ -1013,7 +1013,7 @@ curl -sL -o /tmp/printing-press-spec-<api>.json "<spec-url>" && head -c 200 /tmp
### Step 2.2: Check for existing output, remove if exists
```bash
-cd ~/cli-printing-press && rm -rf <api>-cli 2>/dev/null; echo "CLEAN"
+cd ~/cli-printing-press && rm -rf shelf/<api>-cli 2>/dev/null; echo "CLEAN"
```
### Step 2.3: Run the generator
@@ -1021,7 +1021,7 @@ cd ~/cli-printing-press && rm -rf <api>-cli 2>/dev/null; echo "CLEAN"
```bash
cd ~/cli-printing-press && ./printing-press generate \
--spec /tmp/printing-press-spec-<api>.json \
- --output ./<api>-cli \
+ --output ./shelf/<api>-cli \
--force --lenient --validate 2>&1
```
@@ -1031,7 +1031,7 @@ cd ~/cli-printing-press && ./printing-press generate \
Run:
```bash
-cd ~/cli-printing-press && ./printing-press generate --spec /tmp/printing-press-spec-<api>.json --output ./<api>-cli --force --lenient --validate 2>&1 | grep "skipping body field"
+cd ~/cli-printing-press && ./printing-press generate --spec /tmp/printing-press-spec-<api>.json --output ./shelf/<api>-cli --force --lenient --validate 2>&1 | grep "skipping body field"
```
Save the list of skipped fields. These are NOT acceptable limitations - they are work items for Phase 4.
@@ -1063,14 +1063,14 @@ This phase has TWO parts: (A) code review for tactical fixes, and (B) Non-Obviou
You MUST **Read** these files (not just check they exist):
-- `<api>-cli/internal/cli/root.go`
-- `<api>-cli/README.md`
+- `shelf/<api>-cli/internal/cli/root.go`
+- `shelf/<api>-cli/README.md`
- At least 3 resource command files
### Step 3.2: Count commands and compare to target
```bash
-cd ~/cli-printing-press/<api>-cli && grep -r "Use:" internal/cli/*.go | grep -v "root.go" | wc -l
+cd ~/cli-printing-press/shelf/<api>-cli && grep -r "Use:" internal/cli/*.go | grep -v "root.go" | wc -l
```
Compare against target from Phase 1 research.
@@ -1103,7 +1103,7 @@ For each field skipped by the generator (from Phase 2 Step 2.4):
Before hand-scoring, run the automated scorecard to get objective baseline numbers:
```bash
-cd ~/cli-printing-press && ./printing-press scorecard --dir ./<api>-cli
+cd ~/cli-printing-press && ./printing-press scorecard --dir ./shelf/<api>-cli
```
Use these numbers as the baseline. The hand-scoring in Step 3.7 should explain WHY each dimension got its score, not re-guess the number.
@@ -1302,7 +1302,7 @@ func newStaleCmd(flags *rootFlags) *cobra.Command {
Run the scorecard and fix dimensions below 10/10:
```bash
-cd ~/cli-printing-press && ./printing-press scorecard --dir ./<api>-cli
+cd ~/cli-printing-press && ./printing-press scorecard --dir ./shelf/<api>-cli
```
For each dimension below 10/10:
@@ -1325,7 +1325,7 @@ Only after Priority 1 and 2 are complete:
### Step 4.4: Verify compilation
```bash
-cd ~/cli-printing-press/<api>-cli && go build ./... && go vet ./... && echo "ALL FIXES VERIFIED"
+cd ~/cli-printing-press/shelf/<api>-cli && go build ./... && go vet ./... && echo "ALL FIXES VERIFIED"
```
### PHASE GATE 4
@@ -1602,7 +1602,7 @@ The scorecard measures files. This phase measures behavior. Build the CLI and te
```bash
cd ~/cli-printing-press && ./printing-press verify \
- --dir ./<api>-cli \
+ --dir ./shelf/<api>-cli \
--spec /tmp/<api>-spec.json \
--threshold 80
```
@@ -1611,7 +1611,7 @@ If you collected an API key in Phase 0.1, add it:
```bash
cd ~/cli-printing-press && ./printing-press verify \
- --dir ./<api>-cli \
+ --dir ./shelf/<api>-cli \
--spec /tmp/<api>-spec.json \
--api-key "$<API_ENV_VAR>" \
--env-var <API_ENV_VAR> \
@@ -1657,7 +1657,7 @@ Tell the user: "Runtime verification: [X]% pass rate ([N]/[M] commands). Data pi
Run the automated scorecard again to measure improvement:
```bash
-cd ~/cli-printing-press && ./printing-press scorecard --dir ./<api>-cli
+cd ~/cli-printing-press && ./printing-press scorecard --dir ./shelf/<api>-cli
```
Re-score ALL 10 dimensions. Show the DELTA from the baseline:
@@ -1717,7 +1717,7 @@ Remaining gap: <what they have that we don't, or "none">
**4. Example Commands (with complex body examples):**
```bash
-cd ~/cli-printing-press/<api>-cli
+cd ~/cli-printing-press/shelf/<api>-cli
go install ./cmd/<api>-cli
export <AUTH_ENV_VAR>="..."
← 34e646c2 feat(generator): route generated CLI output to shelf/ direct
·
back to Cli Printing Press
·
refactor(generator): rename shelf/ to library/ for generated 96c28ea4 →