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, our desktop speech-to-text app. You can install it today.
Install | Toolkit | How It Works | Status | Trust | Repo Map | Development | License
Whispering is Epicenter's desktop speech-to-text app for macOS, Windows, and Linux.
brew install --cask whispering
On Windows and Linux, download the installer from the latest release.
Press a shortcut, speak, optionally transform the transcript, and paste the result where you were working. No Epicenter account is required. You can run local Whisper C++ for offline transcription, or bring your own API key for providers like Groq, OpenAI, and ElevenLabs.
Install Whispering | Download latest release
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/workspace answers by making Yjs the source of truth, then projecting app state to SQLite for queries and Markdown for reading.
Alongside typed tables, local persistence, collaboration hooks, and validated actions, the package gives apps materializers, the writers that project state to disk.
import { field } from '@epicenter/field';
import { createWorkspace, defineTable } from '@epicenter/workspace';
const notes = defineTable({
id: field.string(),
title: field.string(),
body: field.string(),
});
const workspace = createWorkspace({
id: 'notes',
tables: { notes },
kv: {},
});
workspace.tables.notes.set({
id: '1',
title: 'Hello',
body: 'Follow up on the README framing.',
});
// Materializers can project that row to Markdown files and SQLite rows.
Read the workspace package docs
Epicenter separates app-owned data from user-owned Markdown. App output belongs under apps/<name>/; folders you own stay ordinary Markdown.
workspace/
|-- apps/<name>/ generated app output; read, grep, quote, copy
|-- .epicenter/ machine state; ignore
|-- journal/ your Markdown; edit, commit, curate, publish
|-- ideas/ your Markdown
`-- publish/ your publishable artifacts
The rule is simple: apps/<name>/ is for reading app output, not hand-editing it. To change app data, use the app or a CLI action validated against the app's schema. To keep something forever, copy it into a folder you own.
Your folders are ordinary Markdown: grep them, open them in Obsidian, version them with Git, publish them with whatever static site stack you like.
purpose-built app
-> Yjs live state
-> Markdown projection for human reading
-> SQLite mirror for local queries
-> curated Markdown when something is worth keeping
Yjs handles live app state, offline edits, and multi-device sync. SQLite gives scripts and views a fast query surface. Markdown gives you files you can read, quote, copy, version, and publish.
A generated Markdown projection is meant to be boring on purpose (this is the target shape):
---
id: note_123
title: Morning capture
source: app
updatedAt: "2026-06-10T16:49:59.180Z"
---
Follow up on the README framing.
Matter applies the same SQLite-mirror idea to the folders you own: it keeps a disposable matter.sqlite mirror of each managed folder, so agents and scripts can query your Markdown as SQL:
sqlite3 matter.sqlite 'select "name" from "journal" limit 5;'
A refresh of Whispering built on the workspace is in progress, and current installs will receive it through the normal release path.
The shared workspace for tabs, notes, drafts, and publishing is being built in public around @epicenter/workspace. 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 with local Whisper C++ | Audio stays on your device when you use local Whisper C++. Transcripts and settings are stored locally by the desktop app. |
| 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 workspace sync sends your Yjs updates to a trusted relay that reads them 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 | Installable app | Desktop speech-to-text with local and bring-your-own-provider transcription paths. |
| 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 shared wiki deployable 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/workspace |
Core workspace primitives: typed schemas, Yjs documents, local persistence, materializers, actions, and collaboration hooks. | MIT |
@epicenter/sync |
Yjs sync protocol encoding and decoding. Protocol framing lives separately from transport. | MIT |
@epicenter/ui |
Shared Svelte component library used by multiple app surfaces. | MIT |
@epicenter/filesystem |
POSIX-style virtual filesystem helpers over workspace data. | MIT |
@epicenter/server |
Shared Hono server library composed by the hosted API and self-host reference deployable. | AGPL-3.0-or-later |
@epicenter/cli |
The epicenter command and local or hosted API workflows. |
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 personal()
owns hosted-only dashboard and billing code
apps/self-host
self-hosted shared wiki reference deployable
composes packages/server with shared({ admit })
community-supported
no hosted billing surface
Full architecture walkthrough | Trust model
Use Bun in this repo.
git clone https://github.com/EpicenterHQ/epicenter.git
cd epicenter
bun install
Root bun dev starts the current default local workflow: the API and Tab Manager.
bun dev
bun run dev:api
bun run dev:tab-manager:ui
See apps/api/README.md for local Postgres and Infisical setup. Rust is needed for Tauri surfaces such as Whispering and Matter.
Useful checks:
bun run typecheck
bun run test
bun run check
Implementation 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:
@epicenter/workspace, @epicenter/ui, @epicenter/filesystem, and @epicenter/sync.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 licensing strategy spec for the full model.
Contact: [email protected] | Discord | @braden_wong_
When an app stops mattering, your files don't. Local-first, open source, built on Yjs.