Help us improve
Share bugs, ideas, or general feedback.
From tools
Build cross-language backends with the iii engine. Register functions in TypeScript, Python, or Rust callable from any connected service via WebSocket. Covers iii-sdk, state, KV Server, streams, triggers (HTTP/cron/queue/log), Bridge Client mesh, OpenTelemetry, Docker deployment, iii Console, and Prometheus metrics. Use when: setting up iii engine, cross-language function calls, iii-sdk integration, registerTrigger configuration, KV Server storage, queue/log triggers, Docker deploy, or debugging "ECONNREFUSED 49134", "type_not_found", "@iii-dev/sdk 404".
npx claudepluginhub evolv3-ai/vibe-skillsHow this skill is triggered — by the user, by Claude, or both
Slash command
/tools:iiiThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> **SDK 0.3.0-alpha Breaking Change (verified 2026-02-18)**: The `registerTrigger` field is `trigger_type` (NOT `type`). HTTP triggers use `trigger_type: "api"` (NOT `"http"`). Using `type: "http"` causes silent 404s on all routes. This was confirmed in the tac-4-go rewrite from motia to direct iii-sdk.
Provides expert guidance on Inngest for serverless background jobs, event-driven workflows, and durable execution with step functions, scheduling, and fan-out patterns.
Builds, deploys, and debugs CloudBase Event Functions and HTTP Functions. Use when creating application runtime code or function triggers on CloudBase.
Builds production-grade backend code for API endpoints, server logic, webhooks, queues, and integrations with error handling, logging, validation, and reliability.
Share bugs, ideas, or general feedback.
SDK 0.3.0-alpha Breaking Change (verified 2026-02-18): The
registerTriggerfield istrigger_type(NOTtype). HTTP triggers usetrigger_type: "api"(NOT"http"). Usingtype: "http"causes silent 404s on all routes. This was confirmed in the tac-4-go rewrite from motia to direct iii-sdk.
SDK Note: The iii.dev docs reference
@iii-dev/sdkwith aBridgeclass — this package does not exist on npm (404 as of 2026-02-17). Always installiii-sdk(no scope). The docs SDK uses different conventions (dot separators,trigger_type,function_path). Seereferences/cross-language.mdfor translation guide.
iii has two fundamental primitives:
Services connect to the iii engine over WebSocket. The engine handles routing, retries, observability, state, streams, cron, and HTTP API exposure.
curl -fsSL https://install.iii.dev/iii/main/install.sh | sh
iii --version
Or run via Docker:
docker pull iiidev/iii:latest
docker run -p 3111:3111 -p 49134:49134 \
-v ./iii-config.yaml:/app/config.yaml:ro \
iiidev/iii:latest
iii-config.yaml)modules:
- class: modules::api::RestApiModule
config:
port: 3111
host: 127.0.0.1
default_timeout: 30000
concurrency_request_limit: 1024
cors:
allowed_origins: ["*"]
allowed_methods: [GET, POST, PUT, DELETE, OPTIONS]
- class: modules::state::StateModule
config:
adapter:
class: modules::state::adapters::KvStore
config:
store_method: file_based
file_path: ./data/state_store.db
- class: modules::shell::ExecModule
config:
exec:
- bun run --enable-source-maps worker.js
See
references/engine-modules.mdfor full module configuration including StreamModule, OtelModule, QueueModule, PubSubModule, CronModule, KvServer, LoggingModule, and BridgeClientModule.
iii -c iii-config.yaml
mkdir my-service && cd my-service
npm init -y
npm install iii-sdk
Set "type": "module" in package.json.
// src/worker.ts
import { init, getContext } from "iii-sdk";
const { registerFunction, registerTrigger, call, callVoid } = init(
process.env.III_BRIDGE_URL ?? "ws://localhost:49134"
);
// Register a function callable by any connected service
const health = registerFunction({ id: "my-service::health" }, async () => {
const { logger } = getContext();
logger.info("Health check OK");
return { status: 200, body: { healthy: true, timestamp: Date.now() } };
});
// Expose as HTTP endpoint via the engine's REST API module
registerTrigger({
trigger_type: "api",
function_id: health.id,
config: { api_path: "health", http_method: "GET" },
});
console.log("Service started - listening for calls");
Run with: npx tsx src/worker.ts
Test: curl http://localhost:3111/health
service-name::function-name convention for function IDs (e.g., "client::health", "data-service::transform")"type": "module" in package.json (SDK uses ESM)process.env.III_BRIDGE_URL ?? "ws://localhost:49134" for the engine addressgetContext() for logging inside function handlers (provides structured OTEL logging)Promise.allSettled() when calling multiple remote functions in parallel (graceful partial failure)GET /health on port 3111 to check engine health before connecting servicesindex (not scope) for KV Server function parameters — scope is for the State module onlyws://localhost:49134 without env var fallbackprocess.env in function IDs (they must be static strings)"*/30 * * * * * *"trigger_type (NOT type) in registerTrigger. Use "api" (NOT "http") for HTTP triggers. Use "queue" for queue triggers, "cron" for cron triggerstype (NOT trigger_type). Use "http" for HTTP triggersiii-sdk/state or iii-sdk/stream for basic state operations - use sdk.call("state::set", ...) instead. Removed in 0.3.0npm install @iii-dev/sdk — this scoped package does not exist on npm (404). Use iii-sdk instead:: (double colon). "kv_server::get" not "kv_server.get"| Import | Purpose |
|---|---|
iii-sdk | Core: init, getContext, withContext, Logger (+ types). init() returns ISdk with registerFunction, registerTrigger, call, callVoid, shutdown methods |
iii-sdk/state | Advanced: Direct IState interface (get/set/delete/list/update) |
iii-sdk/stream | Advanced: Direct IStream interface with groups |
iii-sdk/telemetry | OpenTelemetry: initOtel, withSpan, getTracer, getMeter |
For most use cases, use the core SDK and call("state::set", ...) / call("state::get", ...) for state.
const fn = registerFunction(
{
id: "service::action", // Required: unique function ID
description: "What it does", // Optional: for discovery
request_format: { /* schema */ }, // Optional: input schema
response_format: { /* schema */ }, // Optional: output schema
metadata: { version: "1.0" }, // Optional: custom metadata
},
async (payload) => {
const { logger } = getContext();
logger.info("Processing", { payload });
return { result: "done" }; // Return value sent back to caller
}
);
// fn.id = "service::action"
// fn.unregister() - removes the function
// Awaitable call (returns result)
const result = await call<InputType, OutputType>("other-service::action", { data: "hello" });
// Fire-and-forget (no return value)
callVoid("log-service::audit", { event: "user_login" });
// Parallel calls with graceful failure
const [a, b] = await Promise.allSettled([
call("service-a::process", payload),
call("service-b::process", payload),
]);
// State management (uses 'scope')
await call("state::set", { scope: "shared", key: "VERSION", value: 1 });
const val = await call("state::get", { scope: "shared", key: "VERSION" });
const items = await call("state::list", { scope: "shared" });
// KV Server (uses 'index' — NOT 'scope')
await call("kv_server::set", { index: "default", key: "user:123", value: { name: "Alice" } });
const user = await call("kv_server::get", { index: "default", key: "user:123" });
await call("kv_server::delete", { index: "default", key: "user:123" });
const keys = await call("kv_server::list_keys_with_prefix", { prefix: "user:" });
// Queue — enqueue a message to a topic
await call("enqueue", { topic: "user.created", data: { id: "123", email: "user@example.com" } });
// Engine introspection
const functions = await call("engine::functions::list", {});
const workers = await call("engine::workers::list", {});
// Health check (HTTP, not via SDK)
// curl http://localhost:3111/health
// Graceful shutdown (new in 0.2.0)
await sdk.shutdown(); // Closes WebSocket, cleans up resources
Note:
shutdown()was added in 0.2.0. Always call it during graceful process termination.
Exposes a function as an HTTP endpoint on the engine's REST API (default port 3111).
// iii-sdk 0.3.0-alpha (current working — use this)
registerTrigger({
trigger_type: "api",
function_id: "service::handler",
config: {
api_path: "users/:id", // Path params supported
http_method: "POST", // GET, POST, PUT, DELETE, OPTIONS
},
});
// Accessible at: http://localhost:3111/users/123
Warning: Using
type: "http"(0.2.0 syntax) with iii engine 0.4.0+ causes silent 404s on all routes. Always usetrigger_type: "api"with 0.3.0-alpha SDK.
The handler receives an ApiRequest object:
registerFunction({ id: "service::handler" }, async (req: ApiRequest) => {
const { path_params, query_params, body, headers, method } = req;
return {
status_code: 200,
headers: { "Content-Type": "application/json" },
body: { id: path_params.id, data: body },
};
});
Supports 7-field cron expressions (seconds granularity):
registerTrigger({
trigger_type: "cron",
function_id: "service::cleanup",
config: { expression: "*/30 * * * * * *" }, // Every 30 seconds
});
// Fields: seconds minutes hours day-of-month month day-of-week year
Invokes a function when a message is enqueued to a specific topic. Requires QueueModule in engine config.
const consumer = registerFunction(
{ id: "events::on-user-created" },
async (data) => {
console.log("User created", data);
return { ok: true };
}
);
registerTrigger({
trigger_type: "queue",
function_id: consumer.id,
config: { topic: "user.created" },
});
// Enqueue from anywhere:
await call("enqueue", { topic: "user.created", data: { id: "123", email: "user@example.com" } });
Invokes a function when log events match a level. Requires LoggingModule in engine config.
registerFunction({ id: "monitoring::on-error" }, async (logEntry) => {
// logEntry: { trace_id, message, level, function_name, date }
const { logger } = getContext();
logger.info("Error captured", logEntry);
// Send alert, store in database, etc.
});
registerTrigger({
trigger_type: "log",
function_id: "monitoring::on-error",
config: { level: "error" }, // Optional: info, warn, error, debug (omit for all)
});
| Need | File |
|---|---|
| Full SDK type definitions and state/stream APIs | references/api-reference.md |
| Engine module configuration schemas | references/engine-modules.md |
| Cross-language examples, OpenTelemetry, env vars | references/cross-language.md |
| Docker deployment and project structure | references/docker-deployment.md |
host.docker.internal requires explicit extra_hosts mappingimport and require now workThese are current reality with iii-sdk@0.3.0-alpha.20260210122502 + iii engine 0.4.0:
trigger_type replaces type in registerTrigger — use trigger_type: "api" (NOT type: "http")"api" replaces "http" as the HTTP trigger type nameiii-sdk/state export removed — use call("state::set", ...) and call("state::get", ...)iii-sdk/stream renamed to iii-sdk/streams (plural)ISdk type no longer exported from the main entry point@iii-dev/sdk (Bridge class, dot separators) may become the official SDK. Monitor npm for @iii-dev/sdk availabilityVerified: tac-4-go project uses direct iii-sdk 0.3.0-alpha with
trigger_type: "api"and all 4 HTTP endpoints + queue + cron work correctly.
| Error | Cause | Fix |
|---|---|---|
ECONNREFUSED 127.0.0.1:49134 | Engine not running | Start with iii -c iii-config.yaml |
| Function call times out (30s) | Target service not connected | Start the service; check engine::workers::list |
Cannot find module 'iii-sdk' | SDK not installed | npm install iii-sdk |
| HTTP endpoint returns 404 | Wrong trigger field or type | With 0.3.0-alpha: use trigger_type: "api" (NOT type: "http"). Verify api_path matches URL |
| Cron not firing | Wrong expression format | Use 7-field format: sec min hour dom mon dow year |
| State returns null | Wrong scope or key | Check scope/key strings match exactly |
trigger_type_not_found | SDK/engine version mismatch | 0.2.0: use type. 0.3.0-alpha: use trigger_type |
| All routes 404 (silent) | Used type: "http" with 0.3.0-alpha SDK | Change to trigger_type: "api" — motia sends "http", iii engine 0.4.0 expects "api" |
| KV Server timeout | KV Server module not in config | Add modules::kv_server::KvServer to iii-config.yaml |
module class not found | Wrong singular/plural path | Try stream vs streams in class path; check engine version |
@iii-dev/sdk npm 404 | Package not published | Use iii-sdk (no scope). @iii-dev/sdk is docs-only |
| Queue messages not processing | Missing queue trigger or wrong topic | Verify registerTrigger({ type: "queue", config: { topic } }) matches enqueue topic |