@iii-hq/iii-core-primitives

@iii-hq/iii-core-primitives — AI coding skill

View in AI SkillSafe app
0 downloads
0 stars
0 demos
SKILL.md
nameiii-core-primitives
description>-

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 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:

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.

Embed badges

Add these to your README to show the skill's verification status.

SkillSafe verified badge
Verified badge
[![SkillSafe verified badge](https://api.skillsafe.ai/v1/badge/@iii-hq/iii-core-primitives/verified)](https://skillsafe.ai/skill/@iii-hq/iii-core-primitives/)
Installs badge
Installs badge
[![Installs badge](https://api.skillsafe.ai/v1/badge/@iii-hq/iii-core-primitives/installs)](https://skillsafe.ai/skill/@iii-hq/iii-core-primitives/)
Scan badge
Scan badge
[![Scan badge](https://api.skillsafe.ai/v1/badge/@iii-hq/iii-core-primitives/scan)](https://skillsafe.ai/skill/@iii-hq/iii-core-primitives/)
Eval pass rate badge
Eval pass rate
[![Eval pass rate badge](https://api.skillsafe.ai/v1/badge/@iii-hq/iii-core-primitives/eval)](https://skillsafe.ai/skill/@iii-hq/iii-core-primitives/)