Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
7.7 KiB
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
# 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.
{
"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.
{
"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.
{
"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 for details.
{
"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.
{
"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.
{
"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.
{
"tools": [
{
"name": "lookup_customer",
"description": "Look up customer by email",
"parameters": {
"email": { "type": "string", "required": true }
}
}
]
}
# 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 |