AWS EventBridge skill for Codex
Event routing with tested patterns and no lost events. Codex sets one event envelope for a bus, writes rule patterns with prefix, anything-but and numeric operators, and tests each against matching and non-matching sample events. Every target gets a tuned retry policy and an alarmed DLQ, cron jobs move to EventBridge Scheduler with explicit time zones, glue Lambdas become Pipes, and replays run only with filters and confirmation.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- aws-eventbridge Installs to ~/.agents/skills/aws-eventbridge/ for every project on this machine.
curl -fsSL codexskills.dev/cli.mjs -o codex-skills.mjsnode codex-skills.mjs install aws-eventbridge The CLI also searches, updates and removes skills. Run it with no arguments to pick from a list. Needs Node 20.12+.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- --project aws-eventbridge Installs to .agents/skills/aws-eventbridge/ in the current repository. Commit it and everyone who runs Codex there gets it.
curl -fsSLO codexskills.dev/downloads/aws-eventbridge.zipunzip -o aws-eventbridge.zip -d ~/.agents/skills/ The archive holds the skill folder with its generated agents/openai.yaml. Unzip into .agents/skills/ to scope it to a repo.
& ([scriptblock]::Create((irm codexskills.dev/install.ps1))) aws-eventbridge PowerShell 5.1 or 7. Installs to %USERPROFILE%\.agents\skills\. Add -Project for the current repo.
104-line POSIX script. No sudo, no telemetry. Read install.sh
Use it in Codex
Start a prompt with $aws-eventbridge, or pick it from /skills.
You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.
What Codex reads before loading it
Designs Amazon EventBridge integrations - custom event buses and event envelope conventions, rule event patterns (prefix, anything-but, numeric, exists, wildcard, $or), target retry policies and DLQs, input transformers, archive and replay, cross-account buses, EventBridge Scheduler for cron and one-off schedules, and EventBridge Pipes from SQS, Kinesis or DynamoDB Streams. Use when publishing domain events between services, a rule does not match or fires twice, replacing cron jobs or CloudWatch scheduled rules, reacting to AWS service events, or wiring a stream to a target without glue Lambdas.
Use it when
- Publishing domain events between services or accounts
- A rule does not match, fires twice or loops
- Moving cron jobs or one-off delayed actions to managed schedules
- Connecting SQS, Kinesis or DynamoDB Streams to a target without custom code
Use something else when
- You need a plain work queue or SNS fan-out: use aws-sqs-sns
- The flow is a multi-step workflow with state and compensation: use aws-step-functions
How to check the result
test-event-pattern passes for matching and non-matching samples, MatchedEvents and Invocations rise for a dev test event, and a forced target failure lands in the DLQ.
The mistake it prevents
A rule whose target emits events that match the same rule, creating an infinite loop that bills every iteration.
Done well means: events follow one documented envelope, each rule’s pattern is tested against real sample events, every target has a retry policy and a DLQ with an alarm, consumers are idempotent, and schedules live in EventBridge Scheduler with explicit time zones.
Before changing anything
- Read
AGENTS.mdand the IaC defining buses, rules, schedules and pipes. - Collect real sample events: from the producer’s code, from an archive, or from a temporary rule targeting a CloudWatch Logs group in a dev account.
- Inspect live config when credentials and network are available:
aws events list-event-buses --query 'EventBuses[].Name'
aws events list-rules --event-bus-name orders --query 'Rules[].[Name,State,EventPattern]'
aws events list-targets-by-rule --event-bus-name orders --rule order-created-to-billing
aws scheduler list-schedules --query 'Schedules[].[Name,State,GroupName]'
Which feature
| Need | Use |
|---|---|
| Application domain events between services | Custom event bus per domain or per org, rules per consumer |
| React to AWS service events (EC2 state, ECS task stopped, S3 object created) | Default bus rules; S3 requires EventBridge notifications enabled on the bucket |
| Cron or one-time future actions | EventBridge Scheduler, not scheduled rules |
| Point-to-point from SQS, Kinesis, DynamoDB Streams, Kafka to one target, with filter and enrichment | EventBridge Pipes |
| Strict ordering, high-throughput streaming, replay by offset | Kinesis or Kafka; EventBridge does not order events |
| Simple work queue with one consumer | SQS (see $aws-sqs-sns) |
Event envelope
{
"Source": "com.acme.orders",
"DetailType": "OrderCreated",
"EventBusName": "orders",
"Detail": "{\"version\":\"1\",\"id\":\"evt_01J9...\",\"occurredAt\":\"2026-10-28T10:02:11Z\",\"data\":{\"orderId\":\"o-123\",\"total\":4200,\"currency\":\"EUR\",\"country\":\"DE\"}}"
}
Conventions:
sourceis reverse-DNS of the producing service; never start it withaws..detail-typeis a past-tense event name; version the schema insidedetail.- Include a stable event ID in
detailfor consumer deduplication. - Put identifiers in the event, not whole documents; consumers fetch details if needed. The event size limit is 1 MB, but smaller events are cheaper (billed per 64 KB chunk) and safer.
Publishing:
resp = events.put_events(Entries=entries) # up to 10 entries per call
if resp["FailedEntryCount"]:
failed = [e for e, r in zip(entries, resp["Entries"]) if "ErrorCode" in r]
retry_with_backoff(failed) # the call succeeded; some entries did not
For events that must not be lost when the database commits, use a transactional outbox (write the event row in the same transaction, publish from the outbox).
Rule patterns
{
"source": ["com.acme.orders"],
"detail-type": ["OrderCreated", "OrderUpdated"],
"detail": {
"data": {
"total": [{ "numeric": [">=", 1000] }],
"country": [{ "anything-but": ["US", "CA"] }],
"couponCode": [{ "exists": true }],
"sku": [{ "prefix": "GIFT-" }]
}
}
}
| Operator | Example |
|---|---|
| Exact (OR within array) | "status": ["PAID", "SHIPPED"] |
| Prefix / suffix | [{ "prefix": "eu-" }], [{ "suffix": ".png" }] |
| Not | [{ "anything-but": ["test"] }], [{ "anything-but": { "prefix": "tmp/" } }] |
| Numeric range | [{ "numeric": [">", 0, "<=", 100] }] |
| Field present / absent | [{ "exists": true }] / [{ "exists": false }] |
| Case-insensitive | [{ "equals-ignore-case": "paid" }] |
| Wildcard | [{ "wildcard": "orders/*/invoice.pdf" }] |
| OR across fields | "$or": [{ "detail": { "a": [1] } }, { "detail": { "b": [2] } }] |
Matching rules: all listed fields must match (AND), values in an array are OR, matching is case-sensitive by default, and numeric operators only match JSON numbers, not numeric strings.
Test every new or changed pattern against real samples (API call; needs network and
credentials). The --event must be a full event with id, account, source, time,
region, resources and detail-type:
aws events test-event-pattern --event-pattern file://pattern.json --event file://sample-event.json
Include at least one sample that should match and one that should not.
Targets: retries, DLQs, transforms
- A rule has up to 5 targets. Default retry is up to 185 attempts over 24 hours with
backoff; tune
MaximumRetryAttemptsandMaximumEventAgeInSecondsper target. - Give every target an SQS dead-letter queue (
DeadLetterConfig) and alarm on its depth. The DLQ queue policy must allowevents.amazonaws.comwithaws:SourceArnof the rule. - Delivery is at-least-once and unordered. Consumers deduplicate on the event ID.
- Prefer SQS between EventBridge and slow or rate-limited consumers so they control their own pace.
- Input transformer to shape the payload a target receives:
{
"InputPathsMap": { "orderId": "$.detail.data.orderId", "total": "$.detail.data.total" },
"InputTemplate": "{\"orderId\": <orderId>, \"amountCents\": <total>}"
}
- API destinations call external HTTP endpoints with a connection (API key, basic or OAuth client credentials) and a rate limit. Calling third-party endpoints is outward-facing; confirm the target URL and payload with the user.
Cross-account
Producer account rule targets the consumer account’s bus ARN; the consumer bus has a
resource policy allowing events:PutEvents, ideally conditioned on
aws:PrincipalOrgID. The producer rule needs a role allowed to events:PutEvents on the
target bus. Keep a central bus pattern simple: producers send everything to one bus, and
consumers own their rules on it.
Archive and replay
aws events create-archive --archive-name orders-30d \
--event-source-arn arn:aws:events:eu-west-1:111111111111:event-bus/orders --retention-days 30
aws events start-replay --replay-name orders-fix-0310 \
--event-source-arn arn:aws:events:eu-west-1:111111111111:archive/orders-30d \
--event-start-time 2026-10-03T00:00:00Z --event-end-time 2026-10-03T06:00:00Z \
--destination '{"Arn":"arn:aws:events:eu-west-1:111111111111:event-bus/orders","FilterArns":["arn:aws:events:eu-west-1:111111111111:rule/orders/order-created-to-billing"]}'
Replay re-delivers to the rules you name, re-triggering their side effects. Restrict it
with FilterArns, make sure consumers are idempotent, and get the user’s confirmation
before replaying in production. Replayed events carry a replay-name field.
EventBridge Scheduler
aws scheduler create-schedule --name nightly-report --group-name reports \
--schedule-expression "cron(30 2 * * ? *)" --schedule-expression-timezone "Europe/Berlin" \
--flexible-time-window '{"Mode":"FLEXIBLE","MaximumWindowInMinutes":15}' \
--target '{"Arn":"arn:aws:lambda:eu-west-1:111111111111:function:nightly-report","RoleArn":"arn:aws:iam::111111111111:role/scheduler-invoke","RetryPolicy":{"MaximumRetryAttempts":3},"DeadLetterConfig":{"Arn":"arn:aws:sqs:eu-west-1:111111111111:scheduler-dlq"}}'
# One-off: reminder in 3 days, removed after it fires
aws scheduler create-schedule --name trial-ending-u42 \
--schedule-expression "at(2026-10-31T09:00:00)" --schedule-expression-timezone "UTC" \
--flexible-time-window '{"Mode":"OFF"}' --action-after-completion DELETE \
--target '{"Arn":"arn:aws:sqs:eu-west-1:111111111111:reminders","RoleArn":"arn:aws:iam::111111111111:role/scheduler-sqs","Input":"{\"userId\":\"u42\"}"}'
- Cron has six fields (
minutes hours day-of-month month day-of-week year) and one of day-of-month or day-of-week must be?. - Always set the time zone; schedules in local time handle daylight saving correctly.
- Scheduler can call almost any AWS API directly through universal targets
(
arn:aws:scheduler:::aws-sdk:<service>:<apiAction>). - Per-entity one-off schedules (millions of reminders) are a normal Scheduler use case;
use
ActionAfterCompletion: DELETEto avoid clutter.
Pipes
Source (SQS, Kinesis, DynamoDB Streams, MSK or self-managed Kafka, Amazon MQ) to optional filter, optional enrichment (Lambda, Step Functions Express, API Gateway, API destination), to a target. Use a Pipe instead of a glue Lambda that only reads, filters and forwards. Filters use the same pattern syntax; for SQS sources, filtered-out messages are deleted, so do not filter away messages another consumer needs.
Gotchas
- Infinite loops: a rule whose target publishes events that match the same rule. Make
patterns exclude the target’s own
sourceordetail-type. - AWS service events go to the default bus in the same region; a rule on a custom bus never sees them.
- A rule with no matching events produces no error. Check the
MatchedEventsandFailedInvocationsmetrics, not just that the rule exists. - Lambda targets need a resource-based permission for
events.amazonaws.com; IaC usually adds it, console-copied configs often miss it. - Disabling or deleting rules in production stops delivery silently for consumers; confirm first.
Verification
test-event-patternpasses for match and non-match samples.- Publish a test event in dev and confirm
MatchedEventsandInvocationsincrease and the target received the transformed payload. - Force a target failure and confirm the event lands in the DLQ after retries.
- For schedules,
aws scheduler get-scheduleshows the expected next run and time zone.
What the zip contains
SKILL.md plus the interface file below. Nothing runs on install.
agents/openai.yaml
Gives the Codex app a display name, a one-line description and a starter prompt for this skill.
interface:
display_name: "AWS EventBridge"
short_description: "Event routing with tested patterns and no lost events"
default_prompt: "$aws-eventbridge Publish OrderCreated events to EventBridge and route big orders to the fraud service" About this skill
Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.