shipping-build-artifacts
This skill helps catch broken or stale artifacts in build and release workflows by identifying common packaging failures: missing files shipped silently, size…
Community author
- Agents
- Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode, claude.ai and API
- License
- MIT (permissive)
- Pin
- 008333apinned Oct 9, 2026
- Context cost
- about 1,900 tokenswhen the skill loads
- GitHub stars
- 1,897on kajisho5/ffmpeg-skill
- Scripts
- None found
What it does
“Make the build step a real gate on what you actually distribute — build scripts that warn and exit 0 on a missing input, size checks with only an upper bound, hand-maintained file lists that drift from the entrypoints they must cover, committed bundles that go stale when only the source changes, GNU-only shell in release scripts that aborts on the other OS, and verification that runs against the source tree instead of the artifact. Use when writing or reviewing a build/package script, a `dist/` copy step, a release workflow that uploads a zip or installer, or a committed compiled asset.”
Generated summary from the skill's own text
This skill helps catch broken or stale artifacts in build and release workflows by identifying common packaging failures: missing files shipped silently, size checks that only detect overgrowth not underbuild, hand-maintained file lists that drift from actual dependencies, committed bundles that go stale, cross-OS script incompatibilities, and verification running against source instead of artifacts.
When to use it
- Writing or reviewing build scripts that copy files to dist directories
- Creating or updating release workflows that upload archives or installers
- Working with committed compiled assets or bundles in repositories
- Implementing artifact verification before publishing to registries
When not to
- Projects that only distribute source code without build steps
- When verification against source tree is sufficient for your use case
Install
These commands install from the publisher's repository and need no account.
skills CLI
npx skills add kajisho5/ffmpeg-skill --skill shipping-build-artifactsInstalls from the repository's default branch, which may have changed since the commit we checked.
GitHub CLI 2.90 or later
gh skill install kajisho5/ffmpeg-skill shipping-build-artifacts@008333aaf6722083392eb6bd8bd67b59884a2a26Installs the commit we checked (008333a).
Copy by hand
Download the folder at 008333a and put it in .claude/skills/shipping-build-artifacts for Claude Code and in .agents/skills/shipping-build-artifacts for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode.
Copy for your agent
A prompt for any coding agent. It installs this skill from GitHub at the pinned commit, copies the files as they are, and runs nothing unless you ask.
Prompt
Install the agent skill "shipping-build-artifacts" by kajisho5. Source, pinned to commit 008333aaf6722083392eb6bd8bd67b59884a2a26: https://github.com/kajisho5/ffmpeg-skill/tree/008333aaf6722083392eb6bd8bd67b59884a2a26/.claude/skills/build-artifacts 1. Download that folder at exactly this commit. Do not use the default branch. 2. Copy every file unchanged, keeping the folder structure, into .claude/skills/shipping-build-artifacts/ for Claude Code and .agents/skills/shipping-build-artifacts/ for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode. Create the folders if they do not exist. 3. Do not edit the files, and do not run any script in the folder unless I ask you to. 4. When you are done, list the files you copied and where you put them. Listing and checks: https://www.agentnative.dev/skills/kajisho5/shipping-build-artifacts
SKILL.md at the pin
---
name: shipping-build-artifacts
description: Make the build step a real gate on what you actually distribute — build scripts that warn and exit 0 on a missing input, size checks with only an upper bound, hand-maintained file lists that drift from the entrypoints they must cover, committed bundles that go stale when only the source changes, GNU-only shell in release scripts that aborts on the other OS, and verification that runs against the source tree instead of the artifact. Use when writing or reviewing a build/package script, a `dist/` copy step, a release workflow that uploads a zip or installer, or a committed compiled asset.
---
# Shipping Build Artifacts
Lint, type-check, and tests run against the source tree. What users install is a
*different* set of bytes — assembled by a script that most gates never look at,
then uploaded by a workflow that trusts whatever the script left behind. Every
failure below ships a broken or stale artifact under fully green CI.
## A script that warns and exits 0 is not a gate
The shape is universal: a declared list of inputs, a copy loop, a friendly
warning when one is missing.
```js
for (const f of DIST_FILES) {
if (!fs.existsSync(f)) {
console.warn(`Warning: ${f} not found, skipping`); // build "succeeds"
continue;
}
fs.copyFileSync(f, path.join("dist", f));
}
```
Move one required file aside and the script prints a line nobody reads, exits 0,
and produces a `dist/` without it. Nothing downstream notices: the test job ran
against the source tree, and the release job zips `dist/` and attaches it to a
public release. The artifact is wholly non-functional — the entrypoint imports a
file that isn't there — and the failure is discovered by users.
```js
const missing = DIST_FILES.filter((f) => !fs.existsSync(f));
if (missing.length) {
console.error(`Missing build inputs: ${missing.join(", ")}`);
process.exit(1);
}
```
The rule: inside a build script, `warn` may only describe something the artifact
survives without. If you cannot say what still works when that file is absent, it
is an error and the process must exit non-zero.
## Bound the artifact size on *both* sides
A packaging check with only a ceiling — "fail if the zip exceeds 500 KB" — is a
cost guard, not a correctness one. A build that silently dropped half its files
is *smaller*, so it passes the only check that exists.
```js
assert(bytes < 500 * 1024, "package too large");
assert(bytes > 20 * 1024, "package suspiciously small — inputs likely missing");
assert(entries.length === DIST_FILES.length, "package entry count mismatch");
```
Better still, assert on contents rather than a proxy: list the archive's entries
and compare against the set the entrypoints require.
## Derive the file list, or check it against the entrypoints
`DIST_FILES` — like a build backend's `only-include`, or a hand-written
`package_data` — is a *second* copy of "what this app is made of." The first copy
is the manifest, the entry HTML, and the import graph. They drift in one
direction: someone adds `utils.js`, references it from the popup, and forgets the
copy list. The build stays green and the feature is dead in the packaged app.
Either derive the list (bundle from the real entrypoints), or add a check that
every path referenced by the manifest and by `<script src>` / `importScripts`
exists in `dist/` after the build. A hand-maintained allowlist with no such check
is a bug scheduled for a future commit.
The same rule covers any place dependency or asset metadata is restated by hand —
a standalone launcher script whose inline dependency header duplicates the
project manifest's `dependencies`, for instance. If duplication is unavoidable,
add a test that normalizes both lists and compares them, so drift fails in CI
instead of at a user's install.
## Committed build outputs go stale silently
When a compiled or minified bundle is committed and served directly, *the bundle
is the program* and its source is a comment until someone rebuilds. Editing only
the source ships nothing; the page keeps serving the previous bundle, and no test
or linter says a word.
- Rebuild in CI and `diff` against the committed output; fail on drift.
- Pin the builder to an exact version — the diff is only meaningful if the output
is byte-deterministic.
- Confirm that determinism once across the environments people actually use
(native toolchain vs. container image), so the check is runnable locally too.
```bash
npx -y esbuild@0.24.2 src/app.jsx --jsx=transform --minify --outfile=/tmp/app.js
diff /tmp/app.js web/app.js
```
Rebuild and commit the output in the **same commit** as the source change. A
"rebuild bundles" follow-up commit means every commit in between shipped code
that does not match its source.
## Release scripts run on an OS you didn't write them on
Build scripts are written on a developer machine and executed on the runner.
GNU-only tooling is the usual break, and `set -e` turns it into a total abort on
a line that merely reads a version number:
```bash
# Breaks under BSD grep (macOS): -P / lookbehind are GNU extensions.
VERSION=$(grep -Po '(?<=^version = ")[^"]+' pyproject.toml)
```
Read structured metadata with a parser instead of a regex, and prefer a runtime
you already depend on:
```bash
VERSION=$(python -c 'import tomllib;print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')
VERSION=$(jq -r .version package.json)
```
Then pin it with a test: the version the build script extracts must equal the
version declared in the project manifest. Without that, the failure mode is a
release tagged `v1.4.0` whose artifact reports `1.3.2`, and nothing in the
pipeline disagrees.
## Verify the artifact, then publish — in that order, in that job
Attaching a file to a public release, pushing a tag, or uploading to a registry
are the least reversible steps in the project. The verification must sit between
the build and the upload, in the same job. A separate green "test" job proves
nothing about the artifact: it ran against the source tree.
Minimum ordering:
1. Build.
2. List every entry in the artifact and assert the entrypoints are present.
3. Install or load it **from a directory the source tree is not on the load path
of**, and exercise one real symbol or command — not merely that a top-level
name resolves.
4. Only then upload.
Step 3 is the one that gets skipped, and it is the only step that distinguishes
"the archive has files in it" from "the thing runs." Run it somewhere else on
disk, or it passes against the sources and proves nothing.
## Checklist
```
Build script:
- [ ] Missing declared input → non-zero exit, not a warning
- [ ] Size assertions have a floor as well as a ceiling
- [ ] File list is derived, or checked against manifest/entry-HTML references
- [ ] Duplicated dependency metadata has a drift test
- [ ] No GNU-only flags (grep -P, sed -i'' semantics) in scripts CI also runs
- [ ] Version extracted with a parser, and asserted equal to the declared version
Committed build outputs:
- [ ] CI rebuilds and diffs; drift fails
- [ ] Builder pinned to an exact version; output confirmed deterministic
- [ ] Output committed alongside the source change, not in a follow-up
Release:
- [ ] Artifact contents listed and asserted before upload
- [ ] Artifact installed/loaded from outside the repo and exercised
- [ ] Verification runs in the same job as the upload, before it
```
## Note for this repository (ffmpeg-skill)
`package.json`'s `"files"` list is the equivalent of `DIST_FILES` here — it must
list exactly what ships (`bin/`, `scripts/`, `mcp/`, `references/`, `SKILL.md`,
`README.md`, `LICENSE`), and `.claude/` (this file included) must NEVER appear
in it. `npm publish --dry-run` is the "list every entry and assert the
entrypoints are present" step (step 2 above) — run it before every publish, and
watch for stray `__pycache__`/`.pyc` files sneaking into the tarball from a
local test run (this actually happened once this session and was caught by
exactly this check). There is no separate "install from outside the repo and
exercise a symbol" step in this repo's release process today (`node
bin/install.js --dir /tmp/skills` from README's Development section is the
closest equivalent) — worth doing before a real publish, not just a dry-run.
Source: [wdm0006/python-skills](https://github.com/wdm0006/python-skills) (MIT).
From kajisho5/ffmpeg-skill at 008333a, shown as plain text under its license: MIT (permissive). The license text is in LICENSE.
View SKILL.md on GitHub at 008333aFiles
- SKILL.md8.4 KB · 1892c6f51a87
1 file, 8.4 KB in total. Each file has a sha256 in the pin's manifest; the first 12 characters are shown.
Skill folder on GitHub at 008333aRelated in Cloud and DevOps
n8n-cli
This skill enables agents to manage n8n workflows, credentials, executions, and instance resources via the n8n CLI command-line tool.
by n8nOfficial publisher
Claude Code, Codex, Cursor +4 · about 2.9K tokens · pinned 6 days ago
managing-streamlit-apps
Manage Streamlit apps running in PostHog sandboxes through the full lifecycle: create, set or edit source code, start and stop the sandbox, poll status, and…
by PostHogOfficial publisher
Claude Code, Codex, Cursor +4 · about 1.4K tokens · pinned 6 days ago
release-candidate-prep
Prepares a local Python SDK release candidate in a dedicated Git worktree when explicitly invoked with a version number.
by OpenAIOfficial publisher
Contains scripts
Claude Code, Codex, Cursor +3 · about 4.8K tokens · pinned 6 days ago
cloud-run-basics
Deploys and manages Google Cloud Run services, jobs, and worker pools for running containerized applications or source code.
by GoogleOfficial publisher
Claude Code, Codex, Cursor +4 · about 3.9K tokens · pinned 6 days ago
debug-openshell-cluster
Diagnoses OpenShell gateway deployment problems across Docker, Podman, Kubernetes, and VM compute platforms.
by NVIDIAOfficial publisher
Claude Code, Codex, Cursor +4 · about 19.1K tokens · pinned 6 days ago
hf-cloud-aws-context-discovery
This skill reads the user's local AWS configuration to discover their active profile, region, account ID, and caller identity before any AWS work begins.
by Hugging FaceOfficial publisher
Claude Code, Codex, Cursor +4 · about 830 tokens · pinned 6 days ago