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.
Hand the migration to a coding agent
The steps below are mechanical, so a coding agent with shell access to the project can carry them out. Copy this prompt into the agent, then review the resultingworker-compose.yaml before
starting it.
Prompt
Back up the project
Keep a copy of:config.yamland 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
Build the new engine section
Move these four engine-owned worker configs from list entries inconfig.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.
iii-sandbox is not in this list. The engine injects the iii-sandbox router, and the
sandbox-libkrun worker runs the VMs; see Upgrading to the sandbox worker for
an existing iii-sandbox entry.
worker-compose.yaml
engine.url defaults to ws://127.0.0.1:49134. Compose writes the engine-only representation to
<project-dir>/.iii/compose/<daemon-namespace>/engine-config.yaml by default. When
III_COMPOSE_STATE_DIR is set, the path is
$III_COMPOSE_STATE_DIR/<project-slug>/<daemon-namespace>/engine-config.yaml. Compose writes the
file 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
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. With an iii CLI older than
0.26, run iii trigger instead of iii call, with the same arguments:
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 asiii-state is not copied to
state automatically.
- Before upgrading, read the old value with
configuration::get. - Put it under
config_override, or write it to the new id withconfiguration::set. - Verify the new worker before removing the old stored entry.
Start the result
For a managed engine, the file owns both lifecycles: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 four allowed workers in
the list-shaped config.yaml, add a top-level sandbox: section if anything calls sandbox::*
(see Upgrading to the sandbox worker), start it directly, omit engine: from
the Compose file, and supply the existing URL:
--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 (with an iii CLI older than 0.26, run iii trigger instead of iii call):
Common errors
UNSUPPORTED_CONFIG_WORKERS: directconfig.yamlstill contains project workers.UNSUPPORTED_ENGINE_WORKER:engine.workerscontains 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::addwas given an engine package as a root.CONTAINER_NAME_TAKEN: another live process owns the same(namespace, worker name).