Skip to main content

Apricity — a local, zero-dependency front-end for the MemPalace personal-memory system. Browse, search, edit, and curate your memories and knowledge graph from your browser.

Project description

Apricity

Apricity

A local, zero-dependency front-end for MemPalace — browse, search, write, edit, and curate your personal-memory store and knowledge graph from your browser.

License: MIT PyPI Python 3.11+ No runtime dependencies Local-first Latest release

Design

What is Apricity?

MemPalace gives your AI assistant a structured, durable memory — wings, rooms, drawers, and a knowledge graph, all stored locally. Apricity is the front-end for it. Once you have hundreds of memories, you need a way to see, search, and curate them without dropping to SQL or living inside an MCP shell. That's what Apricity is for.

It is not a memory system of its own — it reads and writes an existing MemPalace install on the same machine, through the official mempalace package. Think of it as the window onto your palace.

  • 🏠 Local-first. Binds to 127.0.0.1. Nothing leaves your machine. No telemetry. No accounts. No cloud.
  • 🪶 Zero runtime dependencies. Pure-Python standard-library server + plain HTML / CSS / vanilla JS front-end. No pip install, no npm, no Docker, no build step.
  • 🛡️ Safe by construction. Every write goes through the official mempalace Python package. Every destructive action is snapshotted and recoverable. ETag concurrency control prevents lost edits.
  • Fast. Reads the SQLite/Chroma backends directly; a localStorage cache, gzip, and serve-time minification make reloads feel instant.
  • ⌨️ Keyboard-driven. ⌘K to search, E to edit, F to maximize/browse — core actions are remappable.

⚠️ Apricity expects an installed and initialised MemPalace instance on the same machine. It does not ship MemPalace itself — install it first from MemPalace/mempalace.

Contents

Features

Browse & navigate

Apricity's search bar: a rotating ring sweeps the border while a query is typed in
The search bar's always-on rotating ring — Apricity's “alive and listening” affordance. ⌘K from anywhere.
  • Search across content and metadata, filter by author, and sort by date or title (with a configurable default). ⌘K focuses it from anywhere; Enter jumps to the first match.
  • Three panes — a Rooms sidebar (wings → rooms, iOS-style drill-down), a Memories list, and a Detail view.
  • Browse mode — maximize the Memories panel into an adaptive multi-column grid; toggle with F.
  • Wiki-style links[[drawer_id|Display Title]] references in memory content become clickable jumps to the linked memory, with one-click back-navigation.
  • URL state — the current wing / room / memory / query / sort survive reloads and are linkable.

Write & edit

Apricity's inline editor: a circular formatting toolbar applying bold and italic, a Markdown heading autoformatting, and a callout block
The inline WYSIWYG editor — circular toolbar, live bold/italic, ## → heading autoformat, and callouts. No modal, no raw-Markdown round-trip.
  • Inline visual editor — a WYSIWYG editor for bold/italic, headings, lists, links, and callouts, with Markdown autoformatting and HTML→Markdown conversion on save. No modal, no raw-Markdown round-trip.
  • Edit metadata — change content, title, wing, and room, or move a memory between rooms, with content-hash ETag protection against concurrent edits.
  • Optimistic saves — edits apply instantly and revert automatically (with a notification and a retry affordance) if the server rejects them.
  • Drafts inbox — stage partial memories, edit them in place, and file them into the palace when ready.

Curate & recover

Apricity's delete-and-recover flow: a memory card slides from Memories into Recently deleted, gains a Restore button, then slides back
Nothing is ever lost — every delete is snapshotted into Recently deleted, one click from restore.
  • Delete a single memory, a whole room, or a whole wing — every delete is snapshotted to a recoverable log.
  • Recently deleted — restore a deleted memory with one click (optimistically), or purge the log.
  • Knowledge graph — view triples, add new facts, invalidate stale ones, and explore a force-directed graph visualisation.
  • Tunnels — cross-room / cross-wing links surfaced inline as room chips; create and delete them, bind them to specific memories, and inspect them on a dedicated tunnel page.

