iii-core-primitives

iii-core-primitives

Popular

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.

19Kstars
1.2Kforks
Updated 8/22/2026
SKILL.md
read-only
name
iii-core-primitives
description

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.

Shape Use for
registerFunction(id, handler, options?) Local worker code
registerFunction(id, HttpInvocationConfig, options?) Existing HTTP services
registerTrigger({ type, function_id, config, metadata? }) Binding an event source
trigger({ function_id, payload, action?, timeout? }) Calling any function by ID

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 run iii worker add <name>
Pin a worker version iii worker add <name>@<version>
Add an OCI worker iii worker add ghcr.io/org/worker:tag
Add a local worker during development iii worker add ./workers/my-worker
Replay installed workers Commit iii.lock, then run iii worker sync

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:

name: math-worker
runtime:
  kind: python
  package_manager: pip
  entry: math_worker.py
scripts:
  install: "pip install -r requirements.txt"
  start: "python math_worker.py"

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.

Code Examples

TypeScript

import { registerWorker, TriggerAction } from "iii-sdk";

const iii = registerWorker("ws://localhost:49134", { workerName: "orders-worker" });

iii.registerFunction("orders::validate", async (order) => {
  if (!order.id) throw new Error("missing order id");
  return { ...order, valid: true };
});

iii.registerFunction("orders::process", async (order) => {
  const validated = await iii.trigger({ function_id: "orders::validate", payload: order });
  await iii.trigger({
    function_id: "orders::charge",
    payload: validated,
    action: TriggerAction.Enqueue({ queue: "payments" }),
  });
  return { accepted: true, orderId: validated.id };
});

iii.registerTrigger({
  type: "http",
  function_id: "orders::process",
  config: { api_path: "/orders", http_method: "POST" },
});

Python

from iii import register_worker

iii = register_worker("ws://localhost:49134")

def validate(order):
    if not order.get("id"):
        raise ValueError("missing order id")
    return {**order, "valid": True}

def process(order):
    validated = iii.trigger({"function_id": "orders::validate", "payload": order})
    iii.trigger({
        "function_id": "orders::charge",
        "payload": validated,
        "action": {"type": "enqueue", "queue": "payments"},
    })
    return {"accepted": True, "orderId": validated["id"]}

iii.register_function("orders::validate", validate)
iii.register_function("orders::process", process)
iii.register_trigger({
    "type": "http",
    "function_id": "orders::process",
    "config": {"api_path": "/orders", "http_method": "POST"},
})

Rust

use iii_sdk::{register_worker, InitOptions, RegisterFunction, TriggerAction};
use iii_sdk::protocol::{RegisterTriggerInput, TriggerRequest};
use serde_json::json;

let iii = register_worker("ws://127.0.0.1:49134", InitOptions::default());

iii.register_function(RegisterFunction::new("orders::validate", |order: serde_json::Value| {
    if order["id"].is_null() {
        return Err("missing order id".into());
    }
    Ok(json!({ "valid": true, "order": order }))
}))?;

let process_client = iii.clone();
iii.register_function(RegisterFunction::new_async("orders::process", move |order: serde_json::Value| {
    let iii = process_client.clone();
    async move {
        let validated = iii.trigger(TriggerRequest::new("orders::validate", order)).await?;
        iii.trigger(TriggerRequest {
            function_id: "orders::charge".into(),
            payload: validated.clone(),
            action: Some(TriggerAction::Enqueue { queue: "payments".into() }),
            timeout_ms: None,
        }).await?;
        Ok(json!({ "accepted": true, "order": validated }))
    }
}))?;

iii.register_trigger(RegisterTriggerInput {
    trigger_type: "http".into(),
    function_id: "orders::process".into(),
    config: json!({ "api_path": "/orders", "http_method": "POST" }),
    metadata: None,
})?;

Advanced Primitive Patterns

  • 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.