Parlane

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

FieldTypeDefaultMeaning
versioninteger ≥ 11Protocol schema version. Additive changes don't bump it; only breaking ones do.
namestringhost of the URLDisplay name of the connected app.
iconstring (uri)generated initialsAbsolute https URL to a square icon.
accentstring ^#[0-9a-fA-F]{6}$neutral system accentHex color that tints this app's chrome.
descriptionstring ≤ 500Shown on the connect/consent screen.
surfacesobjectnone advertisedThe 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 (if attachments) image/text/URL uploads.
  • voice{ mode: "ptt" = "ptt", stt: "device" = "device", tts }. v1 is push-to-talk with on-device STT/TTS; mode and stt accept only their v1 values. From v1.1, tts can 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? }. source is 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:

typerequired propsoptional propskind
stackdirection, spacing, aligncontainer
cardtitle, footercontainer
textvaluestyle: title|body|caption|monoleaf
metriclabel, valuedelta, intent: good|bad|neutralleaf
chartkind, serieslabels[]leaf
tablecolumns[], rows[][]maxHeightleaf
listitems[]leaf
imageurlaspectleaf
buttonlabelintent (requires action)leaf
inputlabel, bindvalue, placeholder, keyboardleaf
togglelabel, bindvalueleaf
sliderlabel, bindvalue, min, max, stepleaf
selectlabel, bind, options[]valueleaf
progressvaluelabelleaf
badgevalueintent: good|bad|neutral|infoleaf
dividerleaf
maplat, lngzoom, 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.

Next

REST contract → · Relay self-hosting →