configuration
v0.16.1Configuration worker for the iii engine.
full markdown
/workers/configuration.md?version=0.16.1. paste it into an llm prompt or pipe it through curl from a worker.install
configuration
- adapter:
config:
directory: ./data/configuration
name: fs
ttl_seconds: 0dependencies
readme
configuration
Schema-validated, reactive registry of named configuration entries. Workers register their configuration ids with a JSON Schema, publish values that are validated against it, and emit configuration triggers on every change so other workers react without polling.
The default fs adapter stores one YAML file per id under a configurable directory and watches it for external edits — manual edits surface as configuration:updated events the same way SDK calls do. The bridge adapter delegates to a remote III Engine and re-broadcasts its events into the local fan-out. Reads expand ${VAR:default} placeholders against the live process env on every call, so env changes propagate without a worker restart.
Sample Configuration
- name: configuration
config:
adapter:
name: fs
config:
directory: ./data/configuration
ttl_seconds: 0Configuration
| Field | Type | Description |
|---|---|---|
adapter |
Adapter | Adapter for configuration persistence. Defaults to fs. |
ttl_seconds |
integer | Per-id cleanup countdown in seconds. When >0, an entry whose last subscriber trigger has been unregistered for this long is deleted. Defaults to 0 (no cleanup). |
Adapters
fs
File-system adapter that stores one YAML file per configuration id and watches the directory for external edits.
name: fs
config:
directory: ./data/configuration| Field | Type | Description |
|---|---|---|
directory |
string | Directory holding files. Created on boot. Defaults to ./data/configuration. |
External writes / edits / removals to the watched directory are debounced (500 ms) and replayed as configuration:registered, configuration:updated, or configuration:deleted events through the same trigger fan-out used by SDK calls.
bridge
Forwards every configuration::* call to a remote III Engine via the iii-sdk and registers a remote configuration trigger so changes on the source engine are mirrored into the local trigger fan-out.
name: bridge
config:
bridge_url: ${REMOTE_III_URL:ws://localhost:49134}| Field | Type | Description |
|---|---|---|
bridge_url |
string | WebSocket URL of the remote III Engine. Defaults to ws://localhost:49134. |
The bridge adapter cannot delete configurations on the remote engine; cleanup happens via the remote's TTL or by operating on the remote engine directly.
Functions
configuration::register
Declare a configuration id with a JSON Schema, name, description, and optional initial value. Idempotent — re-registering replaces the schema, name, description, and metadata; the stored value is kept unless initial_value is supplied. Validates initial_value against schema before persisting. Fires configuration:registered on first registration or configuration:updated on subsequent calls.
Parameters: id (string), name (string), description (string), schema (object — JSON Schema), initial_value (any, optional), metadata (any, optional)
Returns: the stored entry { id, name, description, schema, value, metadata }. Templates inside value are stored verbatim; expansion happens on read.
configuration::set
Replace the stored value for a registered id. Validates value against the registered schema. Fires configuration:updated.
Parameters: id (string), value (any)
Returns: old_value (any, or null if the entry had no prior value), new_value (any)
configuration::get
Read one configuration by id.
Parameters: id (string), raw (boolean, optional — defaults to false)
Returns: id (string), value (any). When raw is false, ${VAR:default} placeholders inside string fields are expanded against the live process env. When raw is true, the stored value is returned verbatim.
configuration::list
Enumerate every registered configuration. Never returns the stored value — pair with configuration::get once you have the id you want.
Returns: configurations (array of { id, name, description, schema, metadata }), sorted lexicographically by id.
configuration::schema
Read the schema, name, description, and metadata for one id without exposing the value.
Parameters: id (string)
Returns: id (string), name (string), description (string), schema (object), metadata (any, optional)
Error Codes
| Code | Meaning |
|---|---|
NOT_REGISTERED |
set was called against an id that has not been passed to register yet. |
INVALID_ID |
The id does not match [a-z0-9_-]{1,64} — the constraint applied so ids are safe filenames for the fs adapter. |
SCHEMA_INVALID |
The supplied value does not satisfy the registered JSON Schema. The error message lists each violation. |
NOT_FOUND |
get or schema was called against an id that is not registered. |
ADAPTER_ERROR |
The adapter failed to persist the change (disk error, bridge unreachable, etc.). |
Trigger Type: configuration
Fires when a configuration entry is registered, updated, or deleted — including external fs file edits and bridge-forwarded events from a remote engine.
| Config Field | Type | Description |
|---|---|---|
configuration_id |
string | Only fire for changes to this id. When omitted, fires for every id. |
event_types |
string[] | Subset of configuration:registered, configuration:updated, configuration:deleted. When omitted, fires for every event type. |
condition_function_id |
string | Function ID for conditional execution. If it returns false, the handler is skipped. |
Configuration Event Payload
| Field | Type | Description |
|---|---|---|
type |
string | Always "configuration". |
event_type |
string | "configuration:registered", "configuration:updated", or "configuration:deleted". |
id |
string | The configuration id that changed. |
name |
string | The registered name at the time of the event. |
description |
string | The registered description. |
schema |
object | The registered JSON Schema. |
old_value |
any | Previous value with ${VAR:default} placeholders expanded. null on configuration:registered. |
new_value |
any | New value with ${VAR:default} placeholders expanded. null on configuration:deleted. |
metadata |
any | Echoes the registered metadata; omitted when none was supplied. |
Sample Code
const fn = iii.registerFunction(
{ id: 'stream::onConfigChange' },
async (event) => {
console.log('Configuration changed:', event.event_type, event.id)
console.log('New value:', event.new_value)
return {}
},
)
iii.registerTrigger({
type: 'configuration',
function_id: fn.id,
config: {
configuration_id: 'iii-stream',
event_types: ['configuration:updated'],
},
})Mutations that fire triggers: configuration::register (:registered on first call, :updated on re-registration), configuration::set (:updated), TTL-driven cleanup (:deleted), and external fs create / edit / delete events. Reads (configuration::get, configuration::list, configuration::schema) do not fire triggers.
TTL Cleanup
The worker tracks the number of triggers currently bound to each configuration id. When ttl_seconds > 0 is configured AND the last trigger for an id is unregistered, a countdown deletes the entry after the TTL elapses. A new trigger registration before the countdown fires aborts the cleanup; while at least one trigger is bound to an id, that entry never expires.
ttl_seconds = 0 (the default) disables expiry entirely — entries persist until they are explicitly deleted via the adapter or, for the fs adapter, by removing the underlying file.
This is the cleanup story for ephemeral workers that come and go (sandboxes, short-lived consumers) and should not leave stale configuration behind when no one is left subscribing.
Usage Example: Migrating a Worker Off config.yaml
import { registerWorker } from 'iii-sdk'
const iii = registerWorker('ws://localhost:49134')
// 1. Declare the schema once at startup.
await iii.trigger({
function_id: 'configuration::register',
payload: {
id: 'iii-stream',
name: 'Stream worker',
description: 'Connection settings for the stream worker.',
schema: {
type: 'object',
required: ['port'],
properties: {
port: { type: 'integer', minimum: 1, maximum: 65535 },
host: { type: 'string' },
},
},
initial_value: { port: 3112, host: '127.0.0.1' },
},
})
// 2. Read the live value (placeholders expanded) anywhere you need it.
const { value } = await iii.trigger({
function_id: 'configuration::get',
payload: { id: 'iii-stream' },
})
// 3. Subscribe to changes elsewhere — set/external-edit/bridge events all
// arrive on the same trigger.
const onChange = iii.registerFunction('stream::onConfigChange', async (event) => {
console.log('Stream config now:', event.new_value)
return {}
})
iii.registerTrigger({
type: 'configuration',
function_id: onChange.id,
config: { configuration_id: 'iii-stream' },
})api reference (json)
{
"functions": [
{
"description": "Read a configuration by id. Expands ${VAR:default} placeholders against the live process env unless raw=true is passed.",
"metadata": {},
"name": "configuration::get",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"type": "string"
},
"raw": {
"default": false,
"description": "When `true`, return the stored value verbatim (including `${VAR}` placeholders). When `false` (default), expand `${VAR:default}` against the live process env.",
"type": "boolean"
}
},
"required": [
"id"
],
"title": "ConfigurationGetInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"type": "string"
},
"value": true
},
"required": [
"id",
"value"
],
"title": "ConfigurationGetResult",
"type": "object"
}
},
{
"description": "List every registered configuration with id, name, description, and schema. Sorted by id; never returns the stored value.",
"metadata": {},
"name": "configuration::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ConfigurationListInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ConfigurationSchemaView": {
"description": "Subset of a [`ConfigurationEntry`] returned from `list` / `schema` — the schema-only view that never leaks the stored value.",
"properties": {
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"metadata": true,
"name": {
"type": "string"
},
"schema": true
},
"required": [
"description",
"id",
"name",
"schema"
],
"type": "object"
}
},
"properties": {
"configurations": {
"items": {
"$ref": "#/definitions/ConfigurationSchemaView"
},
"type": "array"
}
},
"required": [
"configurations"
],
"title": "ConfigurationListResult",
"type": "object"
}
},
{
"description": "Register a configuration id with a name, description, and JSON Schema. Idempotent — re-registering replaces metadata and (when initial_value is provided) the value. Validates initial_value against the schema.",
"metadata": {},
"name": "configuration::register",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"description": {
"description": "Description shown in `configuration::list`.",
"type": "string"
},
"id": {
"description": "Configuration id. Must match `[a-z0-9_-]{1,64}` so it is safe as a filename in the `fs` adapter.",
"type": "string"
},
"initial_value": {
"description": "Optional initial value to install. Validated against `schema`."
},
"metadata": {
"description": "Optional opaque metadata stored alongside the entry."
},
"name": {
"description": "Human-readable name shown in `configuration::list`.",
"type": "string"
},
"schema": {
"description": "JSON Schema describing the value shape. `set` validates against this."
}
},
"required": [
"description",
"id",
"name",
"schema"
],
"title": "ConfigurationRegisterInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "A single configuration entry tracked by the worker.\n\n`value` is stored verbatim — including any `${VAR:default}` template strings. Expansion happens on read (`configuration::get`) and during trigger fan-out so env-var changes propagate without a worker restart.",
"properties": {
"description": {
"description": "One-line description of what this configuration controls.",
"type": "string"
},
"id": {
"description": "Stable identifier (e.g. `iii-stream`, `iii-observability`).",
"type": "string"
},
"metadata": {
"description": "Optional caller-supplied metadata (owner team, change ticket, etc.)."
},
"name": {
"description": "Human-readable display name.",
"type": "string"
},
"schema": {
"description": "JSON Schema describing the shape of `value`."
},
"value": {
"default": null,
"description": "Stored configuration body. May contain `${VAR:default}` placeholders."
}
},
"required": [
"description",
"id",
"name",
"schema"
],
"title": "ConfigurationEntry",
"type": "object"
}
},
{
"description": "Retrieve the schema, name, and description for a configuration id. Mirrors a single entry from configuration::list.",
"metadata": {},
"name": "configuration::schema",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"title": "ConfigurationSchemaInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Subset of a [`ConfigurationEntry`] returned from `list` / `schema` — the schema-only view that never leaks the stored value.",
"properties": {
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"metadata": true,
"name": {
"type": "string"
},
"schema": true
},
"required": [
"description",
"id",
"name",
"schema"
],
"title": "ConfigurationSchemaView",
"type": "object"
}
},
{
"description": "Replace the value of an already-registered configuration. Validates the value against the registered JSON Schema and emits a configuration:updated event.",
"metadata": {},
"name": "configuration::set",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"type": "string"
},
"value": {
"description": "New configuration value. Validated against the registered schema."
}
},
"required": [
"id",
"value"
],
"title": "ConfigurationSetInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"new_value": {
"description": "Current stored value (templates not expanded)."
},
"old_value": {
"description": "Previous stored value, or `null` when the entry had no value yet."
}
},
"required": [
"new_value"
],
"title": "ConfigurationSetResult",
"type": "object"
}
}
],
"triggers": []
}