pubsub

The pubsub worker is topic-based publish/subscribe messaging. Publish an event to a named topic with the publish function and every registered subscribe trigger whose topic matches is invoked with the raw payload — no envelope, no persistence, no retries. It is fire-and-forget broadcast: subscribers…

iii-hq/workers3 installsApache-2.0Synced Aug 26

Tech stack

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI

Agent Skills format with YAML frontmatter. Claude Code reads it as-is.

---
name: "pubsub"
description: "The pubsub worker is topic-based publish/subscribe messaging. Publish an event to a named topic with the publish function and every registered subscribe trigger whose topic matches is invoked with the raw payload — no envelope, no persistence, no retries. It is fire-and-forget broadcast: subscribers…"
license: "Apache-2.0"
---

# pubsub

The `pubsub` worker is topic-based publish/subscribe messaging. Publish an event to a named topic with the `publish` function and every registered `subscribe` trigger whose `topic` matches is invoked with the raw payload — no envelope, no persistence, no retries. It is fire-and-forget broadcast: subscribers receive each event as it arrives, and a subscriber that is offline simply misses it.

Install it with `iii worker add pubsub`. It replaces the former built-in `iii-pubsub` worker: the trigger type (`subscribe`) and the function id (`publish`) are unchanged, so existing application code keeps working — only the owner moved from an in-process builtin to this standalone worker.

The worker exposes one callable function (`publish`, registered with the bare function id `"publish"` — no namespace prefix) and one trigger type (`subscribe`). Two adapters: `local` (default; in-memory broadcast; only delivers to subscribers in this engine process; no external dependency) and `redis` (`redis_url: ${REDIS_URL:redis://localhost:6379}`; uses Redis Pub/Sub so events propagate across multiple engine instances). The adapter is set in the `pubsub` configuration entry and hot-swaps at runtime.

## When to Use

- Real-time notifications consumers may miss without consequence — UI live updates, ephemeral signals, telemetry mirroring.
- Loose coupling where an event source should not know about its consumers.
- Cross-instance fan-out of ephemeral events (configure the `redis` adapter).

## Boundaries

- No persistence, ordering, or retries — a subscriber that is down misses events permanently. Use the `queue` worker (topic mode, `durable:subscriber`) when every consumer must process every event.
- Topic matching is exact string equality; there are no wildcards or hierarchical patterns. Register one trigger per topic.
- An empty topic is rejected: `publish` returns `topic_not_set`, and a `subscribe` trigger registered with an empty topic never fires.
- For key/value or stream change reactivity, use the `state` or `stream` worker instead — `pubsub` carries discrete events, not state.

## Functions

- `publish` — broadcast an event to a topic; every `subscribe` trigger on that exact topic receives the raw `data`. Empty topic returns `topic_not_set`.

## Reactive triggers

Bind a `subscribe` trigger when a function should run every time `publish` broadcasts to a configured topic. The handler receives the raw `data` value from the publish call directly — no envelope. Multiple triggers can subscribe to the same topic; each gets an independent copy (true fan-out).

Reach for it when:

- A domain event from one part of the system should kick off side effects elsewhere without the publisher knowing the consumers.
- You want cross-instance fan-out via the `redis` adapter.

If subscribers must reliably process every event with retries and dead-letter handling, use the `queue` worker's `durable:subscriber` instead — `subscribe` is fire-and-forget.

### How to bind

1. Register a handler: `iii.registerFunction('notifications::on-order-shipped', handler)`.
2. Register the trigger:

```typescript
iii.registerTrigger({
  type: 'subscribe',
  function_id: 'notifications::on-order-shipped',
  config: {
    topic: 'orders.shipped',  // required, non-empty. Exact match only — no wildcards.
  },
})
```

The handler receives the published `data` unchanged, with no `topic` field; if one handler serves multiple topics, embed the topic inside `data` at publish time. The handler's return value is ignored and there is no retry.

For the published payload shape, call `iii get function info` on `publish` or the handler function id.

More General & Other skills

← All General & Other skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY