# Shipping Build Artifacts

Make the build step a real gate on what you actually distribute, build scripts that...

- Repository: https://github.com/kajisho5/ffmpeg-skill (4279 stars)
- Category: Writing
- License: MIT
- Last updated: 2026-10-31
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add kajisho5/ffmpeg-skill --skill shipping-build-artifacts -g -a claude-code -y`
Codex: `npx skills add kajisho5/ffmpeg-skill --skill shipping-build-artifacts -g -a codex -y`
Cursor: `npx skills add kajisho5/ffmpeg-skill --skill shipping-build-artifacts -g -a cursor -y`
Gemini CLI: `npx skills add kajisho5/ffmpeg-skill --skill shipping-build-artifacts -g -a gemini-cli -y`
Claude Code plugin marketplace: `/plugin marketplace add kajisho5/ffmpeg-skill`

## 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.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# 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");
```

The rest: https://github.com/kajisho5/ffmpeg-skill/blob/HEAD/.claude/skills/build-artifacts/SKILL.md