Stay in the loop

Apricity's notification bell ringing as toasts from Claude, Codex, and Gemini cascade in, each tagged created or updated
The bell rings as each model files or revises a memory — per-model avatars, created vs updated at a glance.
  • Notifications — a bell that surfaces newly created and updated memories with the originating model's avatar (Claude, Codex, …), distinguishing created from updated.
  • Recently-updated markers — memories touched recently get a relative-time marker that clears once you've viewed them.
  • Live polling — optional background refresh (15 / 30 / 60 s) that pauses when the tab is hidden, with an optional sound and LAN-wide "seen" sync so dismissing on one device clears it everywhere.

Make it yours

Apricity's Auto / Light / Dark theme switcher morphing a miniature interface between light and dark
Auto / Light / Dark — follow the system or pick a side; your choice is persisted.
  • Tools panel — a power-user sheet that surfaces MemPalace's MCP tools: knowledge-graph query + timeline, tunnels (list, create, delete, find, follow, traverse), diary (read / write), stats, and maintenance (taxonomy, duplicate check, hook settings, sync, reconnect, AAAK spec). Hidden by default; enable it in Settings. See the API reference for the underlying endpoints.
  • Settings — a redesigned sheet with sidebar navigation: Display (theme, reduce-motion, relative time, title/name polishing, panel-control reveal), Notifications, remappable keyboard Shortcuts, Trash, Backup, Account, and an About pane with an update-available check.
  • Theme — Auto / Light / Dark, overriding or following the system preference, with your choice persisted.
  • Auth — optional username + password lock with PBKDF2-SHA256 hashing and HTTP-only session cookies (12-hour default, 30-day "Remember me").

Quickstart

Prerequisites

  • Python 3.11 or newer (Apricity itself uses only the standard library — no pip install required).
  • A working MemPalace install with its own venv. Apricity shells out to it for writes, so it must be importable from $MEMPALACE_PYTHON_BIN.

Run from a clone (no install step)

The whole server is one file of standard-library Python, so the simplest way to run Apricity is straight from a checkout:

git clone https://github.com/epinethrone/apricity
cd apricity
python3 server.py            # equivalent to `python -m mempalace_dashboard`

Then open http://127.0.0.1:8765.

Install as a command

Prefer an isolated, on-PATH install? Use pipx (or uv tool install):

pipx install apricity
apricity

[!NOTE] The PyPI package is named apricity. If it isn't published yet, install from a clone (above) or from a GitHub Release in the meantime.

There's no build step and no third-party runtime dependencies — the package is published purely so installing it is one command. If your MemPalace install lives somewhere non-standard, copy .env.example to .env (or export the variables in your shell) and adjust the paths before launching.

