Busabase

Publish a template

Share a starting context another agent can work with — export the resources, write its operating manual, and show how people can ask for the work and check the result.

Publishing a template gives another person's agent a starting context for a job: its business purpose, initial data structures and examples, and your operating manual. The person can install it from a URL, then keep asking their agent to do the work, inspect results in Busabase, review changes, and adapt the workspace through further conversation.

The path is three steps: export it, fill in the manual, list it in a catalog.

Everything below gets you to a correct template — one that installs. It does not get you to one that reads as worth installing: a generated cover image, screenshots that actually show the workflow, no trace of whoever's data you built this from, and prompts specific enough to be worth clicking. Ask a connected agent to use the busabase-template-creator Skill and it will take a folder through that bar and hand back a busabase-cli check you can trust. It builds on busabase-app-creator's format work rather than repeating it, so run that Skill first if the folder doesn't exist yet.


1. Export the folder

npx busabase-cli export busa-email -o ./busa-email --template

Without --template this is the ordinary package export: busabase.json plus a content/ tree. --template adds three things on top.

It lifts the manual to the package root. If the folder contains a Skill node marked as this app's manual, it is written to the package root as SKILL.md (plus references/, agents/, scripts/) rather than under content/ — so a round trip doesn't create the duplicate the format exists to avoid.

It writes a draft if there is no manual yet. A folder with tables but no Skill node gets a SKILL.md generated from the structure that actually exists — the table names, their fields, whether there is an app — with every judgement left as an explicit TODO:

---
name: "busa-email"
description: "An inbox triage desk."
metadata:
  busabase:
    template: true
    resources:
      - "settings"
      - "reviews"
---

# busa-email

TODO: describe the job this app does, and when an agent should reach for it.

## Busabase resources

- `settings`: TODO: what this table is for. Fields: name, payload, vault-refs.
- `reviews`: TODO: what this table is for. Fields: subject, batch-id, item-id.
...

The draft is deterministic, never written by a model. This text becomes instructions an agent will act on, and a plausible-sounding invention about what a table means is worse than an obvious blank to fill in. Every TODO is a decision only you can make — fill them in before publishing.

It reports what's still missing. After exporting it runs the template validator and prints every failure as Not yet a valid template: …, plus the warnings. Export still succeeds — it is telling you what to fix, not refusing to write files.

Slugs come back as you wrote them

If the folder you're exporting was itself installed from a template, its Base slugs carry the install-time folder prefix (busa-email-settings). Export restores the package's original slug (settings) from the ownership stamp, and rewrites relation targets to match.

Without that, export → install → export would not be a fixed point: a package that had been installed once would come back carrying a prefix, and re-installing it would double the prefix or collide.


2. Finish the template

Two edits by hand, both covered in detail in Template format:

SKILL.md — replace the TODOs. Explain the business purpose, what each resource means, and how an agent should carry out recurring tasks, report results, and respond to corrections. State the operating boundaries and what requires user review. Keep instructions consistent with the actual connection permissions.

busabase.json — the export leaves a placeholder "category": "uncategorized". At minimum, set a real category. Then the fields that decide how your card reads:

"template": {
  "category": "email",
  "tags": ["inbox", "triage"],
  "screenshots": ["assets/screenshots/overview.webp"],
  "agentPrompts": [
    "Triage today's inbox and draft replies for the ones that need one."
  ],
  "airapp": "busa-email-app",
  "schemaVersion": 1
}

Write agentPrompts as requests a person will actually give their agent after installation. Include an everyday task and a follow-up that changes or refines the work. For example: “Draft replies for today's inbox for my review,” then “Make the reply to Acme shorter.” Explain what information or connections the task needs.

Screenshots should show what the person inspects: proposed results, the review surface, progress, and history. Together, prompts and visuals should make the ongoing use clear: the agent operates the resources; the person reviews the work and continues the conversation.

Then push it:

cd ./busa-email
git init && git add . && git commit -m "Add busa-email template"
git remote add origin https://github.com/acme/busa-email.git && git push -u origin main

At this point it is installable by URL, and it is already an Agent Skill. Being listed is the next step.

Sanity-check before you publish: install it into a scratch folder in your own space (busabase-cli install <url> --into-folder scratch --dry-run, then for real). The Base-slug prefix means a template can be installed into two different folders of the same space without colliding, so you can test against your own copy.


