Local-first, open-source apps
One folder of plain text and SQLite on your machine, synced across all your devices.
Grep it, query it, host it wherever you want.
Apps • Architecture • Packages • For Developers • Quick Start • Contributing • Discord
Epicenter is an ecosystem of open-source, local-first apps. All your data—notes, transcripts, chat histories—lives in a single folder of plain text and SQLite on your machine. Every tool we build reads and writes to the same place. It's open, tweakable, and yours. Grep it, open it in Obsidian, version it with Git, host it wherever you want.
Under the hood, Yjs CRDTs are the single source of truth. They materialize down to SQLite (for fast queries) and markdown (for human-readable files). Sync happens over the Yjs protocol; the server is a relay, not an authority—it never sees your content.
The library that powers this, @epicenter/workspace, is something other developers can build on too. Define a typed schema, get CRDT-backed tables with multi-device sync handled for you.
┌──────────────────────────────────┐
│ @epicenter/api │
│ Cloudflare Workers + DO hub │
│ auth · sync relay · AI chat │
└──────────┬───────────────────────┘
│ y-websocket protocol
┌────────────────────┼──────────────────────┐
│ │ │
┌────▼──────┐ ┌─────▼───────┐ ┌──────▼──────┐
│ Whispering│ │ Opensidian │ │ Tab Manager │
│ (Tauri) │ │ (SvelteKit) │ │ (WXT ext) │
└────┬──────┘ └─────┬────────┘ └──────┬──────┘
│ │ │
┌─────────┴────────────────────┴──────────────────────┘
│ All apps share these layers:
│
┌─────▼───────────────────────────────────────────────────────────┐
│ MIDDLEWARE / ADAPTERS │
│ @epicenter/svelte — Svelte integration, auth, persistence │
│ @epicenter/filesystem — POSIX file layer over Yjs │
│ @epicenter/skills — skill/reference tables │
│ @epicenter/ai — LLM tool bridging │
└─────────────────────────────┬───────────────────────────────────┘
│
┌──────────────────────────────▼───────────────────────────────────┐
│ CORE │
│ @epicenter/workspace — typed schemas, Yjs CRDTs, extensions, │
│ E2E encryption, lifecycle, materializers │
│ @epicenter/sync — protocol encoding/decoding, V2 updates │
│ @epicenter/constants — app URLs, versions, shared config │
│ @epicenter/ui — shadcn-svelte component library │
│ @epicenter/cli — TypeBox→yargs CLI, auth/session APIs │
└─────────────────────────────────────────────────────────────────┘
The dependency flow is strict: core has zero upward dependencies, middleware only reaches into core, and apps compose both. @epicenter/workspace is the gravitational center—every middleware package and most apps depend on it. The sync server is a relay, not an authority; it never sees your content because encryption happens client-side before anything leaves the device.
Full architecture walkthrough → · Encryption design →
|
Press shortcut, speak, get text. Desktop transcription that cuts out the middleman. Bring your own API key or run locally with Whisper C++. |
Local-first note-taking with a built-in bash terminal, end-to-end encryption, and real-time sync. Your notes live in a CRDT-backed virtual filesystem. |
|
Browser extension side panel for managing tabs with workspace sync and AI chat that can call workspace tools with inline approval. |
Apple Notes-style local-first notes app. Folders, rich-text editing with ProseMirror, and collaborative sync via Yjs. |
|
The hub server. Auth, real-time sync via Durable Objects, and AI inference. Everything that needs a single authority across devices. |
The |
Also in the repo: Fuji (personal CMS), Zhongwen (Mandarin learning chat), Skills Editor (agent skill manager), Dashboard (billing UI), and Landing (public site).
| Package | Description | License |
|---|---|---|
@epicenter/workspace |
Core library. Typed schemas, Yjs CRDTs, extension builder, E2E encryption, materializers. Everything builds on this. | MIT |
@epicenter/sync |
Yjs sync protocol encoding/decoding. Dumb server, smart client—protocol framing is separate from transport. | AGPL-3.0 |
@epicenter/ui |
shadcn-svelte component library shared across all apps. | MIT |
@epicenter/svelte |
Svelte 5 integration—persisted state, auth, workspace gate, TanStack Query helpers. | MIT |
@epicenter/filesystem |
POSIX-style virtual filesystem over Yjs workspace tables. mkdir, mv, rm, stat. |
MIT |
@epicenter/skills |
Skill and reference tables for AI-enhanced workspace apps. | MIT |
@epicenter/ai |
Bridges workspace actions with LLM tool calling. | MIT |
@epicenter/cli |
The epicenter command. TypeBox schemas become CLI flags automatically. |
MIT |
@epicenter/constants |
Shared URLs, ports, and version info across the monorepo. | MIT |
The hard problem with local-first apps is synchronization. If each device has its own SQLite file, how do you keep them in sync? If each device has its own markdown folder, same question. We ended up using Yjs CRDTs as the single source of truth, then materializing that data down to SQLite (for fast SQL reads) and markdown (for human-readable files). Yjs handles the sync; SQLite and markdown handle the reads.
The @epicenter/workspace package wraps this into a single API. Define a schema, get CRDT-backed tables, attach providers to materialize to SQLite or markdown, and add sync when you're ready.
import { type } from 'arktype';
import { createWorkspace, defineTable, defineWorkspace } from '@epicenter/workspace';
import { indexeddbPersistence } from '@epicenter/workspace/extensions/persistence/indexeddb';
import { createSyncExtension } from '@epicenter/workspace/extensions/sync/websocket';
const posts = defineTable(
type({ id: 'string', title: 'string', published: 'boolean', _v: '1' }),
);
const definition = defineWorkspace({
id: 'epicenter.blog',
tables: { posts },
});
const workspace = createWorkspace(definition)
.withExtension('persistence', indexeddbPersistence)
.withExtension('sync', createSyncExtension({
url: (docId) => `ws://localhost:3913/rooms/${docId}`,
}));
await workspace.whenReady;
workspace.tables.posts.set({ id: '1', title: 'Hello', published: false, _v: 1 });Each user gets their own database. Schema definitions are plain JSON, so they work with MCP and OpenAPI out of the box. Write to Yjs and SQLite updates; edit a markdown file and the CRDT merges it in.
Read the full workspace docs →
More apps are in progress—each one shares the same workspace, so data flows between them without import/export. The @epicenter/workspace library handles the hard parts (schemas, CRDT sync, materialization), so each new app is mostly UI.
Epicenter Cloud will provide hosted sync for people who don't want to run their own server. Same model as Supabase selling hosted Postgres or Liveblocks selling hosted collaboration. Self-hosting is and will remain first-class—the sync server is open source under AGPL, and when you run it yourself, you control the encryption keys and trust boundary.
brew install --cask whisperingOr download directly from GitHub Releases for macOS (.dmg), Windows (.msi), or Linux (.AppImage, .deb, .rpm).
# Prerequisites: Bun (https://bun.sh) and Rust (https://rustup.rs)
git clone https://github.com/EpicenterHQ/epicenter.git
cd epicenter
bun install
cd apps/whispering
bun devIf things break after switching branches or pulling changes:
bun clean # Clears caches and node_modules
bun install # Reinstall dependenciesFor a full reset including Rust build artifacts (~10GB, takes longer to rebuild):
bun nuke # Clears everything including Rust target
bun installYou rarely need bun nuke—Cargo handles incremental builds well. Use bun clean first.
We're looking for contributors who are passionate about open source, local-first software, or just want to build with Svelte and TypeScript.
Contributors coordinate in our Discord.
We publish our implementation specs. These are the reasoning behind non-obvious architectural choices—alternatives considered, trade-offs made, and why we landed where we did.
| Spec | What it decided |
|---|---|
| Encrypted Workspace Storage | XChaCha20-Poly1305 at the CRDT value level; server-managed keys with self-hosting as the trust boundary |
| Y-Sweet Persistence Architecture | How Yjs documents persist and compact in Durable Objects |
| Simple Definition-First Workspace API | The defineTable → createWorkspace → .withExtension() builder pattern |
| Resilient Client Architecture | How workspace clients handle offline, reconnect, and extension failures |
| Migrate to @epicenter/sync | Custom sync protocol replacing Y-Sweet with our own framing layer |
All 112 implemented specs live in specs/.
Most packages and all apps are MIT—use them however you want, no strings attached. The sync server (apps/api) and sync protocol (packages/sync) are AGPL-3.0, which means anyone hosting a modified version shares their changes. This follows the same pattern as Yjs (MIT core, AGPL y-redis), Liveblocks (Apache clients, AGPL server), and Bitwarden (GPL clients, AGPL server).
See FINANCIAL_SUSTAINABILITY.md for the full reasoning behind the split.
Contact: github@bradenwong.com | Discord | @braden_wong_
Local-first · CRDT · Own your data · Open source