First-run checklist

  1. ✅ MemPalace itself is installed and you've successfully filed at least one memory through it.
  2. ~/.mempalace/palace/chroma.sqlite3 and ~/.mempalace/knowledge_graph.sqlite3 exist (or you've pointed MEMPALACE_PALACE_DB / MEMPALACE_KG_DB at where they actually live).
  3. MEMPALACE_PYTHON_BIN points at a Python that can import mempalace.
  4. ✅ You opened Apricity, clicked Settings, and set a username + password.

Configuration

All filesystem locations default to the standard MemPalace home (~/.mempalace). Override with environment variables if your installation differs (see .env.example for a starter file):

Variable Default Purpose
PORT 8765 Port Apricity listens on.
MEMPALACE_HOME ~/.mempalace Root for all of Apricity's data.
MEMPALACE_PALACE_DB <HOME>/palace/chroma.sqlite3 The Chroma SQLite backend.
MEMPALACE_KG_DB <HOME>/knowledge_graph.sqlite3 The knowledge-graph SQLite database.
MEMPALACE_INBOX <HOME>/dashboard-inbox Where drafts are staged before filing.
MEMPALACE_VERSIONS <HOME>/dashboard-versions.jsonl Append-only log of deletions (powers Recently deleted).
MEMPALACE_CREDENTIALS <HOME>/dashboard-credentials.json Username + PBKDF2 hash. Mode 0600.
MEMPALACE_SESSIONS <HOME>/dashboard-sessions.json Active session tokens. Mode 0600.
MEMPALACE_PREFERENCES <HOME>/dashboard-preferences.json Server-side UI preferences (sort, theme, notification settings).
MEMPALACE_PYTHON_BIN ~/.local/share/mempalace-venv/bin/python Python that can import mempalace.
MEMPALACE_TOKEN (unset) Optional shared-secret used by scripts via the X-Auth-Token header. Coexists with the cookie flow.

Securing Apricity

  1. Start the server, open the UI, click Settings.
  2. Choose a username and password (≥ 8 characters).
  3. Save — you're logged in immediately and Apricity refuses every other client until they sign in.

Credentials are stored as pbkdf2_sha256$200000$<salt>$<hash> and never leave the host.

If you forget the password, delete ~/.mempalace/dashboard-credentials.json and ~/.mempalace/dashboard-sessions.json and restart the server — Apricity reverts to open setup mode so you can re-enroll.

For scripted access, set MEMPALACE_TOKEN=<some-secret> in the environment and send it as the X-Auth-Token header. This coexists with the cookie flow; it does not replace it.

Keyboard shortcuts

Four actions are remappable under Settings → Shortcuts (defaults shown); ⌘K and Esc are fixed.

Shortcut Action Remappable
F Maximize / Browse mode
E Edit the selected memory
X Close / collapse the current panel or sheet
Backspace Delete the focused item (with confirmation)
⌘K / Ctrl+K Focus the search box (inserts a link inside the editor)
Esc Close any open sheet — permanent fallback for X
Enter (in search) Jump to the first matching memory

Single-key shortcuts only fire when you're not typing in a field. Full details in the wiki.

API reference

All endpoints are JSON over HTTP. Auth is by session cookie (mempalace_session) or X-Auth-Token header when MEMPALACE_TOKEN is set.

Method Path Auth Purpose
GET /health open Liveness + whether auth is active.
GET /api/session open Current auth state.
POST /api/login open {username, password, remember} — issues a session cookie.
POST /api/logout open Clears the session.
GET /api/palace auth Full palace snapshot (wings, drawers, triples, stats).
GET /api/search?q=… auth Filtered subset of drawers + triples.
GET /api/versions auth Recently deleted snapshots (powers Recently deleted).
POST /api/memories auth File a new memory.
POST /api/memories/update auth Patch content / wing / room of an existing drawer; supports ETag.
POST /api/delete auth Delete a drawer, room, or wing ({scope, …, confirm: "DELETE"}).
GET /api/drafts auth List drafts; ?id=<draft-id> returns one with body.
POST /api/drafts auth Save a new draft.
POST /api/drafts/update auth Replace a draft in place.
POST /api/drafts/delete auth Remove a draft.
POST /api/drafts/commit auth File a draft into the palace.
POST /api/versions/restore auth Recreate a deleted memory from a snapshot.
POST /api/versions/delete auth Remove one snapshot from the log.
POST /api/versions/clear auth Wipe the snapshot log ({confirm: "CLEAR"}).
POST /api/facts auth Add a knowledge-graph triple.
POST /api/facts/invalidate auth Mark a triple as ended.
GET /api/settings auth Whether credentials are configured + username.
POST /api/settings/credentials auth Set or rotate the username + password.
GET /api/kg/query?entity=…&direction=…&as_of=… auth Query KG facts about an entity.
GET /api/kg/timeline?entity=… auth Chronological view of an entity's facts.
GET /api/kg/stats auth Knowledge-graph aggregate stats.
GET /api/graph/stats auth Palace graph stats.
GET /api/taxonomy auth Current wing/room taxonomy tree.
GET /api/checkpoint auth Memories-filed-away state (recent checkpoint).
GET /api/aaak-spec auth AAAK spec reference.
GET /api/diary?agent_name=…&last_n=…&wing=… auth Read agent diary entries (latest last_n, capped at 200).
POST /api/diary auth Write a diary entry ({agent_name, entry, topic?, wing?}).
GET /api/tunnels?wing=… auth List tunnels (optionally filtered by wing).
POST /api/tunnels auth Create a tunnel ({source_wing, source_room, target_wing, target_room, label?, source_drawer_id?, target_drawer_id?}).
POST /api/tunnels/delete auth Delete a tunnel by ID. Snapshotted to the versions log before deletion.
GET /api/tunnels/find?wing_a=…&wing_b=… auth Find tunnels between two wings.
GET /api/tunnels/follow?wing=…&room=… auth List tunnels reachable from a room.
GET /api/traverse?start_room=…&max_hops=… auth Graph-traverse from a starting room (max_hops capped at 5).
POST /api/check-duplicate auth Check whether content is a near-duplicate ({content, threshold?}).
GET /api/hooks auth Current hook settings (silent-save, desktop-toast).
POST /api/hooks auth Update hook settings ({silent_save?, desktop_toast?}).
POST /api/sync auth Sync from a project tree ({apply?, wing?, project_dir?}). Slow — runs with a 5-minute timeout.
POST /api/reconnect auth Force-reconnect the MemPalace backend.

Example — file a memory from the command line:

curl -X POST http://127.0.0.1:8765/api/memories \
  -H "Content-Type: application/json" \
  -H "X-Auth-Token: $MEMPALACE_TOKEN" \
  -d '{"wing":"notes","room":"general","title":"hello","content":"first memory from curl"}'

Safety model

  • No raw DB writes. Every mutation routes through the official mempalace Python package — Apricity never modifies SQLite directly.
  • Snapshot before destruction. Every delete (memory, room, wing, tunnel) appends a record to the versions log so the content is recoverable. Edits aren't snapshotted as history — they're protected from accidental overwrite by ETag concurrency instead.
  • ETag concurrency. The edit form sends the content hash it was opened with; the server refuses to overwrite if it has changed.
  • Confirmation values. Bulk deletes and snapshot wipes require an exact-string confirmation in the request body.
  • No plaintext secrets. Credentials are hashed with PBKDF2-HMAC-SHA256 (200 000 iterations, 16-byte salt). Sessions are stored server-side; cookies are HttpOnly + SameSite=Lax.
  • Loopback by default. The server binds to 127.0.0.1. If you put it behind a reverse proxy, terminate TLS there and keep the upstream on loopback.

Architecture

┌────────────────────┐   HTTP/JSON   ┌───────────────────────┐  subprocess  ┌─────────────────┐
│ Browser (vanilla   │ ────────────► │ server.py             │ ───────────► │ mempalace venv  │
│ HTML + JS, no      │ ◄──────────── │ (stdlib only,         │ ◄─────────── │ (writes only)   │
│ build step)        │   snapshots   │  ThreadingHTTPServer) │              └─────────────────┘
└────────────────────┘               │                       │  read-only
                                     │                       │ ─────────────► palace/chroma.sqlite3
                                     │                       │ ─────────────► knowledge_graph.sqlite3
                                     └───────────────────────┘
  • Reads go directly against the SQLite files for speed.
  • Writes are dispatched to a child Python that imports mempalace — keeps Apricity in lock-step with the canonical schema.
  • State that belongs to Apricity (drafts, snapshots, credentials, sessions, preferences) lives in $MEMPALACE_HOME alongside the palace data so a single backup captures everything.

The Python import package is still named mempalace_dashboard (hence python -m mempalace_dashboard and the directory layout below) — only the distribution, command, and brand are apricity.

Troubleshooting

Apricity loads but the palace is empty

The UI rendered, but Wings: 0 and the list is empty.

  • Confirm ~/.mempalace/palace/chroma.sqlite3 exists. If it doesn't, MemPalace itself hasn't been initialised on this machine.
  • If your palace lives elsewhere, set MEMPALACE_PALACE_DB and MEMPALACE_KG_DB to the correct absolute paths and restart.
  • Check the server log — Apricity reports the exact paths it tried to open.
"mempalace package not found" when writing

Reads work, but every save / delete fails with a subprocess error mentioning ModuleNotFoundError: No module named 'mempalace'.

  • MEMPALACE_PYTHON_BIN points at a Python that can't import mempalace. Run it manually:
    $MEMPALACE_PYTHON_BIN -c "import mempalace; print(mempalace.__file__)"
    
  • Fix the path, or install mempalace into that venv, then restart Apricity.
I forgot my password
rm ~/.mempalace/dashboard-credentials.json ~/.mempalace/dashboard-sessions.json

Restart the server and re-enroll via Settings. This does not touch your memories.

Port 8765 is already in use
PORT=9000 python3 server.py
I want to reach Apricity from another machine on my LAN

The server binds to 127.0.0.1 deliberately. Put it behind a reverse proxy (Caddy, nginx, Tailscale Serve) that terminates TLS and forwards to the loopback port. Never expose the raw port to the public internet — Apricity is designed for a trusted host.

FAQ

Is this an official MemPalace project? No. Apricity is a community front-end that talks to the official mempalace package. The MemPalace project itself lives at MemPalace/mempalace.

Does it work offline? Yes. The server is loopback-only and the front-end is vendored — no CDNs, no analytics, no outbound calls (except an optional, cached check of the GitHub releases API to tell you when a new Apricity version is out).

Do my memories leave my machine? Never. Apricity reads and writes only files under $MEMPALACE_HOME. There's no network code in the data path.

Can I run multiple instances on one host? Yes — give each one its own PORT and (if you want isolated palaces) its own MEMPALACE_HOME.

Why no pip install requirement? The whole server is one file of standard-library Python. Keeping it dependency-free means you can audit it, vendor it, or run it on a fresh box without thinking about supply chains.

Can I script against it? Yes. Set MEMPALACE_TOKEN=… and pass it as X-Auth-Token. See API reference.

Contributing

Issues, ideas, and PRs are welcome. See CONTRIBUTING.md for the development loop, code conventions, and how to file a useful bug report.

If you're adding a feature, please open an issue first to talk through the shape of it — Apricity values being small and dependency-free, so not every feature is the right fit.

Security

If you find a vulnerability, please do not open a public issue. See SECURITY.md for the disclosure process.

License

MIT © Apricity contributors.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

apricity-0.6.0.tar.gz (3.8 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

apricity-0.6.0-py3-none-any.whl (3.8 MB view details)

Uploaded Python 3

File details

Details for the file apricity-0.6.0.tar.gz.

File metadata

  • Download URL: apricity-0.6.0.tar.gz
  • Upload date:
  • Size: 3.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for apricity-0.6.0.tar.gz
Algorithm Hash digest
SHA256 7a5f0b96ca7e77b1c85438a0132efb10a4ef2c81d65e818ccc2f830997f4e148
MD5 d97c93a58ebd0f4fe562f49fbeb2402c
BLAKE2b-256 b4c8580f19bc37fccb12f166867ac438e50d15d29292968af4d60b66e93b5d13

See more details on using hashes here.

Provenance

The following attestation bundles were made for apricity-0.6.0.tar.gz:

Publisher: release.yml on epinethrone/apricity

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file apricity-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: apricity-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 3.8 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for apricity-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3ae1553381923e863961b082915c67f8b407686741f68f5dd83e2b89ba5a31c6
MD5 d327c6d34dde1fca6abe5bc4d7797686
BLAKE2b-256 8d9f44fc5a65d7ca77e3534c7d13534083ea389d95695f9c058d24db916f975f

See more details on using hashes here.

Provenance

The following attestation bundles were made for apricity-0.6.0-py3-none-any.whl:

Publisher: release.yml on epinethrone/apricity

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page