Sno Station
Sno Station은 AI 에이전트를 하나의 팀으로 묶는 오픈소스 워크스테이션으로, 로컬 머신에서 에이전트 협업을 가능하게 함
Claude Code용 장기 기억 플러그인, 의미 검색·컨텍스트 주입·세션 학습 지원
Long-Term Memory plugin for Claude Code — semantic search, context injection, session learning
플러그인TypeScript · PythonGitHub @RohiRIK직접 설치운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
You explained your auth layer once. Why does Claude ask again tomorrow?
Long-Term Memory for AI coding agents — Claude Code, OpenCode, Pi, OpenClaw, and Hermes
Persistent semantic memory that survives every session, every update, every compaction.
OpenLTM began as a private memory layer for one agent. It is now MIT licensed, and the whole engine is on your disk to read, fork, and break.README 전문 보기 ↗Long-Term Memory for AI coding agents — Claude Code, OpenCode, Pi, OpenClaw, and Hermes
Persistent semantic memory that survives every session, every update, every compaction.
OpenLTM began as a private memory layer for one agent. It is now MIT licensed, and the whole engine is on your disk to read, fork, and break.
@rohirik/openltm-core holds the memory logic; each host gets a thin adapter (Hermes gets a native Python plugin over the same database).Migrating from an earlier install? The marketplace is now
RohiRIK/OpenLtmand the plugin isopenltm. Your existing memory database carries over.
The database is local. Embeddings and the janitor LLM are local by default.
Semantic search needs vectors. The default embedding provider is a local llama.cpp server (llama-server --embeddings), model bge-m3, via the OpenAI-compatible POST /v1/embeddings endpoint. If that server is not running, recall stays on FTS5 — memory text is not sent anywhere. Cloud embedding providers are opt-in only; see Configuration.
The janitor LLM defaults to local Ollama (LTM_LLM_PROVIDER unset → ollama). Cloud LLM providers are opt-in; they receive memory content only when you pin them.
There is no telemetry and no analytics in any configuration.
# embeddings (default). Install llama.cpp, then:
llama-server -m bge-m3.gguf --embeddings --pooling mean --port 8080
# optional overrides
export LTM_LLAMA_CPP_URL=http://127.0.0.1:8080
export LTM_EMBED_MODEL=bge-m3
Five-minute setup, including running the server in the background: Local embeddings. /openltm:doctor tells you whether semantic recall is actually on.
Full detail, including which write paths scrub secrets and which don't: Security notes.
Memory should be automatic. Hooks do the work. The session-end hook extracts patterns, the session-start hook injects them back. You shouldn't have to remember to remember.
Decay is a feature, not a bug. A gotcha from six months ago that you never revisited probably no longer applies. Set importance: 5 and a memory never ages out. Everything else fades at a rate set by how confident you were and how often it proved true (janitor/decay.ts).
Semantic over keyword. FTS5 full-text search and vector search run in parallel and are fused with Reciprocal Rank Fusion. You search by meaning — "how we handle async errors" finds the memory even if you never wrote those words.
Own your data. A file on your disk. When you leave the project, so does everything you taught it.
| Capability | What it actually does | Where it lives |
|---|---|---|
| Recall | Hybrid: full-text (FTS5) and vector results fused with Reciprocal Rank Fusion, filtered by project, status and privacy — search by meaning, not exact words | openltm-core/src/db.ts:981 · openltm-core/src/vec/ |
| Learn | Stores a memory with category, importance, and confidence; secrets are scrubbed on every write | openltm-core/src/db.ts:691 |
| Inject | At session start, the project's goal/decisions/gotchas/progress and a compact - [id] title index of top memories | hooks/src/SessionStart.ts:72 |
| Prompt recall | Adds up to 5 memories relevant to each prompt you type, never the same one twice in a session | hooks/lib/promptRecall.ts:146 |
| Stale flags | A commit through Claude flags the memories anchored to the files it touched | openltm-core/src/db.ts:411 |
| Privacy | Memories tagged private never leave the machine or reach the model unasked; egress is secret-scrubbed | openltm-core/src/secretsScrubber.ts · openltm-core/src/privacy.ts |
| Decay | Ages memories by importance × confidence; importance: 5 is permanent | openltm-core/src/janitor/decay.ts |
| Graph | Traverses relations between memories and builds a reasoning chain | openltm-core/src/graph.ts:71 |
| Visualize | A browser explorer over the live database, with janitor controls | src/graph-server.ts · graph-app/ |
| Extensions | sqlite-vec and Honker loaded from disk, with a working fallback when absent | openltm-core/src/extensions.ts:160 |
| Deduplicate | Queues near-duplicate pairs as pending suggestions; nothing merges until you approve | openltm-core/src/janitor/dedup.ts |
The engine is one package. Each host gets an adapter, and all of them open the same openltm.db — so a gotcha learned in Claude Code is already there when you open OpenCode.
| Host | Adapter | Install |
|---|---|---|
| Claude Code | .claude-plugin/ | claude plugin install openltm |
| OpenCode | @rohirik/opencode-ltm | bunx @rohirik/openltm-core --opencode |
| Pi | @rohirik/pi-ltm | bunx @rohirik/openltm-core --pi |
| OpenClaw | @rohirik/openclaw-ltm | openclaw plugins install clawhub:@rohirik/openclaw-ltm |
| Hermes | hermes/openltm_hermes (Python) | hermes plugins install openltm |
Hermes gets a native Python plugin rather than an adapter: a separate implementation over the same database and the same schema.
| Channel | What ships there | Link | Updates |
|---|---|---|---|
| Claude Code (own marketplace) | the openltm plugin | OpenLTM marketplace repository — not Anthropic’s official directory | repository-backed |
| npm | @rohirik/openltm-core | npmjs.com/package/@rohirik/openltm-core | automatic on every tag |
| npm | @rohirik/opencode-ltm | npmjs.com/package/@rohirik/opencode-ltm | automatic on every tag |
| npm | @rohirik/pi-ltm | npmjs.com/package/@rohirik/pi-ltm | automatic on every tag |
| npm | @rohirik/openclaw-ltm | npmjs.com/package/@rohirik/openclaw-ltm | automatic on every tag |
| Pi Package Catalog | @rohirik/pi-ltm extension | Pi marketplace listing · catalog search | indexed from npm via the pi-package keyword |
| ClawHub (OpenClaw) | @rohirik/openclaw-ltm | OpenLTM Memory on ClawHub | dispatch publish.yml at the release tag after npm succeeds (procedure) |
The Hermes Plugin Catalog is pinned to 2.16.2 at sha 687934564e68878ff9646a57aa72f6d3fc4f5fc8 (merged PR #132746). The catalog’s exact commit pin, not the latest repository tag, determines what catalog installs receive.
How each channel is published, and what to do when one breaks: docs/11-publishing.md.
One step (Claude Code 2.1.275 or later):
claude plugin install openltm --marketplace RohiRIK/OpenLtm
Or in a session: /plugin install openltm --marketplace RohiRIK/OpenLtm. On older versions, add the marketplace first:
claude plugin marketplace add https://github.com/RohiRIK/OpenLtm
claude plugin install openltm
Restart Claude Code. Seven hooks auto-wire, seven commands load, four skills and two agents activate, and your openltm.db migrates or creates itself.
bunx @rohirik/openltm-core # auto-detect installed hosts
bunx @rohirik/openltm-core --pi # experimental Pi adapter
bunx @rohirik/openltm-core --dry-run --claude # show me everything you'd write, write nothing
hermes plugins install openltm
hermes config set memory.provider openltm
hermes gateway restart # plugins load only at startup
Installs the reviewed commit pinned in the Hermes Plugin Catalog. Details: docs/10-hermes-plugin.md.
openclaw plugins install clawhub:@rohirik/openclaw-ltm --accept-capabilities # from ClawHub
openclaw plugins install @rohirik/openclaw-ltm --force --accept-capabilities # or straight from npm
Requires OpenClaw >= 2026.9.6, Node 24 (the host's own requirement), and Bun on PATH. --accept-capabilities consents to the plugin registering its memory tools; --force is how OpenClaw makes you acknowledge that an npm install is outside ClawHub review (verified on OpenClaw 2026.9.8). Details: packages/adapter-openclaw/README.md.
git clone https://github.com/RohiRIK/OpenLtm ~/Projects/OpenLtm
cd ~/Projects/OpenLtm && bash install.sh
What that installer does outside this repo. It writes ~/.claude.json, creates ~/.claude/settings.json if it isn't there, and adds mcp__plugin_openltm_memory to the permissions.allow list so the memory tools stop prompting for approval. That's a deliberate widening of your agent's tool permissions, and it's the kind of thing an installer should tell you about. Read scripts/install-wiring.ts first if you'd rather look before running.
Start a new session. Context is injected at the top automatically.
/openltm:memory recall auth — what do we know about auth in this project?
/openltm:memory learn <insight> — save something worth keeping
/openltm:health — memory health + decay summary
/openltm:project init — set a goal for the current project
Slash commands and the ltm_* tools only exist inside an agent TUI. From a plain shell — scripts, cron, CI:
bunx @rohirik/openltm-core memory learn --text "Docker Hub rate limits unauthenticated pulls" \
--category gotcha --importance 4 --project homelab --json
bunx @rohirik/openltm-core memory recall --query "docker rate limit" --json
bunx @rohirik/openltm-core memory forget --id 42 --reason "outdated"
bunx @rohirik/openltm-core memory context --project homelab
The janitor (embed backfill → decay → archive → promote → dedup suggestions, never auto-merge) runs straight against the SQLite file. No graph-server and no Honker are needed:
bunx @rohirik/openltm-core janitor run # one pass; exit 3 = no DB, 4 = another run holds the lock
bunx @rohirik/openltm-core janitor status
bunx @rohirik/openltm-core janitor schedule --write # systemd user timer (Linux) / launchd agent (macOS)
The Claude Code plugin also runs it on SessionEnd, at most once per 6h. Other hook hosts can call ltm hook --name SessionEnd. Details, install and undo steps: docs/13-janitor.md.
Any MCP-capable host can run the full server directly:
bunx @rohirik/openltm-core mcp-serve
Three things worth knowing before this holds anything you care about.
Secret scrubbing is not applied on every write path. learn() scrubs before storing (packages/openltm-core/src/db.ts:561). The janitor's promote and dedup paths, and context capture, write to memories and context_items without it. The scrubber also fails open — on an internal error it returns the original text unchanged (secretsScrubber.ts:101) — and it is a pattern denylist, not a guarantee. Stored memory is not the same as redacted memory.
LTM_SQLITE_LIB and LTM_HONKER_EXT load native code. Both are filesystem paths handed to a SQLite extension loader (extensions.ts:132,144). There is no allowlist and no signature check. Set them only to paths you trust, or turn the loaders off with LTM_DISABLE_VEC=1 and LTM_DISABLE_HONKER=1.
npm publishing is tokenless. Releases authenticate through GitHub OIDC trusted publishing with provenance. No NPM_TOKEN is stored in this repository.
| I want to… | Read |
|---|---|
| Get running in five minutes | Quickstart |
| See every install option | Installation |
| Use every command and its flags | Commands |
| Tune decay, injection, embedding behavior | Configuration |
| See how it works under the hood | How It Works · Architecture |
| Understand the schema and data model | DB Spec |
| Curate the DB without graph-server | Janitor |
| See all hooks, skills, and MCP tools | Hooks · Skills · MCP Tools |
| Publish a release | Publishing |
| Fix a problem | Troubleshooting |
| Variable | Purpose |
|---|---|
LTM_DB_PATH | Where the SQLite file lives. Overrides the default location. |
LTM_EMBED_PROVIDER | Embedding provider. Unset probes local llama.cpp (llamacpp); falls back to FTS if the server is down. ollama / disabled and the cloud providers (openai, gemini) opt in or out. |
LTM_LLM_PROVIDER | Provider for janitor summaries. Unset → ollama (local). Cloud providers (anthropic, openai, gemini, cohere, openrouter) are opt-in. |
LTM_JANITOR_INTERVAL_MINUTES | Minimum minutes between janitor run --if-due passes (hook, timers, daemon). Default 360. |
LTM_JANITOR_ON_SESSION_END | 0 disables the janitor-on-SessionEnd hook. |
LTM_DISABLE_VEC | Turn off the sqlite-vec loader; falls back to JS-cosine. |
LTM_DISABLE_HONKER | Turn off the Honker loader. |
LTM_SQLITE_LIB | Explicit path to a SQLite library. Loads native code. |
LTM_HONKER_EXT | Explicit path to the Honker extension. Loads native code. |
LTM_CHANNEL | Honker pub-sub channel. |
LTM_BACKUP_RETENTION | How many rotated backups to keep. |
MIT — RohiRIK
Built for agents that forget, and shouldn't.
| Hermes Plugin Catalog | openltm | plugin-catalog/openltm.yaml · catalog page | pinned to 2.16.2 (68793456…); each update is a reviewed PR to NousResearch |
| See where it's going | PRD · Roadmap |
| Contribute a change | Contributing |
| Check what changed | Changelog |