This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/docs/PACKAGE-FORMAT.md
Jeffrey Smith 7bdc6df6b4
Some checks failed
CI/CD / detect-changes (pull_request) Successful in 20s
CI/CD / test-frontend (pull_request) Successful in 6s
CI/CD / test-sqlite (pull_request) Has been cancelled
CI/CD / build-and-deploy (pull_request) Has been cancelled
CI/CD / test-go-pg (pull_request) Has been cancelled
Feat v0.6.1-v0.6.2: backup/restore, docs surface, dynamic OpenAPI
v0.6.1 — Backup tooling (.swb ZIP export/import), admin backup section,
docs surface with markdown rendering, 5 reference docs, 6 handler tests.

v0.6.2 — Dark mode contrast fixes, topbar nav, 📖 docs icon, dynamic
OpenAPI spec with extension route merging, docs outline sidebar,
scroll/routing fixes; 7 new tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 10:53:24 +00:00

4.5 KiB

Package Format

Switchboard packages are distributed as .pkg files -- ZIP archives with a standard internal structure.

ZIP Structure

my-package.pkg
├── manifest.json        # required -- package metadata
├── js/                  # browser-side JavaScript
│   └── index.js
├── css/                 # stylesheets
│   └── styles.css
├── script.star          # Starlark entry point
├── star/                # additional Starlark modules
├── assets/              # static assets (images, etc.)
└── migrations/          # schema migration files

Only manifest.json is required. All other directories are optional and included only if present in the source.

manifest.json Reference

{
  "id": "my-package",
  "title": "My Package",
  "type": "surface",
  "tier": "browser",
  "version": "1.0.0",
  "description": "What this package does.",
  "icon": "📦",
  "author": "your-name",
  "route": "/s/my-package",
  "auth": "authenticated",
  "permissions": [],
  "api_routes": [],
  "db_tables": {},
  "settings": {},
  "hooks": {},
  "exports": [],
  "schema_version": 1
}

Required Fields

Field Description
id Unique kebab-case identifier
title Human-readable display name
type surface, extension, full, library, workflow
tier browser, starlark, sidecar
version Semver version string

Optional Fields

Field Description
description Short description
icon Emoji for sidebar/menu display
author Package author
route URL path for surfaces (e.g., /s/my-package)
auth authenticated or public
layout Surface layout mode (e.g., single)
permissions Array of required capabilities (db.write, http, notifications, secrets, realtime.publish)
api_routes Array of {"method": "GET", "path": "/items"}
db_tables Table definitions with columns and indexes
settings User-configurable settings with type, label, description, default
hooks Event bus subscription patterns
exports Functions exported by library packages
schema_version Integer for additive schema migrations

Package Lifecycle

  1. Install: Upload a .pkg file via Admin > Packages or POST /api/v1/admin/packages/install. The kernel extracts the archive, creates database tables, and registers routes.

  2. Enable: Activate the package so its routes, hooks, and UI become available. PUT /api/v1/admin/packages/:id/enable.

  3. Disable: Deactivate without removing data. PUT /api/v1/admin/packages/:id/disable.

  4. Update: Upload a new .pkg with a higher semver version. Schema changes must be additive (new columns/tables only). POST /api/v1/admin/packages/:id/update.

  5. Export: Download the installed package as a .pkg archive. GET /api/v1/admin/packages/:id/export.

  6. Delete: Remove the package and its data. DELETE /api/v1/admin/packages/:id.

Bundled vs User-Installed

Bundled packages ship inside the Docker image at /app/bundled-packages. On first boot, a curated default set is auto-installed. Behavior:

  • First boot: curated defaults are installed and enabled.
  • Subsequent boots: already-installed packages are skipped.
  • Admin uninstalls: the package stays uninstalled (never force-reinstalled).
  • Control via BUNDLED_PACKAGES env var: empty = defaults, "*" = all, or comma-separated IDs.

User-installed packages are uploaded through the Admin UI or API. They follow the same lifecycle but are not tied to the Docker image.

Building Packages

Packages are built by zipping the standard directories alongside manifest.json:

# Build all packages in the packages/ directory
cd packages && bash build.sh

# Build a single package
cd packages && bash build.sh my-package

Output goes to dist/my-package.pkg.

Manual Build

cd packages/my-package
zip -r ../../dist/my-package.pkg manifest.json js/ css/ script.star

The build script automatically includes whichever standard directories exist: js/, css/, assets/, script.star, star/, migrations/.

Custom Docker Image

To bundle custom packages into a Docker image:

  1. Place your package in packages/your-package/ with a manifest.json.
  2. Run cd packages && bash build.sh all.
  3. Build the image: docker build -t my-switchboard .

The Dockerfile builds all packages and copies them into the bundled packages directory.