iii-core-primitives

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.

By iii-hq · 2,266 installs

npx skills add iii-hq/iii --skill iii-core-primitives

Source repository · Upstream listing

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 Since 0.25 every function is also observable : iii.observe(source, target) invokes target on each invocation of source that passes its filters. Observers replace trigger bindings over time; the built in providers ( http , cron , queue, state , stream , pub/sub, database) still use trigger types in 0.25, so keep registerTrigger for them. See iii observe . 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 a built in event source (deprecated in 0.25, still required for providers that have not migrated) observe({ function id, args?, filters? }, target, options?) Running target after another function's invocations, or on an engine event ( iii observe ) 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 or observe 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, database, shell, console, rbac proxy, and other capability workers. ( iii sandbox and iii observability are engine owned and are not added through the registry.) 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 engine::observers::list Observers you may see ( function id , namespace , worker filters) For topology changes, observe the engine hosted sources engine::on workers changed or engine::on functions changed with deliver: 'input' (see iii observe ). The older engine::workers available and engine::functions available trigger types still fire. Built In Trigger Shapes The workers behind these types have not moved to source functions in 0.25, so bind them with registerTrigger . Each call logs a one time deprecation warning per process; it is informational and the binding works as before. For log , the engine also hosts the observability::on log source ( iii observe ). 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 . With observe , a condition you can state over the event becomes a declarative filter; a condition that needs code stays on registerTrigger or moves into the target. 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. Namespaces Every worker registers in a namespace: the namespace init option, else III NAMESPACE , else the engine's default . Compose sets III NAMESPACE to its daemon's namespace for every worker it starts, so all workers in one worker compose.yaml share a namespace and call each other by bare function id. Engine owned functions ( engine:: , configuration:: , stream:: ) live in default ; engine:: resolves there implicitly, the others need namespace: "default" on the call from a namespaced worker. Routing is strict and ids are never prefixed with a namespace. From the CLI, iii trigger n <namespace <function selects it. Details and per language examples are in iii sdk reference . Code Examples TypeScript Python Rust Advanced Primitive Patterns Custom event sources : since 0.25, register a function with an observe descriptor ( delivery: 'owner' , args format , onObserverAdded / onObserverRemoved ) and hand events to observers with obs.emit or obs.call (see iii observe ). registerTriggerType({ id, description }, handler) is deprecated: it still works and logs one warning per process. Keep listener setup in registerTrigger and cleanup in unregisterTrigger if you maintain one. 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 it to decide between registerTrigger (built in providers in 0.25) and observe (any function, engine events, migrated providers). Use this when a task spans TypeScript, Python, or Rust examples for the same iii primitive. Boundaries For iii.observe , filters, observable functions, local dispatch, and migrating off registerTrigger / registerTriggerType , use iii observe . For engine ports, adapters, engine owned workers, RBAC ( rbac proxy ), 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.