c r y s t a l l i z e d
Memory that grows. Identity that forms. Auth that works.
Quick Start ·
Why ·
How ·
FAQ ·
Troubleshooting ·
Русский
Crystallized is a persistent memory MCP server for opencode, the AI coding agent — it gives your agent long-term memory across sessions. It combines three storage layers — Redis facts, ChromaDB semantic vector search, and markdown documents — under power-law memory decay, so important context stays loud while old noise fades and nothing is deleted. On top of memory it forms an evolving agent identity and ships first-party Anthropic authentication, letting you use your Claude Max plan in opencode without third-party client detection.
- Three-layer memory: Redis for instant facts, ChromaDB for semantic search across sessions, filesystem for structured documents
- Automatic memory injection: every prompt gets enriched with relevant context from previous conversations
- Agent identity: beliefs, focus areas, and observations start empty and crystallize over time through work
- Memory decay: power-law fading; important things stay loud, old noise goes quiet, nothing is deleted
- First-party auth: OAuth tokens extracted from Claude.app; your Max plan, not the $200 third-party credit pool
- Sisyphus orchestration: oh-my-openagent with parallel agents, skill loading, structured delegation
- macOS (primary) or Linux
- Python 3.11+
- Claude.app: installed and logged in with your Max account
- Homebrew on macOS
# Quit Claude.app first (Cmd+Q)
git clone https://github.com/enkinvsh/crystallized.git
cd crystallized
./install.sh
opencodeThe installer handles Redis, Python deps, opencode CLI, memory server, config, and auth extraction.
The repository tracks memory/uv.lock so every install resolves to the same Python dependency versions. To refresh the lockfile after editing memory/pyproject.toml, run uv lock inside the memory/ directory and commit the updated lockfile.
- Checks prerequisites (Git, Python 3.11+, Homebrew on macOS, jq).
- Installs and starts Redis via Homebrew (or
apton Linux), or shares an existing local Redis on port 6379. - Installs the
uvPython package manager from astral.sh. - Installs the
opencodeCLI from GitHub releases if it is not already on PATH. - Deploys the memory MCP server scripts to
~/.config/opencode/memory/. - Installs Python dependencies into
~/.config/opencode/memory/.venvviauv sync --frozen. - Seeds identity templates (beliefs, focus, observations, journal) into
~/.config/opencode/memory/notes/. - Writes or merges
~/.config/opencode/opencode.jsonwith the memory MCP entry and pre-prompt hooks. Before merging, it backs up the existing file. - On macOS, extracts your Claude.app OAuth tokens via Keychain and writes them to
~/.local/share/opencode/auth.json.
- Does not modify Claude.app or its files.
- Does not change your shell rc files. If
opencodeis not on PATH after install, the installer prints a one-lineexport PATH=...hint for you to add yourself. - Does not phone home. No telemetry, no analytics, no remote logging.
- Does not work on Windows. WSL is not tested.
- Does not detect Claude.app outside
/Applications/Claude.app. If you installed Claude to a non-default location, runpython3 auth/extract_token.pymanually.
- The Keychain may prompt for your macOS login password during auth extraction. Pick "Always Allow" to skip future prompts.
- Linux skips the automatic auth step. You need to extract tokens from a Mac, or use an API key directly, or accept third-party routing.
- The installer assumes a single-user Mac. Multi-user shared installs are not supported.
- ChromaDB cold start can take 10 to 30 seconds on the first MCP call while the sentence-transformer model downloads.
All runtime environment variables are optional. If you do not set them, the defaults preserve v1.0 behavior.
| Variable | Purpose |
|---|---|
REDIS_URL |
Full Redis connection URL. |
REDIS_HOST |
Redis host when REDIS_URL is not set. |
REDIS_PORT |
Redis port when REDIS_URL is not set. |
REDIS_DB |
Redis database number. |
OPENCODE_MEMORY_SOCKET |
MCP socket path for memory hooks. |
OPENCODE_MEMORY_NOTES_DIR |
Notes directory for saved documents and identity files. |
OPENCODE_MEMORY_CHROMA_DIR |
ChromaDB persistence directory. |
Pull the new code, then re-run ./install.sh. The installer backs up opencode.json before merging the new memory hooks and MCP config.
The new environment variables are optional. If you do not set them, the defaults preserve v1.0 behavior.
If something breaks, run ./uninstall.sh, then re-run ./install.sh.
See CHANGELOG.md for full release notes.
Anthropic detects third-party clients and routes their API calls to a separate $200 credit pool instead of your Max subscription. Community auth plugins obtain OAuth tokens with a third-party client_id, so every request gets flagged.
Crystallized extracts tokens directly from Claude.app. These carry Claude's own client_id, so Anthropic treats your opencode sessions as first-party. Max plan limits apply normally.
memory-inject.py runs as a pre-prompt hook on every message. It searches all three layers for relevant context and prepends it:
| Layer | Engine | Purpose |
|---|---|---|
| Facts | Redis | Names, decisions, preferences, instant key/value lookups |
| Semantic | ChromaDB | Vector similarity across everything the agent ever remembered |
| Documents | Filesystem | Architecture notes, checklists, session summaries |
Decay runs on a power-law schedule. Memories are never deleted, they get quieter.
own-voice.py injects the agent's evolving identity into each prompt. Beliefs, focus areas, and observations start as empty files and fill up as the agent works. The personality is earned through experience, not configured upfront.
auth/extract_token.py decrypts Claude.app's Electron safeStorage (AES-128-CBC via macOS Keychain), extracts OAuth tokens, and writes them to opencode's auth.json. Token refresh is handled by opencode internally, no auth plugin at runtime.
~/.config/opencode/
├── opencode.json # MCP servers, plugins
└── memory/
├── server.py # MCP memory server (Redis + ChromaDB + fs)
├── memory-inject.py # Pre-prompt hook: context injection
├── own-voice.py # Pre-prompt hook: identity injection
├── pyproject.toml # Python dependencies
├── chroma_db/ # Vector database (generated)
├── notes/self/ # Agent identity (generated)
│ ├── beliefs.md
│ ├── focus.md
│ └── observations.md
└── identity.json # Volume map (generated)
~/.local/share/opencode/
└── auth.json # OAuth tokens (from Claude.app)
"Third-party apps" error, wrong token. Quit Claude.app, then:
python3 auth/extract_token.pyTry each index if you have multiple workspaces.
Memory MCP is red, redis-cli ping should return PONG. Also verify the uv path in opencode.json is absolute. The installer handles this, but manual edits can break it.
Keychain access denied, needs GUI terminal, not pure SSH. Or unlock first:
security unlock-keychain ~/Library/Keychains/login.keychain-dbLinux, auth extraction is macOS-only (Claude.app). Bring tokens from a Mac, use an API key directly, or accept third-party routing.
The memory server is a standalone Python package managed with uv. Run the test suite (67 pytest tests covering facts, semantic search, decay, and identity):
cd memory && uv run pytest tests/ -qLint with ruff before sending a change:
uv run ruff check .Release notes live in CHANGELOG.md; the threat model and disclosure policy live in SECURITY.md.
Does opencode forget context between sessions? By default, yes — each session starts cold. Crystallized fixes this: it persists facts, semantic memories, and documents to disk and re-injects the relevant ones into every prompt, so the agent carries long-term memory across sessions.
Will this work with other MCP clients, or only opencode? The memory server is a standard Model Context Protocol server, so any MCP client can connect to it. The installer, pre-prompt hooks, and identity injection are tailored to opencode, so other clients get the memory tools but not the automatic context injection.
Is my data sent anywhere? No. Memory lives entirely on your machine — Redis, ChromaDB, and markdown files on local disk. There is no telemetry, no analytics, and no remote logging. See SECURITY.md for the full threat model.
Why does Anthropic route opencode to a $200 credit pool?
Anthropic detects third-party clients by their OAuth client_id and bills them against a separate credit pool instead of your subscription. Crystallized extracts first-party tokens from Claude.app, so opencode is treated as first-party and your Claude Max plan limits apply normally.
Does memory grow unbounded? No. Memory decays on a power-law schedule: entries get quieter over time unless they are reinforced. Nothing is ever deleted — old noise just stops surfacing while important context stays loud.
Is there Windows support? No. Crystallized targets macOS (primary) and Linux. WSL is untested, and auth extraction depends on macOS Keychain.