Publish a template
Turn a folder you already built into an installable app — busabase-cli export --template, the SKILL.md draft, the catalog index, and how to point a self-hosted server at your own gallery.
You built something in a space: a few tables, an AirApp, some sample rows, and a working routine your agent follows. Publishing it as a template means someone else can install the whole thing from a URL — and their agent will know how to use it, because your manual travels with it.
The path is three steps: export it, fill in the manual, list it in a catalog.
1. Export the folder
npx busabase-cli export busa-email -o ./busa-email --templateWithout --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. State what the app is for, what each table holds, and — explicitly — what an agent must never do with it. An agent follows what is written there.
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
}agentPrompts deserves more thought than it looks like it needs. It is the shortest honest answer to "what would I even ask this thing?" — the question that decides whether an installed app gets used or just sits there.
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 mainAt 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| Flag | Effect |
|---|---|
--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) |
--check | Exit 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.
Where the gallery reads from
By default, Busabase reads templates.json from the busabase/templates repository:
https://raw.githubusercontent.com/busabase/templates/main/templates.jsonThat 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.jsonThe 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.
Checklist
-
busabase-cli export <folder> -o <dir> --templateruns with noNot yet a valid template:lines - Every
TODOinSKILL.mdis filled in, including what the app must never do -
template.categoryis real, notuncategorized - At least one screenshot, and at least one
agentPromptsentry - Sample rows are a demo, not a dataset (50 per Base max)
- Required sample relations are acyclic and every key exists in the relation's target Base
- Each AirApp has a
devscript, and a.busabaseignorethat keepspackage.json - Installed into a scratch folder and opened once, from the change requests up
-
busabase-cli index . --repo <owner/repo> --checkpasses in CI
Related
- Template format — every field, and the validator's rules
- Templates — what installing one does
- Install & Export (packages) — the underlying format and CLI