Manifest (spindle.json)¶
Every extension needs a spindle.json at the repository root.
{
"version": "1.0.0",
"name": "My Extension",
"identifier": "my_extension",
"author": "Your Name",
"github": "https://github.com/you/my-extension",
"homepage": "https://example.com",
"description": "A brief description of what this extension does.",
"permissions": ["generation", "interceptor"],
"entry_backend": "dist/backend.js",
"entry_frontend": "dist/frontend.js",
"minimum_lumiverse_version": "0.1.0"
}
Fields¶
| Field | Required | Description |
|---|---|---|
version |
Yes | Semver version string |
name |
Yes | Human-readable display name |
identifier |
Yes | Unique ID. Lowercase letters, numbers, and underscores only. Must start with a letter. Pattern: /^[a-z][a-z0-9_]*$/ |
author |
Yes | Author name |
github |
Yes | GitHub repository URL |
homepage |
Yes | Extension homepage or docs URL |
description |
No | Short description shown in the Extensions panel |
permissions |
Yes | Array of gated permissions this extension requires (can be []) |
entry_backend |
No | Path to backend entry. Default: "dist/backend.js" |
entry_frontend |
No | Path to frontend entry. Default: "dist/frontend.js" |
minimum_lumiverse_version |
No | Minimum Lumiverse version required |
storage_seed_files |
No | Files/directories to copy into extension storage on install (see below) |
interceptorTimeoutMs |
No | Per-extension override (in milliseconds) for how long the host will wait for this extension's interceptor to return. See Interceptor Timeout below |
Storage Seed Files¶
Seed files let you ship default data (config templates, databases, assets) that get copied into the extension's storage directory on install.
{
"storage_seed_files": [
{ "from": "defaults/config.json", "to": "config.json" },
{ "from": "assets/", "to": "assets/", "overwrite": false },
{ "from": "required-data.db", "required": true }
]
}
| Field | Type | Default | Description |
|---|---|---|---|
from |
string |
required | Source path relative to the extension repo root |
to |
string |
same as from |
Destination path relative to extension storage root |
overwrite |
boolean |
false |
If true, overwrite existing files on update |
required |
boolean |
false |
If true, fail installation when the source file is missing |
Interceptor Timeout¶
Extensions that register a pre-generation interceptor are bound by a wall-clock budget. The host resolves this budget per run, so both the manifest value and the user's Spindle setting take effect on the next generation without requiring the extension to re-register.
Resolution order (highest priority first):
interceptorTimeoutMsin your manifest- The user's
spindleSettings.interceptorTimeoutMssetting (configurable in the Spindle panel) - Default:
10000ms
All values are clamped to [1000, 300000] ms (1 second to 5 minutes).
{
"identifier": "my_retrieval_extension",
"permissions": ["interceptor"],
"interceptorTimeoutMs": 45000
}
Use this when your interceptor performs real work before the LLM call — multi-step retrieval, graph traversal, external API lookups, or controller-driven context assembly — and needs a larger budget than the 10 second default. See Interceptors → Timeout for the full behavior, including what happens when the budget is exceeded.