> ## Documentation Index
> Fetch the complete documentation index at: https://filepacks.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# CI/CD Integration

> Use filepacks in CI to preserve generated output as deterministic evidence and compare it against an explicit baseline.

The public OSS CLI is useful in CI when you want generated files to become deterministic, portable evidence instead of a loose job workspace.

## Basic CI pattern

1. Run a job that generates output files
2. Package that directory with `npx filepacks pack`
3. Verify the artifact with `npx filepacks verify`
4. Compare it against a known baseline artifact with `npx filepacks compare`
5. Upload the `.fpk` file as a job artifact for human review if needed

```bash theme={null}
npx filepacks pack ./build-output --output ./candidate.fpk
npx filepacks verify ./candidate.fpk
npx filepacks compare ./baseline.fpk ./candidate.fpk
```

## Why this works well in CI

* the artifact is one file you can upload
* `verify` confirms integrity before downstream use
* `compare` gives deterministic exit codes for “same”, “changed”, and “failed”
* reviewers can inspect the exact same artifact later

## Exit handling

For the current public CLI:

* `verify` exits `0` when the artifact is valid
* `verify` exits `1` when the artifact is invalid
* `compare` exits `0` when the artifacts are identical
* `compare` exits `20` when files differ

That makes it easy to separate “artifact changed” from “command failed”.

## Example: strict GitHub Actions gate

```yaml theme={null}
- name: Install filepacks
  run: npm install -g filepacks

- name: Package output
  run: filepacks pack ./build-output --output ./candidate.fpk

- name: Verify artifact
  run: filepacks verify ./candidate.fpk

- name: Compare against baseline
  run: filepacks compare ./baseline.fpk ./candidate.fpk

- name: Upload artifact for review
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: candidate
    path: candidate.fpk
```

If you want any structural difference to fail the job, this is enough.

## Example: preserve artifact and fail only after capture

If you want to keep the candidate artifact even when the output changed, capture the exit code explicitly:

```yaml theme={null}
- name: Compare against baseline
  id: compare
  shell: bash
  run: |
    set +e
    npx filepacks compare ./baseline.fpk ./candidate.fpk
    status=$?
    set -e

    if [ "$status" -eq 1 ]; then
      exit 1
    fi

    echo "status=$status" >> "$GITHUB_OUTPUT"

- name: Upload candidate artifact
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: candidate
    path: candidate.fpk

- name: Fail when output changed
  if: steps.compare.outputs.status == '20'
  run: exit 1
```

This treats `20` as “review needed” instead of “tool failure”.

## Agent and eval runner workflows

When an AI coding agent or eval runner produces output files, pack the output directory as an artifact immediately after the run:

```bash theme={null}
# Pack agent output after the run completes
npx filepacks pack ./agent-output --output ./run-$(date +%s).fpk

# Or in an eval harness, pack each run by ID
npx filepacks pack ./eval-output --output ./eval-$RUN_ID.fpk

# Compare the new run against the last accepted run
npx filepacks compare ./eval-baseline.fpk ./eval-$RUN_ID.fpk
```

`compare` exits `0` if the output is structurally identical to the baseline and `20` if anything changed. Either exit code is usable in a script or CI job to decide whether to accept the run.

Use `@filepacks/core` directly to build this into an eval harness:

```ts theme={null}
import {pack, compare} from '@filepacks/core'

const run = await pack({input: outputDir, output: `eval-${runId}.fpk`})
const diff = await compare({baseline: 'eval-baseline.fpk', candidate: `eval-${runId}.fpk`})

if (!diff.ok) {
  console.log(`${diff.summary.changed} file(s) changed`)
  // diff.changed[] has per-file details
}
```

## What to preserve

For the current OSS workflow, keep at least:

* `candidate.fpk`
* the baseline artifact used for comparison, if it is not already versioned elsewhere
* the job log that captured the compare summary

## Baseline management

The public OSS surface does not define a baseline registry or tag workflow. In CI, store the baseline artifact explicitly and compare against that file path.

Common approaches:

* commit a known-good `.fpk` to the repository and compare against it on each run
* upload the accepted run's `.fpk` as a named CI artifact and retrieve it in subsequent jobs

## Good fit for CI

filepacks works well when you want:

* reproducible build evidence
* a reviewable snapshot of generated files
* a stable baseline-versus-candidate comparison primitive
* one artifact file that humans and automation can both inspect later
