LadyM

module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 20, 2026 License: MIT

README

LadyM

Tests MCP Storage

English | 简体中文

A brain-inspired, multi-tier memory framework that lets LLM agents recall workspace knowledge and codebase analysis with one keyword — instead of re-Read-ing and re-Grep-ing the same files every turn.

LadyM caches your workspace's understanding — code analysis, decisions, skills, and episodes — into a hierarchical, consolidating, decaying memory that any agent can recall through a single keyword. Written in Go as a single static binary with zero cgo: SQLite via modernc.org/sqlite, an in-process brute-force cosine vector index, and gotreesitter (a pure-Go tree-sitter runtime) for code indexing. Exposed via MCP, Claude Code Skill, Go SDK, and CLI — all calling the same engine so behaviour is identical everywhere.


What's New in 0.3.0

  • Full Go rewrite — LadyM is now one static binary with no Python dependency and zero cgo. Install with go install or build from source; there is nothing else to set up.
  • Pure-Go storage stack — SQLite runs on modernc.org/sqlite, and the old sqlite-vec extension is replaced by an in-process brute-force cosine index (storage/vector_index.go), so the binary stays hermetic and cross-compiles anywhere.
  • Pure-Go tree-sitter — code indexing uses gotreesitter, which loads the same parse tables as upstream tree-sitter without native builds.
  • One engine, every front — the MCP server, CLI, and Go SDK all wrap the same engine.Engine; behaviour is identical in every host.

The problem

Today's coding agents have no long-term memory. Every turn they re-Read the same files and re-Grep for the same symbols, burning the context window on rediscovery. Plain vector RAG helps, but it forgets why a decision was made, how a task was done before, and what the codebase actually looks like beyond flat chunks.

LadyM turns that throwaway rediscovery into structured, evolving memory.

Why LadyM

What you get
🧠 Code memory + general memory in one layer L2 fuses tree-sitter code symbols and plain facts in a single store, scored by one activation function. Memory and codebase RAG are one system, not two — a unique spot no other framework occupies.
🔒 Local-first, zero-config start Default HashingEmbedding + llm.provider="none" runs the moment install finishes: no network, no model download, no API key. One SQLite file holds everything.
🧬 Brain-inspired six layers + dual-path L0–L4 core store (working / episodic / semantic / procedural / associative) plus a System 2 worker that extracts L5 mental models and L6 forward intents, with a supersedes evolution chain so memories evolve instead of piling up.
🔌 Four fronts, one engine MCP server, Claude Code Skill, Go SDK, and CLI all call the same Engine — identical behaviour whether you're in Claude Code, Cursor, a script, or the terminal.

Quick start (30 seconds)

# 1. install (single static binary — no network or API key needed at runtime)
go install github.com/ProjAnvil/LadyM/cmd/ladym@latest

# 2. index the codebase you keep re-grepping
ladym index ./src

# 3. ask a question — get the analysis back, no Read/Grep needed
ladym recall "how does password verification work" --code

# 4. store a fact for later
ladym remember "auth uses JWT with 24h expiry" --tags auth,security

That's it — ladym is on your PATH and works fully offline.

How it compares

Local-first Codebase RAG fused Brain-inspired tiers Open source MCP/Skill/SDK/CLI
LadyM ✅ L2 fused ✅ L0–L6 + System 1/2 ✅ MIT ✅ all four
mem0 partial flat + graph SDK
Zep / Graphiti cloud temporal knowledge graph SDK
Letta (MemGPT) self-host OS-style agent runtime SDK
Tencent Hy-Memory cloud SaaS ✅ L1–L6 SDK

LadyM borrows academic ideas from all of them (see ARCHITECTURE.md §10) — its distinctive bet is fusing codebase RAG into a brain-inspired memory that runs fully local.

