Skip to content

rung

Run the cheapest rung that works.

rung is a Postgres-centric web-scraping engine built around one idea: any target you want to extract is reachable several ways at different cost and reliability — a cheap static-JSON endpoint, a rendered page, an LLM extraction — so the engine runs the cheapest method that works, remembers the winner per target, and only re-walks the ladder when that winner fails or goes stale.

It leans on Postgres for everything a scraping fleet needs — a FOR UPDATE SKIP LOCKED work queue with leases/heartbeats (no Redis or Celery), the per-target access-method registry, and cross-worker rate limiting — behind an honest-by-default HTTP layer (opt-in TLS impersonation) and a plugin seam for per-domain catalogs.

Start with the story

The cheapest thing that works is the narrative behind rung — the design, the reasoning, and the failures that taught us the design. It's the most enjoyable way in, and the best way to understand why the engine is shaped the way it is. The pages below are the reference; that's the story.

Start here

  • Quickstart — clone → Postgres → run one command → see the ladder resolve.
  • Concepts — the four load-bearing ideas: the cost-ranked access ladder, the SKIP-LOCKED queue, the plugin seam, the honest-HTTP chokepoint.
  • Build your own domain — drive the engine as a library for a non-cannabis pipeline, end to end.
  • Engine API — the surface a pipeline or plugin author calls.

The engine vs. the reference application

The engine is domain-agnostic. The cannabis-dispensary pipeline that ships with it is the reference application — one worked way to use the engine (reconcile government license rosters against operators' own store lists and live menus), not the only way. Its schema and stages live behind db.create_reference_tables() / the reference_db module, cleanly separated from the generic engine so import rung.db loads none of it. The reference-application docs are labelled as such.

Design & background

  • Postgres for everything — why the queue, registry, and rate limiter all live in Postgres.
  • Public/private split — how the open-source core and the private overlay divide, and how the plugin seam holds the boundary.
  • ARCHITECTURE.md — the module map and dependency edges.
  • The story — the "why it's built this way" narrative, in the README.