Skip to content
Back to skills

Creating Workers

ASecurity

... async def unregister_trigger(self, config: TriggerConfig) -> None: ... webhook = worker.register_trigger_type( RegisterTriggerTypeInput(id="webhook", description="Incoming webhook trigger"), WebhookHandler(), ) ``` </Tab> <Tab title="Rust"> ```rust use iii_sdk::{ InitOptions, RegisterTriggerType, TriggerConfig, TriggerHandler, register_worker, }; let url = std::env::var("III_URL").expect("III_URL must be set"); let worker = register_worker(&url, InitOptions::default()); struct WebhookHand...

  • 18,821 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 3, 2026
developmenttypescriptpythonrustgonodeapi

Works with

  • api

Security analysis

A100/100

Pro scans all 9 files and shows the line behind each finding

Scanned September 3, 2026

npx -y skills add iii-hq/iii --skill creating-workers --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Creating Workers?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Creating Workers
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/iii-hq-creating-workers-2c4a5fbc/badge)](https://www.skillsdirectory.com/skills/iii-hq-creating-workers-2c4a5fbc)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
<!-- generated by iii-skill-render. DO NOT EDIT (changes here are overwritten on the next render). Edit docs/0-13-0/creating-workers/triggers.mdx. -->


## What "writing a trigger" means

Workers don't only call functions; they can also _source_ events. When a worker advertises a
trigger type (e.g. `webhook`, a custom schedule, or any external event source you implement), any
other worker can bind its functions to that type. The engine routes binding requests to your
trigger type's handler, and your worker invokes the bound functions when the underlying event
fires.

This page is about authoring new trigger types from inside your worker. For invoking functions and
binding triggers to functions from the consumer side, see [Using iii / Triggers](../using-iii/triggers).

## Declare a trigger type

Inside the worker, register the trigger type once during startup. You pass an `id` and
`description` plus a handler with `registerTrigger` / `unregisterTrigger` callbacks. The engine
calls these whenever a consumer binds or unbinds a function against your trigger type, so your
worker can keep its own table of `{ trigger id → function id, config }` bindings.

`registerTriggerType` returns a typed handle. Use it later to bind functions you own to this
trigger type, or to tear the type down.

<Tabs>
  <Tab title="Node / TypeScript">
    ```typescript
    import { registerWorker } from "iii-sdk";
    import type { TriggerConfig, TriggerHandler } from "iii-sdk";

    const worker = registerWorker(process.env.III_URL);

    type WebhookTriggerConfig = {
      path: string;
      secret?: string;
    };

    const webhookHandler: TriggerHandler<WebhookTriggerConfig> = {
      async registerTrigger(config: TriggerConfig<WebhookTriggerConfig>) {
        // Stash { config.id, config.function_id, config.config } so the
        // worker's HTTP listener knows which function to invoke when a
        // request matches `config.config.path`.
      },
      async unregisterTrigger(config: TriggerConfig<WebhookTriggerConfig>) {
        // Remove the binding from the worker's table.
      },
    };

    const webhook = worker.registerTriggerType(
      { id: "webhook", description: "Incoming webhook trigger" },
      webhookHandler,
    );
    ```
  </Tab>
  <Tab title="Python">
    ```python
    import os
    from iii import (
        InitOptions,
        RegisterTriggerTypeInput,
        TriggerConfig,
        TriggerHandler,
        register_worker,
    )

    worker = register_worker(
        os.environ.get("III_URL"),
        InitOptions(worker_name="webhook-worker"),
    )

    class WebhookHandler(TriggerHandler):
        async def register_trigger(self, config: TriggerConfig) -> None:
            # Stash config.id, config.function_id, config.config
            ...

        async def unregister_trigger(self, config: TriggerConfig) -> None:
            ...

    webhook = worker.register_trigger_type(
        RegisterTriggerTypeInput(id="webhook", description="Incoming webhook trigger"),
        WebhookHandler(),
    )
    ```
  </Tab>
  <Tab title="Rust">
    ```rust
    use iii_sdk::{
        InitOptions, RegisterTriggerType, TriggerConfig, TriggerHandler, register_worker,
    };

    let url = std::env::var("III_URL").expect("III_URL must be set");
    let worker = register_worker(&url, InitOptions::default());

    struct WebhookHandler;

    #[async_trait::async_trait]
    impl TriggerHandler for WebhookHandler {
        async fn register_trigger(&self, config: TriggerConfig) -> Result<(), iii_sdk::IIIError> {
            // Stash config.id, config.function_id, config.config
            Ok(())
        }

        async fn unregister_trigger(&self, config: TriggerConfig) -> Result<(), iii_sdk::IIIError> {
            Ok(())
        }
    }

    let webhook = worker.register_trigger_type(
        RegisterTriggerType::new("webhook", "Incoming webhook trigger", WebhookHandler),
    );
    ```
  </Tab>
</Tabs>

For typed `config` and call-payload schemas, attach Pydantic, Zod, or `schemars::JsonSchema` types
to the registration in your language of choice. See each SDK's reference for the exact builder.

## Dispatch events to bound functions

There is no special "fire" API. When the underlying event source delivers something (an incoming
HTTP request, a cron tick, a webhook hit), your worker looks up the bindings it stashed in its
`registerTrigger` callback and invokes each bound function via `worker.trigger(...)`.

<Tabs>
  <Tab title="Node / TypeScript">
    ```typescript
    // Inside the worker's HTTP listener, after matching a request to a binding:
    await worker.trigger({
      function_id: binding.function_id,
      payload: { method, headers, body },
    });
    ```
  </Tab>
  <Tab title="Python">
    ```python
    # Inside the worker's HTTP listener, after matching a request to a binding:
    worker.trigger({
        "function_id": binding["function_id"],
        "payload": {"method": method, "headers": headers, "body": body},
    })
    ```
  </Tab>
  <Tab title="Rust">
    ```rust
    use iii_sdk::TriggerRequest;
    use serde_json::json;

    // Inside the worker's HTTP listener, after matching a request to a binding:
    worker
        .trigger(TriggerRequest {
            function_id: binding.function_id.clone(),
            payload: json!({ "method": method, "headers": headers, "body": body }),
            action: None,
            timeout_ms: None,
        })
        .await?;
    ```
  </Tab>
</Tabs>

On each dispatched event, the engine evaluates the consumer's `config` and optional
`condition_function_id`, then routes matching invocations to the bound function and returns the
result to the caller.

## Unregister a trigger type

`registerTriggerType` returns a handle with an `unregister()` method that tears down the trigger
type at runtime. When the worker disconnects, all trigger types it advertised are removed
automatically and the engine stops routing events that depended on them.

<Tabs>
  <Tab title="Node / TypeScript">
    ```typescript
    webhook.unregister();
    ```
  </Tab>
  <Tab title="Python">
    ```python
    worker.unregister_trigger_type(
        RegisterTriggerTypeInput(id="webhook", description="Incoming webhook trigger"),
    )
    ```
  </Tab>
  <Tab title="Rust">
    ```rust
    worker.unregister_trigger_type("webhook");
    ```
  </Tab>
</Tabs>

## What goes in Worker Docs

The trigger type _id_, the shape of the `config` consumers pass when binding, the call-payload
shape your worker delivers to bound functions, the event ordering guarantees, and any
back-pressure or retry semantics belong in this worker's Worker Docs so consumers know what to
pass when they call `registerTrigger`. Keep iii-level concepts (the trigger binding model itself,
condition gates) here; document the per-type specifics there.

Files in this skill

  • functions.mdx6.1 KB
  • functions.mdx.skill.md6.1 KB
  • triggers.mdx6.7 KB
  • triggers.mdx.skill.md6.7 KB
  • workers-registry.mdx6.1 KB
  • workers-registry.mdx.skill.md6.1 KB
  • workers.mdx5.6 KB
  • workers.mdx.skill.md5.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…