surfaces/
Source directories for installable extension surfaces. Each subdirectory
contains a manifest.json plus js/, css/, and optionally assets/
directories — matching the archive format expected by
POST /admin/surfaces/install.
Structure
surfaces/
build.sh ← packages each subdir into dist/<name>.surface
hello-dashboard/ ← sample surface (verifies /s/:slug pipeline)
manifest.json
js/main.js
css/main.css
icd-test-runner/ ← ICD contract test runner (dev/test tool)
manifest.json
js/
css/
Building
# Build all surfaces → dist/*.surface
./surfaces/build.sh
# Build one
./surfaces/build.sh icd-test-runner
Output goes to dist/ (gitignored). Each .surface file is a zip
archive ready for upload via the admin UI or:
curl -X POST https://host/api/v1/admin/surfaces/install \
-H "Authorization: Bearer $TOKEN" \
-F "file=@dist/icd-test-runner.surface"
Adding a surface
- Create
surfaces/<id>/manifest.jsonwith at leastidandtitle - Add
js/,css/,assets/as needed - Run
./surfaces/build.sh <id>to verify it packages - Install via admin UI or API
See EXTENSION-SURFACES.md for the full authoring guide including manifest schema, platform API, and CSS custom properties.
Conventions
idin manifest.json must be unique across all surfaces (core + extension)- Core surfaces (
chat,admin,settings,notes,editor) cannot be overridden — the install endpoint returns 409 - Surface routes are served at
/s/<id>(auto-derived from manifest) - Static assets are served from
/surfaces/<id>/js/,/surfaces/<id>/css/ - The
dist/directory is gitignored — archives are build artifacts