shipkit

Download page Source on GitHub

shipkit takes a project from a local folder to a public GitHub repo and a crates.io, npm or PyPI release, safely. Its ship CLI runs every release step as a separate command that prints one JSON object, so Claude Code, a script or you can drive it one step at a time. The Claude Code plugin adds a skill that knows the order of the steps, a hook that blocks the risky ones until you say yes, and a /ship-setup command. There is no MCP server.

  • Safe by default. Creating a repo, tagging a release and publishing are refused without --confirm. Every step has a --dry-run that prints exactly what it would run.
  • No tokens. ship uses your existing gh, cargo, npm or uv logins, and generated release workflows publish with trusted publishing (OIDC).
  • Never overwrites. scaffold and add-workflows only create missing files. Tags are never moved or deleted. Running a step twice is safe.
  • Checks first. A secret scan and the registry dry run must pass before a commit, repo, release or publish.
  • No telemetry. The only network calls are the ones a step needs.

Install

  • Windows installer from qlinter.org (shipkit-setup-0.3.0.exe). It can add ship to your PATH and install the Claude Code plugin.
  • macOS package from qlinter.org (shipkit-0.3.0.pkg). It installs /usr/local/bin/ship.
  • With Rust:
cargo install shipkit
  • Prebuilt binaries for Windows x64 and Linux x64 are on the releases page. Put ship (ship.exe on Windows) on your PATH.

Check it:

ship --version
ship self-test

ship needs git and the GitHub CLI gh, logged in, plus the tool for your registry.

Claude Code plugin

In an interactive claude session:

/plugin marketplace add acus9345/shipkit
/plugin install shipkit@shipkit
/shipkit:ship-setup

/ship-setup runs ship preflight and ship self-test and offers the recommended permission rules. With them, Claude runs the local steps without asking, asks you before create-repo, release and publish, and can't run raw cargo publish, npm publish or force-push. Then ask Claude something like "ship this project to GitHub and crates.io".

Quick start

ship preflight
ship check-names --name hello-ship
ship scaffold --name hello-ship --cli --description "Says hello" --repo-url https://github.com/you/hello-ship
ship scan-secrets && ship checks && ship inspect && ship commit
ship create-repo --confirm

Then ship publish --confirm for the first version only, ship trusted-publishing (you click Save on the registry page), ship release --confirm, ship watch until it reports "done": true, and ship verify.

Registries

The registry is detected from the manifest (Cargo.toml, package.json or pyproject.toml). For a new project, pass --registry crates.io|npm|pypi to scaffold.

Registry Tool Checks Dry run Trusted publishing
crates.io cargo clippy, build, test cargo publish --dry-run Needs the crate to exist, so publish the first version with ship publish.
npm node, npm install, then the lint, typecheck, build and test scripts if present npm publish --dry-run Needs the package to exist, so publish the first version with ship publish.
PyPI uv compile, uv build, unittest uv build and uv publish --dry-run Works before the first release (pending publisher), so CI can publish 0.1.0.

Repo-only projects block publishing the registry's own way: publish = false in Cargo.toml, "private": true in package.json, or the Private :: Do Not Upload classifier in pyproject.toml.

Steps

Run them in order. Each stops at the first problem and explains it.

