packslip is a signed release manifest for software distributed as archives,
installers, or executables. A release publishes one file,
packslip.sigstore.json, beside its artifacts. A consumer, such as a
package manager or mirror, verifies that file against the project's signer
and reads three things from it: which artifact suits the host, where the
executables are inside that artifact, and the digest the download must
match. The consumer does not have to guess from file names or trust a
checksum file served next to the binary.
This repository holds the specification, the
packslip CLI and Rust crate that create and verify packslips, and two
GitHub Actions: jdx/packslip publishes a packslip from a release job, and
jdx/packslip/releases builds a signed release list. The format is stable
at version 1; Stability says
what that fixes and what a revision may add.
Start here
- Try it locally: Getting started creates and verifies a sample release with a local key. It needs no CI account.
- Publish releases: Publish with GitHub Actions adds signing to a release job. Artifact configuration maps your files to platforms and executables. Resources covers completions, man pages, skills, and SBOMs, and Host requirements covers what the host must provide. Release recipes gives complete configurations for Rust, Go, monorepo, and desktop releases.
- Withdraw, recommend, or self-host releases: Manage release lists and Host releases on your own domain.
- Verify or install releases: Verify a release checks a downloaded release with the CLI against a repository, signer fingerprint, or public key you trust. Build an installer or mirror walks through finding, verifying, and selecting a release in your own tool, and shows the Rust crate that implements the verification and selection steps. Use packslip with mise shows how mise installs a tool from its packslip and keeps its completions, man pages, and skills matched to the active version.
How packslip fits a release shows how the pieces connect, and the documentation index lists every guide. For exact fields and rules, read the specification, CLI reference, or JSON schemas.
Add it to a GitHub release
In a tag-triggered release job, after your workflow builds the artifacts and uploads them to the GitHub release, add:
permissions:
contents: write # Upload the bundle to the release.
id-token: write # Sign with the workflow's identity.
attestations: write # Attest the matched files.
steps:
# Build the archives and upload them to the release before this step.
- uses: jdx/packslip@v1
with:
artifacts: dist/*.tar.xz dist/*.zip
bin: mytool
The action attests the matched files, signs a release manifest of their
digests, platforms, and executable paths with the workflow's identity,
verifies it, and uploads
packslip.sigstore.json to the release. It does not upload the artifacts.
No long-lived signing key is needed.
This one-job form gives the action contents: write. To keep it away from
release write access,
run it in a separate read-only job.
Publish with GitHub Actions covers
every input, how @v1 and packslip-version select the CLI, and how to
build the CLI on the runner
when packslip publishes no release for it, such as x64 macOS. A project
hosted on its own domain also publishes a signed release list with
jdx/packslip/releases; see
Host releases on your own domain.
Verify a release
packslip signs its own releases. To check one with the
packslip CLI,
download a release's bundle and one of its archives. packslip verify
checks the bundle against the workflow that signs packslip releases, and
the archive against the digest in the bundle. This example checks the
Linux x64 archive of 1.4.0; packslip show packslip.sigstore.json lists
the others:
packslip 1.4.0 and earlier have no --pin flag and reject it as an
unexpected argument; with those versions, leave that line out.
The bundle's project is packslip.dev, a domain rather than a GitHub
repository name, so verify cannot work out the expected signer from it,
and the identity flags are required. --identity-prefix names the
repository that signs packslip releases by its current name. --pin adds
a check on top of the identity flags: its value is that repository's
signer fingerprint, derived from the repository's ID, so a release signed
from a different repository that later takes the name jdx/packslip is
refused. The fingerprint stays the same if the repository is renamed or
moves to another owner, but --identity-prefix would then need the new
URL. See
Pin a signer with its fingerprint.
Agent skill
The packslip skill helps a coding agent configure a release, declare resources, and diagnose verification failures. packslip releases after 1.4.0 declare the skill for their own version, so mise can link the copy that matches your installed CLI into your agent's skills directory:
mise use packslip resolves through the mise registry, which supplies the
signer pin for packslip's own releases, published as project
packslip.dev. The synced links point into your mise installs, so keep
them out of version control. Run the same
mise skills sync --dir .agents/skills command again after changing the
packslip version. To have mise do that after every mise install and
mise use, set
skills.dir
to .agents/skills and turn on
skills.auto_sync.
Without skills.dir, mise links into .claude/skills.
Work on packslip
See CONTRIBUTING.md for setup, checks, and documentation sources, and RELEASING.md for the maintainer release process. Bug reports and format feedback belong in issues.
Developed by Jeff Dickey (@jdx), author of mise, and Shunsuke Suzuki (@suzuki-shunsuke), author of aqua. MIT licensed; see LICENSE.