Skip to main content
iii 0.23 removes the legacy worker lifecycle. There is no compatibility period or automatic migrator: iii worker, the worker::* functions, engine fallback through iii.toml, and engine-managed project workers are gone. A managed project now has one worker-compose.yaml. Its engine: section configures the engine; containers: declares project workers. If a direct config.yaml still declares a project worker, startup and reload stop with UNSUPPORTED_CONFIG_WORKERS and list every entry to migrate.

Back up the project

Keep a copy of:
  • config.yaml and any path passed with --config
  • an existing worker-compose.yaml
  • the configuration worker’s storage directory, ./config/ by default
  • state, queue, and stream data paths
  • iii.lock, if the project used the removed installer
Rollback requires those files and the previous iii binary. The 0.23 engine does not accept the old project-worker declarations.

Build the new engine section

Move these five engine-owned worker configs from list entries in config.yaml to the direct engine.workers map: The map value is the worker config itself; do not keep the old nested config: key. Multiple instances use a #instance suffix, such as iii-worker-manager#rbac.
worker-compose.yaml
engine.url defaults to ws://127.0.0.1:49134. Compose writes the engine-only representation to ~/.iii/compose/<daemon-namespace>/engine-config.yaml with owner-only permissions and starts the engine from it. Do not edit that generated file. Remove explicit iii-engine-functions, iii-telemetry, and iii-observability entries. The engine injects them automatically, and declaring one under engine.workers fails.

Move project workers to containers

Copy each old project worker’s config: value to config_override, preserve its storage paths, and pin the package version.
worker-compose.yaml
Translate iii-exec commands into pre_run, run, and post_run. Custom local workers use path://; registry workers use package:// plus a version. You can also add a registry worker after the managed daemon is running:
compose::add writes containers: and restarts affected containers. It never edits engine: or restarts the engine. A registry root of kind engine is rejected and points to engine.workers.<name> when the worker is configurable.

Preserve stored configuration

Standalone packages use unprefixed configuration ids. A value stored as iii-state is not copied to state automatically.
  1. Before upgrading, read the old value with configuration::get.
  2. Put it under config_override, or write it to the new id with configuration::set.
  3. Verify the new worker before removing the old stored entry.
Do not rename only the YAML file: filesystem-backed entries also contain id and schema metadata.

Start the result

For a managed engine, the file owns both lifecycles:
The explicit namespace (dev) addresses compose::* and overrides the file’s namespace: for its containers. Changing engine: while the daemon runs returns ENGINE_RESTART_REQUIRED; stop and restart that Compose invocation. A second file with engine: returns ENGINE_ALREADY_OWNED. For an engine supervised separately by systemd or Kubernetes, keep its five allowed workers in the list-shaped config.yaml, start it directly, omit engine: from the Compose file, and supply the existing URL:
Run those commands under separate supervisors. Explicit --engine has highest priority and may override an engine.url in the Compose file. Without either value, Compose uses III_URL, then defaults to ws://127.0.0.1:49134. Verify the migration:

Common errors

  • UNSUPPORTED_CONFIG_WORKERS: direct config.yaml still contains project workers.
  • UNSUPPORTED_ENGINE_WORKER: engine.workers contains a project or unknown worker.
  • ENGINE_WORKER_IS_INJECTED: remove an automatically supplied internal worker.
  • ENGINE_RESTART_REQUIRED: restart Compose to apply a changed engine section.
  • ENGINE_ALREADY_OWNED: start the second managed file in a separate Compose invocation.
  • ENGINE_SECTION_REQUIRES_MANAGED_START: an external daemon was asked to load a managed file.
  • ENGINE_WORKER_IS_BUILTIN: compose::add was given an engine package as a root.
  • CONTAINER_NAME_TAKEN: another live process owns the same (namespace, worker name).