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.tscall the AT Protocol agent and map responses toPostData - 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.