Manifest reference
Served at /.well-known/parlane.json over HTTPS, or returned by the MCP manifest resource parlane://manifest. It declares identity and which surfaces your backend supports.Every field is optional — an empty object {}is a valid manifest, and the client infers unstated surfaces from MCP capability discovery where it can.
Minimal example
{
"name": "House Brain",
"surfaces": {
"chat": { "endpoint": "mcp" }
}
}Top-level fields
| Field | Type | Default | Meaning |
|---|---|---|---|
version | integer ≥ 1 | 1 | Protocol schema version. Additive changes don't bump it; only breaking ones do. |
name | string | host of the URL | Display name of the connected app. |
icon | string (uri) | generated initials | Absolute https URL to a square icon. |
accent | string ^#[0-9a-fA-F]{6}$ | neutral system accent | Hex color that tints this app's chrome. |
description | string ≤ 500 | — | Shown on the connect/consent screen. |
surfaces | object | none advertised | The surface declarations below. |
Surfaces
All surface keys are optional — omit a surface to leave it unadvertised.
- chat —
{ endpoint: "mcp"|"rest" = "mcp", attachments: boolean = false }. Streaming text, markdown, tool-activity, and (ifattachments) image/text/URL uploads. - voice —
{ mode: "ptt" = "ptt", stt: "device" = "device", tts }. v1 is push-to-talk with on-device STT/TTS;modeandsttaccept only their v1 values. From v1.1,ttscan be an object{ mode: "server", endpoint, format? }— the client posts reply text to your endpoint and plays back the returned audio, falling back to device TTS on error or timeout. - dashboards — array of
{ id, title, source, refresh? }.sourceis an MCP resource URI, a REST path, or an absolute URL. - push —
{ relay: boolean = false }. Requires the relay. - shortcuts — array of
{ phrase, tool }, each becomes a Siri/App Intent. - share —
{ accepts: ["url"|"text"|"image", …], tool }.
Full example
Exercises every surface, including the v1.1 server-TTS field.
{
"version": 1,
"name": "Ship's Computer",
"icon": "https://demo.example.com/assets/ships-computer.png",
"accent": "#37E0C8",
"description": "The ship's computer for a fictional smart vessel and hobby lab.",
"surfaces": {
"chat": { "endpoint": "mcp", "attachments": true },
"voice": {
"mode": "ptt",
"stt": "device",
"tts": { "mode": "server", "endpoint": "/tts", "format": "mp3" }
},
"dashboards": [
{
"id": "home",
"title": "Bridge",
"source": "parlane://ui/home",
"refresh": { "mode": "poll", "intervalSeconds": 15 }
},
{ "id": "systems", "title": "Systems", "source": "parlane://ui/systems" }
],
"push": { "relay": true },
"shortcuts": [
{ "phrase": "status report", "tool": "status_summary" }
],
"share": { "accepts": ["url", "text", "image"], "tool": "log_to_research_bay" }
}
}The component catalog (for dashboards)
A dashboard is a UI document: { version: 1, id?, title?, root: Component }. Every component is { type, id?, props?, children?, action? }. The 17 fixed types:
| type | required props | optional props | kind |
|---|---|---|---|
stack | — | direction, spacing, align | container |
card | — | title, footer | container |
text | value | style: title|body|caption|mono | leaf |
metric | label, value | delta, intent: good|bad|neutral | leaf |
chart | kind, series | labels[] | leaf |
table | columns[], rows[][] | maxHeight | leaf |
list | items[] | — | leaf |
image | url | aspect | leaf |
button | label | intent (requires action) | leaf |
input | label, bind | value, placeholder, keyboard | leaf |
toggle | label, bind | value | leaf |
slider | label, bind | value, min, max, step | leaf |
select | label, bind, options[] | value | leaf |
progress | value | label | leaf |
badge | value | intent: good|bad|neutral|info | leaf |
divider | — | — | leaf |
map | lat, lng | zoom, markers[] | leaf |
Limits, stated plainly: max depth 12, max 500 nodes per document, enforced in code (not JSON Schema, which can't cleanly bound recursion). An unknown component type renders as a labeled placeholder rather than crashing — this keeps older clients forward-compatible with future catalog additions. There is no patch format: every update is a full replacement document, diffed by id on the client.