Skip to content

Manifest reference

Every module declares a module-manifest.json at its root. tv-sdk validate checks it against the Zod schema in @tv/extension-sdk/manifest — that is the authoritative gate, the same one CI and the registry run.

Validate

bash
npx @tv/extension-sdk validate module-manifest.json
# exit 0 valid, 1 invalid, 2 usage error

manifest.schema.json for editor validation

The package also ships manifest.schema.json. From 1.1.0 it is generated in input mode — describing what you are allowed to write — so it agrees with tv-sdk validate and is safe to wire into your editor:

json
"$schema": "./node_modules/@tv/extension-sdk/manifest.schema.json"

On 1.0.x it was emitted in output mode, marking every defaulted field required; it rejected 30 of the 31 modules then shipping, so leave $schema out if you're pinned below 1.1.0.

Gate CI on tv-sdk validate, not on the JSON Schema — the validator is the contract the registry enforces, and the schema is generated from it.

Top-level fields

FieldRequiredDescription
idyes@vendor/module-name — globally unique. Use your own scope, not @tv.
nameyesHuman-readable display name shown in the console
versionyesSemver of your module
minCoreVersionyesMinimum tv-api version, e.g. >=2.0.0
categoryyescore / operations / engagement / infrastructure / analytics / ai
sdkVersionyesSDK version you authored against, e.g. 1.1.0. The platform rejects manifests targeting a newer SDK than it runs.
buildingTypesyes["all"] or specific types like ["mall","office"]
capabilitiesyesprovides + requires — named capability contracts between modules
permissionsyesData domains you read/write (see below)
eventsyespublishes + subscribes arrays
mcpToolsyesCopilot/MCP tools your module contributes. [] if none.
lifecycleyeshealthEndpoint, init, dependencies
descriptionnoOne-liner shown in the catalog
maxCoreVersionnoUpper bound, if you know you break above one
mcpEndpointnoCluster-internal URL the platform calls for your MCP tools
uiwhen you have UIroutes + navigation entries
authornoname, email, url

Defaults exist for capabilities, events, mcpTools, lifecycle, and buildingTypes, so tv-sdk validate accepts a manifest that omits them — but declare them explicitly. It's the difference between "I have no events" and "I forgot to think about events", and a reviewer can't tell those apart.

Permissions

json
"permissions": [
  {
    "subject": "building.spaces",
    "actions": ["read"],
    "reason": "Lists spaces on the module's landing page."
  }
]

reason is optional to the validator and mandatory in practice — it's shown verbatim to the admin approving your install.

The catalog

Subjects and actions come from tv-api's permission registry, shipped with the SDK as permissions.snapshot.json. The full list — every subject, every action, and the roles each action is granted to — is rendered from that same snapshot on the Permission catalog page, so it cannot drift from what the platform enforces. That page also lists the reserved first-party-only prefixes.

Read it from the package directly if you'd rather not leave the terminal:

bash
cat node_modules/@tv/extension-sdk/permissions.snapshot.json | jq '.subjects[].subject'

UI

json
"ui": {
  "remoteEntry": "./Shell",
  "routes": [{ "path": "/cafm", "requiresLicense": true }],
  "navigation": [
    { "label": "CAFM", "icon": "Wrench", "path": "/cafm", "section": "operations", "order": 100 }
  ]
}

routes are where your federated Shell mounts. navigation is what appears in the Building OS sidebar; section is one of operations, engagement, infrastructure, analytics, admin.

remoteEntry must be ./Shell — the shell resolves exactly that name. Enforce it in CI:

bash
npx @tv/extension-sdk check-exposes module-manifest.json --config=./vite.config.ts

Lifecycle

json
"lifecycle": {
  "healthEndpoint": "/health",
  "init": "on_demand",
  "dependencies": []
}

init: "on_demand" lazy-loads your module when its route is first hit; on_boot starts it with the shell. dependencies lists module ids that must reach HEALTHY before yours starts — keep it empty unless you genuinely can't function without another module.

Full example

See the reference module for a complete, validated manifest with mcpTools, mcpEndpoint, heartbeat, and HMAC-signed federation. The module catalog lists every module shipping today.

Stability of the schema

The manifest schema follows the SDK's semver. Breaking changes (new required fields, removed fields) bump the SDK major. Additive fields bump the minor. See the stability policy.

Built on the Tango Vision platform. Questions? developers@tango.vision