One release prompt, every channel aligned. A directory-bundle Agent Skill + npm-installable CLI that turns "release this" into a coordinated publish across npm registries, GitHub + Gitee remotes, marketplace listings, repo RP fields, bilingual README, and git tags — all in lockstep.
Works on DSH, Claude Code, Codex CLI, Gemini CLI, Cursor. Runs anywhere Node, Python, Rust, Go, or any exe target lives.
⭐ If you ship software and have ever lost a version to "I forgot to tag it," give it a Star.
Install: npx skills add https://github.com/EternalNight996/publish-kit or npm i -g @eternalnight/publish-kit
🚀 Install
Three install paths, all one command. Pick the one that matches your host.:
# Skill bundle (any agent that reads .agents/skills/ — DSH, Claude Code, Codex, Gemini, Cursor)
npx skills add https://github.com/EternalNight996/publish-kit
# npm package (global CLI: bootstrap-release + release-exe available on PATH)
npm install -g @eternalnight/publish-kit
# DSH plugin via npm wrapper (uses the package's dsh.marketplace metadata)
dsh plugin --profile web add @eternalnight/publish-kit
For project-scoped (committable) installs and dsh-agent-skills UI integration, see INSTALL.md.
📖 Usage
As an Agent Skill (model-invoked)
Once loaded, the agent responds to any of these prompts automatically:
release this cut v0.4.2
publish my new version ship it
bump version and tag submit to marketplace
write the README slim the npm package
cargo publish this publish to PyPI
tag this commit push to GitHub and Gitee
build the exe and upload to GitHub Releases
The skill classifies the request into one of 8 release tracks (npm / DSH plugin / cargo / PyPI / PyInstaller exe / Go binary / Rust binary / Electron desktop), runs the per-track steps, and verifies every channel agrees on the version before declaring the release done. Full workflow in SKILL.md.
As a CLI (manual invocation)
After npm install -g @eternalnight/publish-kit, two commands are available:
# npm package release (six-step SOP: bump + publish + tag + push + RP)
bootstrap-release patch # or minor | major
# exe release (PyInstaller / Go / Rust / Electron cross-platform build + GitHub Release)
release-exe rust mycli 1.0.0 "x86_64-unknown-linux-gnu,x86_64-pc-windows-msvc,x86_64-apple-darwin"
Both scripts take an optional -Draft / --draft flag to publish a draft release for review first.
Every non-DSH track follows the same SOP: bump version → tests + build → publish → git tag → push tags to both remotes → marketplace submission (where applicable) → RP fields.
#
Pain (everyone who ships hits these)
What it costs
1
Forgot the git tag
npm knows v0.4.27 but git has no anchor; git checkout v<x.y.z> returns 404; release history becomes guesswork from commit messages
2
Changed code, forgot to bump version
npm publish returns 403 (cannot publish over); for DSH plugins the marketplace validator silently rejects; changelog drifts behind reality
3
Pushed to GitHub only, forgot Gitee
half your users see a broken README image, the other half get "404 not found" on the install command
4
Shipped to one marketplace, missed the other three
the DSH ecosystem has 4+ marketplaces (awesome-dsh-plugin, dsh-market, dsh-marketplace, dsh-plugin-marketplace); publishing to one and not the others means 75% of potential users never see your work
5
Wrote the token into .npmrc and committed it
one careless git add -A and your npm publish token is on a public GitHub forever — every bot in the world knows it within minutes
This is not paranoia; every one of these happened in real releases documented in EXAMPLES.md.
🚀 After loading the skill: each pain solved with one prompt
Pain
After publish-kit handles it
How
① Forgot the tag
every release creates v<x.y.z> anchored to the version-bump commit, verified before push
git show v<x.y.z> --format=%s gate before --tags
② 403 on republish
version bump is the first step in every SOP; npm view <pkg> version checked before publishing
script enforces it (see scripts/bootstrap-release.{ps1,sh})
③ Gitee drift
one-liner dual-remote push with SSH; force-reset stale remote URLs
throwaway .npmrc.publish is deleted in the same script's finally
token never lives longer than one command
flowchart LR
A["User says:<br/>'release this'"] --> B{"Classify release track"}
B -- "npm package<br/>(incl. DSH plugin)" --> C["npm SOP:<br/>bump → test → build → publish → tag → push tags → RP"]
B -- "cargo / PyPI" --> D["Standard registry flow<br/>(REFERENCE.md H / I)"]
B -- "Git-only project" --> E["git tag SOP:<br/>resolve hash from git log,<br/>verify subject, push both remotes"]
B -- "exe artifact" --> F["PyInstaller:<br/>anchor on sys.executable,<br/>smoke-test no crash.log"]
C & D & E & F --> G["Verify every channel<br/>agrees on version"]
G -- "PASS" --> H["Submit to marketplaces:<br/>awesome PR + dsh-market Issue"]
G -- "FAIL" --> X["❌ Block + report<br/>missing channel"]
🧬 Core design: why a Skill bundle, not an npm package
The publish-kit skill is not a cordis plugin and not an npm runtime dependency. It is a directory of dense facts + copy-paste templates that the agent consults when you ask it to release something. Three design decisions follow from that:
Decision
What
Why
No npm publish required
the skill ships at GitHub + Gitee; install is npx skills add <url>
matches every host that reads directory-bundle skills (DSH, Claude Code, Codex, Gemini) without forcing a registry dependency
Templated, not opinionated
ten copy-paste templates, one per release track (DSH plugin, awesome yml, dsh-market Issue, publish.bat, bilingual README, PUBLISH.md, GitHub Actions, Cargo.toml, pyproject.toml, PyInstaller)
each template is annotated with "when to use" + "knobs to inspect"; no single track dominates
Honest about source
sections A-G and J come from 11 hands-on release memory cards (npm, DSH plugins, GitHub/Gitee, PyInstaller); sections H-I (cargo, PyPI) state the standard registry flow without claiming local battle-testing
you know which advice is hard-won vs baseline
publish-kit complements rather than competes with the release tooling the agent already knows. It encodes specific release traps (npm pack --dry-run for files whitelist, git show for tag verification, full-width punctuation in .bat, the _MEIPASS PyInstaller path) that generic release helpers skip.
H. cargo / crates.io — standard flow (honestly noted: not yet battle-tested locally).
I. PyPI / PyInstaller — _MEIPASS path trap, base_library.zip stale-cache trap, ASCII-punctuation bat trap.
J. Pitfall quick table — 9-row symptom → fix reference.
📝 TEMPLATE.md (10 copy-paste skeletons)
Every template is annotated with when to use + knobs to inspect before publishing. Tracks covered: DSH plugin package.json, awesome-dsh-plugin yml entry, dsh-market Issue body, dual-remote publish.bat, bilingual README skeleton, git-install PUBLISH.md, GitHub Actions release workflow, Cargo.toml, pyproject.toml, PyInstaller build script.
🔧 scripts/bootstrap-release.{ps1,sh}
Six-step automation that runs the entire SOP end-to-end:
./scripts/bootstrap-release.sh patch # or minor / major
Bump version → test → build → commit → npm publish (with throwaway .npmrc.publish deleted in finally) → tag + push both remotes → GitHub RP fields. Pass patch, minor, or major as the argument.
npm package wrapping skills/publish-kit/ as an asset
npm + DSH dsh plugin install path
DSH theme asset
assets/{backgrounds,themes}/ runtime URLs kept in npm tarball; showcase media moved to GitHub raw
npm + GitHub + Gitee
Non-DSH language libraries (host-agnostic)
Track
What ships
Where it lives
npm / JavaScript / TypeScript
package.json + dist/ (or lib/)
npmjs.org + GitHub + Gitee
cargo / Rust
Cargo.toml + src/ (published as immutable versions)
crates.io + GitHub + Gitee
PyPI / Python
pyproject.toml + <pkg>/
pypi.org + GitHub + Gitee
PyInstaller exe (Windows / macOS / Linux)
standalone executable with sys.executable-anchored output paths
GitHub Releases + Gitee Releases
Homebrew formula (macOS)
<formula>.rb
homebrew-core PR or personal tap
Scoop bucket (Windows)
<bucket>/<pkg>.json
main bucket PR or personal bucket
Chocolatey package (Windows)
<pkg>.nuspec + tools/*.ps1
chocolatey.org moderation queue
Go module
go.mod + versioned git tag (no separate registry; modules are tag-resolved)
GitHub + Gitee only
Docker image
multi-stage Dockerfile (linux/amd64, linux/arm64)
Docker Hub + GHCR + Gitee Go Registry
Maven Central / JCenter (Java / Kotlin)
pom.xml + sources jar + GPG-signed artifacts
search.maven.org + GitHub + Gitee
NuGet (.NET)
.nuspec + .nupkg
nuget.org + GitHub + Gitee
RubyGems (Ruby)
<gem>.gemspec
rubygems.org + GitHub + Gitee
Every non-DSH track goes through the same SOP: bump version → tests + build → publish → git tag → push tags to both remotes → marketplace submission (where applicable) → RP fields.
Tracks publish-kit explicitly does NOT cover
Monorepo versioning strategy (lerna/changesets/nx release) — see find-skills for monorepo-specific tooling.
Language-specific lint/test setup (separate skill per language).
Release internals design (package API surface, library architecture).
📚 Skill bundle discovery & inclusion standards
For publish-kit-style bundles to surface on every host that consumes them, the bundle must satisfy the conventions below. This section is both the standard publish-kit itself follows and the checklist you should apply to your own skill bundle.
dropped into ~/.agents/skills/, ~/.claude/skills/, ~/.codex/skills/, ~/.gemini/skills/, or ~/.config/opencode/skills/
GitHub repo RP (required for marketplace auto-scanners)
# Description (one-line, English; keywords help SEO)
gh api -X PATCH repos/<owner>/<repo> -f description="<one-line>"
# Topics (independent endpoint — DO NOT include topics in the PATCH above, it returns 400)
gh api -X PUT repos/<owner>/<repo>/topics --input topics.json
# topics.json content: {"names":["dsh-skill","agent-skills","publishing","release","npm","cargo","pypi"]}
Upload assets/social-preview.png (1280×640 PNG) at Settings → General → Social preview. This is the image GitHub, Gitee, npm, and Twitter use when the URL is shared — a strong preview is the single largest click-rate lever. See the next section for design guidance.
For skill authors (publishing your own bundle)
Use this repo (publish-kit) as the template — copy .agents/skills/<your-skill>/ and the supporting top-level files.
Add the topics your bundle needs (don't add dsh-skill if you're shipping a cordis plugin only).
Open one PR against awesome-dsh-plugin and one Issue against dsh-market.
Run the skill's own SOP once on yourself before publishing (eat your own dogfood — proves the templates work).
🎨 README & repo home: how to maximize clicks
The biggest leverage point for a new release is the first 5 seconds a visitor spends on the GitHub repo home. This section codifies the moves publish-kit itself uses; copy them for your own bundles.
Repo home (the GitHub repo landing page)
Element
What to do
Why
Social preview image
Upload assets/social-preview.png (1280×640) at Settings → General
Single largest click-rate lever when the URL is shared on social, in npm search, in PRs
Description
One line, English, with concrete keywords (not "awesome X framework" but "release playbook covering npm/cargo/PyPI + DSH marketplaces")
Scans show in search results; vague descriptions get passed over
Topics
5-10 topics, all relevant
Sidebar filter + marketplace auto-discovery both depend on topics
Pinned repos
Pin 2-3 most-used skills or sister repos
Signals to visitors that this is part of an ecosystem, not a one-off
About sidebar
Website, Releases link (if using GitHub Releases), Packages link (if shipping npm), Projects (if using project boards)
Each link is a chance to retain the visitor
README structure (the visited page)
Section
Why it matters
Banner image (top, full-width)
Visual hook; lets the visitor decide "is this for me?" in 1 second
One-line tagline + badge row
Tells the visitor what + what language/registry before they scroll
Shows you've understood their problem AND have a specific answer
Mermaid (or static-table) flow
Proves the system has a structure, not just a slogan
"Why X, not Y" core design section
Differentiates from look-alikes; people buy when they see you've made deliberate tradeoffs
Comparison table to alternatives
Visitors want to know "why not just use [alternative]?" — answer before they ask
Install in the first 30 lines
If the install command is below the fold, you lose 50%+ of would-be users
Roadmap
Signals the project is alive; lets visitors vote with issues
Release log (or link to CHANGELOG.md)
Trust signal — "this project has shipped"
License + contributing link
Removes friction for the next step (use, contribute, fork)
Asset hygiene that wins clicks
Banner at the top. Full-width PNG or WebP (GitHub README rendering prefers assets/readme-banner.{svg,png,webp} referenced as relative ./assets/...).
GIFs under 10 MB. Compress with ffmpeg (REFERENCE.md D6). Over the threshold, GitHub silently drops the image.
Use raw.githubusercontent.com URLs for any image rendered on GitHub AND npm AND Gitee. Keeps images in git (so both git hosts render them) but out of the npm tarball.
Mermaid with a static-table fallback. Some hosts (older Cursor, Windsurf, Copilot) don't render Mermaid; provide a parallel table for those viewers.
Pin a screenshot or GIF showing the result, not the install command. Visitors want to see the outcome, then decide.
SEO & shareability
Repo Description: one line, English, with at least 2 keywords that search engines and humans both use (e.g. "release playbook for AI agents npm cargo PyPI").
Topics: never duplicate the description; think of them as tags, not keywords. Aim for 5-10.
README H1 should match the repo name. GitHub renders H1 as the page title.
Social preview must show the project name + one-line tagline + version. A wall of text in social preview kills click-through.
Community signals that move the needle
Star CTA in the README — one line near the top, not aggressive.
"Used by" section if any real project depends on this — concrete social proof.
A pinned Discussion / Q&A category at repo Settings → Features — invites questions, builds community.
An explicit License — MIT for maximum reach. Missing license = legal ambiguity = lost users.
Sponsor button at .github/FUNDING.yml — optional but signals sustainability.
publish-kit itself follows every line above; the README you are reading is the example.
🧪 Pre-release strategy (ship a beta, then promote)
For any non-trivial change, publish a pre-release first, validate, then promote to latest. A bug in latest hits 100% of npm install <pkg> users; a bug in beta only hits opt-in testers.
# Step 1: pre-release (npm `beta` dist-tag + GitHub Pre-release)
./scripts/bootstrap-release.sh patch --pre-release beta
# -> v0.4.1-beta.1
# Step 2: iterate on beta if bugs surface
./scripts/bootstrap-release.sh --pre-release beta --pre-release-bump 2
# -> v0.4.1-beta.2
# Step 3: promote to latest (no version bump; only moves dist-tag)
./scripts/bootstrap-release.sh --promote-from-beta --promote-version v0.4.1-beta.2
# -> v0.4.1 published to npm `latest` + GitHub Production release
Version
npm dist-tag
GitHub Release flag
Use for
0.4.1-beta.1
beta
Pre-release
first external test pass
0.4.1-beta.2
beta
Pre-release
after fixing beta.1 bugs
0.4.1-rc.1
rc
Pre-release
release-candidate (feature-frozen)
0.4.1
latest
Production
promoted from rc.1
Skip pre-release for: doc-only changes (README typo, comment cleanup), patch releases with no behavior change. Full SOP + recovery playbook in REFERENCE.md section K.
v0.1.1 (current): added EXAMPLES.md with two worked transcripts (this release + a fictional DSH plugin npm flow).
v0.1.5 (current): added scripts/release-exe.{ps1,sh} for exe projects (PyInstaller / Go / Rust / Electron cross-platform builds + checksum + GitHub Release upload); TEMPLATE.md K section with 4 GitHub Actions workflows (K.1 PyInstaller / K.2 Go matrix / K.3 Rust matrix / K.4 Electron); EXAMPLES.md Example 3 (Rust CLI end-to-end transcript + 7-row pitfall table); README EN/ZH language toggle buttons.
v0.2.0 (current):npm package @eternalnight/publish-kit published to https://registry.npmjs.org/ — 19 files / 51 KB / scoped / MIT / explicit registry / signed. Bundles the skill directory, ships scripts as bin, includes cordis.patch.yml + dsh.marketplace metadata for dsh plugin install path. README top-of-page Install + Usage + Supported agents/languages tables. All "not published to npm" notes updated to reflect the publication.
v0.2.1 (current): docs cleanup — removed duplicate old Install section in both READMEs; marked npm wrapper Roadmap entry as completed (superseded by v0.2.0 publication).
v0.5.0 (current):postinstall hardening — scripts/postinstall.js now correctly handles pre-existing Windows directory junctions at the 5 skill roots (~/.agents, ~/.claude, ~/.codex, ~/.gemini, ~/.dsh). Previously the script would unlink + symlink('junction') and throw EEXIST warnings on systems where the same source inode was already linked from another path, blocking dsh plugin --profile web add for any user who had the skill installed by the 0.4.0 copy. New behaviour: detect the existing link, compare realpath against the locally bundled source, keep it; honour PUBLISH_KIT_FORCE=1 to overwrite; report installed in N location(s) vs kept M existing link(s) separately. npm @eternalnight/publish-kit@0.5.0 on dist-tag=latest. Withdrew 0.5.0-beta.1 (npm deprecated, git tag deleted on both remotes).
v0.5.0-beta.1 (superseded — withdrawn):Pre-release workflow — REFERENCE.md K section + bootstrap-release.{ps1,sh} with --pre-release beta / --promote-from-beta flags; release-exe.{ps1,sh} with -Prerelease flag; release-doctor prerelease check; verify-release dist-tag channel; SKILL.md Workflow step 2 + README EN/ZH Pre-release strategy section. Withdrawn because the tag pointed at the CHANGELOG/docs commit and missed the post-install junction fix that ships in v0.5.0.
release-doctor.mjs — pre-flight checker that scans a target repo for the 9-row pitfall table in REFERENCE.md J and reports drift before publish
verify-release.mjs — post-publish verifier that walks every channel (npm view, gh release, gitee release, awesome-dsh-plugin search, dsh-market issue status, GitHub topics, marketplace catalog) and reports per-channel status
npm wrapper package (@eternalnight/publish-kit) — ships skills/publish-kit/ as an asset, symlinks into ~/.agents/skills/ via postinstall, exposed via dsh plugin --profile web add (v0.2.0)
v0.5.0 (2026-09-03): postinstall hardening (scripts/postinstall.js keeps pre-existing junctions, detects EEXIST correctly, honours PUBLISH_KIT_FORCE=1, separates installed N vs kept M). npm @eternalnight/publish-kit@0.5.0 promoted to dist-tag=latest. Withdraws 0.5.0-beta.1 (npm deprecate + tag delete on both remotes).