printing-press-score
Score a generated CLI against the Steinberger bar, compare two CLIs side-by-side
By mvanhorn · 5,760 installs
npx skills add mvanhorn/cli-printing-press --skill printing-press-score
Source repository · Upstream listing
/printing press score
Score generated CLIs against the Steinberger bar. Supports rescoring, scoring by name/path, and comparing two CLIs.
Quick Start
Prerequisites
Go 1.26.6 or newer installed
cli printing press binary on PATH (install with go install github.com/mvanhorn/cli printing press/v4/cmd/cli printing press@latest )
Step 0: Setup
Before any other commands, run the setup contract to verify the cli printing press binary is on PATH and initialize scope variables:
<! PRESS SETUP CONTRACT START
<! PRESS SETUP CONTRACT END
After running the setup contract, capture the PRINTING PRESS BIN=<abs path line from stdout. Every subsequent cli printing press ... invocation in this skill must use that absolute path (substitute the value, not the literal $PRINTING PRESS BIN token) — export PATH above only affects the single Bash tool call it runs in, so later calls open a fresh shell where bare cli printing press resolves against the user's default PATH and a stale global can shadow the local build.
After capturing the binary path, check binary version compatibility. Read the min binary version field from this skill's YAML frontmatter. Run <PRINTING PRESS BIN version json and parse the version from the output. Compare it to min binary version using semver rules. If the installed binary is older than the minimum, stop immediately and tell the user: "cli printing press binary vX.Y.Z is older than the minimum required vA.B.C. Run go install github.com/mvanhorn/cli printing press/v4/cmd/cli printing press@latest to update."
Current run state is resolved from $PRESS RUNSTATE . Published CLIs are resolved from $PRESS LIBRARY . Archived manuscripts are resolved from $PRESS MANUSCRIPTS .
Step 1: Parse Arguments
Read the user's input after /printing press score . The input is free form — interpret intent, don't enforce syntax.
Noise words to strip: compare , vs , versus , and , against , with , to
After stripping noise words, count the remaining tokens:
0 tokens → Rescore Current mode
1 token → Score Single mode
2 tokens → Compare mode
Step 2: Resolve CLI Directories
For each CLI identifier, resolve it to a directory path:
If the token contains / or .
Treat it as a path (absolute or relative). Verify the directory exists.
If the token is a plain name
Try these locations in order:
1. $PRESS LIBRARY/<name / — exact match
2. $PRESS LIBRARY/<name pp cli/ — with pp cli suffix
3. If neither exists, Glob $PRESS LIBRARY/<name pp cli
4. If exactly one glob match exists and is a directory, use it
5. If multiple glob matches exist, present a numbered menu using AskUserQuestion
If neither exists, scan current run and archived state:
6. Use Glob to find $PRESS RUNSTATE/runs/ /state.json files
7. Read each, look for an output dir or working dir value whose basename contains the name
8. If found and the directory exists, use it
If nothing resolves, report the error: "Could not find CLI '<name '. Provide a path or check the name."
Rescore Current (0 tokens)
1. Use Glob to find all $PRESS CURRENT/ .json files
2. Read each to get api name , state path , and working dir
3. Filter to those whose working dir actually exists on disk
4. If none are found, Glob $PRESS LIBRARY/ pp cli and use those directories instead
5. If exactly one → use it automatically
6. If multiple → present a numbered menu using AskUserQuestion:
7. If none found → report: "No generated CLIs found. Provide a name or path."
Step 3: Find Spec for Tier 2 Scoring
For each resolved CLI directory, find the OpenAPI spec:
1. Check <cli dir /spec.json — the pipeline converts YAML specs to JSON during generation
2. If not found, scan $PRESS RUNSTATE/runs/ /state.json files for one matching this CLI's directory. Read its spec path field. If that file exists on disk, use it.
3. If no spec found, proceed without spec . Note to the user: "No spec found — spec derived dimensions will be marked N/A and omitted from the denominator. Provide a spec path for full scoring."
Step 4: Run Scorecard
Single Score Mode
Run the scorecard command:
If a spec was found, add spec <spec path .
Parse the JSON output. The structure is:
If unscored dimensions is present, those dimensions should be rendered as N/A , not 0/x , and should be described as omitted from the denominator rather than as fixable CLI defects. For backward compatibility, JSON still encodes the numeric fields as 0 ; consumers must use unscored dimensions to distinguish N/A from a real zero.
Learn loop credit is static behavioral, never presence based: the scorecard credits teach / recall / learnings registration on the root command and non empty entity lookup seeds (or the spec's recorded no entities escape). The learn loop is default on, so internal/learn/ existing earns nothing; when explaining a learn gap, point at missing seeds or unregistered commands, not missing files. Execution proof (verify matrix, learnings stats ) belongs to verify and dogfood; the scorecard runs no binaries.
Compare Mode
Run both scorecard commands in parallel using two simultaneous Bash tool calls:
Parse both JSON outputs.
Step 5: Render Output
Single Score Table
Render a rich markdown table. Note: Tier 1 dimensions are all /10. Tier 2 dimensions are /10 except TypeFidelity and DeadCode which are /5.
If gap report is non empty, list the gaps:
If unscored dimensions is non empty, add a note after the table:
Compare Table
Render a side by side table with a delta column. Show the first CLI name and second CLI name as column headers. Calculate delta as (CLI 1 score CLI 2 score). Show +N for positive, N for negative, — for zero.
Error Handling
If the cli printing press binary is not on PATH → show install instructions: go install github.com/mvanhorn/cli printing press/v4/cmd/cli printing press@latest
If the scorecard command fails → report the error with the full stderr output
If a CLI directory doesn't exist → report which name couldn't be resolved
If JSON parsing fails → show the raw output and report the parsing error