Skip to content

Settings, dependencies, and compatibility

Settings

A user configures an integration under its id in integrations.installed:

{
"integrations": {
"installed": {
"@acme/noemata-docker": { "metrics": { "per_core_cpu": true } }
}
}
}

The package declares the shape of that value as a JSON Schema file, named by settings in the manifest:

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"additionalProperties": false,
"properties": {
"metrics": {
"type": "object",
"additionalProperties": false,
"properties": {
"per_core_cpu": {
"type": "boolean",
"description": "Collect CPU usage per core. Off by default; scales with cores × containers."
}
}
}
}
}

Noemata validates the user’s entry against the schema on every reconcile and reports violations with the package name and the failing path. The schema is also merged into the project’s generated noemata.json schema, so editors offer completion and inline validation for your settings. contribute() receives the validated value as ctx.settings; apply defaults in code, since Noemata validates but does not fill in default values from the schema.

Field names are snake_case, matching the rest of noemata.json. Every setting should describe what it changes about collection or content rather than encode a volume tier; per_core_cpu says what is collected, high_volume does not. A package with no settings accepts only an empty object.

Settings are not the place for secrets. Credentials belong in the project’s .env file, which an integration reads through process.env at contribute time.

Dependencies

requires in the manifest lists the ids of integrations that must be installed in the same project. An id is a short name for an integration Noemata ships, such as opentelemetry, or a package name for one installed from npm:

{
"noemata": {
"requires": ["opentelemetry", "@acme/noemata-kubernetes"]
}
}

A requirement Noemata ships is enabled together with your package, whether or not the project lists it. A requirement that is itself an npm package has to be installed in the project and listed under installed; list it under peerDependencies too, so the package manager installs it alongside yours and the user only has to add both. When a requirement cannot be found, reconcile reports your package with the id it needs and skips it, and noemata integrations list shows the same reason.

Requirements determine the order in which Noemata calls contribute(): every integration runs after the ones it requires. A cycle is an error. The order matters for two things: store.readFile returns a file with earlier integrations’ edits applied, and ctx.integrations exposes earlier integrations’ probe results.

ctx.integrations describes every integration installed in the project:

contribute(probe, ctx) {
const otel = ctx.integrations.get('opentelemetry');
const kubernetes = ctx.integrations.get('@acme/noemata-kubernetes');
if (kubernetes?.probe.available) {
// add the receiver that reads pod labels
}
return { ... };
}
  • ctx.integrations.ids is the list of installed ids, in contribute order.
  • ctx.integrations.get(id) returns { id, name, version, settings, probe } for an installed integration, or undefined. probe is present for integrations that ran before this one; for the rest it is undefined.

Referencing an integration that is not in requires is allowed, and is how a package adapts to what else is installed without making it mandatory.

Frames follow the same rule. A frame that references @opentelemetry/views/services needs opentelemetry in requires, because a reference to a pack the project does not have fails validation when the pack installs.

Compatibility

compatibility in the manifest is a semver range of Noemata versions, checked against the version noemata --version prints. Declare it as a lower bound: the oldest Noemata whose frame schema and collector configuration your package was tested against.

{
"noemata": {
"compatibility": ">=0.5.0"
}
}

An upper bound is not needed, and blocks users on every Noemata release until you publish again. A Noemata release that breaks what packages rely on is announced through the SDK’s major version, described below, rather than through each package’s range. When the running version is outside the range, reconcile reports the package, its range, and the running version, and skips the package. The rest of the reconcile continues and the stack starts, so one incompatible package does not block a project. noemata integrations list shows the package as incompatible until either side is updated. A package that provides several integrations declares one range for all of them.

The SDK’s major version is the second axis. @noemata/integration-sdk follows semver, and a new major means the manifest, the probe() and contribute() contract, or the helpers changed in a way that existing packages cannot rely on. Declare it as a peer dependency at the major you build against ("^1"); Noemata refuses to load a package whose SDK range excludes the SDK version it carries, and reports the two versions.

Frames are validated when the pack installs, against the block and expression schema of the running version. A frame that uses a block option the running version does not know fails validation, and the reconcile output names the frame and the option. Test a release against the version in your lower bound and against the current Noemata release before publishing.