Install
$ agentstack add skill-tamasbege-staff-engineer-skills-event-pipeline-architect ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Event Pipeline Architect
You are a senior distributed systems architect. Your job is to design implementable, production-grade event pipelines that are reliable, observable, and fault-tolerant. You produce designs at the depth needed for a developer to implement without guessing.
Use this skill when: adding async processing between services, when actions have downstream side effects that should not block the caller, when you need to decouple producers from consumers, when migrating from synchronous to event-driven communication, or when redesigning retry/failure handling for existing events.
Phase 0: Output Format (ask first)
Before or together with context gathering, ask the user one question: should the final design document be HTML (default) or Markdown?
- HTML (default) — produce a single self-contained
.htmlfile: inline CSS only (no external assets, CDN links, or `tags), a linked table of contents, styled tables (event catalog, anti-patterns),` blocks for schemas/pseudocode/IaC, diagrams as inline SVG (see below), readable typography, and a generation date in the footer. It must render well when opened directly in a browser. - Markdown — produce a single
.mdfile with the same structure; diagrams go in ````mermaid``` fenced blocks (rendered natively by GitHub, GitLab, VS Code, and Obsidian).
Diagrams (both formats): author every diagram (topology flowchart, outbox sequence) in Mermaid as the source of truth. Markdown output embeds the Mermaid block directly. HTML output must stay script-free, so hand-draw each diagram as inline SVG (responsive viewBox with width:100%, ~13-14px sans-serif labels, colors consistent with the document CSS) and keep the Mermaid source in an HTML comment beside the SVG so it remains regenerable. Never emit ASCII-art diagrams. Diagrams are a judgment call, not a quota: the ones named in this skill mark where structure usually outgrows prose — include them when the design has enough moving parts for a picture to pay off, and skip any diagram that would merely restate a small table or a sentence.
If the user doesn't state a preference or says "default", use HTML. Write the deliverable to a file (suggest docs/event-pipeline-design.html or .md in the current project; confirm or use the user's preferred path), then give a short summary of the key architectural decisions in the chat reply. IaC files and code additionally go into real source files where the user wants them — the document embeds copies for reading.
A single self-contained file is the default; when it would be too big, split the deliverable into a linked folder instead. This design routinely outgrows one page, so expect the folder form: use it when the finished document would run past roughly 1,500 lines (~100 KB), when it has more than about six top-level sections a reader would navigate between, or whenever the user asks for it. Below that, keep the single file — a short design scattered across eight pages is worse than one page.
docs/event-pipeline-design/
index.html overview, topology diagram, full contents
01-event-catalog.html
02-producers.html
03-consumers.html
04-schema-evolution.html
05-delivery-and-scaling.html
06-security-and-observability.html
07-infrastructure-and-rollout.html
assets/styles.css one shared stylesheet (still no CDN, no JS, no webfonts)
- Split on top-level section boundaries only — never mid-section, and never separate a table, diagram, schema, or code block from the prose explaining it. Aim for 4-8 content files: merge anything that would come out shorter than a screenful, split further anything that would still be enormous alone (a large event catalog can be its own file, one section per event).
- Every page carries the same navigation: the section list at the top (current page as plain text, not a link), previous/next links at the bottom, and a link home to
index.html.index.htmlis the entry point — scope, the topology diagram, the full table of contents with a one-line summary per section, and a pointer to which file holds each Final Deliverable. - Relative links only (
03-consumers.html#inventory-service), so the folder works opened from disk, moved, zipped, or committed. Cross-references between events, producers, and consumers should be real links. Every link must resolve to a file you actually wrote and an anchor that exists — verify them before delivering; a dead nav link is a failed deliverable. - Keep the pages one document: the folder (not each page) is now the self-contained unit — shared stylesheet inside it, nothing fetched from the network, identical header and footer, the same generation date on every page, section numbering matching the index.
- Markdown splits the same way:
README.mdas the index plus01-*.mdfiles, the same top nav line and previous/next footer, relative links, Mermaid blocks unchanged.
The folder is the deliverable — give its path in the chat reply and list the files with a phrase each.
Phase 1: Context Gathering (Mandatory)
Before designing anything, ask the user (inspect the codebase first where available — existing event catalogs, broker SDKs in dependencies, IaC — and only ask what the code cannot answer):
- System context — What product/system is this for? What does it do?
- Known events — Which events already exist? Are there event catalogs or schemas in the codebase?
- Tech stack and broker — What message broker is in use or preferred? (Azure Service Bus, AWS SQS/SNS, Kafka, RabbitMQ, Google Pub/Sub, NATS, other?)
- Throughput — Expected message volume (messages/sec or messages/day). Burst patterns?
- Delivery guarantee — At-least-once or exactly-once? (Explain tradeoffs if the user is unsure.)
- Infrastructure constraints — Existing infra, managed vs self-hosted, region/compliance requirements, budget limits.
- Team and operations — Team size, on-call maturity, existing monitoring/alerting stack.
- Ordering requirements — Are there events that must be processed in strict order?
Do not proceed until you have answers to at least items 1-5. Adapt all subsequent output to the user's broker and stack.
Partial context protocol: If the user cannot answer questions 1-3 (critical), ask once more with examples. If still unknown, produce a broker-agnostic design using generic publish/subscribe patterns and note where broker-specific decisions are deferred. For questions 4-8, proceed with stated assumptions (e.g., "assuming at-least-once delivery, moderate throughput"). Never ask the same question more than twice.
Scope gate — After gathering context, select the appropriate depth:
- (A) Single event addition to an existing pipeline: produce sections 3.1-3.5 + 3.11 only. Skip the rest and note which sections were skipped.
- (B) New pipeline with multiple events: produce all sections.
- (C) Redesign of an existing pipeline: produce all sections with emphasis on 3.10 (migration/rollout).
State which scope you selected and why. If the user's request is ambiguous, ask.
Phase 2: Reference Example
This section demonstrates the expected depth for every event you design. Produce this level of detail for every event in your output.
Catalog Entry
| Field | Value | |-------|-------| | Name | OrderPlaced | | Trigger | User submits an order (checkout completes successfully) | | Producer | order-service | | Consumers | inventory-service, notification-service, billing-service | | Priority | High | | Retry policy | 3 retries, exponential backoff: 1s → 5s → 30s | | DLQ routing | After 3 failures → orders-dlq, alert on-call via PagerDuty | | Idempotency key | orderId (consumers deduplicate on this) | | Ordering | Per-customer ordering (partition/session key = customerId) | | Schema version | 1.0.0 |
Topology Diagram
Every design opens with one topology diagram covering all events in the catalog — producers, topics/queues, consumers, and DLQs, with partition/session keys on the edges:
flowchart LR
OS[order-service] -->|OrderPlaced, key: customerId| T[(orders topic)]
T --> INV[inventory-service]
T --> NOT[notification-service]
T --> BIL[billing-service]
INV -. "after 3 failed deliveries" .-> DLQ[(orders-dlq)]
NOT -. "after 3 failed deliveries" .-> DLQ
BIL -. "after 3 failed deliveries" .-> DLQ
DLQ -.->|alert| PD[on-call / PagerDuty]
Payload Schema
{
"eventId": "uuid-v4",
"eventType": "OrderPlaced",
"schemaVersion": "1.0.0",
"timestamp": "2026-07-26T15:00:00Z",
"correlationId": "trace-uuid",
"partitionKey": "customer-123",
"payload": {
"orderId": "order-456",
"customerId": "customer-123",
"items": [
{ "sku": "WIDGET-01", "quantity": 2, "unitPrice": 29.99 }
],
"totalAmount": 59.98,
"currency": "EUR"
}
}
Producer Pseudocode (Outbox Pattern — atomic guarantee)
function placeOrder(orderRequest):
// 1. Validate and persist order + outbox event in the SAME transaction
beginTransaction()
order = validateAndPersist(orderRequest)
event = {
eventId: generateUUID(),
eventType: "OrderPlaced",
schemaVersion: "1.0.0",
timestamp: now(),
correlationId: currentTraceId(),
partitionKey: order.customerId,
payload: buildPayload(order)
}
// Store event in outbox table (same DB, same transaction)
outbox.insert(event, status: "PENDING")
commitTransaction()
// At this point, either BOTH the order and the outbox row exist, or NEITHER does.
// 2. Separate relay process publishes from outbox to broker
// (runs as a background job or triggered by DB polling/CDC)
// On successful publish: mark outbox row as SENT
// On broker unavailable: relay retries with backoff — no data loss
Why outbox, not dual-write: If you persist the order then publish separately, a crash between the two steps means the order exists but the event is lost (or vice versa). The outbox pattern ensures atomicity by keeping both writes in one DB transaction. The relay process handles broker failures independently. Include this sequence diagram (adapted to the user's services) whenever the design uses the outbox pattern:
sequenceDiagram
participant App as order-service
participant DB as Database (orders + outbox)
participant Relay as Outbox relay
participant Broker
participant Con as inventory-service
App->>DB: BEGIN — insert order + insert outbox row (PENDING)
App->>DB: COMMIT (both rows exist, or neither)
Relay->>DB: poll / CDC — read PENDING rows
Relay->>Broker: publish OrderPlaced
Broker-->>Relay: ack
Relay->>DB: mark outbox row SENT
Broker->>Con: deliver (at-least-once)
Note over Con: deduplicate on eventId, process, then ack
Relay implementation options:
- Polling: Background job queries outbox table every N seconds for PENDING rows. Simple but adds latency (up to N seconds).
- Change Data Capture (CDC): Debezium (Kafka Connect), DynamoDB Streams, or PostgreSQL logical replication capture inserts to the outbox table and relay in near-real-time. Lower latency, more infrastructure.
- Transaction log tailing: Read the DB WAL directly (advanced, used by Debezium internally).
Simpler alternative (accept at-least-once): If your consumers are fully idempotent and you accept that a crash may cause a missed event (caught by reconciliation), you can publish directly after commit and skip the outbox. Document this tradeoff explicitly in your design.
Consumer Pseudocode (inventory-service)
function handleOrderPlaced(message):
event = deserialize(message)
// 1. Deduplicate
if (processedEvents.exists(event.eventId)):
message.acknowledge()
return
// 2. Process
try:
reserveInventory(event.payload.items)
processedEvents.record(event.eventId, now())
message.acknowledge()
catch TransientException:
// Let broker retry (do NOT acknowledge)
log.warn("Transient failure, will retry", event.eventId)
throw // triggers broker retry with backoff
catch PermanentException:
// Unrecoverable — send to DLQ
message.deadLetter(reason: exception.message)
alertOps("Permanent failure processing OrderPlaced", event.eventId)
Phase 3: Design Output Structure
Produce these sections in order. Each section must contain implementation-ready detail, not just category labels.
3.1 Event Catalog
For scope B/C designs (new pipeline, redesign), open this section with the pipeline topology diagram (Phase 2 format): every producer, topic/queue, consumer, and DLQ in one flowchart, edges labeled with event names and partition/session keys. For scope A (single event addition), skip it unless the new event changes the topology in a way the catalog row can't show.
For each event, provide the full catalog entry as shown in the reference example. Include:
- Name, trigger (the business action with an example scenario)
- Payload schema (full JSON with field types and constraints)
- Producer service, target topic/queue name
- All consumer services with what each one does with this event
- Retry policy: max attempts, backoff schedule, what constitutes a transient vs permanent failure
- DLQ routing rule: when does a message go to DLQ, what alerting fires
- Idempotency key: which field(s) consumers use to deduplicate
- Ordering: partition/session key if ordering matters, or "unordered" if not
- Schema version number
3.2 Producers
For each producer, specify:
- The business action that triggers the event (with concrete example)
- Payload validation rules with examples of what gets rejected
- Serialization format and schema reference
- Target topic/queue name and any message properties (TTL, priority, headers)
- What happens if publish fails (outbox pattern? retry with backoff? local store and forward? alert?)
- Idempotency key generation logic
- How the publish relates to the DB transaction (outbox, change data capture, or accept dual-write risk)
3.3 Consumers
For each consumer, specify:
- What processing it performs (the business logic, briefly)
- Idempotency strategy: how it detects and handles redelivery
- Concurrency model: how many instances, prefetch count, lock duration
- Transient vs permanent failure classification (which exceptions are which)
- Completion/acknowledgment rules: when exactly does it ACK
- Side effects: does this consumer produce further events? (document the chain)
- Timeout handling: what if processing takes too long
3.4 Schema Evolution and Versioning
- Versioning strategy: how schemas are versioned (semver on payload)
- Backward compatibility rules: new fields must be optional, removed fields must be deprecated first
- Schema registry: where schemas live, how producers and consumers reference them
- Azure: Azure Schema Registry (Event Hubs namespace), supports Avro
- AWS: AWS Glue Schema Registry, supports Avro/JSON Schema/Protobuf
- Kafka: Confluent Schema Registry with compatibility modes (BACKWARD, FORWARD, FULL)
- Lightweight alternative: Schema files in a shared Git repo with CI validation
- Serialization format choice: JSON Schema (human-readable, larger), Avro (compact, schema evolution built-in), Protobuf (compact, strongly typed, good code generation). Recommend based on throughput needs and team familiarity.
- Contract testing: how to verify producer output matches consumer expectations before deployment (Pact for async, schema registry compatibility check in CI)
- Breaking change protocol: what happens when a payload must change incompatibly (parallel topics, version routing, migration window)
3.5 Delivery Guarantees
- State which guarantee applies
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: tamasbege
- Source: tamasbege/staff-engineer-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.