A private keep for friends and family
Everything you say goes somewhere. Almost none of it is still there when you need it.
Emberkeep is a self-hosted community platform built on one idea: chat is where things get said, but it should not be where they get lost. One click turns a message into something the keep remembers — searchable in six months, still there in six years.
macOS · Windows · Linux · Docker Compose · no accounts, no cloud, no one else's servers
The problem with every chat app
Chat is a source. Memory is the destination.
Your group has already decided when the trip is, what the backup plan is, and how long the brine takes. Those answers exist. They were typed by a real person on a real evening — and then four hundred messages landed on top of them.
So every year you have the same argument, and every year somebody scrolls for eleven minutes and gives up. The information was never missing. It was just unreachable.
Where it starts
Conversation
Someone settles it in #general at 9pm on a Tuesday, in one sentence, in passing.
One click
Bank it
Hover the message, bank it. It keeps its author, its channel, and the reason you kept it.
Where it lives
The Keep
Banked things gather by topic, inheriting the exact privacy of the hall they came from.
Six months later
Findable
Search it, or ask the Keeper in plain language. The answer arrives with its receipts.
Bank it
The whole feature is one hover and one click.
No "create a document." No moving it to a wiki nobody opens. You are already reading the message — keep it where you found it, and write one line about why it mattered.
- It keeps its origin. Author, channel, timestamp, and the thread it came out of — all still attached.
- It inherits its ward. Something banked out of a warded hall stays visible only to that hall. Privacy is structural, not a checkbox.
- It has a reason. A memory with no "why we kept this" is just an older message.
The Keeper
An AI that cannot tell you anything you weren't allowed to read.
Ask in plain language. The Keeper answers from your community's own banked memory and shows you every source it drew from, so you can go read the original.
It runs against your AI server — Ollama, OpenWebUI, any OpenAI-compatible endpoint on your own hardware. Your family's conversations are never shipped to a model vendor, because there is no vendor in the loop.
- Charter-bound by construction. Retrieval runs against what the asker could open by hand. A warded hall stays warded, even in an answer.
- Cited, not asserted. Every answer lists the banked entries behind it.
- Optional. Never light it and the rest of the keep works exactly the same.
The live half
It is still a very good place to just talk.
Halls and channels, threads, reactions, DMs, presence, notifications, keyboard-first navigation. Everything you expect, none of it renamed for the sake of it — a channel is still a channel.
What does get its own name is what makes Emberkeep different: the rooms you gather in, the doors on them, and the half of the app that remembers.
- Copper means live. Presence, mentions, unreads, the composer — one accent, one meaning.
- Verdigris means remembered. Banked things and the Keeper. Nothing else gets an accent.
- Firesides are never recorded. Voice is for being in the room, not for producing an artifact.
ek — the terminal client
The same keep, without lifting your hands off the keyboard.
ek is a full Emberkeep client that runs in a terminal. Not a read-only feed, not a notifier — halls, channels, threads, reactions, mentions, images, editing, search, banking and the Keeper, all of it, over the same API the browser uses.
It is modal in the way you would hope. NORMAL to read and move, INSERT to speak, counts that work the way counts work — 12k goes back twelve messages, and the gutter lights up while you aim so you can see how far that is.
- 47 runes, one cheat sheet. Press ? anywhere for the runebook. Every screen can be left with Esc — no traps.
- One door to anywhere. / filters your channels as you type, and the last row spends the same query on a real search of the whole keep.
- 24-bit colour, the same palette. Copper for live, verdigris for remembered — the patina law holds in a terminal. ek --colors tells you whether yours can show it.
╭─ halls ────────── 4/4 ─╮╭─ # general ──────────────────────────────────────────────────────────────────── The Long Hall ─╮ ╭─ Fire ─ Keep ────────╮ │▾ The Long Hall ││ Nina Petrov · 11:30 │ │ │ │ # general ││ I love it here. │ │ ● Ryan Gross founder │ │ # recipes 3 ││ │ │ ○ Amanda Grosswarden │ │▾ The Homelab ││ Ryan Gross · 12:38 │ │ ○ Jess Okafor warden │ │ # homelab 6 ││ Reminder that movie night is Friday and the pick is in #screening-room. │ │ ○ Marcus Hale │ │ # backups ││ Please look at it before Friday at 7:58pm. │ │ ○ Nina Petrov │ │▾ Movie Night ││ │ │ ○ Tom Gross │ │ # screening-room 6 ││ Amanda Gross · 12:42 │ │ │ │▾ The Cabin ◈ ││ That was for one person and we all know who. │ │ │ │ # planning 3 ││ │ │ │ │ ││ Marcus Hale · 12:45 │ │ │ │ ││ I was AT the thing. I was busy. I had a legitimate reason. │ │ │ │ ││ │ │ │ │ ││ Jess Okafor · 12:48 │ │ │ │ ││ You were at a hardware store. │ │ │ │ ││ │ │ │ │ ││ Marcus Hale · 12:50 │ │ │ │ ││ A legitimate reason. │ │ │ │ ││ │ │ │ │ ││ Nina Petrov · 12:56 │ │ │ │ ││ Is there a channel where I can read the history of this feud or │ │ │ │ ││ │ │ │ │ ││ Ryan Gross · 12:59 │ │ │ │ ││ Ask the Keeper. It only answers from what you can already open, so you │ │ │ │ ││ will get the parts of it you are allowed to see. │ │ │ │ ││ │ │ │ │ ││ Nina Petrov · 13:02 │ │ │ │ ││ That is a genuinely nice touch actually. │ │ │ │ ││ │ │ │ │ ││ Amanda Gross · 13:28 │ │ │ │ ││ Griddle at 375 on Friday. I am not reopening it. │ │ │ │ ││ │ │ │ │ ││ Marcus Hale · 13:31 │ │ │ │ ││ Thank you. Justice. │ │ │ │ ││ │ │ │ │ ││ Jess Okafor · 13:34 │ │ │ │ ││ This is not over. │ │ │ │ │├────────────────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ │› │ │ │ ╰────────────────────────╯╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────╯ NORMAL The Long Hall › # general ? runes · q to close emberd · 1ms herald 18 13:41
╭─ halls ────────── 4/4 ─╮╭─ ask the Keeper ───────────────────────────────────────────────────────────── ◠ charter-bound ─╮ ╭─ Fire ─ Keep ────────╮ │▾ The Long Hall ││ │ │ │ │ # general ││ When is the cabin trip and who is bringing what? │ │ ● Ryan Gross founder │ │ # recipes 3 ││ │ │ ○ Amanda Grosswarden │ │▾ The Homelab ││ The cabin trip is the weekend of September 19th. Six of us, two cars. Marcus │ │ ○ Jess Okafor warden │ │ # homelab 6 ││ is bringing the firewood because he owns the good saw. We split the │ │ ○ Marcus Hale │ │ # backups ││ groceries. │ │ ○ Nina Petrov │ │▾ Movie Night ││ │ │ ○ Tom Gross │ │ # screening-room 6 ││ drawn from 4 banked items │ │ │ │▾ The Cabin ◈ ││ 1 The cabin trip is the weekend of September 19th │ │ │ │ # planning 3 ││ 2 Backups: restic nightly, offsite weekly, restore test monthly │ │ │ │ ││ 3 The NAS rebuild takes 14 hours — never start one on a weeknight │ │ │ │ ││ 4 Dad's turkey brine — 24 hours, not 12, not 48 │ │ │ │ ││ │ │ │ │ ││ │ │ │ │ ││ │ │ │ │ ││ │ │ │ │ ││ │ │ │ │ ││ │ │ │ │ │◠ │ │ │ ╰────────────────────────╯╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────╯ KEEPER ask the Keeper · esc closes esc to go back emberd · 1ms herald 18 13:54
╭─ halls ────────── 4/4 ─╮╭─ the runebook ─────────────────────────────────────────────── 1–38 of 47 · j k · esc to close ─╮ ╭─ Fire ─ Keep ────────╮ │▾ The Long Hall ││ │ │ │ │ # general ││ MOVING │ │ ● Ryan Gross founder │ │ # recipes 3 ││ / jump to any channel or thread — type to narrow │ │ ○ Amanda Grosswarden │ │▾ The Homelab ││ J / K next / previous channel │ │ ○ Jess Okafor warden │ │ # homelab 6 ││ Tab move between the halls column and the stream │ │ ○ Marcus Hale │ │ # backups ││ n / p move the halls cursor (halls focused) │ │ ○ Nina Petrov │ │▾ Movie Night ││ z fold a hall (halls focused) │ │ ○ Tom Gross │ │ # screening-room 6 ││ Enter open the channel under the cursor │ │ │ │▾ The Cabin ◈ ││ │ │ │ │ # planning 3 ││ READING │ │ │ │ ││ j / k move by message │ │ │ │ ││ G back to the live edge, and light the gutter to aim │ │ │ │ ││ 12k a count jumps that many — the gutter says how far │ │ │ │ ││ j at top load older messages │ │ │ │ ││ Enter open the thread on a message │ │ │ │ ││ r quote it — your next message points back at it │ │ │ │ ││ e react to the message under the cursor │ │ │ │ ││ E edit your own message │ │ │ │ ││ D withdraw your own message │ │ │ │ ││ │ │ │ │ ││ SEARCHING │ │ │ │ ││ / the same door — the last row searches what you typed │ │ │ │ ││ ↑ / ↓ move through the places (^n / ^p too) │ │ │ │ ││ Tab widen the search to the whole keep │ │ │ │ ││ Enter open the place · or run the query · then open the hit │ │ │ │ ││ j / k move through the results │ │ │ │ ││ / back to the places, from the results │ │ │ │ ││ q close search │ │ │ │ ││ │ │ │ │ ││ KEEPING │ │ │ │ ││ b bank the message under the cursor │ │ │ │ ││ g k ask the Keeper │ │ │ │ ││ g h the hearth │ │ │ │ ││ g b the Keep — everything banked │ │ │ │ ││ g n wherever the last thing was said, hall or direct │ │ │ │ ││ │ │ │ │ ││ SPEAKING │ │ │ │ ││ i compose │ │ │ │ │› │ │ │ ╰────────────────────────╯╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────╯ RUNES the runebook · esc closes esc to go back emberd · 1ms herald 18 13:41
Say it like a keep
Named where it matters. Ordinary everywhere else.
Nobody should have to learn a dialect to say "check the thread." So the commodity words stay — channel, thread, message, DM. Only the things that are genuinely different get their own name.
- the keep
- Your whole community. One deployment is one keep — never a tenant on someone else's.
- halls
- Rooms with a purpose. A warded hall is gated by a key you hand out yourself.
- charters
- Permissions, expressed as three doors: the keep gate, the hall, the channel.
- at the fire
- Who is actually here right now, and what they're in the middle of.
- banked
- A message promoted to memory, carrying its origin and its ward with it.
- the Keeper
- Your local AI. Writes the brief, answers questions, honours every charter.
- keys & the arrival
- How people get in. You forge a key, you hand it over. There is no sign-up page.
- firesides
- Voice rooms you draw up a chair to. Never recorded, by design.
The rest of it
Run by a person, not an admin console.
You are the founder of exactly one community, and it is small. The settings look like that: a roster you actually recognise, keys you hand to people, and a page that tells you what the machinery is doing.
High noon
Dark by default. Bright when you want it.
Emberkeep is a dark-first room — soot and ember, because that is what a keep at night looks like. High noon is the same room at midday: parchment, warm ink, sunlit stone.
One exception, deliberately kept: code blocks stay dark in both themes. The forge keeps its own light.
It's yours
The whole point is that it runs on your hardware.
Emberkeep is not a service with a self-hosted tier. It is a stack you deploy, on a box you own, holding a database you can dump to a file tonight.
- One community per deployment. Not multi-tenant, on purpose. Running a second, fully separate keep means running a second stack from the same images.
- Your AI, or none. The Keeper points at a local endpoint. Community data never goes to a model provider.
- Backups you understand. One Postgres volume holds everything that matters.
pg_dumpis the whole disaster-recovery plan. - No lock-in worth the name. Plain Postgres, plain files, plain Docker Compose. If you walk away, you walk away with it.
- Old clients keep working. Backward compatibility is a hard rule — the desktop app you installed a year ago still talks to today's server.
Emberkeep for desktop
Your keep, in its own window.
A native shell around the same interface, so the keep is not one more browser tab you lose. It still talks to your own server — the desktop app is a window, not a copy.
.deb is published alongside it.
Download AppImage
These downloads come straight from here. Your own keep serves the same packages at
/download, where it detects your platform for you.
The desktop app needs a keep to connect to — it does not run standalone.
# Homebrew — brings its own runtime, macOS and Linux brew tap ry4-n/emberkeep brew install ek # or, if you already have the .NET 10 runtime dotnet tool install -g Emberkeep.Tui # then point it at your keep ek --keep https://keep.example.com --email [email protected]
ek keeps its session in
~/.config/emberkeep/ek.json, so you sign in once.
Neither path is a browser download, so macOS never quarantines it and there is no
Gatekeeper prompt to argue with — unlike the desktop packages above.
Host your own
Five services, one compose file, about twenty minutes.
The reference stack is Docker Compose behind a Cloudflare Tunnel. Only Compose is actually required — any reverse proxy that forwards WebSockets will do.
CPU / RAM
2 / 4 GB
more if the Keeper is lit
Disk
20 GB
grows with media
Docker
24+
Compose v2
Host OS
Any Linux
Debian / Ubuntu tested
Open ports
0
with a tunnel
Configure the stack
Drop a .env beside the compose file. In Portainer, paste these into the stack's environment variables instead — never commit real secrets.
# Database POSTGRES_DB=sanctum POSTGRES_USER=sanctum POSTGRES_PASSWORD=change-me-to-something-long-and-random # Image source — CI overrides the tag to the commit SHA per deploy SANCTUM_REGISTRY=registry.example.com/you/emberkeep SANCTUM_TAG=prod # Host ports (change if these collide on your box) SANCTUM_WEB_PORT=8080 SANCTUM_SEQ_PORT=5341 # Docker network holding the trusted reverse proxies. Never 0.0.0.0/0. SANCTUM_PROXY_NETWORK=172.16.0.0/12
Bring it up
Postgres starts first; the API applies its migrations on boot and seeds the founder if none exists; the worker connects; Nginx serves the app and proxies /api, /auth and /hubs.
docker compose -f docker-compose.prod.yml --env-file .env pull docker compose -f docker-compose.prod.yml --env-file .env up -d # watch it come up docker compose -f docker-compose.prod.yml logs -f sanctum-api
Put a domain in front
A Cloudflare Tunnel means no inbound ports on your firewall at all. Any proxy works as long as it forwards the WebSocket upgrade — the realtime hub needs it.
keep.example.com { reverse_proxy docker-host:8080 }
Light the Keeper (optional)
Point it at a local model server. Nothing leaves your network, and the retrieval layer is charter-bound before the model ever sees a token.
Features__Keeper__Enabled=true Keeper__Chat__Enabled=true Keeper__Chat__BaseUrl=http://192.168.1.34:11434/v1 # Ollama Keeper__Chat__Model=qwen3:8b
Back it up tonight
One volume holds every conversation and every banked memory. Two more hold uploaded media and the cookie-signing keys — lose those and everyone logs in again, but nothing is gone.
docker exec <project>-postgres-1 \ pg_dump -U sanctum -d sanctum --format=custom \ > emberkeep-$(date +%F).dump
Emberkeep
Remember has an ember in it, and a member.
The ember is the live half — the talking, the presence, the voices in the room tonight. The keep is the lasting half. You need both, or you are just generating scrollback.