Architecture

   System 1 — online (ms)                 System 2 — offline worker (s–min)
   ┌───────────────────────────┐          ┌───────────────────────────┐
   │ L0  Working      (scratch)│          │ L5  Mental Model          │
   │ L1  Episodic     (events) │ extract  │     (cognitive frameworks)│
   │ L2  Semantic  (facts+CODE)│─────────▶│ L6  Forward Intent        │
   │ L3  Procedural  (playbook)│          │     (predictive actions)  │
   │ L4  Associative (graph)   │          └───────────────────────────┘
   └───────────────────────────┘
                 ▲
   read ◀──── recall(query) : two-tier (lightweight → deep) + reflection gate
   write ───▶ encode / consolidate / proceduralize / link / forget / decay
Layer Brain analogue LadyM behaviour
L0 Working Prefrontal cortex (working memory) In-process bounded scratch buffer
L1 Episodic Hippocampus Time-stamped events; base-level decay
L2 Semantic Neocortex Consolidated facts and code analysis — one store
L3 Procedural Basal ganglia Playbooks + verified snippets, versioned
L4 Associative Associative cortex Zettelkasten edges with temporal validity
L5 Mental Model (metacognition) Cognitive frameworks abstracted from recurring episodes
L6 Forward Intent (planning) Predictive next-actions, asynchronously distilled

Operations: encode (perception), consolidate (hippocampal replay → neocortex), proceduralize (skill acquisition), recall (retrieval), link (association), forget (synaptic pruning), reflect (metacognition).

The read path is heuristic-only — no LLM judge is ever invoked during recall, so it stays fast and predictable. For the full cognitive-science provenance (what's borrowed from MemGPT, mem0, A-MEM, Zep, HyMem, CoALA, ACT-R, and Anthropic's context-engineering work) see ARCHITECTURE.md.

Install

go install github.com/ProjAnvil/LadyM/cmd/ladym@latest

This drops a single static ladym binary on your Go bin path ($(go env GOPATH)/bin). Requires Go 1.26+ to build; the binary itself has no runtime dependencies.

Build from a clone
git clone https://github.com/ProjAnvil/LadyM.git && cd LadyM
go build -o bin/ladym ./cmd/ladym
./bin/ladym stats

Or use the install script, which builds and copies the binary to ~/.local/bin:

scripts/install.sh            # or: scripts/install.sh /custom/bin/dir
For development
git clone https://github.com/ProjAnvil/LadyM.git && cd LadyM
go build ./...                # compile everything
go test ./...                 # full suite, fully offline

The module is pure Go (github.com/ProjAnvil/LadyM) with a handful of library dependencies — no native toolchain needed on macOS/Linux/Windows.

Integration

All four fronts call the same Engine, so behaviour is identical everywhere.

MCP server (Claude Code, Cursor, …)

Add to your MCP client config:

{
  "mcpServers": {
    "ladym": {
      "command": "ladym",
      "args": ["serve", "--db", "/absolute/path/to/ladym.db"]
    }
  }
}

The server speaks MCP over stdio and exposes nine tools — recall, remember, record_event, search_code, index_code, consolidate, stats, link, forget — described in mcp/server.go. record_event logs an L1 episodic event that feeds the System 2 worker's consolidation (L1 → L2) and the gated L5 / L6 extractors (record ~3+ to arm those cycles).

Claude Code Skill

A drop-in skill is in skills/ladym-recall.md. Copy it to your .claude/skills/ directory and the agent will pull workspace memory into context with a keyword instead of re-reading files.

Go SDK

The ladym package is a one-import facade over the engine (ladym/ladym.go):

import "github.com/ProjAnvil/LadyM/ladym"

eng, err := ladym.NewEngine(ladym.DefaultConfig())
if err != nil {
	// handle error
}
defer eng.Close()

// index once (incremental — skips unchanged files)
report, err := eng.IndexCode("./src", false, "", nil)

// write path
eng.Remember("auth uses JWT with 24h expiry", ladym.LayerSemantic, ladym.TypeFact,
	[]string{"auth"}, nil, "sdk", "")
