Contrail

Pre-alpha. Expect breaking changes.

Contrail turns public AT Protocol records into a queryable AppView.

It provides:

  • historical backfill from relays and PDSes;
  • current updates from Jetstream;
  • D1, SQLite, and PostgreSQL storage;
  • getRecord and listRecords HTTP endpoints;
  • filters, sorting, search, and pagination;
  • custom queries;
  • relationship counts and hydration; and
  • profile and label hydration.

Cloudflare Workers with D1 is the primary deployment target. Node.js with SQLite or PostgreSQL is also supported.

Install

pnpm add @atmo-dev/contrail

Minimal Worker

// src/contrail.config.ts
import type { ContrailConfig } from "@atmo-dev/contrail";

export const config: ContrailConfig = {
  namespace: "com.example",
  collections: {
    event: {
      collection: "community.lexicon.calendar.event",
      queryable: {
        mode: {},
        startsAt: { type: "range" },
      },
      searchable: ["name", "description"],
    },
  },
};
// src/worker.ts
import { createWorker } from "@atmo-dev/contrail/worker";
import { config } from "./contrail.config";

export default createWorker(config);

Add a D1 binding and one-minute cron to wrangler.jsonc:

{
  "main": "src/worker.ts",
  "d1_databases": [
    { "binding": "DB", "database_name": "contrail", "database_id": "..." }
  ],
  "triggers": { "crons": ["*/1 * * * *"] }
}

Then deploy and backfill:

pnpm wrangler d1 create contrail
pnpm wrangler deploy
pnpm contrail backfill --remote

Query the resulting AppView:

GET /xrpc/com.example.event.listRecords?startsAtMin=2026-01-01&limit=10
GET /status

The JSON status response reports live cursor lag, indexed records, known backfill progress, and mutually exclusive pending/retrying/failed account counts. Failed PDS work is retried automatically in small scheduled slices with backoff up to 48 hours.

For ordinary Lexicon parsing, validation, pulling, and TypeScript generation, use Atcute directly. Contrail no longer ships a separate Lexicon toolchain.

Other databases

import { createSqliteDatabase } from "@atmo-dev/contrail/sqlite";
import { createPostgresDatabase } from "@atmo-dev/contrail/postgres";

See Indexing for adapter setup and Querying for the query and hydration model.

Documentation

Repository layout

There is one published package and one implementation:

packages/contrail/   @atmo-dev/contrail

The previous AppView, base, community, authority, record-host, sync, and Lexicon packages have been removed.

See development.md for repository commands.

contrail