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

# Write a pack

> Scaffold a pack in a packs repository, check and test it, and release it as a tag.

A packs repository holds one pack per directory, so one repository can publish all of your packs. Each pack is released as tags named after its directory, such as `files/v1.0.0`.

## Scaffold the pack

From the repository's root:

```bash theme={null}
graph pack new files
```

graph writes a pack that passes its own checks as written:

```text theme={null}
files/
├── pack.toml
├── README.md
├── CHANGELOG.md
├── MIGRATING.md
├── tools/word_count.yaml
├── plans/count_words.yaml
└── agents/word_counter.yaml
```

When the repository has no `.github/workflows/packs.yaml`, graph also writes one that runs `graph pack test` on every push and pull request.

Replace the sample tool, plan and agent with your own, in the same formats as [tool](/tools/reference/tool-file), [plan](/plans/reference/plan-file) and [agent](/agents/reference/agent-file) files. Then fill in [`pack.toml`](/packs/reference/pack-file), including the systems the pack runs on in `requires.os`:

```toml files/pack.toml theme={null}
version = 1
name = "files"
description = "Count and summarize the files in a directory."

[requires]
graph = ">=0.15"
os = ["macos", "linux"]
binaries = ["sh", "wc", "tr"]
```

## Try an item

`graph pack run` runs one of the pack's items without installing it:

```bash theme={null}
graph pack run tool__word_count --input file=files/README.md --path files
```

```json theme={null}
{
  "words": 321
}
```

## Check and test

```bash theme={null}
graph pack test
```

```text theme={null}
✓ ok
  note: ./files: pack 'files' passes check: 3 items, 0 migration items
    no tests/migrations/v<N>/ sample files to migrate
```

`graph pack test` first runs `graph pack check`, which loads the pack the way an install would and checks every plan and agent against it. Then it runs each major's migration over the sample files in `tests/migrations/v<N>/`. Run at the repository's root, it covers every pack.

## Release

Commit your changes, then create the release tag:

```bash theme={null}
graph pack release major files
```

```text theme={null}
✓ ok
  note: tagged files/v1.0.0 at 293cb16 (major release, the first)
  nothing was pushed; publish it with `git push origin files/v1.0.0`
```

Push the tag to publish the release:

```bash theme={null}
git push origin files/v1.0.0
```

For later releases, `graph pack release` compares every public item's name, input schema and output schema with the previous release, and refuses a bump too small for the changes:

```text theme={null}
✗ a minor release can't carry these changes since files/v1.0.1; they need a major
  problems:
    - tool__word_count: output property 'words' removed (major)
    - tool__word_count: output property 'count' added (minor)
```

A major release also needs a `## v1 to v2` section in `MIGRATING.md` or a migration plan in `plans/migrations/migrate_v2.yaml`. `graph pack update --major` runs that plan over your users' files.

> [!WARNING]
>
> graph refuses to install or update a release whose tag has moved. Never move or delete a pushed release tag; release a new version instead. Protect release tags in your repository's settings so they can't be changed.

## Related guides

> **[Install and update packs](/packs/guides/install-packs)**
>
> Add a pack, keep it current and remove it.

> **[Create a tool in the workbench](/tools/guides/create-in-workbench)**
>
> Draft, test-run and save a tool with the tool drafter.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.