Install & Export (packages)
Turn part of a Busabase space into a git repo anyone can install from a GitHub URL — and install someone else's, review-first, from the dashboard or with busabase-cli.
Install & Export (packages)
A package is a subtree of a Busabase space rendered as plain files in a git repo: a busabase.json manifest plus a content/ tree of real markdown docs, real Base definitions, and records as one JSON object per line. busabase-cli export writes one; the dashboard's Install from GitHub… dialog — or busabase-cli install — pulls one from a GitHub URL into your space. It's how you hand someone a template, a skill, or a whole knowledge base — and because a package is just files, they can read it, diff it, and review it in a pull request before it ever touches a space.
Install is approval-first by default, and it splits the package in two. Structure — folders, Bases, their fields and their views — is created immediately: a pending Base has no id, and without an id there is nowhere to hang a view, a field, or a record. Content — the records, docs, skills and AirApps — lands as a Change Request for you to review; install prints how many are waiting, and busabase-cli change-requests list shows them. So a stranger's repo can lay out empty tables in your space, but nothing anyone wrote into them is live until you've read it and merged it.
Install from the dashboard
You don't need the CLI to install a package. In the sidebar, among the shortcuts next to Activity — above Favorites and the Bases tree — there's an Install from GitHub… entry. It opens a dialog that walks three steps: paste a URL, read what it would create, confirm.
Installing is a space owner/admin action. The server enforces this on both the preview and the install, because a package can carry skills and AirApps — code this space's agents will execute. The sidebar entry is only shown to roles that can use it, so a member never sees a door that is locked; the server-side check remains the authority either way. On a self-hosted single-user server there is no role to check and everyone passes.
Step 1 — the URL
One field, Repository URL, taking the same URLs the CLI takes (https://github.com/owner/repo, optionally /tree/<ref>[/<subdir>]). The only thing checked in your browser is that it isn't blank — everything else is the server's call: it accepts GitHub hosts only, re-resolves the hostname to reject anything pointing at a private or loopback address, and then checks that what it downloaded is really a package. Editing the URL clears the preview below it, so what's on screen is never an answer about a different repo.
Step 2 — the preview
Preview fetches the package and shows you what installing it would do. Your browser never fetches the repo — the server does, and hands back an outline:
- The package's identity — name, description, and whichever of version, author and license its
busabase.jsondeclares — plus the source it actually resolved, asowner/repo at <ref> in <subdir>. - What this would create — the node tree, each row showing its icon, name and slug, with
N fields · N recordson every Base andN fileson every skill, AirApp and drive. Under it, a total: folders · docs · bases · records · files. - Names already taken — every slug that clashes with something you already have, and if renaming is on, the slug each one would be installed under instead.
- Worth knowing — the same warnings the CLI prints (skipped binaries, dropped attachment values, and so on).
Three options sit below the preview:
| Control | Effect | CLI equivalent |
|---|---|---|
| Install into folder | Target folder slug. Pre-filled with the package's own name, slugified. Changing it re-runs the preview, because the target folder decides which slugs collide | --into-folder <name> |
| Install clashing items under new names | Adds a -2, -3 suffix rather than failing. Only appears when there is a collision, and re-runs the preview the moment you tick it | --rename |
| Install immediately, without review | Merges the package's content on the spot instead of leaving change requests. Always shown, off by default | --auto-merge |
There is no way to skip the preview: the Install button doesn't exist until a preview is on screen. Where --dry-run is opt-in on the CLI, in the dashboard it's the only route in.
Install stays disabled while a collision is unresolved, or while a package that requires auto-merge has the box unticked — in that case a red This package can only be installed without review notice explains why and points at the checkbox rather than leaving you at a dead end.
Step 3 — the result
While it runs you get a spinner and "This can take a while — each item is created one at a time." There's no progress bar; items are created one by one.
When it finishes the dialog is replaced by Installed into <folder> and a count of what was created — folders · bases · views · docs · records · files. Then the part that matters:
- If anything is pending, "N change requests are waiting for you", with a Review them now link straight to your Inbox. The package's content is proposed, not live.
- If you ticked Install immediately, without review, "Everything was merged — the package is live in your space."
Done closes the dialog and reloads the dashboard — structure was created immediately, so the tree has changed even when every record is still awaiting review.
If something goes wrong, the dialog shows the server's own message inline rather than a generic failure — "Not a Busabase package — expected busabase.json at …", the refused-host message, the role refusal. That wording is the useful part, so it's shown as-is (these are server messages and aren't translated to match your interface language).
Install from the command line
npx busabase-cli install https://github.com/acme/support-kb-template| Flag | Effect |
|---|---|
--into-folder <name> | Target folder slug (default: the package's manifest name) |
--dry-run | Print the plan (tree, record counts, collisions) and create nothing |
--auto-merge | Merge the package's records and docs on the spot instead of leaving them as change requests — see below |
--rename | Install colliding items under suffixed slugs (-2, -3, …) instead of failing |
Start with --dry-run: it prints the exact node tree, per-Base record counts, and every collision, and creates nothing. Set GITHUB_TOKEN to install from a private repo.
Dashboard or CLI?
Both run the same install — the same package format, the same plan, the same five-pass apply, the same approval-first split. What differs is worth knowing before you pick one:
| Dashboard | busabase-cli install | |
|---|---|---|
| Preview | Always — you cannot install without one | Opt-in, via --dry-run |
| Who downloads the repo | The server | Your own machine |
| Private repos | The server's GITHUB_TOKEN, set by whoever operates the host — not yours | Your own GITHUB_TOKEN |
| Permission needed | Space owner/admin | Ordinary write access — it drives the same per-node endpoints any client uses, so it doesn't pass through the owner/admin install gate |
| Exporting | Not available | busabase-cli export |
The practical consequences: on Busabase Cloud you can't install a private repo from the dashboard unless the operator has configured a token — use the CLI, which uses yours. And exporting has no dashboard equivalent at all; it's a CLI command.
The URL is the version pin
| URL | Installs |
|---|---|
https://github.com/acme/kb | The repo's default branch, as it is right now |
https://github.com/acme/kb/tree/v1.2.0 | The v1.2.0 tag — that tag's content, forever, even after the branch moves on |
https://github.com/acme/packages/tree/v1.2.0/skills/pdf-summarizer | One package out of a repo that hosts many |
Any git ref works — a branch, a tag, or a commit SHA. Use a tag for anything you'll re-install or hand to a teammate: it's the only form that can't change under you.
Export a node as a package
Exporting is CLI-only — there is no dashboard equivalent.
npx busabase-cli export support-kb -o ./support-kb-templateThe node you name becomes the package; its children are what land under content/:
busabase.json
content/getting-started.md
content/cms/_folder.json
content/cms/blog/base.json
content/cms/blog/records.ndjson
content/cms/agent-integrations/base.json
content/pdf-summarizer/_node.json
content/pdf-summarizer/SKILL.mdEvery file is meant to be read by a human: a doc is a real .md with YAML frontmatter, base.json is a Base's fields and views, records.ndjson is one JSON object per line with slug-keyed values, and a skill or AirApp's own files are carried verbatim. Push it and it's installable:
cd ./support-kb-template
git init && git add . && git commit -m "Add support-kb package"
git remote add origin https://github.com/acme/support-kb-template.git && git push -u origin main| Flag | Effect |
|---|---|
-o, --out-dir <dir> | Output directory for the package (required) |
--name <name> | Package name (default: reuse busabase.json, else the node slug) |
--dry-run | List the files that would be written and write nothing |
Output is deterministic: exporting twice from an unchanged space produces byte-identical files, so a GitHub diff shows exactly what changed — one edited record is one changed line. Re-exporting cleans content/ first, so a node you deleted doesn't linger in the repo. Anything you hand-add to busabase.json (version, author, license, tags) is preserved across re-exports.
A package has no slot for node permissions, change history, vault secrets, or webhook rules — you cannot leak what the format cannot express. Attachment values aren't carried either; the attachment field definitions are, and export warns you how many values it dropped.
Skipping review means you trust the author
--auto-merge — and its dashboard twin, Install immediately, without review — waives review and merges the package's records and docs on the spot. Skills and AirApps carry code your agents will run, so only skip review for a repo you've read, or an author you'd hand commit access to.
Limits worth knowing first
- A package whose records carry relation values can only be installed without review. The CLI refuses up front and tells you to re-run with
--auto-merge; the dashboard shows the same verdict as a notice pointing at its checkbox. The reason is the same either way: a relation stores the ids of the records it points at, and those exist only once the records are merged — so a review-first install would give you every relation empty. Only actual values force this; a Base that merely defines a relation field, with nothing linked yet, installs review-first like any other. - Binary files are skipped on hosts that issue a non-absolute upload url — typically a self-hosted server on local-filesystem storage, whose upload url only its own web UI knows how to use. Install warns, names the file, and installs everything else. Hosts backed by S3/R2/MinIO (Cloud included) upload them normally, and text carried inside a skill, AirApp, or drive — markdown, JSON, SVG — is inlined rather than uploaded, so it's unaffected either way.
- The same package can't be installed twice into one space. Base slugs are unique per space and node slugs unique per folder, so the second install fails at plan time listing the colliding slugs.
--rename— Install clashing items under new names in the dashboard — is the escape hatch: it installs them as-2,-3, and rewrites every relation to point at the renamed Base.
Configuration
This applies to busabase-cli only — the dashboard already knows which host and space you're in, and authenticates as you. Same precedence as busabase-cli everywhere else:
| What | Flag | Env var | Saved in |
|---|---|---|---|
| Host | --base-url <url> | BUSABASE_BASE_URL | ~/.busabase/.env |
| API key | --api-key <token> | BUSABASE_API_KEY | ~/.busabase/.env |
| Space | --space-id <id> | BUSABASE_SPACE_ID | ~/.busabase/.env |
See Troubleshooting if install/export can't reach a host or comes back 401/403.
See also: Node Types · Change Requests · Backup & Restore · Troubleshooting