Step Risk What it does
preflight low Checks that git, gh and the registry's tools are installed, which accounts are logged in, and the git identity. Never starts a login.
check-names low Is the package name valid and free on the registry, and the repo name free on GitHub? Suggests the best free alternative.
scaffold medium Creates sources, tests, README, LICENSE, CHANGELOG, .gitignore, .gitattributes and a manifest at 0.1.0. --cli adds --help and --version, --target repo blocks publishing, --repo-url adds workflows, --private keeps CI on Ubuntu.
scan-secrets low Finds .env files, private keys and tokens in what would be committed. Reports the file and line, never the secret.
checks low The registry's lint, typecheck, build and test steps.
inspect low The publish dry run, the list of files that would ship, and any junk or secrets among them.
commit medium git init on main if needed, refuses if secrets would be committed, then commits.
create-repo high Creates the GitHub repo (public unless --private) and pushes. --topics adds topics.
add-workflows medium ci.yml and release.yml. On v* tags, release.yml tests, builds, publishes with trusted publishing unless the version exists, and makes the GitHub release from the CHANGELOG with the binaries attached.
trusted-publishing medium Opens the registry's trusted-publishing page and prints the exact values. You click Save.
bump medium Bumps the patch, minor or major version and records it in the CHANGELOG. Doesn't commit.
release high Tags v<version>, pushes the branch and tag, and creates the GitHub release unless release.yml does.
watch low Waits up to about 45 s for the current commit's workflow runs and returns the failing log on failure. Call it again while runs are in progress.
verify medium In a fresh temp folder, installs from the real registry (or clones the repo) and runs the README's commands one at a time.
publish high Publishes from your terminal with cargo publish, npm publish or uv publish. Skipped if the version exists. After a rate limit (HTTP 429) it refuses to retry for 24 hours unless --force.

npm with 2FA only asks for approval in a terminal, so ship publish re-runs npm publish in a window: press Enter there and approve in the browser. PyPI uses a uv auth login credential or UV_PUBLISH_TOKEN; a credential in .pypirc or TWINE_PASSWORD is uploaded with twine instead.

Setup helpers

Command Risk What it does
login gh|npm|cargo|pypi medium Opens the tool's official login in a visible window and waits up to 15 minutes. crates.io and PyPI open the token page, and you paste the token into the tool's own prompt; ship never sees it. Windows only; elsewhere it prints the command to run.
install-tool gh|git|node|uv high Installs the tool with winget (Windows) or Homebrew (macOS). Refused without --confirm.

Output format

Every command prints exactly one JSON object:

success  {"v":1,"ok":true,"step":"<step>","risk":"low|medium|high","dry_run":false,"data":{...}}
failure  {"v":1,"ok":false,"step":"<step>","error":{"code":"E_...","message":"...","details":{...}}}
  • Exit codes: 0 success, 1 failure, 2 bad usage or input, 3 refused for lack of --confirm.
  • Stable error codes include E_CONFIRM_REQUIRED, E_DIRTY_TREE, E_TOOL_MISSING, E_SECRETS_FOUND, E_CHECK_FAILED, E_RATE_LIMITED, E_COOLDOWN and E_TIMEOUT.
  • Arguments come from flags, or one JSON object with --input '{"name":"x"}' (also a file path, or - for stdin). --confirm and --dry-run are only read from the command line, so a hook can always see them.
  • --dir <path> runs a step on another folder.

How it works

ship is one static Rust binary with three dependencies (clap, serde and serde_json). Each step runs once as its own process and calls the real tools (git, gh, cargo, npm, uv). Nothing is cached, so preflight re-checks everything each time. The registry layer is a Registry trait implemented for crates.io, npm and PyPI.

Safety comes in layers, so no single mistake publishes anything:

  1. ship itself refuses create-repo, release, publish and install-tool without --confirm. Before the first three it refuses a dirty working tree (unless --allow-dirty) and runs the secret scan and the dry run.
  2. The plugin's PreToolUse hook, on Bash and PowerShell, blocks those four commands without --confirm or --dry-run, so Claude has to show you the plan first. --confirm only counts in the same command.
  3. The skill tells Claude to dry-run, show you the plan, and wait for your yes before each gated step.
  4. Your permission rules make Claude Code ask before each gated step, and deny raw cargo publish, npm publish, uv publish, gh repo create and force-pushes.

READMEs, CI logs and web pages are treated as data. verify only runs README lines in bash or sh blocks that start with the project's own binary, use no shell syntax and don't look outward, and it runs them without a shell.

Compared with publish-pilot, which does the same job as an MCP server, shipkit costs about 100 tokens per turn for the skill description (plus about 1,500 when the skill loads), against about 2,400 for publish-pilot's tool list.

Files

Item Where
Action log (JSON lines, secrets redacted) %LOCALAPPDATA%\ship\ship.log on Windows; $XDG_STATE_HOME/ship/ship.log (default ~/.local/state/ship/ship.log) elsewhere
Recommended permission rules docs/permissions.md in the repo

