# 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 |
| `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.