eng.RecordEvent("claude", "fixed login bug", "", "success", nil, nil)

// read path: two-tier retrieval, ACT-R activation ranking
resp, err := eng.Recall("how does auth work", "", 8, nil, nil, 0)
for _, r := range resp.Results {
	fmt.Printf("%.3f [%s] %s\n", r.Score, r.Memory.Layer, r.Memory.Summary)
}

// code-only shortcut
codeResp, err := eng.SearchCode("verify password", 8, "")

// cognitive operations
eng.Consolidate("", 0)          // L1 episodes → L2 facts (ADD/UPDATE/DELETE/NOOP)
eng.Proceduralize("", 0)        // recurring successful episodes → L3 playbooks
eng.Decay("", true, 0, 0)       // ACT-R base-level forgetting (dry run)
eng.Link(srcID, dstID, "depends_on") // Zettelkasten edge

One-shot helpers — ladym.Recall(query, dbPath, workspace, topK), ladym.Remember(...), ladym.IndexCode(...) — open a short-lived engine, run, and close, for scripts that don't want to manage the lifecycle.

Python SDK (MCP wrapper)

Python apps talk to the Go engine through wrapper/py — a thin typed client that spawns the ladym serve MCP server (JSON-RPC 2.0 over stdio) and exposes the nine tools (recall, remember, record_event, search_code, index_code, consolidate, stats, link, forget) as Python methods. No memory logic lives in Python; the Go binary is the single source of truth.

from ladym_wrapper import LadymClient        # sync
from ladym_wrapper import AsyncLadymClient  # async

with LadymClient() as client:
    client.remember("deploys go through Argo CD", source="notes")
    hits = client.recall("how do we deploy?")

The Go binary is resolved in order: binary= argument → LADYM_BIN env var → PATH → repo-local bin/ladym. Requires Python ≥ 3.12. See wrapper/py/README.md for details. (The full 0.2.x Python implementation is preserved on the python branch.)

Injecting your own langchain-golang models

If your app already configures langchain-golang chat / embedding models (with api key, base URL, model), wrap them and pass them straight to the Engine via ModelRouting — no need to re-declare credentials in LadyM's config (adapter/adapter.go):

import (
	"github.com/ProjAnvil/LadyM/adapter"
	"github.com/ProjAnvil/LadyM/ladym"
	"github.com/projanvil/langchain-golang/core/modelconfig"
	"github.com/projanvil/langchain-golang/partners/openai"
)

eng, err := ladym.NewEngineWithModels(ladym.DefaultConfig(), &adapter.ModelRouting{
	Consolidate: adapter.WrapChatModel(openai.NewChatModel(
		modelconfig.WithModel("gpt-4o"),
		modelconfig.WithAPIKey(key),
		modelconfig.WithBaseURL(url),
	), ""),
	AttentionGate: adapter.WrapChatModel(openai.NewChatModel(
		modelconfig.WithModel("gpt-4o-mini"),
		modelconfig.WithAPIKey(key),
	), ""),
	Embedding: adapter.WrapEmbeddings(openai.NewEmbeddings(
		modelconfig.WithModel("text-embedding-3-small"),
		modelconfig.WithAPIKey(key),
	)),
})

Each of the five cognitive ops (consolidate, proceduralize, attention_gate, l5_mental_model, l6_forward_intent) can take a different model; unset ops fall back to Config.

LangGraph

The langgraph/ package integrates LadyM as a long-term memory layer for langchain-golang LangGraph / LangChain agents. Two equivalent paths:

  • Toolslanggraph.CreateTools(eng, workspace, defaultTopK) returns LangChain tools (recall_memory, remember_fact, search_code) for ReAct-style agents where the LLM decides when to recall/remember.
  • Nodeslanggraph.CreateRecallNode(eng, topK, prefix, wsFn) / langgraph.CreateRetainNode(eng, wsFn) return graph NodeFuncs that inject recalled memory as a SystemMessage every turn and store the latest turn automatically. langgraph.WorkspaceFromUserID() gives per-user workspace isolation from the run-scoped user_id.