Limits and troubleshooting

  • ship login opens a window only on Windows; elsewhere it prints the command to run.
  • crates.io and npm need the first version published with ship publish before trusted publishing can be set up.
  • E_CONFIRM_REQUIRED (exit code 3): review the plan in details, then re-run with --confirm.
  • E_DIRTY_TREE: commit or stash first, or pass --allow-dirty.
  • E_COOLDOWN after a rate limit: wait 24 hours. Every retry can extend npm's block.

Worked examples

A Rust CLI to crates.io.

ship scaffold --name hello-ship --cli --description "Says hello" --repo-url https://github.com/you/hello-ship

Then ship scan-secrets, ship checks, ship inspect, ship commit, ship create-repo --confirm, ship publish --confirm for 0.1.0, ship trusted-publishing, and for every later version ship bump, commit, ship release --confirm and ship watch.

Preview a risky step. ship create-repo --dry-run prints the exact gh repo create command it would run. Without --confirm it refuses with E_CONFIRM_REQUIRED and puts the plan in details.

A Python package's first release from CI. PyPI accepts a pending publisher, so run ship trusted-publishing before anything is published, then ship release --confirm. release.yml publishes 0.1.0.

Pass arguments as JSON. ship check-names --input '{"name":"hello-ship"}', or --input args.json, or --input - for stdin.

Work on another folder. ship checks --dir C:\code\other.

Check a release really installs. ship verify installs from the registry in a temp folder and runs the README's commands one at a time.

Edge cases

  • Dirty working tree: create-repo, release and publish refuse with E_DIRTY_TREE unless --allow-dirty.
  • --confirm in the wrong command: the hook only counts it on the gated command itself; ship preflight --confirm && ship publish is still blocked.
  • The version exists: publish skips it and release.yml skips it too.
  • Rate limited (HTTP 429): publish refuses to retry for 24 hours unless --force.
  • Workflows still running: watch waits about 45 s; call it again until it reports "done": true.
  • README commands that look outward: verify skips lines with --confirm, publish, push, delete and the like, and lines that use shell syntax.
  • Unknown input fields: --input rejects them with E_INPUT.
  • Running a step twice: safe; nothing is overwritten and tags never move.

FAQ

Is there an MCP server? No. It's a CLI; the plugin adds a skill, a hook and /ship-setup.

Does it store tokens? No. It uses your existing logins, and releases publish with OIDC.

Can it log in for me? ship login opens the official login in a window; you finish it there.

Does it work without Claude? Yes. Every step is a plain command with JSON output.

What does exit code 3 mean? The step needs --confirm.

Where is the log? %LOCALAPPDATA%\ship\ship.log on Windows, ~/.local/state/ship/ship.log elsewhere.

Does it collect telemetry? No.

Version and source

This page describes shipkit 0.3.0.

shipkit 安全地把專案從本機資料夾帶到公開的 GitHub repo,以及 crates.io、npm 或 PyPI 的 release。它的 ship CLI 把每個發布步驟做成獨立指令,各輸出一個 JSON 物件,所以 Claude Code、指令稿或你自己都能一步一步操作。Claude Code 外掛加入一個知道步驟順序的 skill、一個在你同意前擋下高風險步驟的 hook,以及 /ship-setup 指令。沒有 MCP 伺服器。

  • 預設安全。 沒有 --confirm 時,建立 repo、打 release tag 和發布都會被拒絕。每個步驟都有 --dry-run,印出它將執行的確切內容。
  • 不存權杖。 ship 使用你現有的 gh、cargo、npm 或 uv 登入,產生的 release workflow 以 trusted publishing(OIDC)發布。
  • 從不覆寫。 scaffold 和 add-workflows 只建立缺少的檔案。tag 永遠不會移動或刪除。同一步驟執行兩次也安全。
  • 先檢查。 在 commit、建立 repo、release 或發布之前,密鑰掃描和套件庫 dry run 都必須通過。
  • 沒有遙測。 唯一的網路請求是步驟本身需要的。

