Skip to content
RoutineOS
Esc
↑↓navigate↵open⌘Jpreview
On this page

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

  1. Size: 512 KiB.
  2. JSON, with no duplicate keys.
  3. Unknown keys.
  4. Types and formats.
  5. Routine lint, and first_run absent or report-only.
  6. The definition compiles.
  7. Stages and connectors.
  8. Files.
  9. Content scan: secrets, email addresses, Slack-style ids.
  10. 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, definition or files in pack.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.

Was this page helpful?