# Package Format & Manifest Reference > v0.30.2 A `.pkg` file is a ZIP archive containing a `manifest.json` and optional assets. Packages extend Chat Switchboard with surfaces (routable UIs), extensions (server-side hooks/tools), or workflows. ## Archive Structure ``` manifest.json required — package metadata and configuration js/ optional — JavaScript assets (served at /surfaces/:id/js/) main.js entry point (loaded by surface template) css/ optional — stylesheets assets/ optional — images, icons, etc. script.star optional — Starlark script (extension/sidecar tiers) migrations/ optional — Starlark migration scripts (keyed by version) 1.star 2.star ``` ## Building & Installing ```bash # Build from packages/ directory bash packages/build.sh my-package # one package bash packages/build.sh # all packages # Install via API curl -X POST http://localhost:3000/api/v1/admin/packages/install \ -H "Authorization: Bearer $TOKEN" \ -F file=@dist/my-package.pkg # Install via admin UI # Admin → System → Packages → Upload ``` ## Manifest Schema ### Required Fields | Field | Type | Description | |-------|------|-------------| | `id` | `string` | Unique package identifier (kebab-case). Used as directory name and DB key. | | `title` | `string` | Human-readable display name. | ### Optional Fields | Field | Type | Default | Description | |-------|------|---------|-------------| | `type` | `string` | `"surface"` | Package type (see below). | | `version` | `string` | `""` | Semver version string. | | `description` | `string` | `""` | Short description shown in admin UI. | | `author` | `string` | `""` | Author name or org. | | `tier` | `string` | `"browser"` | Execution tier: `browser`, `starlark`, `sidecar`. | | `route` | `string` | — | URL path for surface routing (e.g. `/s/my-surface`). | | `auth` | `string` | `"authenticated"` | Auth requirement: `authenticated` or `public`. | | `layout` | `string` | `"single"` | Page layout template. | | `permissions` | `string[]` | `[]` | Required permissions (see Permissions below). | | `tools` | `object[]` | — | Server-side tool declarations for AI tool-use. | | `hooks` | `string[]` | — | Lifecycle hooks: `surface`, `on_install`, `on_uninstall`. | | `settings` | `object` | — | Settings schema for admin-configurable options. | | `schema_version` | `integer` | `0` | Current data schema version (for migrations). | | `migrations` | `object` | — | Starlark migration scripts keyed by target version. | | `network_access` | `string[]` | — | Allowed external hostnames (sidecar tier). | | `api_routes` | `object[]` | — | Custom HTTP routes handled by Starlark `on_request`. | | `db_tables` | `object[]` | — | Extension-owned database tables. | | `pipes` | `object` | — | Filter pipeline registrations. | | `components` | `string[]` | — | UI component identifiers. | | `workflow_definition` | `object` | — | Embedded workflow definition (type `"workflow"` only). | ## Package Types ### `surface` (default) A routable page served at the `route` path. The browser loads `js/main.js` and renders into `#extension-mount`. ```json { "id": "my-dashboard", "title": "My Dashboard", "type": "surface", "route": "/s/my-dashboard", "auth": "authenticated", "layout": "single", "version": "1.0.0" } ``` ### `extension` Server-side logic without a routable UI. Runs Starlark code with granted permissions. ```json { "id": "auto-tagger", "title": "Auto Tagger", "type": "extension", "tier": "starlark", "version": "1.0.0", "permissions": ["filters.pre_completion"], "tools": [ { "name": "tag_message", "description": "Auto-tag messages based on content" } ] } ``` ### `full` Both a surface and an extension. Has a routable page and server-side hooks/tools. ```json { "id": "analytics", "title": "Analytics Suite", "type": "full", "tier": "starlark", "route": "/s/analytics", "version": "1.0.0", "permissions": ["db.read", "db.write"], "db_tables": [ { "name": "events", "columns": { "ts": "text", "event": "text", "data": "text" } } ] } ``` ### `workflow` A packaged workflow definition with optional surfaces and handlers. See [WORKFLOW-PACKAGES.md](WORKFLOW-PACKAGES.md) for details. ```json { "id": "onboarding-flow", "title": "Employee Onboarding", "type": "workflow", "version": "1.0.0", "workflow_definition": { "name": "Employee Onboarding", "slug": "employee-onboarding", "entry_mode": "public_link", "stages": [...] } } ``` ## Permissions Declared in `manifest.permissions`. Admins grant/revoke per-package in the admin UI. | Permission | Description | |-----------|-------------| | `secrets.read` | Read secrets from the vault | | `notifications.send` | Send push notifications | | `filters.pre_completion` | Intercept messages before AI completion | | `db.read` | Read from extension-owned tables | | `db.write` | Write to extension-owned tables | | `api.http` | Make outbound HTTP requests (sidecar tier) | | `provider.complete` | Call LLM completion APIs | | `forms.validate` | Validate workflow form submissions | | `workflow.access` | Access workflow definitions and stage data | ## Settings Schema Packages can declare admin-configurable settings. The schema drives a form in the admin UI under System → Packages → Settings. ```json { "settings": { "api_key": { "type": "string", "label": "API Key", "description": "External service API key", "required": true }, "max_results": { "type": "number", "label": "Max Results", "default": 10 }, "enabled": { "type": "boolean", "label": "Enable Feature", "default": true } } } ``` Settings are stored in the `package_settings` column and accessible from Starlark via `settings.get("key")`. ## Data Migrations Packages with `db_tables` can version their schema using Starlark migration scripts. The engine runs migrations sequentially on install/upgrade and rejects downgrades. ```json { "schema_version": 2, "migrations": { "1": "def migrate(db):\n db.query('CREATE TABLE ...')\n", "2": "def migrate(db):\n db.query('ALTER TABLE ...')\n" } } ``` Or reference files in the archive: ``` migrations/ 1.star # def migrate(db): ... 2.star # def migrate(db): ... ``` ## Extension Database Tables Tables are namespaced to `ext_{pkg_id}_{table}` to prevent collisions. Platform views provide read-only access to core data: | View | Columns | |------|---------| | `ext_view_users` | `id`, `display_name`, `email` | | `ext_view_channels` | `id`, `title`, `type`, `team_id` | The `ext_data_tables` catalog tracks all extension-owned tables for install/uninstall lifecycle management. ## Server-Side Tools Extensions can declare tools for AI tool-use. The `on_tool_call` entry point in the Starlark script handles dispatching. ```json { "tools": [ { "name": "lookup_customer", "description": "Look up customer by email", "parameters": { "email": { "type": "string", "required": true } } } ] } ``` ```python # script.star def on_tool_call(tool_name, params): if tool_name == "lookup_customer": result = http.get("https://api.example.com/customers?email=" + params["email"]) return {"name": result["name"], "plan": result["plan"]} ``` ## User-Installable Packages Packages can be scoped to individual users or teams (v0.30.0). Only `browser`-tier packages support user installation. Scope options: | Scope | Visibility | |-------|-----------| | `global` | All users (admin-installed only) | | `team` | Team members only | | `personal` | Installing user only |