安裝

  • Windows 安裝程式,來自 qlinter.org(shipkit-setup-0.3.0.exe)。它可以把 ship 加入 PATH,並安裝 Claude Code 外掛。
  • macOS 安裝套件,來自 qlinter.org(shipkit-0.3.0.pkg)。它會安裝 /usr/local/bin/ship。
  • 使用 Rust:
cargo install shipkit
  • 預先建置的執行檔(Windows x64 和 Linux x64)在 發行版頁面。把 ship(Windows 上是 ship.exe)放到 PATH 上。

檢查一下:

ship --version
ship self-test

ship 需要 git 和已登入的 GitHub CLI gh,再加上你的套件庫對應的工具。

Claude Code 外掛

在互動式 claude 工作階段中:

/plugin marketplace add acus9345/shipkit
/plugin install shipkit@shipkit
/shipkit:ship-setup

/ship-setup 會執行 ship preflight 和 ship self-test,並提供建議的權限規則。套用後,Claude 不需詢問就能執行本機步驟,在 create-repo、release 和 publish 之前會先問你,而且不能執行原始的 cargo publish、npm publish 或強制推送。然後跟 Claude 說類似「ship this project to GitHub and crates.io」的話。

快速開始

ship preflight
ship check-names --name hello-ship
ship scaffold --name hello-ship --cli --description "Says hello" --repo-url https://github.com/you/hello-ship
ship scan-secrets && ship checks && ship inspect && ship commit
ship create-repo --confirm

接著只有第一版要 ship publish --confirm,然後 ship trusted-publishing(你在套件庫頁面上按 Save)、ship release --confirm、反覆 ship watch 直到回報 "done": true,最後 ship verify。

套件庫

套件庫由 manifest(Cargo.toml、package.json 或 pyproject.toml)判斷。新專案請在 scaffold 時傳入 --registry crates.io|npm|pypi。

套件庫 工具 檢查 Dry run Trusted publishing
crates.io cargo clippy、建置、測試 cargo publish --dry-run crate 必須已存在,所以第一版用 ship publish 發布。
npm node、npm 安裝,再執行存在的 lint、typecheck、build 和 test script npm publish --dry-run 套件必須已存在,所以第一版用 ship publish 發布。
PyPI uv 編譯、uv build、unittest uv build 和 uv publish --dry-run 第一次 release 前就能用(pending publisher),所以 CI 可以發布 0.1.0。

只要 repo 的專案會用套件庫自己的方式禁止發布:Cargo.toml 中的 publish = false、package.json 中的 "private": true,或 pyproject.toml 中的 Private :: Do Not Upload classifier。

步驟

依序執行。每個步驟在第一個問題處停下並說明。

步驟 風險 作用
preflight 低 檢查 git、gh 和套件庫工具是否已安裝、登入了哪些帳號,以及 git 身分。從不啟動登入。
check-names 低 套件名稱在套件庫上是否有效且可用,repo 名稱在 GitHub 上是否可用?會建議最好的可用替代名稱。
scaffold 中 建立原始碼、測試、README、LICENSE、CHANGELOG、.gitignore、.gitattributes,以及版本 0.1.0 的 manifest。--cli 加入 --help 和 --version,--target repo 禁止發布,--repo-url 加入 workflow,--private 讓 CI 只跑 Ubuntu。
scan-secrets 低 在會被 commit 的內容中找出 .env 檔、私密金鑰和權杖。回報檔案和行號,從不顯示密鑰本身。
checks 低 套件庫的 lint、型別檢查、建置和測試步驟。
inspect 低 發布 dry run、會發布的檔案清單,以及其中的垃圾檔或密鑰。
commit 中 需要時在 main 上 git init,有密鑰會被 commit 時拒絕,然後 commit。
create-repo 高 建立 GitHub repo(除非 --private,否則為公開)並推送。--topics 加入主題。
add-workflows 中 ci.yml 和 release.yml。在 v* tag 上,release.yml 會測試、建置、以 trusted publishing 發布(版本已存在則略過),並從 CHANGELOG 建立附上執行檔的 GitHub release。
trusted-publishing 中 打開套件庫的 trusted publishing 頁面,並印出要填的確切數值。由你按 Save。
bump 中 升級 patch、minor 或 major 版本,並記錄到 CHANGELOG。不會 commit。
release 高 打 v<version> tag,推送分支和 tag,並建立 GitHub release(除非 release.yml 會做)。
watch 低 最多等約 45 秒,等待目前 commit 的 workflow 執行,失敗時回傳失敗的 log。執行還在進行時再呼叫一次。
verify 中 在新的暫存資料夾從真實套件庫安裝(或 clone repo),逐一執行 README 的指令。
publish 高 從你的終端機以 cargo publish、npm publish 或 uv publish 發布。版本已存在則略過。碰到速率限制(HTTP 429)後,24 小時內拒絕重試,除非加 --force。

