docs: add VitePress documentation site
- 22 content pages across Guide, Concepts, and Reference sections - Custom indigo/cyan theme with Lucide icons and Mermaid diagrams - GitHub Actions workflow for GitHub Pages deployment - Live preview: https://mempalace-docs.netlify.app/
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# AAAK Dialect
|
||||
|
||||
AAAK is an experimental lossy abbreviation system designed to pack repeated entities and relationships into fewer tokens at scale. It is readable by any LLM — Claude, GPT, Gemini, Llama, Mistral — without a decoder.
|
||||
|
||||
::: warning Experimental
|
||||
AAAK is a separate compression layer, **not the storage default**. The 96.6% benchmark score comes from raw verbatim mode. AAAK mode currently scores 84.2% R@5 — a 12.4 point regression. We're iterating.
|
||||
:::
|
||||
|
||||
## What AAAK Is
|
||||
|
||||
- **Lossy, not lossless.** Uses regex-based abbreviation, not reversible compression.
|
||||
- **A structured summary format.** Extracts entities, topics, key sentences, emotions, and flags from plain text.
|
||||
- **Readable by any LLM.** No decoder needed — models read it naturally.
|
||||
- **Designed for scale.** Saves tokens when the same entities appear hundreds of times.
|
||||
|
||||
## What AAAK Is Not
|
||||
|
||||
- **Not lossless compression.** The original text cannot be reconstructed.
|
||||
- **Not efficient at small scale.** Short text already tokenizes efficiently — AAAK overhead costs more than it saves.
|
||||
- **Not the default storage format.** MemPalace stores raw verbatim text in ChromaDB.
|
||||
|
||||
## Format
|
||||
|
||||
```
|
||||
Header: FILE_NUM|PRIMARY_ENTITY|DATE|TITLE
|
||||
Zettel: ZID:ENTITIES|topic_keywords|"key_quote"|WEIGHT|EMOTIONS|FLAGS
|
||||
Tunnel: T:ZID<->ZID|label
|
||||
Arc: ARC:emotion->emotion->emotion
|
||||
```
|
||||
|
||||
### Entity Codes
|
||||
|
||||
Three-letter uppercase codes: `ALC=Alice`, `KAI=Kai`, `MAX=Max`.
|
||||
|
||||
### Emotion Codes
|
||||
|
||||
| Code | Meaning | Code | Meaning |
|
||||
|------|---------|------|---------|
|
||||
| `vul` | vulnerability | `joy` | joy |
|
||||
| `fear` | fear | `trust` | trust |
|
||||
| `grief` | grief | `wonder` | wonder |
|
||||
| `rage` | rage | `love` | love |
|
||||
| `hope` | hope | `despair` | despair |
|
||||
| `peace` | peace | `humor` | humor |
|
||||
| `tender` | tenderness | `raw` | raw honesty |
|
||||
| `doubt` | self-doubt | `relief` | relief |
|
||||
| `anx` | anxiety | `exhaust` | exhaustion |
|
||||
|
||||
### Flags
|
||||
|
||||
| Flag | Meaning |
|
||||
|------|---------|
|
||||
| `ORIGIN` | Origin moment (birth of something) |
|
||||
| `CORE` | Core belief or identity pillar |
|
||||
| `SENSITIVE` | Handle with absolute care |
|
||||
| `PIVOT` | Emotional turning point |
|
||||
| `GENESIS` | Led directly to something existing |
|
||||
| `DECISION` | Explicit decision or choice |
|
||||
| `TECHNICAL` | Technical architecture detail |
|
||||
|
||||
## Example
|
||||
|
||||
**Input:**
|
||||
```
|
||||
We decided to use GraphQL instead of REST because the frontend team needs
|
||||
flexible queries. Kai recommended it after researching both options. The team
|
||||
was excited about the schema-first approach.
|
||||
```
|
||||
|
||||
**AAAK output:**
|
||||
```
|
||||
0:KAI|graphql_rest_decided|"decided to use GraphQL instead of REST"|determ+excite|DECISION+TECHNICAL
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Compress drawers
|
||||
|
||||
```bash
|
||||
# Preview compression
|
||||
mempalace compress --wing myapp --dry-run
|
||||
|
||||
# Compress and store
|
||||
mempalace compress --wing myapp
|
||||
```
|
||||
|
||||
### With entity config
|
||||
|
||||
```bash
|
||||
mempalace compress --wing myapp --config entities.json
|
||||
```
|
||||
|
||||
Entity config format:
|
||||
```json
|
||||
{
|
||||
"entities": {"Alice": "ALC", "Bob": "BOB"},
|
||||
"skip_names": ["Gandalf", "Sherlock"]
|
||||
}
|
||||
```
|
||||
|
||||
### Python API
|
||||
|
||||
```python
|
||||
from mempalace.dialect import Dialect
|
||||
|
||||
# Basic compression
|
||||
dialect = Dialect()
|
||||
compressed = dialect.compress("We decided to use GraphQL...")
|
||||
|
||||
# With entity mappings
|
||||
dialect = Dialect(entities={"Alice": "ALC", "Kai": "KAI"})
|
||||
compressed = dialect.compress(text, metadata={"wing": "myapp", "room": "arch"})
|
||||
|
||||
# From config file
|
||||
dialect = Dialect.from_config("entities.json")
|
||||
```
|
||||
|
||||
## When to Use AAAK
|
||||
|
||||
AAAK is most useful when:
|
||||
- You have **many repeated entities** across thousands of sessions
|
||||
- You need to **compress context** for local models with small windows
|
||||
- You want **structured summaries** pointing back to verbatim drawers
|
||||
|
||||
For most users, raw verbatim mode is the better default.
|
||||
@@ -0,0 +1,61 @@
|
||||
# Specialist Agents
|
||||
|
||||
MemPalace currently supports **agent diaries** through MCP tools. The practical model is simple: give an agent a stable name, and write/read diary entries under that agent's wing.
|
||||
|
||||
::: warning Current Scope
|
||||
This page documents the diary workflow that exists today. MemPalace does **not** currently ship an agent registry, `~/.mempalace/agents/*.json`, or a `mempalace_list_agents` tool.
|
||||
:::
|
||||
|
||||
## What Agents Do
|
||||
|
||||
Each agent:
|
||||
|
||||
- **Has a focus** — what it pays attention to
|
||||
- **Keeps a diary** — entries persist across sessions
|
||||
- **Can read recent history** — useful for patterns, continuity, and follow-up work
|
||||
|
||||
## Agent Diary
|
||||
|
||||
The diary is a lightweight memory stream for one named agent: observations, findings, decisions, and recurring patterns.
|
||||
|
||||
### Writing Entries
|
||||
|
||||
```text
|
||||
MCP tool: mempalace_diary_write
|
||||
arguments: {
|
||||
"agent_name": "reviewer",
|
||||
"entry": "PR#42|auth.bypass.found|missing.middleware.check|pattern:3rd.time.this.quarter|★★★★"
|
||||
}
|
||||
```
|
||||
|
||||
### Reading History
|
||||
|
||||
```text
|
||||
MCP tool: mempalace_diary_read
|
||||
arguments: { "agent_name": "reviewer", "last_n": 10 }
|
||||
→ returns last 10 findings, compressed in AAAK
|
||||
```
|
||||
|
||||
### MCP Tools
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `mempalace_diary_write` | Write an AAAK diary entry |
|
||||
| `mempalace_diary_read` | Read recent diary entries |
|
||||
|
||||
## How It Works
|
||||
|
||||
Each named agent maps to its own wing in the palace:
|
||||
- `wing_reviewer` — the reviewer's diary, findings, patterns
|
||||
- `wing_architect` — the architect's decisions, tradeoffs
|
||||
- `wing_ops` — the ops agent's incidents, deploys
|
||||
|
||||
All entries go into a `diary` room within the wing, tagged with topic, timestamp, and agent name.
|
||||
|
||||
## Specialization
|
||||
|
||||
Separate diary streams let you keep different working contexts apart. A reviewer can keep bug patterns, an architect can keep decisions, and an ops agent can keep incident notes without mixing them into one shared log.
|
||||
|
||||
::: tip
|
||||
If you use multiple specialist prompts or toolchains, keep the agent names stable so each one writes back to the same diary wing over time.
|
||||
:::
|
||||
@@ -0,0 +1,33 @@
|
||||
# Contradiction Detection
|
||||
|
||||
::: warning Experimental
|
||||
Contradiction detection is a planned capability, not a shipped end-to-end feature in the current MCP workflow. The examples below show the intended behavior rather than a fully integrated command path.
|
||||
:::
|
||||
|
||||
## What It Does
|
||||
|
||||
Checks assertions against entity facts in the knowledge graph. When enabled, it catches contradictions like:
|
||||
|
||||
```
|
||||
Input: "Soren finished the auth migration"
|
||||
Output: 🔴 AUTH-MIGRATION: attribution conflict — Maya was assigned, not Soren
|
||||
|
||||
Input: "Kai has been here 2 years"
|
||||
Output: 🟡 KAI: wrong_tenure — records show 3 years (started 2023-04)
|
||||
|
||||
Input: "The sprint ends Friday"
|
||||
Output: 🟡 SPRINT: stale_date — current sprint ends Thursday (updated 2 days ago)
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
Facts are checked against the knowledge graph:
|
||||
- **Attribution conflicts** — the wrong person credited for a task
|
||||
- **Temporal errors** — wrong dates, tenures, or durations
|
||||
- **Stale information** — facts that have been superseded
|
||||
|
||||
Ages, dates, and tenures are calculated dynamically from the entity's recorded facts — not hardcoded.
|
||||
|
||||
## Status
|
||||
|
||||
The current codebase includes the temporal knowledge graph primitives needed for this direction, but not a complete contradiction-checking tool exposed through the CLI or MCP server.
|
||||
@@ -0,0 +1,91 @@
|
||||
# Knowledge Graph
|
||||
|
||||
MemPalace includes a temporal entity-relationship graph — like Zep's Graphiti, but SQLite instead of Neo4j. Local and free.
|
||||
|
||||
## What It Stores
|
||||
|
||||
Entity-relationship triples with temporal validity:
|
||||
|
||||
```
|
||||
Subject → Predicate → Object [valid_from → valid_to]
|
||||
```
|
||||
|
||||
Facts have time windows. When something stops being true, you invalidate it — and historical queries still find it.
|
||||
|
||||
## Usage
|
||||
|
||||
### Python API
|
||||
|
||||
```python
|
||||
from mempalace.knowledge_graph import KnowledgeGraph
|
||||
|
||||
kg = KnowledgeGraph()
|
||||
|
||||
# Add facts
|
||||
kg.add_triple("Kai", "works_on", "Orion", valid_from="2025-06-01")
|
||||
kg.add_triple("Maya", "assigned_to", "auth-migration", valid_from="2026-01-15")
|
||||
kg.add_triple("Maya", "completed", "auth-migration", valid_from="2026-02-01")
|
||||
|
||||
# Query: everything about Kai
|
||||
kg.query_entity("Kai")
|
||||
# → [Kai → works_on → Orion (current), Kai → recommended → Clerk (2026-01)]
|
||||
|
||||
# Query: what was true in January?
|
||||
kg.query_entity("Maya", as_of="2026-01-20")
|
||||
# → [Maya → assigned_to → auth-migration (active)]
|
||||
|
||||
# Timeline
|
||||
kg.timeline("Orion")
|
||||
# → chronological story of the project
|
||||
```
|
||||
|
||||
### Invalidating Facts
|
||||
|
||||
When something stops being true:
|
||||
|
||||
```python
|
||||
kg.invalidate("Kai", "works_on", "Orion", ended="2026-03-01")
|
||||
```
|
||||
|
||||
Now queries for Kai's current work won't return Orion. Historical queries still will.
|
||||
|
||||
### MCP Tools
|
||||
|
||||
Through the MCP server, the knowledge graph is available as tools:
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `mempalace_kg_query` | Query entity relationships with time filtering |
|
||||
| `mempalace_kg_add` | Add facts |
|
||||
| `mempalace_kg_invalidate` | Mark facts as ended |
|
||||
| `mempalace_kg_timeline` | Chronological entity story |
|
||||
| `mempalace_kg_stats` | Graph overview |
|
||||
|
||||
## Storage
|
||||
|
||||
The knowledge graph uses SQLite with two tables:
|
||||
|
||||
**`entities`** — people, projects, tools, concepts:
|
||||
- `id` — lowercase normalized name
|
||||
- `name` — display name
|
||||
- `type` — person, project, tool, concept, etc.
|
||||
- `properties` — JSON blob for extra metadata
|
||||
|
||||
**`triples`** — relationships between entities:
|
||||
- `subject` → `predicate` → `object`
|
||||
- `valid_from` — when this became true
|
||||
- `valid_to` — when it stopped being true (NULL = still current)
|
||||
- `confidence` — 0.0 to 1.0
|
||||
- `source_closet` — link back to the verbatim memory
|
||||
|
||||
Database location: `~/.mempalace/knowledge_graph.sqlite3`
|
||||
|
||||
## Comparison
|
||||
|
||||
| Feature | MemPalace | Zep (Graphiti) |
|
||||
|---------|-----------|----------------|
|
||||
| Storage | SQLite (local) | Neo4j (cloud) |
|
||||
| Cost | Free | $25/mo+ |
|
||||
| Temporal validity | Yes | Yes |
|
||||
| Self-hosted | Always | Enterprise only |
|
||||
| Privacy | Everything local | SOC 2, HIPAA |
|
||||
@@ -0,0 +1,104 @@
|
||||
# Memory Stack
|
||||
|
||||
MemPalace uses a 4-layer memory stack. Each layer loads progressively more data only when needed.
|
||||
|
||||
## The Layers
|
||||
|
||||
| Layer | What | Size | When |
|
||||
|-------|------|------|------|
|
||||
| **L0** | Identity — who is this AI? | ~50-100 tokens | Always loaded |
|
||||
| **L1** | Essential Story — top moments | ~500-800 tokens | Always loaded |
|
||||
| **L2** | Room Recall — filtered retrieval | ~200–500 each | When topic comes up |
|
||||
| **L3** | Deep Search — full semantic query | Variable | When explicitly asked |
|
||||
|
||||
In the current implementation, a typical wake-up is roughly **~600-900 tokens** for L0 + L1. Searches only fire when needed.
|
||||
|
||||
## Layer 0: Identity
|
||||
|
||||
A plain text file at `~/.mempalace/identity.txt`. Always loaded as the AI's self-concept.
|
||||
|
||||
```text
|
||||
I am Atlas, a personal AI assistant for Alice.
|
||||
Traits: warm, direct, remembers everything.
|
||||
People: Alice (creator), Bob (Alice's partner).
|
||||
Project: A journaling app that helps people process emotions.
|
||||
```
|
||||
|
||||
~50 tokens. Tells the AI who it is and who it works with.
|
||||
|
||||
## Layer 1: Essential Story
|
||||
|
||||
Auto-generated from the highest-importance drawers in the palace. Groups by room, picks the top moments, and keeps the output bounded.
|
||||
|
||||
The generation process:
|
||||
1. Reads all drawers from ChromaDB
|
||||
2. Scores each by importance/emotional weight
|
||||
3. Takes the top 15 moments
|
||||
4. Groups by room for readability
|
||||
5. Truncates to fit within 3,200 characters
|
||||
|
||||
```
|
||||
## L1 — ESSENTIAL STORY
|
||||
|
||||
[auth-migration]
|
||||
- Team decided to migrate from Auth0 to Clerk — pricing + DX (session_2026-01-15.md)
|
||||
- Kai debugged the OAuth token refresh issue (session_2026-01-20.md)
|
||||
|
||||
[deploy-process]
|
||||
- Switched to blue-green deploys after the January outage (session_2026-02-01.md)
|
||||
```
|
||||
|
||||
## Layer 2: On-Demand Recall
|
||||
|
||||
Loaded when a specific topic or wing comes up in conversation. Retrieves drawers filtered by wing and/or room — typically ~200–500 tokens.
|
||||
|
||||
```python
|
||||
stack = MemoryStack()
|
||||
stack.recall(wing="driftwood", room="auth")
|
||||
# → returns recent drawers about auth in the driftwood project
|
||||
```
|
||||
|
||||
## Layer 3: Deep Search
|
||||
|
||||
Full semantic search against the entire palace. This is what fires when you or the AI explicitly asks a question.
|
||||
|
||||
```python
|
||||
stack.search("why did we switch to GraphQL")
|
||||
# → returns top-5 matching drawers with similarity scores
|
||||
```
|
||||
|
||||
## Wake-Up Budget
|
||||
|
||||
The point of the stack is bounded startup context, not a fixed universal token count. The exact size depends on your identity file and what Layer 1 selects, but the implementation keeps wake-up meaningfully smaller than loading the full corpus into the prompt.
|
||||
|
||||
## Using the Stack
|
||||
|
||||
### CLI
|
||||
|
||||
```bash
|
||||
# Wake-up context (L0 + L1)
|
||||
mempalace wake-up
|
||||
|
||||
# Project-specific wake-up
|
||||
mempalace wake-up --wing driftwood
|
||||
```
|
||||
|
||||
### Python API
|
||||
|
||||
```python
|
||||
from mempalace.layers import MemoryStack
|
||||
|
||||
stack = MemoryStack()
|
||||
|
||||
# L0 + L1: wake-up (~600-900 tokens in typical use)
|
||||
print(stack.wake_up())
|
||||
|
||||
# L2: on-demand recall
|
||||
print(stack.recall(wing="myapp"))
|
||||
|
||||
# L3: deep search
|
||||
print(stack.search("pricing change"))
|
||||
|
||||
# Status
|
||||
print(stack.status())
|
||||
```
|
||||
@@ -0,0 +1,110 @@
|
||||
# The Palace
|
||||
|
||||
Ancient Greek orators memorized entire speeches by placing ideas in rooms of an imaginary building. Walk through the building, find the idea. MemPalace applies the same principle to AI memory.
|
||||
|
||||
## Structure
|
||||
|
||||
Your conversations are organized into a navigable hierarchy:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph wing_person["WING: Person"]
|
||||
direction TB
|
||||
RA["Room A"] -- hall --> RB["Room B"]
|
||||
RA --> CA["Closet"]
|
||||
CA --> DA["Drawer (verbatim)"]
|
||||
end
|
||||
|
||||
subgraph wing_project["WING: Project"]
|
||||
direction TB
|
||||
RA2["Room A"] -- hall --> RC["Room C"]
|
||||
RA2 --> CA2["Closet"]
|
||||
CA2 --> DA2["Drawer (verbatim)"]
|
||||
end
|
||||
|
||||
RA -.->|tunnel| RA2
|
||||
|
||||
style wing_person fill:#1e1b4b,stroke:#4f46e5,color:#e0e7ff
|
||||
style wing_project fill:#164e63,stroke:#06b6d4,color:#cffafe
|
||||
style RA fill:#312e81,stroke:#6366f1,color:#e0e7ff
|
||||
style RB fill:#312e81,stroke:#6366f1,color:#e0e7ff
|
||||
style CA fill:#3b0764,stroke:#8b5cf6,color:#f3e8ff
|
||||
style DA fill:#0f766e,stroke:#14b8a6,color:#ccfbf1
|
||||
style RA2 fill:#155e75,stroke:#22d3ee,color:#cffafe
|
||||
style RC fill:#155e75,stroke:#22d3ee,color:#cffafe
|
||||
style CA2 fill:#3b0764,stroke:#8b5cf6,color:#f3e8ff
|
||||
style DA2 fill:#0f766e,stroke:#14b8a6,color:#ccfbf1
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### Wings
|
||||
|
||||
A person or project. As many as you need.
|
||||
|
||||
Every project, person, or topic gets its own wing in the palace. Wings are the top-level organizational unit.
|
||||
|
||||
### Rooms
|
||||
|
||||
Specific topics within a wing. Examples: `auth-migration`, `graphql-switch`, `ci-pipeline`.
|
||||
|
||||
Rooms are named ideas. They're auto-detected from your folder structure during `mempalace init`, and you can create additional rooms manually.
|
||||
|
||||
### Halls
|
||||
|
||||
Halls are the conceptual categories that describe how related memories connect *within* a wing:
|
||||
|
||||
- `hall_facts` — decisions made, choices locked in
|
||||
- `hall_events` — sessions, milestones, debugging
|
||||
- `hall_discoveries` — breakthroughs, new insights
|
||||
- `hall_preferences` — habits, likes, opinions
|
||||
- `hall_advice` — recommendations and solutions
|
||||
|
||||
### Tunnels
|
||||
|
||||
Connections *between* wings. When the same room appears in different wings, the graph layer can treat that as a cross-wing connection.
|
||||
|
||||
```
|
||||
wing_kai / hall_events / auth-migration → "Kai debugged the OAuth token refresh"
|
||||
wing_driftwood / hall_facts / auth-migration → "team decided to migrate auth to Clerk"
|
||||
wing_priya / hall_advice / auth-migration → "Priya approved Clerk over Auth0"
|
||||
```
|
||||
|
||||
Same room. Three wings. The graph can use that shared room name as a bridge.
|
||||
|
||||
### Closets
|
||||
|
||||
Closets are the summary layer in the broader MemPalace vocabulary: compact notes that point back to the original content. In the current implementation, the main persisted storage path is still the underlying drawer text plus metadata.
|
||||
|
||||
### Drawers
|
||||
|
||||
The original stored text chunks. This is the primary retrieval layer used by the current search and benchmark flows.
|
||||
|
||||
## Why Structure Matters
|
||||
|
||||
Tested on 22,000+ real conversation memories:
|
||||
|
||||
| Search scope | R@10 | Improvement |
|
||||
|-------------|------|-------------|
|
||||
| All closets | 60.9% | baseline |
|
||||
| Within wing | 73.1% | +12% |
|
||||
| Wing + hall | 84.8% | +24% |
|
||||
| Wing + room | 94.8% | +34% |
|
||||
|
||||
The practical point is that structure improves retrieval. In the project benchmarks, narrowing the search scope by wing and room outperformed searching the entire corpus at once.
|
||||
|
||||
## Navigation
|
||||
|
||||
The palace supports graph traversal across wings:
|
||||
|
||||
```text
|
||||
MCP tool: mempalace_traverse
|
||||
arguments: { "start_room": "auth-migration" }
|
||||
→ discovers rooms in wing_kai, wing_driftwood, wing_priya
|
||||
|
||||
MCP tool: mempalace_find_tunnels
|
||||
arguments: { "wing_a": "wing_code", "wing_b": "wing_team" }
|
||||
→ auth-migration, deploy-process, ci-pipeline
|
||||
```
|
||||
|
||||
This is the navigation story: shared room structure gives the model more than one way to reach relevant context.
|
||||
Reference in New Issue
Block a user