TypeScript-native memory palace for AI agents
A complete, zero-Python port of the MemPalace project. Provides persistent memory, knowledge graphs, semantic search, and automatic session saving for AI coding agents.
| Requirement | Version | Notes |
|---|---|---|
| Node.js | >= 20 | Required by engine constraints |
| pnpm | >= 10 | Enforced via packageManager field (pnpm@10.11.0) |
| ChromaDB server | Latest | Required for vector search features; runs on localhost:8000 by default |
pip install chromadb
chroma run --path /tmp/chroma-dataOr via Docker:
docker run -p 8000:8000 chromadb/chromagit clone <repo-url>
cd mempalace-ts
pnpm install
pnpm buildVerify the build:
pnpm testThe monorepo contains three packages:
@mempalace-ts/core-- Core library (memory stack, mining, search, hooks, knowledge graph)@mempalace-ts/cli-- Command-line interface@mempalace-ts/mcp-- MCP server (Model Context Protocol)
MemPalace hooks integrate with Claude Code's hook system to automatically save session context at regular intervals and before context compaction. Three hooks are available:
| Hook | Function | Purpose |
|---|---|---|
stop |
hookStop |
Blocks every 15 exchanges to trigger an auto-save checkpoint |
precompact |
hookPrecompact |
Blocks before compaction to save all context that would otherwise be lost |
session-start |
hookSessionStart |
Initializes session tracking state |
Create a file at ./scripts/mempalace-hook.mjs (or any convenient location):
#!/usr/bin/env node
/**
* Hook runner for Claude Code.
* Reads JSON from stdin, calls the appropriate mempalace hook,
* and writes JSON response to stdout.
*
* Usage: echo '{"session_id":"..."}' | node mempalace-hook.mjs <hook-name>
*/
import { runHook } from '@mempalace-ts/core';
const hookName = process.argv[2]; // "stop", "precompact", or "session-start"
let input = '';
process.stdin.setEncoding('utf-8');
for await (const chunk of process.stdin) {
input += chunk;
}
const data = JSON.parse(input);
const result = runHook(hookName, 'claude-code', data);
process.stdout.write(JSON.stringify(result));Make it executable:
chmod +x ./scripts/mempalace-hook.mjsAdd the following to your project-level .claude/settings.json or your user-level ~/.claude/settings.json:
{
"hooks": {
"stop": [
{
"command": "node /absolute/path/to/mempalace-ts/scripts/mempalace-hook.mjs stop",
"timeout": 10000
}
],
"precompact": [
{
"command": "node /absolute/path/to/mempalace-ts/scripts/mempalace-hook.mjs precompact",
"timeout": 10000
}
],
"session-start": [
{
"command": "node /absolute/path/to/mempalace-ts/scripts/mempalace-hook.mjs session-start",
"timeout": 10000
}
]
}
}Replace /absolute/path/to/mempalace-ts/ with the actual path to your installation.
- Stop hook: Every 15 human messages, the hook returns
{ "decision": "block", "reason": "..." }, which instructs Claude Code to pause and save key topics, decisions, quotes, and code to the memory system before continuing. - Precompact hook: When context compaction is about to occur, the hook always blocks to ensure comprehensive saving of all session context.
- Session-start hook: Initializes state tracking for the session. Returns no blocking decision.
Hook state is stored in ~/.mempalace/hook_state/ and logs are written to ~/.mempalace/hook_state/hook.log.
The @mempalace-ts/mcp package contains a Model Context Protocol server. This is a work in progress and not yet fully implemented in the TypeScript port. When complete, it will allow Claude Code to access memory search and storage through MCP tool calls.
You can import and use mempalace functions directly:
import {
searchMemories,
mine,
mineConvos,
MemoryStack,
MempalaceConfig,
KnowledgeGraph,
} from '@mempalace-ts/core';
// Wake-up flow: load identity + essential memories
const stack = new MemoryStack();
const context = await stack.wakeUp();
// Search memories by query
const results = await searchMemories('authentication refactor decisions');
// Mine a project directory into the memory palace
await mine('/path/to/project');
// Mine conversation transcripts
await mineConvos('/path/to/transcripts');MemoryStack provides tiered memory retrieval:
| Layer | Name | Purpose |
|---|---|---|
| L0 | Identity | Core identity and personality (always loaded) |
| L1 | Essential | Most important memories, capped for context efficiency |
| L2 | On-demand | Retrieved when a specific topic is queried |
| L3 | Deep search | Full semantic search across the entire palace |
MemPalace hooks support Codex as a harness out of the box. The hook system accepts 'codex' as a harness name.
#!/usr/bin/env node
import { runHook } from '@mempalace-ts/core';
const hookName = process.argv[2];
let input = '';
process.stdin.setEncoding('utf-8');
for await (const chunk of process.stdin) {
input += chunk;
}
const data = JSON.parse(input);
const result = runHook(hookName, 'codex', data);
process.stdout.write(JSON.stringify(result));Register the runner script for the stop, precompact, and session-start events according to your Codex environment's hook configuration. The input/output contract is the same:
- Input (stdin): JSON object with
session_id,transcript_path, andstop_hook_activefields - Output (stdout): JSON object, optionally containing
{ "decision": "block", "reason": "..." }
import { searchMemories, mine, MemoryStack } from '@mempalace-ts/core';
// Load context at session start
const stack = new MemoryStack();
const context = await stack.wakeUp();
// Search for relevant memories mid-session
const results = await searchMemories('database migration strategy');
// Mine project files
await mine('/path/to/project');- Session start: Call
MemoryStack.wakeUp()to hydrate L0 + L1 context. - Mid-session: Use
searchMemories()for L2/L3 retrieval when the agent encounters a topic that needs deeper context. - Session end / checkpoints: The hook system handles this automatically, or call
mineConvos()on the transcript manually. - Project onboarding: Run
mine()on new project directories to build the memory palace with room/wing taxonomy.
pnpm test # Unit tests (vitest)
pnpm bench # Performance benchmarks (requires a running ChromaDB instance)Additional commands:
pnpm lint # ESLint across all packages
pnpm typecheck # TypeScript type checking (tsc --build)
pnpm clean # Remove all build artifactspackages/
core/ Core library
config Palace configuration and project detection
miner File mining: scans projects, chunks text, stores in ChromaDB
convo-miner Conversation transcript mining
searcher Semantic search across the memory palace
knowledge-graph Entity/triple store backed by SQLite (better-sqlite3)
palace-graph Graph traversal and tunnel detection across wings/rooms
layers L0-L3 memory stack with tiered retrieval
dialect AAAK compression for token-efficient storage
hooks Session hooks for Claude Code and Codex
entity-detector Named entity recognition in text
room-detector Automatic room/wing classification
instructions Instruction templates for AI agents
spellcheck Transcript spellchecking
split-mega-files Large file splitting at session boundaries
cli/ Command-line interface
mcp/ MCP server (Model Context Protocol)
L0 (Identity) Always loaded. Core identity, personality, preferences.
|
L1 (Essential) Top-priority memories. Capped by drawer count and char limit.
|
L2 (On-demand) Topic-specific retrieval. Loaded when a query matches.
|
L3 (Deep search) Full semantic vector search across ChromaDB.
The Dialect module compresses memories using emotion codes and shorthand notation to reduce token usage while preserving semantic content. This is the "AAAK" (Abbreviated Adaptive Associative Knowledge) encoding.
Memories are organized into wings (broad categories) containing rooms (specific topics). The miner automatically detects appropriate rooms based on file paths, content patterns, and folder structure.
This project follows strict supply chain security practices. See SECURITY.md for full details, including:
- All dependencies pinned to exact versions (no
^or~ranges) - Reproducible installs via
packageManagerfield - No
eval(),new Function(), or dynamic code execution - All SQL queries use parameterized statements
- No telemetry or phone-home behavior
Ensure ChromaDB is running on localhost:8000 (the default). Start it with:
chroma run --path /tmp/chroma-data- Check that the path in your
settings.jsonis absolute and correct. - Verify the script is executable:
chmod +x scripts/mempalace-hook.mjs - Check hook logs:
cat ~/.mempalace/hook_state/hook.log - Test manually:
echo '{"session_id":"test"}' | node scripts/mempalace-hook.mjs stop
Ensure you are using the correct pnpm version:
corepack enable
corepack prepare pnpm@10.11.0 --activate
pnpm install
pnpm build