ATProto social network
TypeScript 48%
Svelte 31%
20%
JavaScript <1%
CSS <1%
HTML <1%
Dockerfile <1%

README.md

Riven #

A social client for the AT Protocol (Bluesky network) with custom content types and block-based posts.

Overview #

Riven is an AT Protocol client built with SvelteKit that extends the standard Bluesky experience with a block-based content model. Posts can contain structured blocks (text, images, quotes, links, chat, audio, video) defined by custom lexicons. It includes content moderation via a label visibility system, dual-theme support, and cursor-based feed pagination.

Features #

  • Feed browsing -- view your following feed with cursor-based pagination
  • Block-based posts -- create posts with structured content blocks (text, images, quotes, links, chat, audio, video)
  • Post mode inference -- automatically classifies posts as micro, longform, media-heavy, or standard
  • Content moderation -- label visibility system with user preference overrides
  • Search and follow -- search for users and manage your follows
  • Dual theming -- light ("riven") and dark ("riven-dark") DaisyUI themes with toggle
  • AT Protocol OAuth -- supports both public and confidential client modes

Tech Stack #

Layer Technology
Framework SvelteKit 2, Svelte 5 (runes), TypeScript
Styling Tailwind CSS 4, DaisyUI 5
Database SQLite via Drizzle ORM + better-sqlite3
Protocol @atproto/api, @atproto/oauth-client-node
Unit tests Vitest, Testing Library
E2E tests Playwright
Runtime Bun

Getting Started #

Prerequisites #

Environment #

Copy .env.example to .env and set at minimum:

DATABASE_URL=local.db
DEV=true

For production, also set OAUTH_DOMAIN and optionally OAUTH_JWK (generate with node ./bin/gen-jwk.js) for a confidential client.

Install and Run #

bun install
bun run dev

The dev server starts at http://localhost:5173.

Other Commands #

bun run build          # Production build
bun run test           # Vitest unit tests
bun run test:e2e       # Playwright E2E tests (builds first)
bun run check          # Svelte type checking
bun run lint           # ESLint
bun run db:push        # Apply Drizzle schema to database
bun run db:generate    # Generate migration files
bun run db:studio      # Open Drizzle Studio UI

Architecture #

Content Model #

Posts use custom AT Protocol lexicons defining seven block types under at.riven.block.*:

  • text, image, quote, link, chat, audio, video

Block types are defined in src/lib/types/content-blocks.ts as a discriminated union on $type, with type guards (isTextBlock, isImageBlock, etc.) for narrowing.

Data Layer #

  • Server-side feed functions in src/lib/server/feed.ts call the AT Protocol agent and map responses to PostData
  • API routes at src/routes/api/{posts,feed,search,follow,blobs,like}/ expose these to the client

Database #

SQLite stores OAuth sessions and state (two tables: sessionStore, keyValueStore). Managed via Drizzle ORM with migrations.

See CLAUDE.md for detailed architecture documentation.