Bugler is an open-source event relay. Point GitHub, Stripe, Sentry, CI, any webhook at it. Agents in any harness subscribe with filters and sleep until a matching event arrives. Zero polling, zero tokens while idle, and a queryable event history to catch up from.
Self-hosting works today, free forever. The hosted relay is in early access: join the waitlist, we onboard in small batches.
bugler · end-to-end proof, real GitHub events
01:34:11Zwaker long-poll open, outbound only · agent fully stopped, 0 tokens in flight01:34:15Zgithub pull_request.opened · HMAC verified · appended to the log01:34:15Zwaker filter matched · relaunching claude -p from stopped01:34:19Zagent wake summary written · exit 0 · cursor committed [+4 s]01:34:36Zgithub pull_request_review.submitted · appended01:34:41Zagent wake summary written · exit 0 · cursor committed [+5 s]between idle 0 model requests · 0 GitHub API calls · one outbound long-poll
Condensed from the recorded proof run: real GitHub events on a real repository, timestamps from machine logs.
4 s
from GitHub sending a PR-opened event to a fully stopped agent's written wake summary.
Machine-logged timeline
8 s
from a GitHub comment landing to a parked Codex CLI agent's completed reply, via the in-session MCP wait.
Machine-logged timeline
0
GitHub API calls between events, corroborated by GitHub's own delivery log: push-only traffic, three deliveries, all HTTP 200.
Externally corroborated
0
inference tokens while waiting. No model request is in flight while an agent sleeps; the bill starts at the wake.
By construction, not measured
Latencies measured on real GitHub events with machine-log timestamps. The token figure is structural, true by construction rather than benchmarked: there is simply no request to bill.
01 · How it works
Webhooks in. Filters in the middle. Agents woken at the end.
One relay, three moving parts. Events are stored and delivered as CloudEvents 1.0 envelopes, so every source and every subscriber speaks the same shape.
STEP 1
Point webhooks at it
Verifier presets for GitHub, Stripe, Sentry, GitLab (Standard Webhooks), CircleCI, and generic token sources. A dozen-line bridge covers SQS, Pub/Sub, NATS, or Redis. Poll-only systems get the bundled poll agent: one poll, shared by fifty subscribers.
POST /ingest/github
X-Hub-Signature-256: sha256=9f2c…
→verified, appended as a
CloudEvents 1.0 envelope
STEP 2
Subscribe with a filter
CloudEvents filter dialects, exact, prefix, and suffix composed with all, any, and not, evaluated relay-side. A subscriber's entire delivery state is a filter plus one integer bookmark in a shared append-only log. Committing the cursor is the ack.
The waker holds one ordinary outbound long-poll, so nothing ever connects inward to your machine. It relaunches your stopped CLI, or resolves an in-session wait_for_event call. The cursor advances only on exit 0; a crash means redelivery, never a lost event.
$ bugler waker -- \
claude -p "review the new PR"
or, in-session MCP:
wait_for_event · check_events
exit 0 → cursor commits
crash → redelivered
Sources push
GitHub
Stripe
Sentry
GitLab / CircleCI
Queues via bridge
Poll agent (for the rest)
Bugler relay
Verify signature, record provenance
Append to a durable event log, ack after commit
Filter relay-side, CloudEvents dialects
Wake long-poll, SSE, signed push, or MCP wait
History queryable within retention
Agents wake
Claude Code (relaunch)
Codex CLI (MCP wait)
Any CLI via the waker
OpenClaw hooks
Temporal / Inngest / Restate
LangGraph / CF Workflows
Two harnesses, two wake modes, both proven on real GitHub events: Claude Code relaunched from fully stopped, and Codex CLI parked in-session on the bounded MCP wait. The waker daemon can relaunch any CLI; native push adapters cover OpenClaw hooks and Claude Code Routines; a generic signed webhook feeds Temporal, Inngest, Restate, LangGraph, and Cloudflare Workflows through a small bridge.
02 · The economics
Stop paying your agent to ask if anything happened yet.
Polling every 5 minutes is 288 wake-ups a day, almost all of them empty, and every empty one still spins up a model to hear "nothing yet." A subscribed agent wakes only when a matching event arrives, in seconds.
PR opened
review submitted
Polling every 5 minutes288 wakes a day, almost all empty
Subscribed to Bugler2 wakes, seconds after each event
00:0006:0012:0018:0024:00
An illustrative day with two real events. Each gray tick is one scheduled 5-minute poll; each accent dot is one event-driven wake. The exact count varies with your day; the asymmetry is structural.
While asleep
No model request in flight, so waiting costs zero inference tokens by construction. No consumer-side API calls to the source either: during the proof run, GitHub's own delivery log showed push-only traffic, and the only standing connection was one outbound long-poll to the relay.
At the wake
The agent receives the matching event and can query the history API to catch up from its cursor. Non-matching events cost an agent nothing, because filters run relay-side. Babysit a PR for hours; spend tokens only when it moves.
03 · Runs anywhere
One relay, eight documented homes, most of them $0.
Five storage drivers ship today: bun:sqlite, pure memory, Cloudflare Durable Object SQLite, DynamoDB, and Cosmos DB NoSQL. All pass one shared conformance suite that defines correctness for every driver, and no storage behavior leaks outside src/storage.
Local single process
bun run src/cli.ts init, then serve. One process, no external dependencies. bun run smoke drives a full signed GitHub flow locally.
Storage SQLite file (WAL, synchronous=FULL)$0, no third party
Docker / Compose
docker compose up --build -d. First start initializes the database and prints a show-once admin key in the service logs; rotate it right away, since container logs persist.
Storage SQLite on one persistent volume$0 on your own machine
Home lab + tunnel
The same binary or container on any spare machine. Webhooks arrive through a free Cloudflare Tunnel or Tailscale Funnel: outbound-only daemons, no open ports.
Storage SQLite on local disk$0, zero billing relationships
GCP e2-micro VM
deploy/gcp/setup-vm.sh cross-compiles a Linux binary, creates one always-free e2-micro, and installs it under systemd. Never touches billing settings.
Storage SQLite on the 30 GB persistent disk$0 always-free (IPv4 ~$3/mo, erasable with a free tunnel)
Driver queued
GCP Cloud Run
The standard container on request-based billing, scale to zero, sub-10 s cold starts. This is the ingest-and-push profile, queued behind the Firestore driver (P5d).
Storage Firestore free tier (driver queued)$0 at low volume within always-free grants
Cloudflare Workers
deploy/cloudflare/setup.sh: one named SQLite Durable Object owns the log, delivery, and a persisted single-alarm scheduler. Hard caps fail rather than bill.
Storage Durable Object SQLite (free plan)$0 within the published free-plan budget
AWS: DynamoDB + your compute
deploy/aws/setup.sh provisions only a DynamoDB table and a least-privilege IAM user; you run the container on compute you already operate. AWS has no always-free home for a long-polling core, and we say so.
Storage DynamoDB single table + one GSIStorage $0 within the always-free allowance
Azure Container Apps + Cosmos
deploy/azure/setup.sh forces an explicit choice: scale-to-zero at exactly $0 idle with documented cold-start risk on ingest, or always-on to keep every GitHub delivery inside its 10-second deadline.
Storage Cosmos DB NoSQL free tier (lifetime)$0 idle, or ~$3 to $5/mo always-on
04 · The gap
Good tools stop exactly where agents start.
An 8-agent research sweep with roughly 235 web fetches found no existing project that combines a permissive license, a single-process zero-dependency footprint, durability, and a harness-neutral agent wake contract. Here is where the nearest ones stop.
smee.io · webhook forwarding
Fire-and-forget SSE to currently connected clients only: a disconnected client loses the event.
Channels are unauthenticated capability URLs; anyone with the ID can read payloads.
No persistence, no filtering, no at-least-once, no wake action, and the maintainers say it is not for production.
Authenticated, durable, filtered, and built around a wake contract.
Hookdeck · event gateway
The Event Gateway is not self-hostable.
Free tier caps at 10,000 events/month with 3-day retention.
The consumer is an HTTP endpoint or CLI tunnel, with no notion of waking a sleeping agent. Hookdeck's own "put Hookdeck in front of OpenClaw" guides confirm demand for exactly the half it does not cover.
Self-host free forever, and the consumer is an agent, not an endpoint.
Svix · webhook platform
Platform-scale multi-tenant infrastructure; self-hosting needs Redis plus Postgres.
Consumers are HTTP endpoints, not long-poll or SSE subscribers with cursors, and there is no agent-wake concept.
The free-to-paid cliff jumps from $0 to roughly $490/month.
A single process with zero dependencies, and a $0 → $12 → $29 ladder instead of a cliff.
Claude Code Routines · vendor trigger
Requires a claude.ai subscription and runs only Claude Code, in Anthropic's cloud.
Covers two GitHub event categories (pull_request and release); hourly caps drop excess events rather than delivering at-least-once.
No local trigger layer, no generic event sources, no subscription-cursor model for an agent that is already awake.
The same trigger idea, generalized across harnesses and event sources, delivered at-least-once.
All four are good at what they aim for; none of them aim at waking agents. Based on each product's public docs and pricing: competitor prices and limits checked 2026-08-23.
05 · Pricing
Self-host free forever. Hosted tiers in early access.
Every hosted limit is volume, never capability: the full engine ships in the open-source build with no feature deltas. The hosted product sells operations, ingress URLs, uptime, and retention storage, not withheld code.
Early accessThe hosted service is not live yet. These are the prices we intend to charge at launch; joining the waitlist costs nothing and commits you to nothing.
What counts: a delivered event is a verified webhook matched and delivered to a subscription. Unmatched requests and retries are free.
Why these numbers: outgrowing the free tier costs $12 here, not a $490 cliff. Pro's included volume equals Svix's entire free tier; Team stays under Hookdeck's $39 entry with 25x its included events, and 30-day retention at $29 matches what Svix gives away free. Each step in the ladder is 2.4x or less. Heavy free users are not a problem to solve: they have self-host.
Need SSO, an SLA, or VPC peering? That is the contact-us Scale line above Team. Write to us from the waitlist form below, or email hello@bugler.dev.
Honesty note: hosted tiers are not live yet. This is early-access pricing, published so you can decide before you commit, and subject to refinement before general availability. hello@bugler.dev is the contact address used across this page and is live; if you prefer, open a GitHub issue instead.
06 · Honest engineering
Claims you can audit, limits we say out loud.
a. At-least-once, bounded honestly
Delivery is at-least-once within retention. An agent that stays away past the window gets an explicit gap notification telling it to reconcile, never a silent hole in history. Because GitHub never auto-retries a failed delivery, Bugler acks only after a durable commit, dedupes on GitHub's delivery GUID, and can run GitHub's own list-and-redeliver recovery on a schedule.
b. Verified never means obey
Signature verification is recorded as provenance: verified means authentic, never safe to obey. Payload text is always delivered as labeled untrusted data and never interpolated into instruction fields. The waker scrubs the subscriber token from every spawned handler's environment, so a prompt-injected handler cannot acknowledge events away.
c. Reviewed across vendors, to zero
The design survived five independent review rounds before a line of product code, converging 22 → 19 → 11 → 1 → 0 findings. Every build phase then closed its loop at zero blocking, zero material, zero minor findings: code built under a Claude orchestrator, independently reviewed by GPT-5.6 Sol at high effort. Core tests grew 38 → 89 through those rounds, plus 17 DynamoDB, 14 Cosmos, and 11 workerd tests.
d. Secrets fail closed
Tokens are shown once, carry CRC32 typo checks, are stored only as SHA-256 hashes, and are rejected in query strings. Signing secrets stay env: or file: references resolved at use time and fail closed when missing. Deploy scripts are consent-first: tested --dry-run transcripts, explicit --yes for external changes, secrets via stdin, ShellCheck 0.11.0 at zero findings.
50.004 s. The MCP server exposes exactly two tools: wait_for_event (45 s default, hard-clamped to 50 s to stay under the universal 60 s client timeout floor) and non-blocking check_events. The clamp was measured at 50.004 s under live review probes.
1.7M → 48. Review quantitatively confirmed a Workers fix that took an idle-subscription hot loop from roughly 1.7 million alarm invocations per day to a 30-minute cadence, keeping the free plan's budget math honest. Oversized payloads are rejected with 413 at the HTTP boundary, with caps derived from measured envelope overhead per storage engine.
07 · FAQ
Practical questions, direct answers.
Is the hosted relay live?
Not yet. Hosted Bugler is in early access: you join the waitlist, we onboard in small batches, and the published prices are early-access pricing. None of this gates the open-source relay, which works today and is free forever.
What does zero tokens while idle actually mean?
It is a structural property, not a benchmark: while an agent is stopped, or parked inside a bounded wait_for_event tool call, no model request is in flight, so no inference tokens are consumed. The bill starts only at the wake. We label this "by construction" rather than "measured" because that is the honest description.
Does my machine need an open inbound port?
No. Nothing ever connects inward to your machine. The waker holds one ordinary outbound long-poll, the same pattern GitHub's self-hosted Actions runners use, so it works from a laptop behind NAT, a container, or a locked-down corporate network.
Which agents and harnesses can it wake?
Any CLI the waker daemon can relaunch. Claude Code (wake-from-stopped) and Codex CLI (in-session MCP wait) are proven against real GitHub events. Native push adapters cover OpenClaw hooks and Claude Code Routines, and a generic signed webhook feeds Temporal, Inngest, Restate, LangGraph, and Cloudflare Workflows through a small bridge.
What happens if my agent is away longer than retention?
It receives an explicit gap notification telling it to reconcile, never a silent hole in history. Inside the window, delivery is at-least-once: the cursor advances only when your handler exits zero, so a crashed or failing handler means redelivery, not a lost event, with consecutive failures backing off to a cap.
Is the open-source version feature-limited?
No. There are no feature deltas between self-host and the paid tiers, and every hosted limit is volume, never capability. The hosted product sells operations: uptime, ingress URLs, and retention storage. There is no phone-home in the open-source build.
What about sources that cannot push?
A bundled polling agent turns poll-only systems into events at the relay, so fifty subscribers share one poll instead of running fifty polling loops. On the push side, verifier presets cover GitHub, Stripe, Sentry, GitLab (Standard Webhooks), CircleCI, and generic token sources, and a dozen-line bridge covers SQS, Pub/Sub, NATS, or Redis.
First light for your agents
Let your agents sleep. That is the point.
Self-host tonight from GitHub, or join the early-access waitlist for the hosted relay: we run it, you sign in and point webhooks at us.
Your mail client should now hold a pre-filled note. Send that email to finish joining. If nothing opened, write to hello@bugler.dev yourself and you are on the list all the same.