SKILL.md
/printing-press-import
Bring a published CLI from the public library
(mvanhorn/printing-press-library)
into the internal library at ~/printing-press/library/ so it matches
the form the generator would produce. Manuscripts ride along.
/printing-press-import notion
/printing-press-import cal.com
/printing-press-import allrecipes --from-clone ~/Code/printing-press-library
The internal library is the working copy; the public library is the
durable artifact. After import, the CLI is ready for polish, emboss, or
re-publish — the publish step will re-apply the module path rewrites.
When to run
- The public library has a CLI you don't have locally
- The internal copy is broken, lost, or out of sync
- You want a clean baseline before running polish on a published CLI
If the user is asking to polish a CLI and mentions "in/from the public
library" or "from the repo", suggest running this skill first.
Setup
PRESS_HOME="$HOME/printing-press"
PRESS_LIBRARY="$PRESS_HOME/library"
PRESS_MANUSCRIPTS="$PRESS_HOME/manuscripts"
SCRIPTS_DIR="$(dirname "${BASH_SOURCE[0]:-$0}")/references"
The four reference scripts live alongside this SKILL.md under
references/:
import-fetch.sh <library-path> <staging> [--clone <path>]
import-backup.sh <api-slug>(prints zip path on stdout)
import-rewrite.sh <staging> <api-slug>
import-place.sh <staging> <api-slug>
Phase 1 — Resolve the CLI
The argument can be anything natural: an API slug (notion), a brand
name (cal.com), an old CLI name (notion-pp-cli), or close enough
(Allrecipes). Resolve via the public library's registry.json —
which carries name, category, api, description, and path for
every entry, in one fetch.
REGISTRY=$(mktemp)
gh api -H "Accept: application/vnd.github.v3.raw" \
repos/mvanhorn/printing-press-library/contents/registry.json \
> "$REGISTRY"
Match in this order:
- **Exact
namematch** —jq --arg q "$ARG" '.entries[] | select(.name == $q)' "$REGISTRY"
- Normalized exact — strip
-pp-clisuffix, lowercase, dot→hyphen, then exact match
- **Substring on
nameordescription** — case-insensitive contains
# Exact:
jq --arg q "$ARG" '.entries[] | select(.name == $q)' "$REGISTRY"
# Normalized exact (after $ARG2 = lowercase, dot→hyphen, suffix-stripped):
jq --arg q "$ARG2" '.entries[] | select(.name == $q)' "$REGISTRY"
# Fuzzy (substring on name or description):
jq --arg q "$ARG2" '.entries[]
| select((.name | ascii_downcase | contains($q | ascii_downcase))
or (.description | ascii_downcase | contains($q | ascii_downcase)))
' "$REGISTRY"
If you get one match: use it. If multiple: present at most 4 to the user
via AskUserQuestion showing name + description per candidate. If
zero: tell the user the public library doesn't have that CLI.
The matched entry gives you everything you need:
LIB_PATHfrom.path(e.g.,library/productivity/cal-com)
API_SLUGfrom.name
CATEGORYfrom.category
Don't slurp whole files when reasoning over candidates. The fields
above are enough; if you genuinely need more, the per-CLI manifest is
just <LIB_PATH>/manifest.json and the description there can be pulled
the same way (gh api -H "Accept: ... raw" .../manifest.json | jq -r '.description').
Phase 2 — Decide on overwrite
Check whether the internal library already has this CLI:
LIB_TARGET="$PRESS_LIBRARY/$API_SLUG"
MAN_TARGET="$PRESS_MANUSCRIPTS/$API_SLUG"
If neither exists: straightforward import — proceed to Phase 3.
If either exists: read provenance from both sides to decide whether
to overwrite. Don't read whole .printing-press.json files — pull just
the fields that matter:
# Internal provenance (if present):
jq '{run_id, generated_at, printing_press_version, spec_checksum}' \
"$LIB_TARGET/.printing-press.json" 2>/dev/null
# Public provenance (one-shot via raw):
gh api -H "Accept: application/vnd.github.v3.raw" \
repos/mvanhorn/printing-press-library/contents/$LIB_PATH/.printing-press.json \
| jq '{run_id, generated_at, printing_press_version, spec_checksum}'
Reason over the diff:
- **Same
run_id** — public is the same generation as internal. Likely
no-op; ask before clobbering. If the user wants to import anyway
(e.g., to recover from a broken internal copy), proceed.
- **Public newer
generated_at** — public has changes the internal
doesn't. Importing is the safe move; ask the user to confirm.
- **Internal newer
generated_at** — internal has work the public
doesn't (in-progress polish, manual fixes). Importing would clobber
that. Stop and surface this to the user — they likely want to publish
the internal changes first.
- **Either side missing
.printing-press.json** — older or hand-imported.
Ask the user.
When the user confirms overwrite, the backup step in Phase 3 captures
the current internal state.
Phase 3 — Import
STAGING=$(mktemp -d)
# Fetch (remote unless --from-clone was passed)
if [[ -n "${CLONE_PATH:-}" ]]; then
bash "$SCRIPTS_DIR/import-fetch.sh" "$LIB_PATH" "$STAGING" --clone "$CLONE_PATH"
else
bash "$SCRIPTS_DIR/import-fetch.sh" "$LIB_PATH" "$STAGING"
fi
# Backup if anything is being clobbered. Prints zip path on stdout.
if [[ -d "$LIB_TARGET" || -d "$MAN_TARGET" ]]; then
BACKUP_ZIP=$(bash "$SCRIPTS_DIR/import-backup.sh" "$API_SLUG")
echo "Backed up to: $BACKUP_ZIP"
fi
# Reverse the publish-step module path rewrites.
bash "$SCRIPTS_DIR/import-rewrite.sh" "$STAGING" "$API_SLUG"
# Atomically move staging into place.
bash "$SCRIPTS_DIR/import-place.sh" "$STAGING" "$API_SLUG"
Phase 4 — Verify internal consistency
After the move, confirm the imported CLI builds and is structurally
intact. Treat any failure as a real problem — don't paper over it.
cd "$LIB_TARGET"
# Module path is local form
grep -q "^module ${API_SLUG}-pp-cli\$" go.mod \
|| { echo "FAIL: go.mod still on public module path"; exit 1; }
# No public module path leaked into source
if grep -rq "github.com/mvanhorn/printing-press-library/library" \
--include='*.go' --include='*.yaml' --include='*.yml' .; then
echo "FAIL: source still references public module path"
exit 1
fi
# Build
go build ./... \
|| { echo "FAIL: go build"; exit 1; }
# Doctor (self-check)
make doctor 2>/dev/null \
|| ./bin/${API_SLUG}-pp-cli doctor 2>/dev/null \
|| true # best-effort; not all CLIs have doctor wired the same way
Report the import outcome:
- Source path (from registry:
<category>/<api-slug>)
- Run ID (from
.printing-press.json)
- Manuscripts run-ids placed (count + names)
- Backup zip path (if any)
- Build status
Polish-side hint
If the user's request to import was triggered by a polish ask (e.g.,
they said "polish notion in the public library"), suggest:
Imported $API_SLUG. To polish: /printing-press-polish $API_SLUG
The polish skill operates on the internal library, so import-then-polish
is the right flow when starting from a published CLI.