# Package Format Armature 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 ```json { "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 | | `capabilities` | Environment requirements: `{"required": [...], "optional": [...]}` | | `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`: ```bash # 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 ```bash 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-armature .` The Dockerfile builds all packages and copies them into the bundled packages directory.