npm 開啟 2FA 時只在終端機中要求核准,所以 ship publish 會在一個視窗中重新執行 npm publish:在那裡按 Enter,然後在瀏覽器中核准。PyPI 使用 uv auth login 的認證或 UV_PUBLISH_TOKEN;放在 .pypirc 或 TWINE_PASSWORD 的認證則改用 twine 上傳。

設定輔助指令

指令 風險 作用
login gh|npm|cargo|pypi 中 在看得見的視窗中打開該工具的官方登入,最多等 15 分鐘。crates.io 和 PyPI 會打開權杖頁面,由你把權杖貼到工具自己的提示中;ship 從不看到它。僅限 Windows;其他系統會印出要執行的指令。
install-tool gh|git|node|uv 高 用 winget(Windows)或 Homebrew(macOS)安裝工具。沒有 --confirm 時拒絕。

輸出格式

每個指令都只印出一個 JSON 物件:

success  {"v":1,"ok":true,"step":"<step>","risk":"low|medium|high","dry_run":false,"data":{...}}
failure  {"v":1,"ok":false,"step":"<step>","error":{"code":"E_...","message":"...","details":{...}}}
  • 結束代碼:0 成功,1 失敗,2 用法或輸入錯誤,3 因缺少 --confirm 被拒絕。
  • 穩定的錯誤代碼包括 E_CONFIRM_REQUIRED、E_DIRTY_TREE、E_TOOL_MISSING、E_SECRETS_FOUND、E_CHECK_FAILED、E_RATE_LIMITED、E_COOLDOWN 和 E_TIMEOUT。
  • 參數可以來自旗標,或用 --input '{"name":"x"}' 傳一個 JSON 物件(也可以是檔案路徑,或 - 代表 stdin)。--confirm 和 --dry-run 只從命令列讀取,所以 hook 一定看得到。
  • --dir <path> 讓步驟作用在另一個資料夾。

運作原理

ship 是一個只有三個相依套件(clap、serde 和 serde_json)的 Rust 靜態執行檔。每個步驟都以獨立程序執行一次,並呼叫真正的工具(git、gh、cargo、npm、uv)。沒有任何快取,所以 preflight 每次都重新檢查一切。套件庫層是一個 Registry trait,為 crates.io、npm 和 PyPI 各實作一次。

安全分成好幾層,所以單一錯誤不會發布任何東西:

  1. ship 本身沒有 --confirm 時拒絕 create-repo、release、publish 和 install-tool。前三者在執行前會拒絕有未 commit 變更的工作目錄(除非 --allow-dirty),並執行密鑰掃描和 dry run。
  2. 外掛的 PreToolUse hook(作用於 Bash 和 PowerShell)會擋下沒有 --confirm 或 --dry-run 的這四個指令,所以 Claude 必須先給你看計畫。--confirm 只在同一個指令中才算數。
  3. skill 告訴 Claude 在每個受控步驟前先 dry run、給你看計畫,並等你同意。
  4. 你的權限規則讓 Claude Code 在每個受控步驟前詢問,並禁止原始的 cargo publish、npm publish、uv publish、gh repo create 和強制推送。

