Local-first apps over files you own.
Apps keep their data as ordinary Markdown and JSON files in a folder on your computer, and sync it with an Epicenter server, hosted or self-hosted. An editor, Git tool, or agent can open the same files.
Whispering and Honeycrisp are built on it today.
Run the apps freely under AGPL-3.0-or-later. What that means.
The Folder | Status | Trust | Repo Map | Development | License
Epicenter is your folders, and apps are lenses. Every directory directly inside
~/Epicenter is a folder; an optional epicenter.json gives it a title and a
contract. @epicenter/folder opens an app's folder as the typed client its file
contract derives: items are Markdown files at the contract's paths, and the
contract's schemas interpret them. Opening needs no account, remote, or
declaration file. A desktop app or a Bun script opens a directory; in a browser
the folder is the signed-in account's folder on the server.
import { openFolder } from '@epicenter/folder';
import { directory } from '@epicenter/folder/node';
const folder = openFolder(todos, directory('/Users/me/Epicenter/todos'));
await folder.todos.set({ id: 'milk' }, { title: 'Milk', done: false });A write never fails: the folder keeps it, in order, until it lands. Sync is separate from opening, and nothing syncs these folders while the folder sync product waits (ADR-0840).
Whispering runs in the browser and as a desktop app. The epicenter command
runs apps: each is a folder in ~/Epicenter whose epicenter.ts defines its
actions, and each action is a commit in that folder's repository. Local Books is a headless mirror
that pulls a QuickBooks account into local SQLite and keeps its own format.
Most of the rest of this repository is the folder sync product, which waits
(ADR-0840).
Honeycrisp and Messages are frozen on it as they were; each is rebuilt as an
app whose actions the epicenter command runs, with its pages on top, in its
turn, as Capture, Tasks, and Vocab already are (apps/README.md)
(ADR-0843).
Pick the trust model you want.
| Path | What leaves your device |
|---|---|
| No sync | Nothing. The folder is complete on the device that holds it. |
| Hosted Epicenter | Account and session data and any hosted feature you enable; your folder too, when you sync it. |
| Self-hosted API | You control the server, secrets, deployment, and infrastructure boundary. Your folder goes only there. |
| A provider an app calls | Whatever that app sends it: transcript text to an LLM, audio to a transcription provider. Epicenter servers are not in that path. |
A folder syncs only with an Epicenter server, which can read its files in plaintext. Choosing that server is choosing who can read your data. See the trust model for the details.
| App | Status | Notes |
|---|---|---|
| Honeycrisp | Runs, development milestone | Markdown notes on the file contract, edited as Markdown with live preview: in a browser, the signed-in person's folder on the server; on the desktop, a folder on the computer. |
| Local Books | Runs, separately | Headless CLI mirror that pulls QuickBooks into local SQLite. |
| API | Hosted infrastructure | Personal cloud Worker. Owns sign-in, each folder's ledger, the AI gateways, hosted-only billing, and the dashboard. Self-host it on Bun with Postgres (apps/api/server.ts). |
| Whispering | Runs, development milestone | Voice recorder in a browser tab. Recordings, transcripts, and settings are files in a folder. |
| Capture, Reading, Tasks, Vocab | Runs, on epicenter serve |
Apps in ~/Epicenter, each its own code repository with its records in a data repository inside it: actions in one epicenter.ts, and a UI served at /<app>/. Not in this repository (ADR-0877). |
| 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/folder |
A folder: its collections and files, opened in a browser, a desktop page, or Bun, and synced with its ledger on the server. | AGPL-3.0-or-later |
@epicenter/app |
What an app's epicenter.ts imports: defineApp, fields, and the places an action receives. |
AGPL-3.0-or-later |
@epicenter/cli |
The epicenter command: runs each app's actions as commands and MCP tools, commits what they change, and syncs app repositories. |
AGPL-3.0-or-later |
@epicenter/definition |
A folder's contract, the front-matter and merge rules, and the names a site derives. | AGPL-3.0-or-later |
@epicenter/ai |
Every source of models as an endpoint, one OpenAI-compatible client, the agent loop, and the model picker. | AGPL-3.0-or-later |
@epicenter/ui |
Shared Svelte component library used by multiple apps. | AGPL-3.0-or-later |
@epicenter/server |
Shared Hono server library composed by the API on Cloudflare Workers and on Bun. | 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, folders (each a ledger
of changes in Postgres), and provider-backed inference
and transcription
apps/api
hosted personal Cloudflare Worker
composes packages/server with a Better Auth principal resolver
owns hosted-only dashboard and billing code
server.ts runs the same composition on Bun with Postgres: the self-host pathFull 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 bun dev:honeycrisp, and bun run with no arguments lists every target.
| Command | Starts | App port |
|---|---|---|
bun dev:honeycrisp |
Honeycrisp in the browser, no API | 5175 |
bun dev:api |
Hosted API worker alone | 8787 |
bun dev:api-dashboard |
API + dashboard UI | 5178 |
bun dev:landing |
Landing site, standalone | 4321 |
bun dev:posthog-reverse-proxy |
PostHog reverse proxy Worker | wrangler default |
bun dev:whispering runs Whispering in a browser tab.
The API needs local Postgres and Infisical; see apps/api/README.md. Rust is needed for Tauri apps such as Epicenter. Local Books runs its own multi-process dev flow; its README documents it.
bun run check is the gate. It runs lint, typecheck, every workspace test, and the structural checks, and it is the same gate CI runs, so a green local run predicts a green pull request. Formatting is handled separately by the autofix workflow.
bun run checkRun the pieces on their own while you work:
bun run format # rewrite formatting (CI autofixes this for you)
bun run lint:check
bun run typecheck
bun run test
bun run check:structure # doc paths, catalog pins, API paths, UI boundary, boot purity, vocabulary, state pathsOne check sits outside the gate on purpose. bun run check:doc-hygiene flags specs and ADRs that time has made stale, so it belongs to review rather than to merge.
Durable decisions and their reasoning live in docs/adr/. Specs in specs/ are in-flight design scaffolding rather than current truth; when a spec and an ADR disagree, the ADR wins. Start with docs/README.md.
Contributions are welcome. Good entry points are docs, local-first infrastructure, Svelte interfaces, moving an app onto folders, and small changes that make the repo easier to understand.
Contributors coordinate in Discord.
Everything is AGPL-3.0-or-later. An MIT toolkit tier existed until 2026-08 and was dissolved; versions already published under MIT stay MIT for those versions.
See the root LICENSE, FINANCIAL_SUSTAINABILITY.md, and the licensing strategy for the full model.
Contact: github@bradenwong.com | Discord | @braden_wong_
Your data outlives the app that wrote it. Local-first, open source, built on plain files, with a history you can take with you as Git.