Skip to content

Products & Templates

norsk-ctl is a runner. The thing it runs is a product; you stand one up by turning a product template into an instance. Three nouns, one pipeline:

product → template → instance
(the app) (saved config) (running copy)

Norsk Studio is one such product; Norsk Probe, Norsk Playout, and Norsk Remote Commentary are coming online alongside it, all managed the same way. The guides walk this path end to end with Studio — register the product, launch one of its templates, and you have a running instance.

  • Product — a registered Norsk application (e.g. norsk-studio). A product is a manifest plus one or more default product templates. norsk-ctl knows nothing about a product until you register it with norsk-ctl product add; from then on the daemon can launch it. Think of it as the application.
  • Product template — a configuration of settings for a product, from which instances are launched: the compose services to run, the parameters you can set, and any seed files. A template is versioned to the product that produced it. Think of it as a saved configuration of the app.
  • Instance — a running launch of a product template. norsk-ctl instance launch-template <id> --template <name> turns the saved configuration into containers. Think of it as a running copy; you can have several from the same template.

product add has two modes — same manifest contract, same persistence:

  • --image <image> — the customer path. The daemon runs the product container itself (internal port 4321, host port allocated from 14321), polls GET /manifest.json until it’s ready, then registers it.
  • --dev-url <url> — for product authors iterating on a backend they’re already running locally; norsk-ctl just records the dev URL.

The zero-to-hero guides use the customer path, product add --image ….

On registration the daemon fetches the manifest and imports the product’s default templates. Products persist to ~/.norsk-ctl/products.yaml (separate from config.yaml) and live inside the daemon — the CLI, web UI, and MCP all drive it over HTTP. A product’s own configuration UI is served, iframed, under /products/<name>/ through the proxy.

A product template always bundles the same things:

FileWhat it is
manifest.jsonProduct identity + the runtime-screen URL and proxy exposes
compose.ymlThe instance’s services (for Studio: studio + media)
parameters.yamlValues you supply at launch (e.g. INSTANCE_NAME)
workdir-seed/Files copied into the working directory on first launch

Templates arrive two ways:

  • Default — fetched from the product manifest’s defaultProductTemplates at registration time. Studio ships studio-examples, a ready-to-launch bundle of example workflows. You get a launchable template the moment a product is registered.
  • Built — an operator configures the product through its config screen; the iframe hands the resulting template back and norsk-ctl stores it alongside the defaults. Both kinds appear in norsk-ctl template list and in the dashboard’s Add Instance menu.

The base template compose.yml is deliberately minimal — just images. The runtime concerns are layered on at launch by the runner, not baked into the template, so the same template launches correctly under different hosts and network modes. The runner’s override adds:

  • docker healthchecks for studio and media,
  • the working-directory volume mount (→ /data),
  • the studio command and environment,
  • the license as a docker secret,
  • the network-mode overlay (docker or hybrid) and any sidecars.

The result is a docker-compose project named from the INSTANCE_NAME parameter, with containers <id>-studio-1 and <id>-media-1, proxied at /instance/<id>/. See Architecture for the runtime topology and how requests reach a running instance.

Products and templates answer what you run and how it’s configured to launch. Libraries and plugins answer a different question — what extra components live inside the Studio image’s catalog. Libraries are configured on the Studio template itself (e.g. the STUDIO_LIBRARIES parameter on Studio Dev); plugins live in your working directory. Don’t conflate the saved configuration with what’s on the shelf inside the image.