README、CI log 和網頁都被視為資料。verify 只執行 bash 或 sh 區塊中、以專案自己的執行檔開頭、不使用 shell 語法且不會對外動作的 README 行,而且不經過 shell 執行。

publish-pilot 以 MCP 伺服器做同樣的事;相比之下,shipkit 的 skill 描述每回合約花 100 個 token(skill 載入時再加約 1,500),publish-pilot 的工具清單則約 2,400。

檔案

項目 位置
動作 log(JSON lines,密鑰已遮蔽) Windows 上為 %LOCALAPPDATA%\ship\ship.log;其他系統為 $XDG_STATE_HOME/ship/ship.log(預設 ~/.local/state/ship/ship.log)
建議的權限規則 repo 中的 docs/permissions.md

限制與疑難排解

  • ship login 只在 Windows 上打開視窗;其他系統會印出要執行的指令。
  • crates.io 和 npm 必須先用 ship publish 發布第一版,才能設定 trusted publishing。
  • E_CONFIRM_REQUIRED(結束代碼 3):檢查 details 中的計畫,再加上 --confirm 重新執行。
  • E_DIRTY_TREE:先 commit 或 stash,或加上 --allow-dirty。
  • 速率限制後出現 E_COOLDOWN:等 24 小時。每次重試都可能延長 npm 的封鎖。

實例

一個 Rust CLI 發布到 crates.io。

ship scaffold --name hello-ship --cli --description "Says hello" --repo-url https://github.com/you/hello-ship

接著 ship scan-secrets、ship checks、ship inspect、ship commit、ship create-repo --confirm、為 0.1.0 執行 ship publish --confirm、ship trusted-publishing;之後每個版本都是 ship bump、commit、ship release --confirm 和 ship watch。

預覽高風險步驟。 ship create-repo --dry-run 會印出它將執行的確切 gh repo create 指令。沒有 --confirm 時,它以 E_CONFIRM_REQUIRED 拒絕,並把計畫放在 details 中。

Python 套件第一次從 CI 發布。 PyPI 接受 pending publisher,所以在發布任何東西之前先執行 ship trusted-publishing,再 ship release --confirm。release.yml 會發布 0.1.0。

以 JSON 傳參數。 ship check-names --input '{"name":"hello-ship"}',或 --input args.json,或用 --input - 代表 stdin。

作用在另一個資料夾。 ship checks --dir C:\code\other。

確認 release 真的能安裝。 ship verify 會在暫存資料夾從套件庫安裝,並逐一執行 README 的指令。

特殊情況

  • 工作目錄有未 commit 的變更: create-repo、release 和 publish 會以 E_DIRTY_TREE 拒絕,除非加 --allow-dirty。
  • --confirm 放錯指令: hook 只認受控指令本身上的 --confirm;ship preflight --confirm && ship publish 仍會被擋下。
  • 版本已存在: publish 會略過,release.yml 也會略過。
  • 被速率限制(HTTP 429): publish 在 24 小時內拒絕重試,除非加 --force。
  • workflow 還在跑: watch 等約 45 秒;持續呼叫直到回報 "done": true。
  • 會對外動作的 README 指令: verify 會略過含有 --confirm、publish、push、delete 等的行,以及使用 shell 語法的行。
  • 未知的輸入欄位: --input 會以 E_INPUT 拒絕。
  • 同一步驟執行兩次: 安全;不會覆寫任何東西,tag 也不會移動。

常見問題

有 MCP 伺服器嗎? 沒有。它是 CLI;外掛加入 skill、hook 和 /ship-setup。

它會儲存權杖嗎? 不會。它使用你現有的登入,release 以 OIDC 發布。

它能幫我登入嗎? ship login 會在視窗中打開官方登入;由你在那裡完成。

不用 Claude 也能用嗎? 可以。每個步驟都是一般指令,輸出 JSON。

結束代碼 3 是什麼意思? 這個步驟需要 --confirm。

log 在哪裡? Windows 上在 %LOCALAPPDATA%\ship\ship.log,其他系統在 ~/.local/state/ship/ship.log。

有收集遙測嗎? 沒有。

版本與原始碼

本頁說明 shipkit 0.3.0。