3. Build the catalog

The Template Center's gallery reads one JSON file, and that file is not hand-maintained — a card that claims "6 tables" for a package that installs five is a trust bug, not a typo. busabase-cli index builds it from a checkout of a repository holding templates:

npx busabase-cli index . --repo acme/templates -o templates.json
FlagEffect
--repo <owner/repo>Required. The repository the entries' subdirs are relative to
--ref <ref>The git ref entries are read at (default main) — the version a card installs
-o, --out <file>Write here (default: print)
--checkExit non-zero if the file on disk isn't what would be written

index is a local command — it reads a directory and needs no host, API key or space. That is what makes it usable as a CI step: run it with --check on every pull request and the catalog can never drift from the repository it describes.

Whether a template is listed is decided by the same validator the installer uses, so a card can never promise something its install does not do. A package that declared itself a template and did not qualify is published in a rejected array with its reasons — the person most likely to read this file is the author of the entry that is missing from it, and "your skill is not in the catalog" without a reason is the least actionable message a build can produce.

{
  "format": "busabase-template-index@1",
  "repo": "acme/templates",
  "ref": "main",
  "templates": [
    {
      "subdir": "busa-email",
      "name": "busa-email",
      "description": "An inbox triage desk.",
      "category": "email",
      "tags": ["inbox", "triage"],
      "screenshots": ["assets/screenshots/overview.webp"],
      "agentPrompts": ["Triage today's inbox …"],
      "version": "1.2.0",
      "license": "MIT",
      "stats": {
        "folders": 1, "docs": 0, "bases": 3, "records": 7,
        "files": 41, "airapps": 1, "skill": true
      }
    }
  ],
  "rejected": [
    {
      "subdir": "half-done",
      "name": "half-done",
      "errors": ["AirApp \"ui\": package.json has no `dev` script. …"]
    }
  ]
}

Entries are sorted by name, so an unchanged repository rebuilds to a byte-identical file — a catalog whose diff is noise stops being reviewed.


By default, Busabase reads templates.json from the busabase/templates repository:

https://raw.githubusercontent.com/busabase/templates/main/templates.json

That is a repository of its own rather than a corner of busabase/skills: the skills repo is cloned to install general-purpose skills, and a single template — an app's whole source, its screenshots, its sample data — is easily most of the tracked bytes. Templates living there would make every skill install pay for every template.

A self-hosted server can point at its own catalog with one environment variable:

BUSABASE_TEMPLATE_CATALOG_URL=https://raw.githubusercontent.com/acme/templates/main/templates.json

The fetch happens server-side: the file is cross-origin, a per-user browser fetch would share no cache, and letting the page name the host would make "which catalog do I trust" a client-side decision. The result is cached for an hour — the catalog changes when someone merges a template, which is rare, and an operator behind a rate limit shouldn't be able to exhaust it by refreshing a page.

Screenshot paths are resolved to URLs against the same repo and ref the card installs from, so a card cannot end up showing one version and installing another. A template's per-locale media (template.locales) is carried into templates.json and resolved the same way, so a viewer in /zh-CN/ sees the zh-CN screenshots and clip when the template ships them and the English ones otherwise. See Localized screenshots and video.


Checklist

  • busabase-cli export <folder> -o <dir> --template runs with no Not yet a valid template: lines
  • Every TODO in SKILL.md is filled in, including what the app must never do
  • template.category is real, not uncategorized
  • At least one screenshot, and at least one agentPrompts entry (busabase-template-creator raises this further: a generated cover as the first screenshot, and enough of the rest to show the actual workflow)
  • Default screenshots / video are the English set; other languages' files are under template.locales, never mixed into the default list
  • More than one demo clip? Use template.videos (at most three), and give each a title
  • Sample rows are a demo, not a dataset (50 per Base max) (busabase-template-creator checks these against the Base's declared schema, not just the row count)
  • Required sample relations are acyclic and every key exists in the relation's target Base
  • Each AirApp has a dev script, and a .busabaseignore that keeps package.json
  • Installed into a scratch folder; asked an agent to do a real task, inspected the result, reviewed its proposed changes, and gave it a follow-up correction
  • busabase-cli index . --repo <owner/repo> --check passes in CI
  • No trace of whoever this was migrated or copied from — in screenshot pixels, not just source text (this is what busabase-template-creator's brand sweep exists to catch)

On this page