Portfolio case study

celevent

An event-driven system on the AT Protocol that finds every Pittsburgh show it can, from Bluesky posts and the live firehose to venue websites, City Paper's event guides, and Ticketmaster. It has an LLM vet each one and publishes them as a Bluesky account and a custom feed. It started as a federated calendar experiment and grew into a production service with real identity, data, and operations work.

  • Node.js
  • PostgreSQL
  • AT Protocol
  • Jetstream
  • OAuth 2.0 + DPoP
  • Ollama (gpt-oss)
  • Ticketmaster Discovery API
  • Docker
  • GitHub Actions

Operations dashboard: health, ingest lag, and recent runs

1/2

How it works

  1. 1. Collect

    Bluesky accounts, searches, Jetstream firehose, venue sites, City Paper guides, Ticketmaster

  2. 2. Filter

    Cheap keyword prefilter; dedupe by post URI and normalized text

  3. 3. Review

    Batched LLM calls with schema-constrained JSON; accept rules in code

  4. 4. Publish

    Reposts, original posts for scraped shows, and a custom feed

By the numbers

Ticketmaster shows pulled in a single refresh
115
Ticketmaster shows pulled in a single refresh
LLM calls to review 84 queued posts (batched)
5
LLM calls to review 84 queued posts (batched)
shows posted to Bluesky on the first night
49
shows posted to Bluesky on the first night
automated tests, run in CI against Postgres (92.5% line coverage)
54
automated tests, run in CI against Postgres (92.5% line coverage)

Shipped

  • Event-driven ingest from Bluesky's live Jetstream firehose plus batch collection from followed accounts and searches, with checkpointed cursors so restarts never miss or double-process posts.
  • LLM review that turns messy posts into structured events (headliner, venue, date). The model returns schema-constrained JSON; acceptance rules (confidence, date window, locality) live in tested code, not in the prompt.
  • A published custom Bluesky feed, “PGH Shows This Week,” served by a did:web feed generator straight from Postgres.
  • One event identity across every source (date + normalized venue + headliner), so a show announced by the venue, the band, City Paper, and Ticketmaster is shared exactly once.

Engineering highlights

Identity: OAuth with DPoP, done properly

  • Confidential client: the bot hosts its own client metadata and JWKS and authenticates to the token endpoint with a private_key_jwt.
  • Pushed Authorization Requests with PKCE; every API call carries a DPoP proof bound to a per-session key, so a leaked access token is useless on its own.
  • Sign-in is gated by an admin token, and the callback rejects and revokes any account other than the bot's own DID.
  • Refresh tokens are single-use, so refresh runs under a Postgres advisory lock to keep overlapping processes from revoking the session.

Operate what you ship

  • Structured JSON logs with spans per stage and per source; every run records ingest lag (p50/p95) and post-to-publish latency.
  • A /healthz check the host uses to restart a stuck process, Prometheus /metrics, and a server-rendered dashboard.
  • Webhook alerts for failed runs, LLM errors, failing sources, or climbing lag, with cooldowns and a recovery notice.
  • Dockerized, with free-tier deploy paths and CI that runs the full suite against a real Postgres.

LLM agents with guardrails

  • A discovery agent (tool calling with Bluesky account search, web search, and page fetch) finds each venue's official account and events page.
  • Its answers are claims, not facts: code verifies a handle against the live profile (official domain, linked site, or name match) and checks that URLs actually load before anything is followed or scraped.
  • Post text and scraped pages are treated as untrusted input to resist prompt injection, and a forced final step keeps the agent from looping.

Cost and reliability by design

  • A deterministic prefilter runs before the LLM; it caught a venue search returning 300 unrelated posts per run.
  • Idempotent everywhere: retries, overlapping sources, and dry-run to live switching never double-post.
  • Swappable LLM backends (local Ollama, Ollama Cloud, or Claude) behind one interface.