What to build
Package, Agent Skill, template, or AirApp — the four things you can build for Busabase, how they nest, which one your idea actually is, and what each one costs you to ship.
You have something you want other people to be able to install into their Busabase. Before you can follow a how-to, you have to know which of four things you are building — and they are easy to confuse, because three of them can live in the same directory.
This page is the decision. Once you have made it, every other page here assumes you already did.
They are not four of the same kind of thing
This is worth getting straight first, because it is the reason the list feels longer than it is. Busabase has two separate vocabularies, and these four words come from both of them.
Node types — what lives inside a workspace. There are ten: Folder, Base, Doc, Drive, File, Whiteboard, Workflow, HTML, and the two that matter here — Skill and AirApp.
Shipping formats — how a bundle of nodes travels between workspaces. There are two: package and template.
So "AirApp" and "package" are not alternatives you choose between. An AirApp is a node; a package is the box it arrives in.
Four definitions
Package — a directory that installs into a workspace as a set of nodes. busabase.json at the root, resources under content/. That is the entire format.
Template — a package that also carries a SKILL.md at its root and opts in with one line. It is not a second format: below the root, a template is byte-identical to a plain package. What it adds is a manual, and a different install — that manual lands in the workspace as a Skill node, in the folder beside the resources it describes.
AirApp — a node type. A small web app that opens inside the workspace and reads its live data. It ships inside a package, at content/<name>-app/.
Skill — a node type as well. But a SKILL.md has a second life no other node type has: an agent can read it directly, with npx skills add, and no Busabase workspace anywhere. That double life is the genuinely confusing part — and it is deliberate.
One directory, two readers
busa-email/
├── SKILL.md ← npx skills add reads this and ignores everything below
├── busabase.json ← busabase-cli install reads this and ignores the manual
└── content/
├── reviews/base.json ← installs as a Base node
└── busa-email-app/ ← installs as an AirApp nodeAdd template: true to that SKILL.md and the two readers stop ignoring each other: install now also lands the manual as a Skill node, and the directory appears in the Template Center.
That is what "template" names — a package and an Agent Skill in one directory, with a flag saying you meant it. Not a bigger package, and not a fancier Skill.
Which one is yours?
Start from what you actually have, not from what sounds most complete.
| You have | You want the other person to end up with | Build a |
|---|---|---|
| Tables, fields, some sample rows | Those tables in their workspace | Package |
| A written procedure your agent follows | An agent that knows how to do the job | Agent Skill |
| Both, plus a screen people open | A working app they can install once and use | Template (with an AirApp inside) |
| An interface over data that already exists | A view inside a workspace they already have | AirApp on its own |
The most common mistake is reaching for "template" because it sounds like the finished version. It is not a quality tier — it is a combination. A package of well-modelled tables is a perfectly good thing to publish, and so is a Skill with no data.
If what you have is knowledge rather than data, you are done in one file — a directory with a SKILL.md, no busabase.json, no content/. Busabase's own busabase-app-creator, the Skill that builds everything on this page, is exactly that. Do not wrap a package around it to make it feel more official.
What each one costs you
| You must write | Broken looks like | |
|---|---|---|
| Package | busabase.json, content/<base>/base.json | Install fails, or lands the wrong shape |
| Agent Skill | SKILL.md with valid frontmatter | An agent does the wrong thing confidently |
| Template | Both, plus the template object and the opt-in | Silently absent from the gallery |
| AirApp | A Node project with a dev script | Installs, then never boots |
All four are checked by the same command — see Check before you publish.
The Skill is the one a checker can least help with. It can tell you the frontmatter parses and the files you reference exist; it cannot tell you the manual is true. Everything in SKILL.md becomes instructions an agent acts on, so a plausible-sounding guess about what a table means is worse than an obvious blank. Leave the blank.
Why the opt-in is a line you type
Template-ness is never inferred from the shape of your directory, and that catches almost everyone once: a directory holding a manual, three Bases and a working app installs as a plain package and never appears in the Template Center. It is the single most common "why isn't my thing in the gallery".
The flag is explicit on purpose. Publishing a template means accepting that people will run your code and hand your SKILL.md to their agent — a decision worth making deliberately, rather than by having the right files lying around.
Check before you publish
One command reads the directory, works out which of the four it is, and reports each layer:
npx busabase-cli check .busa-email
package ✓
skill ✓
template ✓ declared, qualifies
airapp ✗ 1 error, 2 warnings busa-email-app
✗ [airapp/runtime-engine-list] Hosting is decided from a hardcoded list of
engine names. Use presence, not membership.
! [airapp/read-budget] readLimit is 100, above the 50-record default page budget.Note the difference between a tick and a dash. A pure Agent Skill reports:
busabase-app-creator
package – no busabase.json
skill ✓ standalone Agent Skill
template – not a package
airapp – not a package– means not applicable, not "passed". Keeping those visually distinct is the point: the usual way an author ends up unprotected is believing a check covered something it never looked at.
Flags
| Flag | Use it when |
|---|---|
--strict | Warnings fail too. Good default for CI on a shared catalog |
--json | Machine-readable findings, for a CI annotation |
--as template | You are building toward a template but have not added the opt-in yet, and want it judged as one now |
--only airapp | You are iterating on the app and do not want the package layers in your way |
Without --only, any layer reporting an error exits 1.
--as exists for the one thing the directory cannot tell the command: intent. Everything else is detected, because the format carries its own declarations — busabase.json makes it a package, a parseable SKILL.md makes it a Skill, and metadata.busabase.template: true makes it a template that gets judged strictly.
The catalog check is separate
check tells you whether one directory is sound. It does not know about your repository's catalog file, so a template repo still runs both:
npx busabase-cli check . --strict
npx busabase-cli index . --repo <owner>/<repo> -o templates.json --checkA directory that declares itself a template and does not qualify shows up in the catalog's rejected list with its reasons. That list is the first place to look when something you added is missing from the gallery.
Passing these is a precondition, never the finish line. Install the package into a scratch space, merge it, and open the app. A package can satisfy every static rule and still be broken at runtime — install reads content/<base>/base.json and never exercises the code path your app provisions from. Only a real install-and-open finds those.
Next
- Building a package → Install & Export covers the format and
export - Building an Agent Skill → Bring Your Own Agent for how agents load one
- Building a template → Template format, then Publish a template
- Building an AirApp → Node types for what it is; ask your agent to run the
busabase-app-creatorSkill to scaffold one - Adding Busabase to your own product instead → Build a Platform Integration
Related
- Templates — what installing one looks like from the other side
- Core concepts — spaces, nodes, and change requests
- Node types — Skill, AirApp, Base, Drive, and the rest
@AI Comments
Revise content in natural language, right from the review thread.
Build an AirApp
Write an interface that opens inside a Busabase workspace — the project layout, Hono plus vanilla browser code, reading the injected runtime instead of the hostname, page budgets, and shipping it through review.