Use when registering iii functions, binding triggers, selecting sync/void/enqueue invocation, creating workers, inspecting the live worker registry, installing registry workers, authoring custom triggers, moving channel data, or adapting external HTTP functions across TypeScript, Python, and Rust.
Use when registering iii functions, binding triggers, selecting sync/void/enqueue invocation, creating workers, inspecting the live worker registry, installing registry workers, authoring custom triggers, moving channel data, or adapting external HTTP functions across TypeScript, Python, and Rust.
Core Primitives
iii has three top-level primitives:
Function: a named unit of work such as orders::validate
Trigger: an event source bound to a function
Worker: a process that connects to the engine and executes functions
Use :: in function IDs, leading slashes in HTTP api_path, and expression for cron config.
Function Registration
Register local handlers when you control the implementation. Register HTTP-invoked functions when
iii should call an existing external endpoint.
Functions and triggers can carry metadata for ownership, discovery, and generated skills. Do not put
secrets in metadata.
Workers and Registry
A worker is any process that connects to the engine and registers functions or trigger types. There
are two common paths:
Task
Use
Create your own worker
Write SDK code that calls registerWorker, registerFunction, and registerTrigger
Add an existing capability
Browse https://workers.iii.dev/, then call compose::add worker=<name>
Pin a worker version
compose::add worker=<name>@<version>
Declare a local worker
Add worker: path://./workers/my-worker under containers:
Reproduce a project
Commit the exact versions in worker-compose.yaml
The public worker registry at workers.iii.dev is for installable workers such as HTTP, state,
queue, pub/sub, cron, observability, sandbox, database, shell, console, and other capability
workers. Those workers may ship their own function-level skills; do not duplicate every capability
as a top-level iii skill.
Worker Manifest
Use iii.worker.yaml when iii should start a local worker project:
The manifest describes how to start the process. Once running, the WebSocket connection and function
registrations are what make the worker part of iii.
Live Engine Registry
The engine keeps a live registry of connected workers, registered functions, triggers, and trigger
types. Read it through the built-in discovery functions:
Function
Returns
engine::workers::list
Connected workers and metrics
engine::functions::list
Registered functions
engine::triggers::list
Registered triggers
engine::trigger-types::list
Advertised trigger types and schemas
For topology changes, bind triggers to engine::workers-available or
engine::functions-available.
Built-In Trigger Shapes
Trigger type
Registration config
Handler payload
http
{ api_path: "/orders/:id", http_method: "POST" }
{ query_params, path_params, headers, path, method, body }
cron
{ expression: "0 0 9 * * * *" }
{ trigger, job_id, scheduled_time, actual_time }
durable:subscriber
{ topic: "payments" }
The queued message payload
subscribe
{ topic: "orders.created" }
The published event payload
state
{ scope: "orders", key?: "order-123" }
{ event_type, scope, key, old_value, new_value }
stream
{ stream_name, group_id, item_id? }
Stream event details
log
{ level: "warn" }
OpenTelemetry-style log data
Add condition_function_id to built-in trigger config when the handler should only run if a boolean
condition function returns true.
Invocation Modes
Mode
Shape
Use when
Sync
trigger({ function_id, payload })
The caller needs the result
Void
TriggerAction.Void()
Optional side effect, no result needed
Enqueue
TriggerAction.Enqueue({ queue })
Reliable async work with queue policy
Use enqueue for work that must complete with retries. Use void for analytics, notifications, and
other non-critical side effects.
Custom triggers: use registerTriggerType({ id, description }, handler) when the event source is
not built in. Keep listener setup in registerTrigger and cleanup in unregisterTrigger.
Channels: use createChannel() for binary or streaming data that should not be serialized into
JSON payloads. Pass readerRef or writerRef through a function payload.
HTTP-invoked functions: use HttpInvocationConfig for legacy APIs, third-party endpoints, or
immutable services. Use environment variable names for auth fields, not raw secrets.
Schemas: Rust can derive request/response schemas with schemars::JsonSchema; Python can use
type hints or Pydantic; Node can pass JSON Schema manually.
When to Use
Use this skill for function registration, trigger binding, trigger payload shapes, invocation mode
decisions, worker creation, worker registry access, trigger conditions, custom trigger types,
channels, and HTTP-invoked functions.
Use this when a task spans TypeScript, Python, or Rust examples for the same iii primitive.
Boundaries
For engine ports, adapters, queue retry policy, worker manager, RBAC listeners, and deployment
config, use iii-engine-config.
For SDK-specific package exports and language caveats, use iii-sdk-reference.
For complete backend designs such as workflows, CQRS, agentic systems, and reactive apps, use
iii-architecture-patterns.
For failed invocations, timeouts, RBAC denials, and retryability, use iii-error-handling.
Worker-backed capability details live with the worker docs, not as top-level iii skills.