Local-first apps that write to files you own.
Your data lives on your machine as plain Markdown and SQLite: grep it, version it, open it in Obsidian. When an app stops mattering, your files don't.
Start with Whispering in the browser, or run it as a native surface inside Epicenter.
Run the apps freely under AGPL-3.0; build on the developer toolkit freely under MIT. What that means.
Whispering | Toolkit | How It Works | Status | Trust | Repo Map | Development | License
Whispering is a speech-to-text SPA with two hosts. Open the hosted browser app, or run the same source as a native surface inside Epicenter.
Press record, speak, optionally transform the transcript, and copy or deliver the result. Both hosts support cloud providers and self-hosted endpoints. Epicenter adds system-global shortcuts, native paste delivery, and local GGUF transcription.
Open Whispering | Read the app architecture
The developer toolkit is MIT: build anything on it, including closed-source and commercial products, and you own what you build, with no obligation back to Epicenter. @epicenter/lens, @epicenter/field, and @epicenter/ui are the packages meant to leave this repo. They are pre-1.0 and tuned for our own apps, so treat them as fork-and-own rather than a stability-guaranteed SDK for now.
The hard problem with local-first apps is synchronization. If each device has its own SQLite file or Markdown folder, how do you keep them in sync?
Epicenter's answer is that a person has one Epicenter, replicated on every device, and applications never own storage. A row holds bounded JSON fields in runtime-native SQLite, and may also own one lazy Yjs document for collaborative rich content and one write-once blob for bytes. An application declares a Lens: a pure JSON interpretation of one durable namespace, which creates no storage and no lifecycle of its own.
import { defineLens, defineTable, optional } from '@epicenter/data';
import { field } from '@epicenter/field';
const notesLens = defineLens({
namespace: 'com.example.notes',
tables: {
notes: defineTable({
fields: {
title: field.string(),
body: field.string(),
pinned: optional(field.boolean()),
},
}),
},
values: {},
});
const data = epicenter.bind({ notes: notesLens });
await data.notes.tables.notes.create({
title: 'Hello',
body: 'Follow up on the README framing.',
});Two Lenses may interpret the same namespace differently, and neither becomes authoritative. That is what lets one application read another's data without depending on its build.
One person has one Epicenter: a single body of rows and values, replicated completely onto every device they sign in on. Applications do not own storage. They bind a Lens over the shared data, and Epicenter Home is the shell that launches them.
one Epicenter
|-- rows bounded JSON fields in runtime-native SQLite
|-- values typed singletons
|-- documents zero or one lazy Yjs document per row, for collaborative content
`-- blobs zero or one write-once immutable byte stream per rowEach plane converges on its own terms. Scalar rows and values synchronize through the account authority. Row documents publish over HTTP automatically and pull remote state explicitly when a handle is open. Blobs upload once and download on demand. There is no distributed transaction across them, and applications receive no SQL: relational inspection belongs to Home.
Matter keeps a disposable matter.sqlite mirror of each Markdown folder you
own, so agents and scripts can query your Markdown as SQL:
sqlite3 matter.sqlite 'select "name" from "journal" limit 5;'Whispering is independently deployable as a browser SPA and is also mounted inside the Epicenter desktop host. Epicenter is the only native runtime; Whispering no longer ships a standalone desktop shell.
The shared data model for tabs, notes, drafts, and publishing is being built in public around @epicenter/data. Matter is an early app for user-owned Markdown folders: it edits ordinary Markdown directly and keeps matter.sqlite as a query mirror. Other app folders are public research and prototypes.
Pick the trust model you want.
| Path | What leaves your device |
|---|---|
| Whispering in Epicenter with local GGUF transcription | Audio stays on your device. Transcripts and settings use Epicenter's local desktop storage. |
| Whispering with a cloud transcription provider | Audio goes from your device to the provider you choose. Epicenter servers are not in that transcription path. |
| Whispering transformations | Transcript text goes to the LLM provider you choose when you enable that step. |
| Hosted Epicenter API or sync | Workspace updates, account/session data, and enabled hosted feature requests go to Epicenter servers. |
| Self-hosted deployable | You control the server, secrets, deployment, and infrastructure boundary. |
Signed-in sync sends your data to a trusted server that reads it in plaintext. On hosted Epicenter the relay is ours, so that data sits inside our trust boundary; self-hosting puts the relay on infrastructure you control, so Epicenter never holds it. See the trust model for the details, including where this is heading with the anchor.
The detailed privacy notes for Whispering live in apps/whispering.
| Surface | Status | Notes |
|---|---|---|
| Whispering | Browser and Epicenter surface | One speech-to-text SPA with browser-safe providers and Epicenter-only native capabilities. |
| Epicenter | Desktop host | The only Tauri runtime. Serves trusted app surfaces, including Whispering, under one native shell. |
| Matter | WIP product work | Typed grid for user-owned Markdown folders. It edits ordinary .md files directly; matter.sqlite is a disposable query mirror. |
| API | Hosted infrastructure | Personal cloud Worker for hosted Epicenter services. Includes hosted-only billing and dashboard code. |
| Self-host | Reference deployable | Community-supported single-partition instance without hosted billing. |
| Other app folders | Research and prototypes | Useful history and experiments, not the current product lineup. |
These packages carry the main architecture.
| Package | Role | License |
|---|---|---|
@epicenter/data |
The row-owned SQLite replica: scalar row protocol, admission, deterministic folding, exact-retry digests, sync supervision, and relational inspection. | MIT |
@epicenter/lens |
Lens, table, and value definitions plus structured addresses and canonical JSON. | MIT |
@epicenter/sqlite |
Neutral embedded-SQLite driver and Browser, Bun, and Durable Object adapters. It owns no product schema. | MIT |
@epicenter/document-sync |
Row-document HTTP publication and pull, separate from scalar row synchronization. | MIT |
@epicenter/ui |
Shared Svelte component library used by multiple app surfaces. | MIT |
@epicenter/server |
Shared Hono server library composed by the hosted API and self-host reference deployable. | AGPL-3.0-or-later |
The server side is split into one shared library and two deployable folders:
packages/server
shared Hono library
route composition for auth, sessions, rooms, assets, and provider-backed APIs
apps/api
hosted personal Cloudflare Worker
composes packages/server with a Better Auth principal resolver
owns hosted-only dashboard and billing code
apps/self-host
self-hosted single-partition instance reference deployable
composes packages/server with the instance principal resolver
community-supported
no hosted billing surfaceFull architecture walkthrough | Trust model
Use Bun in this repo.
git clone https://github.com/EpicenterHQ/epicenter.git
cd epicenter
bun installEvery app starts from the repo root. bun dev:<app> runs every process the app needs; for apps that talk to the hosted API, that includes the API worker on localhost:8787. bun dev:<app>:ui runs the app's frontend alone when that split exists, and bun dev:api runs just the backend. Bare bun dev is the current default workflow (API and Tab Manager), and bun run with no arguments lists every target.
| Command | Starts | App port |
|---|---|---|
bun dev:api |
Hosted API worker alone | 8787 |
bun dev:api-dashboard |
API + dashboard UI | 5178 |
bun dev:honeycrisp |
API + Honeycrisp desktop | 5175 |
bun dev:tab-manager |
API + Tab Manager extension | extension build |
bun dev:vocab |
API + Vocab | 8888 |
bun dev:whispering |
API + hosted Whispering browser app | 1420 |
bun dev:epicenter |
Epicenter desktop host, including Whispering | Tauri window |
bun dev:landing |
Landing site, standalone | 4321 |
bun dev:matter |
Matter desktop, standalone | 5180 |
bun dev:posthog-reverse-proxy |
PostHog reverse proxy Worker | wrangler default |
bun dev:self-host |
Self-host server (needs INSTANCE_TOKEN) |
8787 |
bun dev:skills |
Skills editor, standalone | vite default |
The API needs local Postgres and Infisical; see apps/api/README.md. Rust is needed for Tauri apps such as Epicenter, Matter, and Honeycrisp. Local Books and Local Mail run their own multi-process dev flows; their READMEs document them.
Useful checks:
bun run typecheck
bun run test
bun run checkImplementation specs and design notes live in specs/. Start with docs/README.md and specs/README.md.
Contributions are welcome. Good entry points are docs, Whispering fixes, local-first infrastructure, Svelte interfaces, and small changes that make the repo easier to understand.
Contributors coordinate in Discord.
Epicenter uses a two-tier split by how you use the code:
- MIT for code you build with: the toolkit roots (
@epicenter/lens,@epicenter/field,@epicenter/ui) and the toolkit-internal contracts they carry (@epicenter/data,@epicenter/sqlite,@epicenter/identity,@epicenter/agent-protocol,@epicenter/chat). - AGPL-3.0 or later for code we ship or run: every app, the shared server library, the CLI, and the rest of the internal packages.
- There is no proprietary tier today. Revenue is intended to come from hosting and services, not from selling closed licenses.
Every dependency of the toolkit packages is MIT-compatible, enforced by bun run check:licenses. The license split follows the same broad pattern as Plausible and PostHog for hosted open-source services, and Yjs for MIT core libraries with copyleft server pieces.
See the root LICENSE, FINANCIAL_SUSTAINABILITY.md, and the licensing strategy for the full model.
Contact: github@bradenwong.com | Discord | @braden_wong_
When an app stops mattering, your files don't. Local-first, open source, built on Yjs.