# How build-skill.sh Creates the `.skill` Bundle for Claude AI: A Complete Breakdown

> Discover how build-skill.sh crafts the .skill bundle for Claude AI. Learn about git archive, state validation, file limits, and SKILL.md integrity.

- Repository: [bradautomates/claude-video](https://github.com/bradautomates/claude-video)
- Tags: internals
- Published: 2026-08-02

---

**[`build-skill.sh`](https://github.com/bradautomates/claude-video/blob/main/build-skill.sh) is a Bash bundler that packages the watch skill into a `.skill` archive for Claude AI using `git archive`, enforces clean git state, validates file count limits, and ensures exactly one [`SKILL.md`](https://github.com/bradautomates/claude-video/blob/main/SKILL.md) exists.**

The [`build-skill.sh`](https://github.com/bradautomates/claude-video/blob/main/build-skill.sh) script in the `bradautomates/claude-video` repository automates the creation of Claude AI-compatible skill bundles. Located at [`skills/watch/scripts/build-skill.sh`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/build-skill.sh), this utility ensures that every `.skill` file meets Claude AI's packaging requirements before upload.

## Locating the Repository Root

The script begins by establishing a reliable working directory. It navigates three levels up from its own location to reach the repository root:

```bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/../../.." && pwd)"

```

Source: [Line 11‑12](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/build-skill.sh#L11-L12)

This path calculation makes the script location-independent. Whether invoked from the repository root or a nested subdirectory, it consistently resolves to the correct project base.

## Enforcing a Clean Git Working Tree

Before generating the `.skill` bundle, the script validates repository cleanliness. It checks both unstaged and staged changes:

```bash
if [ -n "$(git diff --stat)" ] || [ -n "$(git diff --cached --stat)" ]; then
    echo "Error: Working tree has uncommitted changes."
    exit 1
fi

```

Source: [Line 14‑17](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/build-skill.sh#L14-L17)

This safeguard prevents ephemeral or unreviewed code from entering production bundles. Developers must commit or stash changes before proceeding.

## Creating the Output Directory

The script ensures the `dist` folder exists at the repository root:

```bash
mkdir -p "${ROOT_DIR}/dist"

```

Source: [Line 19](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/build-skill.sh#L19)

This directory serves as the destination for the final `.skill` archive. The `-p` flag creates parent directories as needed without error if the directory already exists.

## Archiving the Skill with git archive

The core bundling operation uses `git archive` to create a zip file from the `skills/watch` subtree:

```bash
git archive --format=zip --prefix=watch/ --output="${ROOT_DIR}/dist/watch.skill" HEAD:skills/watch

```

Source: [Line 21](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/build-skill.sh#L21)

Key parameters:

- **`--format=zip`** — Produces a zip archive (Claude AI's required format)
- **`--prefix=watch/`** — Prepends a top-level `watch/` directory inside the archive, matching Claude AI's expected layout
- **`HEAD:skills/watch`** — Archives the committed state of the skill directory, not the working tree

This approach guarantees reproducible builds from version-controlled source rather than arbitrary filesystem state.

## Validating Bundle Constraints

### File Count Limit

Claude AI enforces a hard limit of **200 files per skill**. The script validates compliance:

```bash
FILE_COUNT=$(unzip -l "${ROOT_DIR}/dist/watch.skill" | tail -1 | awk '{print $2}')
if [ "${FILE_COUNT}" -gt 200 ]; then
    echo "Error: Bundle contains ${FILE_COUNT} files (max 200)."
    exit 1
fi

```

Source: [Line 23‑30](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/build-skill.sh#L23-L30)

### SKILL.md Verification

The script ensures exactly one [`SKILL.md`](https://github.com/bradautomates/claude-video/blob/main/SKILL.md) file exists in the bundle:

```bash
SKILL_MD_COUNT=$(unzip -l "${ROOT_DIR}/dist/watch.skill" | grep -c "SKILL.md")
if [ "${SKILL_MD_COUNT}" -ne 1 ]; then
    echo "Error: Bundle must contain exactly one SKILL.md (found ${SKILL_MD_COUNT})."
    exit 1
fi

```

Source: [Line 32‑36](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/build-skill.sh#L32-L36)

[`SKILL.md`](https://github.com/bradautomates/claude-video/blob/main/SKILL.md) serves as the canonical skill contract that Claude AI uses to understand the skill's capabilities, tools, and instructions. Absence or duplication would cause upload failures.

### Bundle Size Reporting

After validation, the script reports the final bundle metrics:

```bash
echo "built ${ROOT_DIR}/dist/watch.skill (${FILE_COUNT} files, $(du -h "${ROOT_DIR}/dist/watch.skill" | cut -f1))"

```

Source: [Line 38‑39](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/build-skill.sh#L38-L39)

## Running the Build Script

Execute the bundler from any directory within the repository:

```bash
bash skills/watch/scripts/build-skill.sh

```

Successful output follows this format:

```

built /path/to/claude-video/dist/watch.skill (42 files, 3.1M)
upload via the claude.ai skill UI

```

Inspect the generated bundle contents with:

```bash
unzip -l dist/watch.skill

```

Expected structure:

```

Archive:  dist/watch.skill
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  01-15-2025 10:30   watch/
     2456  01-15-2025 10:30   watch/SKILL.md
     1843  01-15-2025 10:30   watch/scripts/download.py
     2156  01-15-2025 10:30   watch/scripts/frames.py
     1987  01-15-2025 10:30   watch/scripts/transcribe.py
...

```

## Key Files in the Bundle

| File | Purpose |
|------|---------|
| [`skills/watch/scripts/build-skill.sh`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/build-skill.sh) | The bundling script itself |
| [`skills/watch/SKILL.md`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/SKILL.md) | Claude AI skill definition and metadata |
| [`skills/watch/scripts/download.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/download.py) | Video download runtime |
| [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py) | Frame extraction runtime |
| [`skills/watch/scripts/transcribe.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/transcribe.py) | Audio transcription runtime |

## Summary

- **[`build-skill.sh`](https://github.com/bradautomates/claude-video/blob/main/build-skill.sh)** computes the repository root dynamically to ensure consistent execution from any working directory
- **Clean git enforcement** prevents uncommitted code from entering production bundles
- **`git archive`** creates reproducible, prefix-structured zip files from version-controlled source
- **200-file limit validation** enforces Claude AI's platform constraints
- **Single [`SKILL.md`](https://github.com/bradautomates/claude-video/blob/main/SKILL.md) verification** guarantees valid skill metadata
- The resulting `.skill` file requires no post-processing before Claude AI upload

## Frequently Asked Questions

### What is a `.skill` file?

A `.skill` file is a zip archive containing a Claude AI skill definition. It must include exactly one [`SKILL.md`](https://github.com/bradautomates/claude-video/blob/main/SKILL.md) file at its root plus any runtime scripts or assets. The file extension distinguishes it from generic zip archives in the Claude AI upload interface.

### Why does build-skill.sh use git archive instead of regular zip?

`git archive` guarantees that the bundle contains only committed, version-controlled files. This prevents temporary files, uncommitted experiments, or `.gitignore`d artifacts from polluting the production bundle. It also enables reproducible builds from any commit ref.

### What happens if my skill exceeds 200 files?

The script aborts with an explicit error message. You must reduce the file count by consolidating scripts, excluding non-essential assets, or restructuring the skill. Claude AI enforces this limit strictly during upload validation.

### Can I build the skill with uncommitted changes?

No. The script checks `git diff` and `git diff --cached` and exits with an error if either reports changes. This ensures traceability: every uploaded `.skill` corresponds to a specific git commit.