Your own note-to-self chatrooms — infinite rooms, like a private Telegram "Saved Messages". Self-hosted, open-source, Astro SSR + Prisma/SQLite.
![]() |
![]() |
| Room list — all three room types, tags visible | Persistent room — Markdown rendered server-side |
![]() |
![]() |
| Search across rooms, messages, and tags | Composer — Markdown, image attach, Ctrl+Enter to send |
| Type | Storage | Lifetime |
|---|---|---|
| persistent | SQLite (disk) | until you delete it |
| ephemeral | Node heap (RAM) | TTL, or until the process restarts — not a retention guarantee |
| incognito | Node heap (RAM) | until the tab closes (client-fired wipe via sendBeacon) |
- Markdown messages — rendered server-side, sanitized (XSS-safe)
- Image attachments — disk for persistent rooms, inline data-URL in RAM for ephemeral/incognito
- Link previews — persistent rooms only, with SSRF guard
- Room tags + search across names, messages, and tags
- JSON import / export (persistent rooms)
- Multi-user with password auth, or
require_password = falseanonymous demo mode - All limits configurable: per-user room cap, per-room message cap, image size, heap budget
git clone https://github.com/didvc/chatnote
cd chatnote
npm install
cp config.example.toml config.toml
npm run db:push
npm run dev # http://localhost:4321Production:
npm run build
npm startLoaded once at server launch. See config.example.toml and the config reference.
Key flags:
| Flag | Default | Purpose |
|---|---|---|
require_password |
true |
Set false for anonymous demo mode |
allow_image_uploads |
true |
Set false on public demos |
allow_link_previews |
true |
Server-side link unfurling (persistent rooms only) |
wipe_persistent_every |
"off" |
e.g. "1d" for a daily demo wipe |
Apache-2.0
- visited — Securely collect browsing history over browsers.
- dead-mans-ping — Cross-platform CLI that HTTP-GET pings endpoints on mouse (in)activity — dead-man's switch, presence beacon, idle notifier.



