printing-press-publish
Publish a generated CLI to the printing-press-library repo
By mvanhorn · 6,086 installs
npx skills add mvanhorn/cli-printing-press --skill printing-press-publish
Source repository · Upstream listing
/printing press publish
Publish a generated CLI from your local library to the [printing press library](https://github.com/mvanhorn/printing press library) repo as a pull request.
PR shape guard
This skill opens only a generated CLI publish PR or, with
blocked api journal , a blocked apis.json journal PR. It never opens a
docs only, plan, proposal, or spec PR as a substitute for a CLI that is not
ready to publish. If generation, validation, or live testing is blocked, report
the exact blocker and stop.
Direct User Invocation Required
Publishing can fork mvanhorn/printing press library , push a branch, and open or
update a PR. Before setup or validation, check the invocation context. If this
skill was invoked as a chained continuation from printing press polish 's
Publish Offer, including an AskUserQuestion answer or auto resolved polish
recommendation, stop immediately and tell the user to send
/printing press publish <cli name from polish in a fresh message. A fresh
user authored request that explicitly asks to publish is sufficient; do not add
another confirmation prompt on top of a direct publish request.
If the fresh user authored request includes from polish , record
POLISH HANDOFF=true for the terminal state step and ignore that marker when
resolving the CLI name. The marker is not a second confirmation and is not
passed to cli printing press ; it only preserves standalone polish's old
post publish retro offer after the fresh turn publish completes.
If the request includes blocked api journal , enter Blocked API Journal
Mode below instead of the normal printed CLI publish flow. This mode may be
invoked from /printing press 's hold path menu after the user explicitly chose
"Add to blocked API journal"; that parent menu choice is sufficient user
authorization for the public library journal write. Do not require a second
fresh turn invocation for this journal only mode.
If the fresh user authored request includes skip live test=<reason , record
the exact non empty reason as SKIP LIVE TEST REASON and remove the flag before
resolving the CLI name. This is the only supported escape valve for the
publish time live test gate. Use it only for auth unavailable, known upstream
outage, LAN unreachable hardware APIs, or similarly concrete operator approved
cases; never infer a skip from ordinary latency or from the presence of an
older Phase 5 marker.
The public library treats library/<category /<api slug /.printing press.json
and manifest.json as the source of truth for registry display fields. Do not
edit registry.json , README catalog cells, or cli skills/pp <api slug /SKILL.md
in publish PRs; all three are bot regenerated post merge by the library's own
workflows. The library's Fail on changes to generated artifacts check in
verify library conventions.yml hard fails any PR — fork or same repo — whose
diff against base touches registry.json or cli skills/pp /SKILL.md , so a
publish that includes either is pre rejected before review.
The public library also owns per CLI release accounting. Do not manually bump
CHANGELOG.md , .printing press release.json , or runtime var version = ...
for a publish PR. Fresh printed CLIs may include blank release ledger skeletons;
the library's post merge workflow assigns the final YYYY.M.N release and
stamps the runtime version after merge. When replacing an existing public
library CLI, preserve its existing release ledger files so changelog history is
not lost in the reprint PR.
blocked apis.json is different: it is a hand maintained public library journal,
not a generated registry surface. Journal only PRs may edit blocked apis.json
and must not stage library/ , registry.json , README catalog cells, or
cli skills/ .
Blocked API Journal Mode
Use this mode only when the invocation includes blocked api journal . It
records a held /printing press attempt whose blocker is likely to repeat for
other users until a machine or upstream issue changes.
Required fields from the caller:
slug : canonical API slug, not the CLI binary name.
attempted at : YYYY MM DD .
verdict : hold .
reason : concise blocker reason, with no secrets, local paths, cookies,
tokens, or account specific details.
blocking issue : Printing Press issue number if known, otherwise null .
permanent : boolean.
If the caller did not provide one of these fields, infer only safe values from
the current run context. If reason is missing or vague, stop and ask for one
specific blocker sentence; do not write an unhelpful journal entry.
Run the normal Setup, Configuration, scoped clone cleanup, and GitHub auth
checks, then prepare the public library clone exactly as the normal publish
flow does: fork if needed, ensure upstream points to
mvanhorn/printing press library , fetch upstream , and reset the clone to
upstream/main before editing.
Then update only $PUBLISH REPO DIR/blocked apis.json :
Create a journal branch and PR:
Open the PR against mvanhorn/printing press library with a body that includes:
the held API slug and reason
whether the block is permanent or tied to blocking issue
the expected Phase 0 behavior: future /printing press <api slug runs warn
before repeating the attempt
After the PR is open, report the URL and stop. Do not continue into normal
printed CLI package, live test, registry, or skill mirror steps.
Setup
Before doing anything else:
<! 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.
If setup emitted [go toolchain old] or [low disk] , surface the advisory to the user and continue unless setup also emitted [setup error] . [go toolchain old] means later Go commands may download the required toolchain or fail when downloads are blocked; [low disk] means this run may need several GiB for generated files, Go build cache, module downloads, or repository clones.
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."
Configuration
Publish config
$PUBLISH CONFIG stores persistent publish settings as JSON. On first publish, create it with defaults. The user can edit it to change the library repo or module path base.
The module path base field sets the Go module path prefix for published CLIs. During packaging, the full module path is constructed as <module path base /<category /<api slug . If the user wants CLIs published to a different repo or path, they edit this field.
Store expanded absolute paths for clone path and scope dir so cleanup can
check them without relying on shell specific ~ expansion. The managed by
field is required before cleanup may delete anything.
Scoped clone cleanup
Before creating or reusing $PUBLISH REPO DIR , prune scoped publish clones whose
source worktree no longer exists. This keeps concurrent worktrees isolated
without accumulating one library clone forever per short lived worktree.
Step 1: Prerequisites
Verify gh is authenticated:
If this fails, stop and tell the user: "GitHub CLI is not authenticated. Run gh auth login first."
Step 2: Resolve API Slug
Run:
Parse the JSON output into a list of CLIs. The library is now keyed by API slug (the directory name), not CLI name.
Name resolution order (matches the score skill for consistency):
1. Exact match: If the argument matches a directory name (API slug) exactly, use it
2. CLI name match: If no exact match, try matching against cli name fields, then derive the API slug from the manifest's api name field
3. Suffix match: If no match yet, try <argument pp cli against cli name fields
4. Glob match: If no suffix match, search for entries where cli name or api name contains the argument as a substring. Cap at 5 most recent matches. If multiple matches, present them via AskUserQuestion and let the user pick
5. No match: List all available CLIs and ask the user to pick or re enter
6. No argument: If invoked with no name, list all CLIs sorted by modification time and let the user pick
Once resolved, read the manifest's api name field to get the API slug. Use this slug for all downstream operations (branch names, registry entries, collision detection, path construction). The cli name from the manifest is only used for binary level operations.
When presenting matches, show the API slug and modification time in a human friendly format (e.g., "2 hours ago", "3 days ago").
Step 3: Determine Category
Read .printing press.json from the resolved CLI directory.
Category resolution order:
1. If the manifest has a category field, present it for confirmation:
"Publishing as <category . OK?"
Give the user the option to change it
2. If the manifest does not provide a category, present the full list via AskUserQuestion:
developer tools, monitoring, cloud, project management
productivity, social and messaging, sales and crm, marketing
payments, auth, commerce, ai, food and dining, health, maps, media and entertainment, devices, other
travel
Step 3.5: The Greptile review contract — read before opening the PR
Every PR into the public library gets an automated Greptile review plus a Greptile policy gate CI job. The canonical contract is the library's [ AGENTS.md → "Automated code review with Greptile" ](https://github.com/mvanhorn/printing press library/blob/main/AGENTS.md automated code review with greptile); the essentials:
The bar is resolving every Greptile finding before merge — the 0 5 score is a confidence signal, not the gate. A 4/5 with everything resolved is ready; a 5/5 with open P1s is not. Treat every P0 and P1 as blocking; P2s need a fix or a concrete deferral reply.
Reviews are incremental : every push re triggers a fresh review that can surface new findings. Drive the PR to a stable green — never declare done after round one.
Read the latest greptile apps top level summary, not just inline threads. Summaries can carry actionable Comments Outside Diff blocks even when the thread list is empty. Run the repo's review state helper before declaring ready:
Timeout recovery : if the policy gate fails with Timed out waiting for Greptile Review to complete (large new CLI diffs are the common trigger), the gate auto posts @greptileai review after ~3 minutes; if that doesn't recover, post @greptileai review yourself and wait.
The score gate : the policy gate requires the latest Greptile comment on the current head SHA to carry Confidence Score: ≥ 4/5 . A new push re runs it — keep the score meeting threshold on the final head.
Step 4: Validate
Run:
govulncheck in this step is intentionally scoped to <cli dir only. It
uses the default govulncheck ./... mode so reachable symbol findings block
publish, while merely required vulnerable modules without a call path do not
become release blockers. Do not replace this with a full public library scan or
govulncheck show verbose .
Parse the JSON result. Display each chec