Epicenter

Epicenter

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.

GitHub stars Apps license: AGPL-3.0 Toolkit license: MIT Discord

Whispering | Toolkit | How It Works | Status | Trust | Repo Map | Development | License

--- ## Whispering [Whispering](apps/whispering) is a speech-to-text SPA with two hosts. Open the [hosted browser app](https://whispering.epicenter.so), or run the same source as a native surface inside [Epicenter](apps/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](https://whispering.epicenter.so) | [Read the app architecture](apps/whispering) ## Build With The Toolkit 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. These are the packages meant to leave this repo: [`@epicenter/workspace`](packages/workspace), [`@epicenter/ui`](packages/ui), [`@epicenter/filesystem`](packages/filesystem), and [`@epicenter/sync`](packages/sync). 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/workspace`](packages/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. ```typescript 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](packages/workspace/README.md) ## How It Works Epicenter separates app-owned data from user-owned Markdown. App output belongs under `apps//`; folders you own stay ordinary Markdown. ```txt workspace/ |-- apps// 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//` 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. ```txt 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): ```md --- 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: ```bash sqlite3 matter.sqlite 'select "name" from "journal" limit 5;' ``` ## Status 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 workspace for tabs, notes, drafts, and publishing is being built in public around `@epicenter/workspace`. [Matter](apps/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. ## Trust Boundaries 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 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](docs/trust-model.md) for the details, including where this is heading with the anchor. The detailed privacy notes for Whispering live in [apps/whispering](apps/whispering). ## Repo Map ### Product And Workspace Surfaces | Surface | Status | Notes | | --- | --- | --- | | [Whispering](apps/whispering) | Browser and Epicenter surface | One speech-to-text SPA with browser-safe providers and Epicenter-only native capabilities. | | [Epicenter](apps/epicenter) | Desktop host | The only Tauri runtime. Serves trusted app surfaces, including Whispering, under one native shell. | | [Matter](apps/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](apps/api) | Hosted infrastructure | Personal cloud Worker for hosted Epicenter services. Includes hosted-only billing and dashboard code. | | [Self-host](apps/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. | ### Packages These packages carry the main architecture. | Package | Role | License | | --- | --- | --- | | [`@epicenter/workspace`](packages/workspace) | Core workspace primitives: typed schemas, Yjs documents, local persistence, materializers, actions, and collaboration hooks. | MIT | | [`@epicenter/sync`](packages/sync) | Yjs sync protocol encoding and decoding. Protocol framing lives separately from transport. | MIT | | [`@epicenter/ui`](packages/ui) | Shared Svelte component library used by multiple app surfaces. | MIT | | [`@epicenter/filesystem`](packages/filesystem) | POSIX-style virtual filesystem helpers over workspace data. | MIT | | [`@epicenter/server`](packages/server) | Shared Hono server library composed by the hosted API and self-host reference deployable. | AGPL-3.0-or-later | | [`@epicenter/cli`](packages/cli) | The `epicenter` command and local or hosted API workflows. | AGPL-3.0-or-later | ## Architecture The server side is split into one shared library and two deployable folders: ```txt 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 surface ``` [Full architecture walkthrough](docs/architecture.md) | [Trust model](docs/trust-model.md) ## Development Use Bun in this repo. ```bash git clone https://github.com/EpicenterHQ/epicenter.git cd epicenter bun install ``` Every app starts from the repo root. `bun dev:` runs every process the app needs; for apps that talk to the hosted API, that includes the API worker on `localhost:8787`. `bun dev::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:opensidian` | API + Opensidian | 5176 | | `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 | | `bun dev:todos` | Todos, standalone | 5177 | The API needs local Postgres and Infisical; see [apps/api/README.md](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: ```bash bun run typecheck bun run test bun run check ``` ## Design Notes Implementation specs and design notes live in [specs/](specs). Start with [docs/README.md](docs/README.md) and [specs/README.md](specs/README.md). ## Contributing 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. [Read the Contributing Guide](CONTRIBUTING.md) Contributors coordinate in [Discord](https://go.epicenter.so/discord). ## License Epicenter uses a two-tier split by how you use the code: - [MIT](licenses/LICENSE-MIT) for code you build with: the toolkit roots (`@epicenter/workspace`, `@epicenter/ui`, `@epicenter/filesystem`, `@epicenter/sync`) and the toolkit-internal contracts they carry (`@epicenter/identity`, `@epicenter/agent-protocol`, `@epicenter/encryption`, `@epicenter/field`, `@epicenter/chat`). Nine packages today. - [AGPL-3.0](licenses/LICENSE-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](LICENSE), [FINANCIAL_SUSTAINABILITY.md](FINANCIAL_SUSTAINABILITY.md), and the [licensing strategy](docs/licensing/licensing-strategy.md) 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.