From genvid-dev
Set up a TypeScript package to publish publicly on npmjs.com via the shared genvid-public-ci GitHub Actions recipe with OIDC trusted publishing (automatic provenance, no stored npm token). This is the rare, once-per-package setup nobody remembers the steps for, so reach for it WHENEVER someone wants a package onto npm or made publicly installable — even when they don't say "npm", "publish", or name the recipe. Trigger on requests like "open-sourcing this library", "make this package public", "get it onto npm so others can npm install it", "set up a release pipeline for this lib", "publish the first version to npmjs", "have releases show up on npm automatically", "wire up trusted publishing / provenance", "stop keeping an npm token in repo secrets", scoping a package under @genvid, or moving a repo from pnpm to npm or CircleCI to GitHub Actions for releasing. It owns the whole job — package.json publish-readiness, the ci.yml/publish.yml workflows, the lockfile migration, and the one-time npm bootstrap handoff — so prefer it over wiring these steps together ad hoc or a generic planning skill. Genvid-first, but the npm-readiness and OIDC steps apply to any package. Do NOT use it for a routine version bump or release tag of a package that already publishes, publishing to a private/internal registry (e.g. Azure Artifacts, GitHub Packages), adding or installing a dependency, or non-npm publishing such as Docker images, the Construct3 marketplace, or GitHub Pages.
How this skill is triggered — by the user, by Claude, or both
Slash command
/genvid-dev:publish-npm-packageThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill converts a buildable TypeScript package into one that publishes to
This skill converts a buildable TypeScript package into one that publishes to
npmjs.com automatically on a version tag, using OIDC trusted publishing (no
long-lived npm token) and the shared genvid-holdings/genvid-public-ci
GitHub Actions workflows.
It executes the migration directly, with verification gates, and then hands off the parts only a human with npm-account access can do (the one-time bootstrap and the release tag).
Work in small, reviewable commits — one logical change per commit — so the diff
reads as a sequence (metadata → lockfile → CI → docs → fix). The same
preparation-before-feature discipline applies: get the package publishable
before wiring the automation that publishes it.
Use it when a package needs to start publishing to npm, or when migrating an existing package's release pipeline to the genvid-public-ci recipe. Signals: "publish to npmjs.com", "pnpm → npm", "CircleCI → GitHub Actions", "trusted publishing", "@genvid scope", "provenance".
It is not for: publishing to a private/internal registry, packages that
aren't built with tsc/a build script, or first-time repo creation. If the
repo isn't a git repo with a working npm run build, fix that first.
genvid-public-ci owns the canonical workflows and the onboarding runbook.
Do not embed or guess its contents — fetch the current versions so you never
act on a stale copy:
# Runbook + templates (decode base64 from the contents API):
gh api repos/genvid-holdings/genvid-public-ci/contents/README.md --jq .content | base64 -d
gh api repos/genvid-holdings/genvid-public-ci/contents/templates/ci.yml --jq .content | base64 -d
gh api repos/genvid-holdings/genvid-public-ci/contents/templates/publish.yml --jq .content | base64 -d
Read the README's "Onboarding" and "Cutting a release" sections — they are
authoritative. If the file layout has changed, list the tree first:
gh api repos/genvid-holdings/genvid-public-ci/git/trees/HEAD?recursive=1 --jq '.tree[].path'.
The templates are designed to be drop-in with zero per-package edits. Copy
them verbatim. In particular, publish.yml must keep that exact filename —
the npm trusted-publisher registration matches against it.
Non-genvid package? There's no genvid-public-ci to fetch. Reuse the same shape: a
ci.ymlthat runs lint/typecheck/test/build on PRs and pushes, and apublish.ymltriggered onv*.*.*tags withpermissions: id-token: writethat runsnpm publish --provenance --access public. The Phase 2–4 readiness and verification steps below are identical.
Establish these facts before touching anything; each one drives a later decision. Report a short summary to the user.
package.json: current name, version, main/types/exports,
files, scripts (is there build/lint/typecheck/test?),
publishConfig, repository, engines. Are scripts runner-agnostic or do
they hardcode pnpm?package.json's
engines.node. If they disagree, flag it — the README gets reconciled in the
Docs step (Phase 3). Shipping a published README that understates the runtime
requirement is the same class of stale-doc bug as pnpm→npm command drift.package-lock.json committed? (npm ci and the gate's
cache: npm require it.) Is pnpm-lock.yaml tracked?.circleci/, other .github/workflows/)? What does
it publish to (npm? a blob store?) — that's what you're replacing.gh repo view <org>/<repo> --json visibility. npm
provenance requires a public repo — flag loudly if private.npm view <name> version and the scoped form. Is the
name taken? At what versions? Scoped vs unscoped? This decides the publishable
version (you cannot republish an existing version).dist/ gitignored? If yes, the published tarball needs a prepack
build step (see Phase 3).src/test import the package by its own
name? (Usually tests use relative paths — confirm, because it affects whether
changing entry points is safe.)These genuinely change the outcome — present them, don't pick silently:
@genvid/<pkg>. If the
package is currently unscoped (or published unscoped), renaming to a scope is
a new package name — its bootstrap and trusted-publisher setup do not
carry over from the old name and must be done fresh. Make that cost explicit.If a genvid-public-ci setup already exists for the chosen name and the user
says trusted publishing is configured, confirm which exact name it was
configured for — a scope change invalidates that assumption.
Make the package publishable first, then wire the automation.
package.json publishing metadata.
name.repository in the git+https://github.com/<org>/<repo>.git form
(npm provenance matches against it; this exact form avoids npm's
auto-normalize warning).description (the npm page) and optionally homepage,
bugs, keywords."publishConfig": { "access": "public" } —
scoped packages are private by default.dist/ is gitignored, add "prepack": "npm run build" so local
npm pack/npm publish always ship built output.dist/ directly (see the gotcha in Phase 4): top-level
main/types/exports resolve to the built files.pnpm → npm. git rm pnpm-lock.yaml; run npm install to generate and
commit package-lock.json. The package.json scripts are usually already
runner-agnostic (tsc/mocha/eslint); only change them if they hardcode
pnpm.
Capability/config files. If the repo has a .genvid-agent.json (or
similar) with pnpm run … commands or the old name, update them to npm and
the new name.
GitHub Actions. Add .github/workflows/ci.yml and
.github/workflows/publish.yml verbatim from the fetched templates.
Remove the old CI. git rm -r .circleci/ (or whatever is being
replaced). Don't leave a dual pipeline.
Docs. Update CLAUDE.md/README.md: pnpm→npm commands, old-CI→GitHub
Actions, the public-install instructions (npm install <name>), import
examples using the final (possibly scoped) name, and drop any "private
package" framing. Grep for stale references to the old package name and the
old package manager. Also grep the README for any Node-version claim and
reconcile it with package.json's engines.node — update the README to
match engines (or fix engines if the README is the source of truth).
Run the full suite the gate will run: npm run lint && npm run typecheck && npm run test && npm run build.
Then verify what actually gets published — this is the step people skip and regret:
npm publish --dry-run --access public # lists tarball contents + warnings
npm pack # then inspect the PACKED manifest:
tar -xzO -f *.tgz package/package.json | node -e "const d=JSON.parse(require('fs').readFileSync(0)); console.log(d.main, d.types, JSON.stringify(d.exports))"
rm -f *.tgz
Confirm: the tarball contains dist/, LICENSE, and README.md; and the
packed package.json entry points resolve to ./dist/…, not ./src/….
🔴 The publishConfig-override gotcha. Older guidance put
main/types/exportsinsidepublishConfigto swapsrc→distonly at publish time. npm 11.x no longer applies those overrides — it warns "Unknown publishConfig config" and ships the top-level (source-pointing) values. A package published this way resolves to./src/index.ts, which isn't even in the tarball, and breaks for every consumer. The fix is simple and robust: point top-levelmain/types/exportsatdist/and keep onlyaccessinpublishConfig. Always confirm via the packed manifest, not the dry-run notice alone —npm packis the ground truth.
If a CI-driven release won't run a build before npm publish, the prepack
script (Phase 3) is what guarantees dist/ exists in the tarball.
The remaining steps are outward-facing. Do the in-repo/git parts only with the user's go-ahead, and clearly mark the npm-account step as theirs.
npm version <v>-bootstrap.0 --no-git-tag-version → npm publish --access public (using a shortest-expiry granular token, used locally
only) → npm deprecate "<name>@<v>-bootstrap.0" "bootstrap placeholder" →
restore the real version.publish.yml, environment
blank.git tag v<X.Y.Z> && git push origin v<X.Y.Z> →
publish.yml re-runs the gate, enforces tag↔package.json version equality,
and publishes with --provenance.If the name was changed in Phase 2, note that any previously-published versions
under the old name are now orphaned (and may have been published with the broken
source-pointing manifest); they can be npm deprecated later, pointing at the
new name.
ci.yml/publish.yml edit-free means
every package upgrades by re-copying, and the trusted-publisher match against
publish.yml stays stable.npm pack
shows you the truth a consumer will see.Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub genvid-holdings/claude-code-marketplace --plugin genvid-dev