Capability manifests
Capability manifests
Section titled “Capability manifests”The contract between what gets built and what can be designed. A module declares the pipeline components it provides; that declaration travels inside its container image; and Architect’s palette is assembled by reading it back out of the registry.
- Producer: every image-producing module, via
phrame-manifest.json - Carrier: the OCI image label
com.phrame.manifest - Consumer: the Architect backend’s catalog service
The problem it solves
Section titled “The problem it solves”A visual designer needs a palette of components, each with its parameters, its inputs and its outputs. The obvious implementation is a list maintained inside the designer — and it is wrong, because it is a second description of something that already exists. The list and the software drift, and the failure is particularly unpleasant: the designer offers a component that the deployed image cannot provide, or hides one it can, and nothing is detectably broken until somebody tries to run it.
So the description lives with the thing it describes, and travels with it.
How it works
Section titled “How it works”Producer side, per module:
<module>/phrame-manifest.jsondescribes the module’s pipeline components. Each component carries atype, alabel, acategory(input/process/output), an optionalplugin,noteorurlField, and itsparams[],inputs[]andoutputs[].- The Dockerfile copies it to
/phrame/manifest.jsonin the runtime stage, so the running container can be asked what it is. - The Makefile gzips and base64-encodes the same file and attaches it as an OCI
image label:
--label com.phrame.manifest=$(MANIFEST_B64). manifest-lint.sh <image:tag>asserts the label matches the file, guarding against the copied file and the label drifting apart.
Consumer side, in Architect’s catalog service:
- It lists repositories and tags from the registry, and for each tag reads the
com.phrame.manifestlabel out of the image config blob over the Docker Registry v2 API. No layers are pulled and no container is run — reading a capability costs a metadata request, not an image download. - It gunzip- and base64-decodes the label, validates it against the shared schema, and folds the components into a matrix keyed by component type.
- The default provider is scoped to the
phramegroup, so anyphrame/*image carrying the label is discovered with no per-module code change in Architect.
Why the build fails without one
Section titled “Why the build fails without one”capability-images.json at the repository root is the inventory of every image
in the platform, and marks which ones are required to carry a manifest. A
complete build fails if any image marked required lacks a valid manifest.
This is the part that makes the mechanism trustworthy rather than merely convenient. Discovery from a registry is only as good as the guarantee that the thing being discovered is present — without the build gate, a missing manifest would produce an image that simply never appears in the palette, which looks identical to a component nobody has got round to adding yet.
An invalid manifest, by contrast, is skipped silently on the consumer side. That asymmetry is deliberate: the build is the place to be strict, because it is the place where somebody is watching.
Limits worth knowing
Section titled “Limits worth knowing”The parameter model is flat. A param.type is string, number, boolean or
select, and the schema does not admit arrays or nested objects. Three real
capabilities exceed that today and are documented in prose within the manifest
rather than expressed structurally:
output-processor’swebrtc.ice_servers— an array of objectshls-encoder’svariantsABR ladder — an array of objects- the vision-mixers compositor and overlay per-input placement (x, y, z, alpha) — per-connection configuration a flat parameter list cannot express
The consequence is that these can be configured, but not offered as form fields by a designer reading the manifest alone.