See docs/langgraph-integration.md for the design walkthrough.

CLI
ladym index ./src                      # index a codebase (incremental)
ladym recall "auth flow"               # recall across code AND facts
ladym recall "auth flow" --code --json # code-only, machine-readable
ladym remember "..." --tags auth       # store a fact
ladym record --agent claude --action "fixed login bug" --outcome success
ladym consolidate                       # L1 → L2
ladym worker --once                     # fire the System 2 L5/L6 extractors
ladym stats                             # what's in memory

Run ladym <command> --help for flags; ladym completion <shell> generates shell autocompletion. Each indexed result carries the symbol's identity, signature, docstring, body snippet, and source file — plus the callers/callees are queryable via the symbol graph. That is what saves the agent from re-reading.

Configuration

Config resolves through (highest precedence first): CLI flags → LADYM_* env vars → ./ladym.toml~/.ladym/config.toml → built-in defaults. ladym --config <path> loads an extra TOML file on top.

Env var Default Purpose
LADYM_DB ./ladym.db SQLite path (one DB per project by default)
LADYM_WORKSPACE default Multi-workspace isolation in a shared DB
LADYM_EMBEDDING hashing hashing / openai / ollama / http
LADYM_EMBEDDING_MODEL (provider default) Model name for a hosted embedding provider
LADYM_EMBEDDING_BASE_URL (provider default) Override embedding API base URL (OpenAI/Ollama-compatible)
LADYM_EMBEDDING_API_KEY_ENV (none) Name of the env var holding the embedding API key
LADYM_LLM_PROVIDER none none / openai / anthropic / ollama / http
LADYM_LLM_BASE_URL (provider default) Override LLM API base URL (OpenAI/Ollama-compatible)
LADYM_LLM_MODEL gpt-4o-mini LLM model name for the consolidation classifier
LADYM_LLM_API_KEY_ENV (none) Name of the env var holding the LLM API key
LADYM_ENABLE_WAL true Enable SQLite WAL journal mode (default on so multiple processes can share one db; set false on filesystems without WAL support)

base_url support lets you point embedding and LLM calls at any OpenAI/Ollama-compatible endpoint (e.g. vLLM, LiteLLM, local Ollama); the http providers let you template an arbitrary embedding/LLM HTTP API. Finer knobs (LADYM_EMBEDDING_TIMEOUT_S, LADYM_LLM_MAX_TOKENS, LADYM_LLM_TEMPERATURE, per-op overrides under [agents], and the recall/activation weights) live in TOML or on the config.Config struct — see config/config.go. Secret literals in TOML are rejected with a warning; use <name>_env indirection or the secret store below.

Secret store (encrypted keys at rest)

Provider API keys can be stored encrypted (AES-256-GCM) under ~/.ladyM/ instead of being pasted into your shell rc or CI secrets:

ladym config set-master-key              # first time: generate a random master key
ladym config set DEEPSEEK_API_KEY sk-... # store a key (encrypted)
ladym config list                        # list names (values never echoed)
ladym config rm DEEPSEEK_API_KEY         # remove
ladym config reset-master-key <newpass>  # rotate master key; all secrets re-encrypted in place

Key resolution order — LLM providers: Config.LLMAPIKey plaintext field (dev escape hatch, only honoured with allow_plaintext_secrets, off by default) → secret store (~/.ladyM/secrets.enc) → process env var named by api_key_env. Embedding providers skip the plaintext tier, resolving: secret store → env var. If none is set, commands fail fast with a one-line ConfigError naming the env var and the fix command (exit 1; MCP tools return a structured error instead of a stack trace).

