{/* TODO: Re-link worker references to https://workers.iii.dev/workers/<name> once the Worker Docs migration ships. */} <Note> This page documents the wire-level protocol the engine and SDK workers exchange. Most projects use a language SDK ([Node](./sdk-node), [Python](./sdk-python), [Rust](./sdk-rust), [Browser](./sdk-browser)) and never touch the protocol directly. The shapes below are the source of truth those SDKs serialize to. </Note> <Note> Observability introspection (traces, logs, me...
Scanned 9/3/2026
Install to Claude Code
npx -y skills add iii-hq/iii --skill reference --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Reference?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/iii-hq-reference)More formats (shields.io, HTML) on the badges page.
<!-- generated by iii-skill-render. DO NOT EDIT (changes here are overwritten on the next render). Edit docs/next/reference/engine-protocol.mdx. -->
# Engine protocol
{/* TODO: Re-link worker references to https://workers.iii.dev/workers/<name> once the Worker Docs migration ships. */}
<Note>
This page documents the wire-level protocol the engine and SDK workers exchange. Most projects use
a language SDK ([Node](./sdk-node), [Python](./sdk-python),
[Rust](./sdk-rust), [Browser](./sdk-browser)) and never touch the
protocol directly. The shapes below are the source of truth those SDKs serialize to.
</Note>
<Note>
Observability introspection (traces, logs, metrics, sampling rules, alerts, rollups) is owned
end-to-end by the iii-observability worker.
</Note>
## Connection ports
The engine binds three ports of its own and runs alongside one more from the observability worker:
| Port | Bound by | Surface |
| ------- | ------------------ | ------------------------------------------------------------- |
| `3111` | engine | REST API. |
| `3112` | engine | Stream API (WebSocket; consumer-side stream subscriptions). |
| `49134` | engine | SDK WebSocket; this is what `iii_sdk::register_worker` opens. |
| `9464` | `iii-observability` worker | Prometheus metrics endpoint (typically exposed from the same container as the engine). |
The console UI runs on `3113` and is launched separately by `iii console`.
## Connection flow
A worker opens the SDK WebSocket (default `ws://127.0.0.1:49134`). On connect the engine assigns the
worker a UUID and sends a `WorkerRegistered { worker_id }` frame carrying it. The worker sends the
registrations it holds in memory (each `RegisterFunction`, `RegisterTrigger`, and
`RegisterTriggerType` it intends to expose) and calls `engine::workers::register` to publish its own
metadata (runtime, version, OS, PID, isolation, and an optional one-line `description`), which the
engine acknowledges with a `RegisterWorkerResult`.
The connection is bidirectional from that point on: the engine pushes `InvokeFunction` frames at the
worker, and the worker pushes `InvocationResult`, additional registrations, or unregistrations back.
## Message types
Every frame is a JSON object discriminated by `type` (the lowercased variant name, e.g.
`registerfunction`). The full set, defined on `Message` in
[`engine/src/protocol.rs`](https://github.com/iii-hq/iii/blob/main/engine/src/protocol.rs):
| Frame | Direction | Purpose |
| --------------------------- | ---------------- | ------------------------------------------------------ |
| `RegisterFunction` | worker -> engine | Make a function callable by `function_id`. |
| `UnregisterFunction` | worker -> engine | Drop a previously registered function. |
| `RegisterTrigger` | worker -> engine | Bind a function to a trigger instance. |
| `UnregisterTrigger` | worker -> engine | Drop a trigger binding. |
| `TriggerRegistrationResult` | engine -> worker | Ack / error for a `RegisterTrigger`. |
| `RegisterTriggerType` | worker -> engine | Declare a new trigger type the worker advertises. |
| `RegisterService` | worker -> engine | Group related functions under a service id. |
| `InvokeFunction` | engine -> worker | Call a registered function with a payload. |
| `InvocationResult` | worker -> engine | Carry the function's result or error back. |
| `WorkerRegistered` | engine -> worker | Acknowledge the worker, with the assigned `worker_id`. |
| `Ping` / `Pong` | bidirectional | Liveness; keeps idle connections from timing out. |
## `RegisterFunction`
```json
{
"type": "registerfunction",
"id": "math::add",
"description": "Add two numbers.",
"request_format": {
"type": "object",
"properties": { "a": { "type": "number" }, "b": { "type": "number" } }
},
"response_format": { "type": "object", "properties": { "c": { "type": "number" } } },
"metadata": { "owner": "math-team" },
"invocation": null
}
```
`id` is required. `description`, `request_format`, `response_format`, and `metadata` are optional
and feed the iii console and the agent-readable skills. `invocation` is reserved for external HTTP
functions (`HttpInvocationRef`); leave it `null` for in-process handlers.
## `RegisterTrigger`
```json
{
"type": "registertrigger",
"id": "math::add@http",
"trigger_type": "http",
"function_id": "math::add",
"config": { "api_path": "/math/add", "http_method": "POST" },
"metadata": null
}
```
`config` is the per-trigger-type configuration; the shape is defined by whatever worker advertised
that `trigger_type` (e.g. `http` for `http` triggers). The engine responds with a
`TriggerRegistrationResult` carrying an optional `error: ErrorBody`.
## `RegisterTriggerType`
```json
{
"type": "registertriggertype",
"id": "webhook",
"description": "HTTP webhook trigger",
"trigger_request_format": { "type": "object", ... },
"call_request_format": { "type": "object", ... }
}
```
`trigger_request_format` is the JSON Schema for the trigger's per-binding `config`.
`call_request_format` is the JSON Schema for the payload delivered to bound functions when the
trigger fires.
## `InvokeFunction`
```json
{
"type": "invokefunction",
"function_id": "math::add",
"data": { "a": 2, "b": 3 },
"metadata": { "tenant": "acme" },
"traceparent": "00-…",
"baggage": "k=v,…",
"action": { "type": "void" }
}
```
`invocation_id` is omitted on `Void` invocations (the worker has no result channel to reply on).
The optional `metadata` field on a trigger registration (`null` / `None` in the examples above)
is arbitrary JSON stored with the trigger and delivered to the receiving function as a
distinct argument alongside the payload. It is useful for providing contextual information about
the trigger or execution context to the receiving function. A target function shared by many
triggers can use it to recover which registration fired and with what context.
`metadata` can be provided both via `registerTrigger` and direct `trigger()` invocations.
`traceparent` and `baggage` contain W3C trace
context. `action` is the routing flag (see [Trigger actions](#trigger-actions) below);
absent / `null` means synchronous.
## `InvocationResult`
Success:
```json
{
"type": "invocationresult",
"invocation_id": "9f3c…",
"function_id": "math::add",
"result": { "c": 5 },
"error": null,
"traceparent": "00-…",
"baggage": "k=v,…"
}
```
Failure:
```json
{
"type": "invocationresult",
"invocation_id": "9f3c…",
"function_id": "math::add",
"result": null,
"error": {
"code": "invocation_failed",
"message": "boom",
"stacktrace": "TraceError: …"
}
}
```
`ErrorBody.code` values that appear in `InvocationResult.error` include `invocation_failed` (handler threw),
`invocation_stopped` (the owning worker disconnected mid-flight, so the engine cancels the in-flight
call and surfaces this code to the caller), `function_not_found`, `function_not_invokable`,
`TIMEOUT` (client-side timeout), `FORBIDDEN` (RBAC denial).
## Trigger actions
`InvokeFunction.action` is tagged by `type` and lowercase-encoded on the wire:
| Wire shape | Meaning |
| ---------------------------------------- | -------------------------------------------------------- |
| omitted / `null` | Synchronous; the worker replies with `InvocationResult`. |
| `{ "type": "void" }` | Fire-and-forget; no `invocation_id`, no reply. |
| `{ "type": "enqueue", "queue": "math" }` | Route through the named queue (provided by `queue`). |
## Invocation lifecycle
For synchronous calls the engine assigns an `invocation_id`, forwards the `InvokeFunction` to the
owning worker, and waits for the matching `InvocationResult`. For `Void` actions the engine forwards
without an `invocation_id` and never expects a reply. For `Enqueue` the engine hands the invocation
to the queue worker, which persists it and re-invokes the target function on a subscriber according
to the queue's retry policy.
## Engine discovery functions
The engine registers a set of functions under the `engine::*` namespace for introspection
and worker lifecycle. Defined in
[`engine/src/workers/engine_fn/mod.rs`](https://github.com/iii-hq/iii/blob/main/engine/src/workers/engine_fn/mod.rs):
| Function | Purpose |
| ----------------------------- | ----------------------------------------------------------------------------- |
| `engine::channels::create` | Create a streaming-channel reader / writer pair. |
| `engine::functions::list` | List every registered function (filterable by `include_internal`). |
| `engine::functions::info` | Inspect one or more functions (a single `function_id`, or up to 32 `function_ids`): schemas, owner, and registered triggers. |
| `engine::workers::list` | List every connected worker with metrics. |
| `engine::workers::info` | Inspect one connected worker's full surface (functions, trigger types, registered triggers). |
| `engine::triggers::list` | List every registered trigger type (filterable by `include_internal`). |
| `engine::triggers::info` | Inspect one trigger type: schemas, owner, and live instance count. |
| `engine::registered-triggers::list` | List every registered trigger instance (filterable by `include_internal`). |
| `engine::registered-triggers::info` | Inspect one registered trigger instance, with denormalized trigger and function detail. |
| `engine::workers::register` | Publish the calling worker's metadata (runtime, version, OS, PID, isolation, optional `description`). |
| `engine::register_trigger` | Register a trigger that fires `function_id` directly, with optional `metadata` delivered to the handler as a distinct argument. Returns the trigger id. |
| `engine::unregister_trigger` | Unregister a trigger by id. Idempotent; reports whether it existed. |
## Engine discovery triggers
| Trigger | Fires when |
| ----------------------------- | ----------------------------------------- |
| `engine::functions-available` | A function is registered or unregistered. |
| `engine::workers-available` | A worker connects or disconnects. |
## Engine-collected metrics
These metrics are emitted by the engine regardless of which language SDK a worker uses. Names and
units come from
[`engine/src/workers/observability/metrics.rs`](https://github.com/iii-hq/iii/blob/main/engine/src/workers/observability/metrics.rs).
### Invocations
| Metric | Instrument | Unit |
| ----------------------------- | ---------- | ----------- |
| `iii.invocations.total` | counter | invocations |
| `iii.invocation.duration` | histogram | s |
| `iii.invocation.errors.total` | counter | errors |
### Workers
| Metric | Instrument | Unit |
| -------------------------- | ---------- | ------- |
| `iii.workers.active` | gauge | workers |
| `iii.workers.spawns.total` | counter | workers |
| `iii.workers.deaths.total` | counter | workers |
| `iii.workers.by_status` | gauge | workers |
### Per-worker
| Metric | Instrument | Unit |
| ------------------------------ | ---------- | ----- |
| `iii.worker.memory.heap.bytes` | gauge | bytes |
| `iii.worker.memory.rss.bytes` | gauge | bytes |
| `iii.worker.cpu.percent` | gauge | % |
| `iii.worker.event_loop.lag.ms` | gauge | ms |
| `iii.worker.uptime.seconds` | gauge | s |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!