Build a first-party plugin
A Tilecast plugin is one directory below plugins/. Tilecast discovers its server code, Studio pages, Player runtime, migrations, API description, and public docs from that directory.
Plugins ship with Tilecast. Plugin API v1 does not download or run third-party code.
Pick the part you need
Section titled “Pick the part you need”- Create a plugin starts with
plugins:newand gets a new plugin to a clean conformance check. - Write the manifest explains the fields in
tilecast.plugin.json. - Add server behavior covers Host services, routes, workers, status, removal blockers, and Demo Mode.
- Add Studio pages covers management routes, standalone routes, translations, and secondary navigation.
- Draw on the Player covers manifest projection, surfaces, tiers, CSS, and runtime tests.
- Publish a Data Source or private asset covers
DataSourceProvider,Host.DataSources, andHost.PluginAssets. - Bundle Widgets and Data Sources ships ordinary Widget and declarative Data Source modules inside the plugin directory.
- Add migrations and tests covers the global migration sequence, conformance, PostgreSQL tests, and generated files.
- Offer CLI commands and MCP tools covers
automation.yaml.
For the exact API contract, use the Plugin API v1 engineering reference.
What belongs in a plugin
Section titled “What belongs in a plugin”Directoryplugins/
Directorytransit-alerts/
- tilecast.plugin.json Identity, capabilities, and entry points.
- plugin.go Go entry point.
- plugin_test.go Conformance test.
Directoryserver/ Optional server implementation.
- …
Directorymigrations/ Optional Goose migrations.
- …
- api/openapi.yaml Optional API description.
- automation.yaml Optional automation mapping (Automation Contract v1).
- automation.gen.json Generated from automation.yaml and the API description.
Directorywidgets/ Optional bundled Widgets.
- …
Directorydata-sources/ Optional declarative Data Sources.
- …
Directorystudio/ Optional Studio pages and translations.
- …
Directoryruntime/ Optional Player runtime and styles.
- …
Directorydocs/ Optional public docs pages.
- …
The plugin ID uses underscores. The directory uses hyphens, so transit_alerts lives in plugins/transit-alerts/.
The build owns the few files that list every plugin. Run npm run plugins:generate instead of editing those files by hand.
Automation mapping
Section titled “Automation mapping”A plugin with an HTTP API can offer its operations in the tilecast CLI and the MCP server through automation.yaml (Automation Contract v1). The file maps operation IDs from the plugin’s api/openapi.yaml to a CLI path, an MCP action, and a risk level. It doesn’t redefine any path, schema, authorization, or validation; the server stays authoritative for all of those.
apiVersion: 1
operations: - operationId: listCountdownBarInstances risk: read description: List the configured Countdown Bar instances. cli: path: [countdown-bar, instance, list] mcp: action: list_instances
- operationId: createCountdownBarInstance risk: routine description: Create a Countdown Bar instance from a JSON document. cli: path: [countdown-bar, instance, create] mcp: action: create_instance input: documentOnce the plugin is installed, each mapped operation appears in two places:
- CLI: below
tilecast plugin, at the declared path, such astilecast plugin countdown-bar instance list. Path parameters are positional arguments, query parameters become flags, and an operation withinput: documenttakes its JSON body from--inputor--file. - MCP: as a tool named after the plugin ID and the action, such as
countdown_bar_list_instances. Its input schema comes from the operation’s OpenAPI parameters and request body.
Choose the risk level that matches the operation’s effect: read, routine, sensitive, high-impact, or security-critical. The CLI asks for confirmation at sensitive and above, MCP requires confirm: true for the same levels, and tilecast mcp --read-only offers only read operations. The MCP guide explains what each level means to an operator. A risk level describes the operation; it never replaces the server’s authorization.
List operations that must stay out of automation under exclusions, each with a reason, such as a browser-only security step.
The CLI and MCP server read the resolved mappings from Tilecast Server at run time. Nothing about the plugin is written into the CLI, so no CLI change ships with the plugin. npm run plugins:generate derives parameter and body metadata into the plugin’s generated automation.gen.json, and npm run plugins:check rejects a mapping that doesn’t match the OpenAPI fragment.
The schema lives in @tilecast/plugin-sdk (./automation, plus the portable schema/tilecast-automation.schema.json). Countdown Bar’s automation.yaml is the worked example. For the exact contract, see the programmable control plane reference.
Widgets and plugins
Section titled “Widgets and plugins”A plugin can bundle ordinary Widgets and declarative Data Sources in its own directory. A bundled Widget is the same Widgets V2 module as a core Widget in widgets/; only its owner differs, and tilecast.plugin.json doesn’t change. See Bundle Widgets and Data Sources.
A plugin can also put its data on a screen without its own Widget: publish a Data Source that core Widgets such as List, Table, or Cards can display. Forms works this way.
Use the existing plugins as examples
Section titled “Use the existing plugins as examples”The three bundled plugins cover different parts of the API:
- Countdown Bar is the smallest Player-facing example. It has Studio configuration, a manifest projector, and shared-runtime surfaces.
- Emergency Alerts shows routes, background work, network access, Takeovers, and an emergency Player surface.
- Forms shows a larger workflow plugin with standalone Studio routes, secondary navigation, a Data Source provider, private assets, and PostgreSQL-heavy tests.
Start with the example closest to what you are building. Don’t copy a contribution interface that your plugin does not need.