Iii iii-event-driven-cqrs
install
source · Clone the upstream repo
git clone https://github.com/iii-hq/iii
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/iii-hq/iii "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/iii-event-driven-cqrs" ~/.claude/skills/iii-hq-iii-iii-event-driven-cqrs && rm -rf "$T"
manifest:
skills/iii-event-driven-cqrs/SKILL.mdsource content
Event-Driven CQRS & Event Sourcing
Comparable to: Kafka, RabbitMQ, CQRS/Event Sourcing systems
Key Concepts
Use the concepts below when they fit the task. Not every CQRS system needs all of them.
- Write side: Commands validate input and publish domain events via pubsub
- Read side: Multiple projections subscribe to events independently, building query-optimized views in state
- Event log: Events are appended to state as an ordered log (event sourcing)
- PubSub handles fan-out — one event reaches all projections and downstream consumers
- HTTP triggers expose both command endpoints (POST) and query endpoints (GET)
Architecture
HTTP POST /inventory (command) → cmd::add-inventory-item → validate → append event to state → publish('inventory.item-added') ↓ (fan-out via subscribe triggers) → proj::inventory-list (updates queryable list view) → proj::inventory-stats (updates aggregate counters) → notify::inventory-alert (sends low-stock alerts) HTTP GET /inventory (query) → query::list-inventory → reads from projection state
iii Primitives Used
| Primitive | Purpose |
|---|---|
| Initialize the worker and connect to iii |
| Define commands, projections, and queries |
trigger , , | Event log and projection state |
| Publish domain events |
| Subscribe projections to events |
| Command and query endpoints |
| Fire-and-forget notifications |
Reference Implementation
See ../references/event-driven-cqrs.js for the full working example — an inventory management system with commands that publish domain events and multiple projections building query-optimized views.
Common Patterns
Code using this pattern commonly includes, when relevant:
— worker initializationregisterWorker(url, { workerName })
— event log appendtrigger({ function_id: 'state::set', payload: { scope: 'events', key, value } })
— domain event publishingtrigger({ function_id: 'publish', payload: { topic, data } })
— projection subscriptionsregisterTrigger({ type: 'subscribe', function_id, config: { topic } })- Command functions with
prefix, projection functions withcmd::
prefix, query functions withproj::
prefixquery:: - Multiple projections subscribing to the same topic independently
— structured logging per command/projectionconst logger = new Logger()
Adapting This Pattern
Use the adaptations below when they apply to the task.
- Add new projections by registering subscribe triggers on existing event topics
- Use separate state scopes for each projection (e.g.
,inventory-list
)inventory-stats - Commands should validate before publishing — reject invalid commands early
- For critical event processing, use
instead of pubsub for guaranteed deliveryTriggerAction.Enqueue({ queue }) - Event IDs should be unique and monotonic for ordering (e.g.
)evt-${Date.now()}-${counter}
Pattern Boundaries
- If the task is about simple CRUD with reactive side effects, prefer
.iii-reactive-backend - If the task needs durable multi-step pipelines with retries, prefer
.iii-workflow-orchestration - Stay with
when command/query separation, event sourcing, and independent projections are the primary concerns.iii-event-driven-cqrs
When to Use
- Use this skill when the task is primarily about
in the iii engine.iii-event-driven-cqrs - Triggers when the request directly asks for this pattern or an equivalent implementation.
Boundaries
- Never use this skill as a generic fallback for unrelated tasks.
- You must not apply this skill when a more specific iii skill is a better fit.
- Always verify environment and safety constraints before applying examples from this skill.