···11+---
22+"@atmo-dev/contrail": minor
33+---
44+55+add `contrail dev` — local dev wrapper for cloudflare workers deployments.
66+77+replaces `wrangler dev --test-scheduled` + a separate cron-trigger script with one command. on start it:
88+99+1. connects to your local D1 via wrangler's `getPlatformProxy`, inspects state
1010+2. prompts to run `backfillAll` if no completed backfills exist yet
1111+3. prompts to run `refresh` if the ingest cursor is older than 60 minutes (configurable with `--stale-after`)
1212+4. spawns `wrangler dev --test-scheduled`
1313+5. fires `GET /__scheduled?cron=...` every 60 seconds so the cron actually runs in local dev (wrangler's scheduler only works in deployed production)
1414+1515+flags: `--cron <expr>` (default `"*/1 * * * *"`), `--stale-after <min>` (default 60), `--yes` to auto-accept prompts, plus the standard `--config` / `--root` / `--binding`.
1616+1717+prompts are skipped in non-TTY environments (default-declined).
1818+1919+also adds `--yes` to the CLI-wide arg parser.
+2
docs/01-indexing.md
···97979898`ingest()` connects to Jetstream, streams events since the saved cursor, stops when caught up. Running every minute is fine — the next fire resumes where this one left off. Each cycle is bounded, so it can't blow past the Worker time limit.
9999100100+**Local dev:** wrangler's cron scheduler only runs in deployed production. For local dev use `pnpm contrail dev` — it runs `wrangler dev --test-scheduled`, fires `/__scheduled` on your configured cron interval, and prompts you to run backfill or refresh if the local DB looks stale on start.
101101+100102### Persistent (node / any long-lived server)
101103102104If your runtime can keep a socket open, skip the cron entirely:
-65
docs/08-examples.md
···11-# Examples
22-33-Every example lives in [`apps/`](https://github.com/flo-bit/contrail/tree/main/apps) and pins contrail as `workspace:*`. Clone the repo, `pnpm install`, and each one runs.
44-55-## `rsvp-atmo` — the reference deployment
66-77-[`apps/rsvp-atmo`](https://github.com/flo-bit/contrail/tree/main/apps/rsvp-atmo)
88-99-Cloudflare Workers + D1. Indexes `community.lexicon.calendar.event` and `rsvp`. Exposes the full spaces + community + realtime surface. Cron-driven Jetstream ingestion every minute.
1010-1111-Use this if you're building on Workers and want a starting point that already has deploy config wired up.
1212-1313-```bash
1414-pnpm --filter rsvp-atmo dev # local wrangler + auto-cron
1515-pnpm --filter rsvp-atmo deploy # requires D1 database created
1616-pnpm --filter rsvp-atmo sync # discover + backfill against D1
1717-```
1818-1919-## `group-chat` — full app showcase
2020-2121-[`apps/group-chat`](https://github.com/flo-bit/contrail/tree/main/apps/group-chat)
2222-2323-SvelteKit + Cloudflare Workers. The one that exercises everything: permissioned spaces for private rooms, community-controlled DIDs for groups, client-side `contrail-sync` for reactive messages, Durable Object-hibernated WebSockets for realtime delivery, OAuth-based login.
2424-2525-This is the canonical "what can contrail do" demo. If you're trying to understand how the pieces fit together end to end, read this app's code before anything else.
2626-2727-```bash
2828-pnpm --filter sveltekit-group-chat dev
2929-```
3030-3131-## `postgres` — Node + PG minimal
3232-3333-[`apps/postgres`](https://github.com/flo-bit/contrail/tree/main/apps/postgres)
3434-3535-The smallest possible Node deployment. Docker Compose for Postgres, three scripts: `sync` (discover + backfill), `ingest` (persistent Jetstream), `serve` (HTTP handler). Skips spaces/communities/realtime.
3636-3737-Use this as a template if you're running on a normal server and don't need Cloudflare's bells.
3838-3939-```bash
4040-cd apps/postgres
4141-docker compose up -d
4242-pnpm sync
4343-pnpm serve
4444-```
4545-4646-## `cloudflare-workers` — minimal Workers
4747-4848-[`apps/cloudflare-workers`](https://github.com/flo-bit/contrail/tree/main/apps/cloudflare-workers)
4949-5050-The simplest working Worker. One collection (events), one HTTP handler, cron-driven ingest. No spaces, no communities. Good for reading top-to-bottom in one sitting to see what contrail does at minimum.
5151-5252-## `sveltekit-cloudflare-workers` — SvelteKit Statusphere
5353-5454-[`apps/sveltekit-cloudflare-workers`](https://github.com/flo-bit/contrail/tree/main/apps/sveltekit-cloudflare-workers)
5555-5656-A Statusphere-style SvelteKit app with OAuth login, contrail-indexed public records, and Cloudflare adapter. No spaces/communities — think "atproto blog or status post UI." Useful as a scaffold for public-only apps.
5757-5858-## Choosing a starting point
5959-6060-| Need | Start from |
6161-|---|---|
6262-| "Just index some records" | `cloudflare-workers` or `postgres` |
6363-| "Index + SvelteKit UI, public only" | `sveltekit-cloudflare-workers` |
6464-| "Private rooms / group chat / full stack" | `group-chat` |
6565-| "Calendar-ish domain, Workers deploy" | `rsvp-atmo` |
+4-2
apps/cloudflare-workers/README.md
···1717```bash
1818pnpm install
1919npx wrangler d1 create contrail # copy database_id into wrangler.jsonc
2020-pnpm deploy # deploy the worker
2120pnpm contrail backfill --remote # discover + backfill historical events
2121+pnpm deploy # deploy the worker
2222```
23232424then hit:
···3030## local dev
31313232```bash
3333-pnpm dev # wrangler dev, cron fires every minute
3333+pnpm dev # wraps wrangler dev + auto-fires cron + prompts for backfill/refresh if needed
3434pnpm contrail backfill # backfill against the local D1 created by wrangler
3535```
3636+3737+`pnpm dev` runs `contrail dev` under the hood. On start it inspects the local D1 and prompts to run backfill (if nothing's indexed yet) or refresh (if the ingest cursor is >1h old), then runs `wrangler dev --test-scheduled` with a 60s timer hitting `/__scheduled` so the cron actually fires locally.
36383739## extending
3840