compose-ui
v0.1.9Compose project supervision in the Console — a page over compose::* with live container state, lifecycle actions, worker packages, and per-container log tails.
Install
iii trigger compose::add worker=compose-uiRun in your project with the iii engine running. Exact versions are immutable and digest-pinned.
Full markdown
/registry/workers/compose-ui.md. Paste it into an LLM prompt or pipe it through curl from a worker.Install
iii trigger compose::add worker=compose-ui@0.1.9Dependencies
Readme
compose-ui
The compose daemon in the Console. A Compose page opens on a topology map (engine, namespace group, containers laid out by start_after, ports and sources on the cards, upstream/downstream tracing on select) and lists every container the
daemon supervises with live state, PID, and last error; starts, stops, and
restarts containers or the whole project in dependency order; adds, updates,
and removes declared worker packages; and tails each container's log. Every
lifecycle action is the daemon's own compose::* function, so the page and
iii trigger compose::… are the same operation. The worker adds the two things
the daemon does not expose on the bus: a compose-ui::changed trigger type
that fires when the daemon writes its durable project state or the compose
file changes on disk, and compose-ui::logs, a read-only log tail.
Install
iii compose add compose-uiCompose starts it beside the Console in the project's namespace. The page
appears in the Console nav as Compose (page compose) and in the command
palette as "Open Compose"; the palette also searches containers by name.
Companion workers
console≥ 1.9.14 hosts the injectable page.- A running
iii composedaemon answerscompose::*in the same namespace; without one the page shows how to start it.
Quickstart
Explain a failed container from an agent or a script:
iii trigger compose::status
iii trigger compose-ui::logs container=provider-openai lines=50{
"container": "provider-openai",
"path": "/home/me/.iii/compose/app/harness-3d528231/logs/provider-openai.log",
"lines": ["… last 50 lines …"],
"size": 17910,
"truncated": true,
"missing": false
}See what the project declares and what each container listens on:
iii trigger compose-ui::project{
"namespace": "my-project",
"engine_url": "ws://127.0.0.1:49134",
"containers": [
{ "name": "ade", "source": "path", "ref": "../ade", "pid": 27129, "ports": [{ "port": 3113, "address": "*" }] },
{ "name": "web", "source": "package", "ref": "api.workers.iii.dev/web", "version": "1.2.10", "ports": [] }
]
}React to supervisor changes without polling — bind the trigger type with an
empty config and re-read compose::status on each event:
iii.registerTrigger({ type: 'compose-ui::changed', function_id: 'my-worker::on-compose-change', config: {} })The payload is { kind: 'state' | 'file', file, namespace, state_dir, path, captured_at }.
Configuration
None. The worker locates the project through compose::status (compose file,
namespace, state directory) the first time a page or trigger binds, and again
if the watch is lost. Environment:
| Variable | Purpose |
|---|---|
III_URL |
Engine address; compose sets it. |
III_NAMESPACE |
Project namespace for a process started by hand; compose sets it. |
III_COMPOSE_UI_UI_WATCH |
1 serves the page from ui/dist and hot-reloads it into open Console tabs while pnpm --dir ui watch runs. |
Custom trigger types
| Type | Config | Fires |
|---|---|---|
compose-ui::changed |
{} |
Once per coalesced burst (200 ms) of writes to the daemon's state.json (kind: state) or edits to the compose file (kind: file). |
Run from source with compose
containers:
compose-ui:
worker: path://../compose-ui
scripts:
run: cargo run --releaseA worker started by hand needs III_NAMESPACE= or the
Console never sees its page.
Skills
API reference (JSON)
{
"functions": [
{
"description": "Read the last lines of one compose container's log file (default 200, at most 500; a missing log answers with missing: true).",
"metadata": {},
"name": "compose-ui::logs",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"container": {
"description": "Container name as declared in the compose file.",
"type": "string"
},
"file": {
"description": "Compose file on the daemon host; defaults to the daemon project.",
"type": [
"string",
"null"
]
},
"lines": {
"description": "Lines from the end; defaults to 200 and is capped at 500.",
"format": "int64",
"maximum": 500,
"minimum": 1,
"type": [
"integer",
"null"
]
}
},
"required": [
"container"
],
"title": "LogsInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"container": {
"type": "string"
},
"lines": {
"items": {
"type": "string"
},
"type": "array"
},
"missing": {
"type": "boolean"
},
"path": {
"type": "string"
},
"size": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"truncated": {
"type": "boolean"
}
},
"required": [
"container",
"lines",
"missing",
"path",
"size",
"truncated"
],
"title": "LogTail",
"type": "object"
}
},
{
"description": "Read the declared compose file plus what each container listens on: namespace, engine endpoint, timeouts, worker source, dependencies, environment keys, run script, PID, listening TCP ports.",
"metadata": {},
"name": "compose-ui::project",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"file": {
"description": "Compose file on the daemon host; defaults to the daemon project.",
"type": [
"string",
"null"
]
}
},
"title": "ProjectInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ContainerSource": {
"enum": [
"path",
"package",
"unknown"
],
"type": "string"
},
"ListeningPort": {
"properties": {
"address": {
"type": "string"
},
"port": {
"format": "uint16",
"minimum": 0,
"type": "integer"
}
},
"required": [
"address",
"port"
],
"type": "object"
},
"ProjectContainer": {
"properties": {
"environment": {
"items": {
"type": "string"
},
"type": "array"
},
"name": {
"type": "string"
},
"pid": {
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"ports": {
"items": {
"$ref": "#/definitions/ListeningPort"
},
"type": "array"
},
"ref": {
"type": "string"
},
"run": {
"type": [
"string",
"null"
]
},
"source": {
"$ref": "#/definitions/ContainerSource"
},
"start_after": {
"items": {
"type": "string"
},
"type": "array"
},
"version": {
"type": [
"string",
"null"
]
}
},
"required": [
"environment",
"name",
"ports",
"ref",
"source",
"start_after"
],
"type": "object"
}
},
"properties": {
"containers": {
"items": {
"$ref": "#/definitions/ProjectContainer"
},
"type": "array"
},
"daemon_pid": {
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"daemon_ports": {
"items": {
"$ref": "#/definitions/ListeningPort"
},
"type": "array"
},
"engine_host": {
"type": [
"string",
"null"
]
},
"engine_port": {
"format": "uint16",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"engine_url": {
"type": [
"string",
"null"
]
},
"file": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"startup_timeout": {
"type": [
"string",
"null"
]
},
"stop_timeout": {
"type": [
"string",
"null"
]
}
},
"required": [
"containers",
"daemon_ports",
"file"
],
"title": "ProjectResult",
"type": "object"
}
},
{
"description": "Serve the compose-ui worker's injected console UI assets (content function for its console:script / console:style triggers).",
"metadata": {
"internal": true
},
"name": "compose-ui::ui-content",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Input of the content function: the console asks for one asset by path.",
"properties": {
"path": {
"description": "The asset path from the trigger config (e.g. `state/page.js`).",
"type": "string"
}
},
"required": [
"path"
],
"title": "UiContentInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Output of the content function.",
"properties": {
"content": {
"description": "The asset source, verbatim.",
"type": "string"
},
"content_type": {
"description": "MIME type the console should serve the asset with.",
"type": "string"
}
},
"required": [
"content",
"content_type"
],
"title": "UiContentResult",
"type": "object"
}
}
],
"triggers": [
{
"description": "Fires when the compose daemon writes state.json or the compose file changes. Bind with an empty config.",
"invocation_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"title": "ChangedTriggerSpec",
"type": "object"
},
"metadata": {},
"name": "compose-ui::changed",
"return_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ChangeKind": {
"enum": [
"state",
"file"
],
"type": "string"
}
},
"properties": {
"captured_at": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"file": {
"type": "string"
},
"kind": {
"$ref": "#/definitions/ChangeKind"
},
"namespace": {
"type": "string"
},
"path": {
"type": "string"
},
"state_dir": {
"type": "string"
}
},
"required": [
"captured_at",
"file",
"kind",
"namespace",
"path",
"state_dir"
],
"title": "ChangedEvent",
"type": "object"
}
}
]
}