Security boundary: the store guarantees encryption at rest — it prevents plaintext leaking via cat secrets.enc, shoulder-surfing, or accidental paste into chat/logs/commits. It does not protect against full ~/.ladyM/ exfiltration: the master key and ciphertext live in the same directory (the trade-off for non-interactive MCP / background workers that must decrypt without a passphrase prompt). For stronger isolation, keep ~/.ladyM/ on encrypted storage and rely on OS file permissions (dir 0700, files 0600). Losing master.key makes all secrets unrecoverable — back it up.

More CLI surface:

Command What it does
ladym serve --http :8080 HTTP data-plane API (/api/*, optional Basic auth) plus the embedded management console at / (login, memory CRUD, user admin, stats)
ladym config <sub> Encrypted secret store: set / set-master-key / reset-master-key / list / rm
ladym worker Background System 2 consolidation daemon; flags: --once, --interval N (seconds)

Testing

go test ./...            # full suite, fully offline
go test ./engine/ -v     # one package
go vet ./...             # lint

The whole suite runs without network and without model downloads — the default HashingEmbedding is deterministic and dependency-free, so CI is hermetic.

Documentation

  • ARCHITECTURE.md — full design: the six memory layers, cognitive operations, two-tier retrieval, the ACT-R activation function, storage layout, and the code-indexing subsystem. English only.
  • scenarios/ — executable end-to-end scenarios (S01 write/recall, S03 code index, S07 L5 mental model, S08 L6 forward intent, S09 attention gate, …) that double as a living spec. scenarios/README.md is in Chinese.
  • docs/ — deep dives (code-indexing analysis, LangGraph integration) and the enterprise deployment guide (container image, docker-compose reference deployment, workspace isolation, ops baseline).
  • The Go test suite (*_test.go beside each package) — the executable specification.

Status & roadmap

✅ Six-layer engine, two-tier recall, ADD/UPDATE/DELETE/NOOP consolidation, proceduralization, decay, pure-Go tree-sitter indexer (full symbol specs for Python/JS/TS/Go/Rust/Java/C/C++, line-window chunking for Kotlin/C#/Ruby/PHP/Swift/Scala/ Bash/Lua/SQL/HTML/CSS), MCP server, CLI, Skill, Go SDK, pluggable providers + TOML config, System 2 background worker, L5 mental-model / L6 forward-intent extraction, embedded management console (ladym serve --http, Vue 3 SPA under console/), encrypted secret store.

🚧 Next: GraphRAG-style cross-file ref resolution and multi-modal episodes.

Contributing

Contributions are welcome. The fastest way to help:

  1. Run go test ./... (hermetic) and go vet ./... before submitting.
  2. Add a scenario under scenarios/ or a *_test.go beside the changed package for any new behaviour — they are the spec.
  3. Keep the read path heuristic-only; route any LLM use through the System 2 worker.

For the design rationale behind any layer or operation, read ARCHITECTURE.md first, then open an issue to discuss before large changes.

Citation

If LadyM informs your research or project, a citation is appreciated:

@misc{ladym2026,
  title  = {LadyM: A brain-inspired, multi-tier memory framework for LLM agents and codebase RAG},
  author = {ProjAnvil},
  year   = {2026},
  url    = {https://github.com/ProjAnvil/LadyM}
}

License

MIT © ProjAnvil

Directories

Path Synopsis
Package adapter holds the host-model injection bridge.
Package adapter holds the host-model injection bridge.
Package api implements LadyM's HTTP data-plane front-end (`ladym serve --http`): one POST endpoint per MCP tool, mirroring the engine calls and parameter semantics of mcp/server.go, with optional database-backed HTTP Basic auth (users table) and per-user workspace enforcement.
Package api implements LadyM's HTTP data-plane front-end (`ladym serve --http`): one POST endpoint per MCP tool, mirroring the engine calls and parameter semantics of mcp/server.go, with optional database-backed HTTP Basic auth (users table) and per-user workspace enforcement.
Package cli holds the LadyM command-line interface (cobra-based).
Package cli holds the LadyM command-line interface (cobra-based).
client
golang
Package client is ladyM's Go SDK for the HTTP data-plane (`ladym serve --http`): one method per /api/* endpoint — the nine MCP-tool endpoints (remember/recall/record_event/search via recall code_only/consolidate/ stats/link/forget, plus login) and the management-console CRUD for memories and users — with database-level Basic auth (users table).
Package client is ladyM's Go SDK for the HTTP data-plane (`ladym serve --http`): one method per /api/* endpoint — the nine MCP-tool endpoints (remember/recall/record_event/search via recall code_only/consolidate/ stats/link/forget, plus login) and the management-console CRUD for memories and users — with database-level Basic auth (users table).
cmd
ladym command
Command ladym is the LadyM CLI entry point.
Command ladym is the LadyM CLI entry point.
ladymconsole command
Personal-edition placeholder so `go build ./...` / `go vet ./...` see a buildable package in this directory without the enterprise tag.
Personal-edition placeholder so `go build ./...` / `go vet ./...` see a buildable package in this directory without the enterprise tag.
Package code holds the codebase indexing subsystem (ARCHITECTURE.md §7).
Package code holds the codebase indexing subsystem (ARCHITECTURE.md §7).
Package config holds LadyM's runtime configuration.
Package config holds LadyM's runtime configuration.
Package console embeds the built LadyM management console (Vue 3 + Vite, sources in this directory, build via `make console-build`) so `ladym serve --http` can serve it at "/" without node on the machine.
Package console embeds the built LadyM management console (Vue 3 + Vite, sources in this directory, build via `make console-build`) so `ladym serve --http` can serve it at "/" without node on the machine.
Package engine holds the Engine — the single orchestrator and entry point for the SDK / CLI / MCP.
Package engine holds the Engine — the single orchestrator and entry point for the SDK / CLI / MCP.
Package ladym is the Go SDK facade for LadyM — a brain-inspired, multi-tier memory framework for LLM agents and codebase RAG.
Package ladym is the Go SDK facade for LadyM — a brain-inspired, multi-tier memory framework for LLM agents and codebase RAG.
Path B — LangGraph graph nodes for automatic memory injection, mirroring the Python langgraph/nodes.py on the main branch.
Path B — LangGraph graph nodes for automatic memory injection, mirroring the Python langgraph/nodes.py on the main branch.
Package layers holds LadyM's five memory layers (L0–L4).
Package layers holds LadyM's five memory layers (L0–L4).
Package mcp implements LadyM's MCP server (JSON-RPC 2.0 over stdio).
Package mcp implements LadyM's MCP server (JSON-RPC 2.0 over stdio).
Package operations holds LadyM's cognitive operations (activation, recall, consolidation, decay, proceduralization, supersedes, attention, L5/L6).
Package operations holds LadyM's cognitive operations (activation, recall, consolidation, decay, proceduralization, supersedes, attention, L5/L6).
LangChainLLM adapts a langchain-golang language.ChatModel to ladyM's LLMProvider — the Go equivalent of Python's LangChainLLMProvider (adapter.py on the main branch).
LangChainLLM adapts a langchain-golang language.ChatModel to ladyM's LLMProvider — the Go equivalent of Python's LangChainLLMProvider (adapter.py on the main branch).
Package schema holds LadyM's core data models.
Package schema holds LadyM's core data models.
Package secrets provides an encrypted secret store — AES-256-GCM over ~/.ladyM.
Package secrets provides an encrypted secret store — AES-256-GCM over ~/.ladyM.
Package storage holds LadyM's persistence layer: the SQLite store, pluggable embedding providers, and the vector index.
Package storage holds LadyM's persistence layer: the SQLite store, pluggable embedding providers, and the vector index.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL