Writing a pack
Author a routine pack by hand or from a folder. Required parts, stages, connectors, files, the validation order and the content scan.
Since 0.6.0.
What it is
A pack is a JSON object with the keys below, in this order. The easiest way to write one is to build the routine as a folder, add a pack.json with its metadata, and export it.
Why it exists
Pack rules are strict so a stranger’s pack is safe to install. Knowing them up front saves a round of FAIL lines.
How it works
Top level
| Key | Required | Notes |
|---|---|---|
$schema |
no | The schema URL |
format |
yes | routineos.pack.v1 |
id |
yes | ^[a-z0-9][a-z0-9-]{0,63}$, equal to routine.routine.name |
version |
yes | semver |
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 | |
inspiration |
no | Up to 10 {source, title, url}, https only |
routine |
yes | routine.toml as data |
prompt, readme |
yes | Text |
definition |
when the workspace is enabled | The Desk definition |
stages |
yes | 1 to 20; see Workflow routines |
connectors |
yes | 0 to 20; see Connectors in packs |
files |
no | Up to 40, {path: text} |
Every object refuses unknown keys.
Files
Paths match ^(lib|skills)/[a-z0-9_-]+(/(?!\.\.?/)[A-Za-z0-9_.-]+)*\.(py|md|json|txt)$, so a . or .. segment is refused. A skill stage needs skills/<name>/SKILL.md with a matching frontmatter name. A code stage’s command is one line starting python3 that names routineos.py or a lib/ file in files.
Validation order
- Size: 512 KiB.
- JSON, with no duplicate keys.
- Unknown keys.
- Types and formats.
- Routine lint, and
first_runabsent orreport-only. - The definition compiles.
- Stages and connectors.
- Files.
- Content scan: secrets, email addresses, Slack-style ids.
- A setting named like a recipient (
recipient,approver,email,address,cc,bcc,channel,phone) defaults to an empty list.
Worked example
To share Hiring Signals, add hiring-signals/pack.json:
{
"format": "routineos.pack.v1", "id": "hiring-signals", "version": "1.0.0",
"title": "Hiring Signals", "summary": "Watches job boards for commerce rebuild roles.",
"category": "sales", "maturity": "piloted",
"stages": [
{"id": "search", "kind": "model", "title": "Search", "does": "Search each market for matching postings."},
{"id": "write", "kind": "code", "title": "Write", "does": "Apply settings and write the Desk.",
"command": "python3 skills/routineos/scripts/routineos.py write --docs snapshot.json --run run.json --out plan"},
{"id": "intro", "kind": "gate", "title": "Intro note", "does": "Hold any intro note for approval."}
],
"connectors": []
}
then routineos.py pack export hiring-signals --out hiring-signals.pack.json and pack validate it. This exact pack.json, on the Hiring Signals folder, exports and prints ok: hiring-signals 1.0.0 is a valid pack.
Common pitfalls
- An approver’s address as a default. Refused; people add addresses on the Desk.
routine,prompt,readme,definitionorfilesinpack.json. They come from their own files: “‘’ belongs in its own file, not pack.json”. - A
lib/file outside the folder or a symlink. Export refuses both.