---
title: Pack schema
description: Every key in a routineos.pack.v1 pack file and a routineos.catalog.v1 index, with patterns, limits and the jobs-watch pack as the example. Taken from site/templates/schema/.
sidebar:
  order: 6
---

> Since 0.6.0. The schemas are at `site/templates/schema/pack.v1.schema.json` and `catalog.v1.schema.json`.

A pack is one JSON file holding a whole routine: its `routine.toml` as data, its prompt, readme, definition, stages and connectors. A catalog is an index of packs. For the authoring walkthrough, see [Writing a pack](/templates/writing-a-pack). Both schemas are JSON Schema draft 2020-12 and set `additionalProperties: false`, so an unknown key is an error (unlike `routine.toml`, where lint ignores unknown keys).

## Top level

| Key | Required | Rule |
|---|---|---|
| `$schema` | no | Text |
| `format` | yes | `routineos.pack.v1` |
| `id` | yes | `^[a-z0-9][a-z0-9-]{0,63}$` |
| `version` | yes | `MAJOR.MINOR.PATCH`, no leading zeros |
| `title` | yes | At most 80 characters |
| `summary` | yes | At most 280 characters |
| `category` | yes | `sales`, `marketing`, `ops`, `support`, `finance`, `recruiting`, `content`, `dev`, `general` |
| `maturity` | yes | `piloted` or `unpiloted` |
| `license` | no | At most 64 characters |
| `inspiration` | no | Up to 10 entries, see below |
| `routine` | yes | See [routine](#routine) |
| `prompt` | yes | Text, the routine's `prompt.md` |
| `readme` | yes | Text, the routine's `README.md` |
| `definition` | no | The Desk definition, see [definition](#definition) |
| `stages` | yes | 1 to 20 stages |
| `connectors` | yes | 0 to 20 connectors |
| `files` | no | Extra files, see [files](#files) |

## routine

`routine.toml` as JSON.

| Key | Rule |
|---|---|
| `routine` | `{name, type, schedule, first_run}`. `type` is a routine type. `first_run` must be `report-only` |
| `store` | `{adapter}` |
| `workspace` | `{enabled, name, template, template_version}` |
| `setting` | List of settings, each requiring `name`, `type` and `default` |
| `gate` | `{enabled, transport, timeout_hours}` |
| `action` | List of `{name, kind}` |

A pack can never ship a routine that runs live on its first run.

## definition

The same shape as `definition.json` (see [Definition schema](/reference/definition-schema)). `version` and `types` are required; the learning keys are allowed.

## stage

| Key | Required | Rule |
|---|---|---|
| `id` | yes | `^[a-z0-9][a-z0-9-]{0,63}$` |
| `kind` | yes | `code`, `model`, `skill` or `gate` |
| `title` | yes | 1 to 80 characters |
| `does` | yes | 1 to 500 characters |
| `connectors` | no | Up to 20 connector ids |
| `reads`, `writes` | no | Up to 20 store paths each, `^[a-z0-9][a-z0-9_-]*(/[a-z0-9_-]+)*$` |
| `command` | no | `^python3 [^\n]+$`, one line |
| `skill` | no | A skill name |

See [Workflow routines](/routine-kinds/workflow) and [Stages](/concepts/stages).

## connector

| Key | Required | Rule |
|---|---|---|
| `id` | yes | Slug |
| `label` | yes | Shown in the install report |
| `kind` | yes | `connector`, `mcp`, `builtin` or `http` |
| `purpose` | yes | Why the routine needs it |
| `required` | yes | bool |
| `access` | yes | `read` or `write` |
| `stages` | yes | Stage ids that use it |
| `connect` | yes | How a person connects it |
| `alternatives` | no | Other options, by name |

See [Connectors in packs](/templates/connectors).

## inspiration

Each entry is `{source, title, url}`; `url` must start `https://`. It credits the public workflow or post a pack was modelled on.

## files

An object of at most 40 entries. Each key is a path matching `^(lib|skills)/[a-z0-9_-]+(/(?!\.\.?/)[A-Za-z0-9_.-]+)*\.(py|md|json|txt)$` (a `.` or `..` segment is refused) and each value is the file's text. Only `.py`, `.md`, `.json` and `.txt` files under `lib/` or `skills/` travel in a pack.

## Example: jobs-watch

The source `templates/jobs-watch/pack.json` holds the metadata; `pack export` adds `routine`, `prompt`, `readme` and `definition` from the folder.

```json
{
  "format": "routineos.pack.v1",
  "id": "jobs-watch",
  "version": "1.0.0",
  "title": "Jobs watch",
  "category": "sales",
  "maturity": "piloted",
  "license": "MIT",
  "stages": [
    {"id": "search", "kind": "model", "title": "Search postings", "connectors": ["web-search", "web"]},
    {"id": "record", "kind": "model", "title": "Record roles and companies"},
    {"id": "learn", "kind": "code", "title": "Learn",
     "command": "python3 skills/routineos/scripts/routineos.py learn --docs snapshot.json --run run.json --out learn"},
    {"id": "write", "kind": "code", "title": "Write",
     "command": "python3 skills/routineos/scripts/routineos.py write --docs snapshot.json --run run.json --out batches"},
    {"id": "approve", "kind": "gate", "title": "Approve an intro note", "connectors": ["mail"]}
  ],
  "connectors": [
    {"id": "web-search", "label": "Web search", "kind": "builtin", "required": true, "access": "read", "stages": ["search"]},
    {"id": "web", "label": "Web fetch", "kind": "builtin", "required": true, "access": "read", "stages": ["search"]},
    {"id": "mail", "label": "Mail", "kind": "connector", "required": false, "access": "write",
     "stages": ["approve"], "alternatives": ["Slack"]}
  ]
}
```

`summary`, each stage's `does` and each connector's `purpose` and `connect` are left out above for width. The write stage also declares `writes: ["runs", "entities", "inbox", "pending"]`. The schema checks only the shape of these names.

## Catalog

`routineos.catalog.v1` is `{format, templates}`. Each entry in `templates` requires:

| Key | Rule |
|---|---|
| `id`, `version`, `title`, `summary`, `category`, `maturity` | As in the pack (title and summary at least 1 character) |
| `type`, `schedule` | From the pack's routine |
| `path` | The pack file, relative to the index |
| `bytes`, `sha256` | Size and hash of the pack file |
| `connectors`, `inspiration` | From the pack |

`pack catalog` writes the index; `pack catalog --check` exits 1 when it would change. See [Catalog](/templates/catalog).

## Common pitfalls

- **`first_run = "live"` in the routine.** Refused by the schema.
- **An unknown key.** Every object is closed; a typo fails validation.
- **A file outside `lib/` or `skills/`, or a `.sh` file.** Not allowed in `files`.
- **A multi-line `command`.** The pattern allows one `python3` line only.

## Related

- [Writing a pack](/templates/writing-a-pack)
- [Install](/templates/install)
- [Export](/templates/export)
- [CLI reference: pack](/reference/cli#pack)
