SafeFlo
Local MCP server for Claude Code providing persistent memory, task planning, and agent coordination with full transparency and no network calls.
README
SafeFlo
A local, transparent agent memory server for Claude Code.
MCP server with persistent hybrid memory (lexical + semantic search), a memory
lifecycle (types, importance, supersession, consolidation), task planning, and
logical agent coordination — all data in ./.safeflow/, no hidden install
scripts, no modification of files outside the project.
🇷🇺 Read in Russian: README.ru.md
TL;DR
Give Claude Code persistent, searchable memory that understands paraphrases — plus structured plans and logical agents. All data lives in
./.safeflow/. Uninstall with a single command. No surprises.
Contents
- What's inside
- Installation
- Using from Claude Code
- Memory model
- Search
- Benchmark
- Programmatic API
- Trade-offs and limitations
- Uninstall
- Security
- Contributing
- License
What's inside
| Module | Description |
|---|---|
| Memory store | SQLite with hybrid search — FTS5 (lexical) + sqlite-vec (semantic) fused via Reciprocal Rank Fusion. Memory lifecycle: types, importance, supersession, consolidation. Parameterized SQL only. |
| Task planner | Structured goal decomposition into steps with dependencies and verified status transitions. |
| Agent coordinator | Registration of logical agents with an isolated memory namespace each. No background processes. |
| MCP server | 18 tools with transparent, functional-only descriptions. |
| Audit log | Append-only JSONL of all operations. |
| CLI | init, status, mcp, backfill-embeddings, uninstall (with real, complete cleanup). |
Installation
# Clone the repository — no curl | bash installers.
git clone https://github.com/G1ngercy/SafeFlo.git
cd safeflow
# npm ci strictly follows package-lock.json — no version substitution.
# package.json contains no preinstall/postinstall scripts.
npm ci
# Build and test
npm run build
npm test
To use in your project:
cd /path/to/your/project
node /path/to/safeflow/dist/cli.js init
This creates:
./.safeflow/— local databases, model cache, and audit log./.claude/commands/safeflow-*.md— slash commands for Claude Code
To register the MCP server with Claude Code:
claude mcp add safeflow -- node /path/to/safeflow/dist/mcp/server.js
Using from Claude Code
Once connected, Claude Code gains these tools:
Memory:
memory_store(namespace, key, content, metadata?, memory_type?, importance?, source?)memory_get(namespace, key)memory_recall(namespace, query, limit?, memory_types?, include_superseded?)— hybrid search (recommended)memory_search(namespace, query, limit?)— [deprecated, usememory_recall] FTS5-onlymemory_list(namespace, limit?)memory_delete(namespace, key)memory_supersede(old_id, new_content, reason)— replace an outdated factmemory_consolidate(namespace, dry_run?)— find episodic clusters to summarize
Planning:
plan_create(goal)plan_add_step(planId, title, description, dependsOn?)plan_update_step_status(stepId, status)plan_get(planId)plan_ready_steps(planId)— steps that are ready to startplan_list(limit?)
Agents:
agent_register(role, task?)agent_list(status?)agent_update_status(agentId, status)
Audit:
audit_tail(n?)— last N events from the audit log
And slash commands: /safeflow-plan, /safeflow-memory, /safeflow-agents.
Memory model
Episodic / semantic / procedural. Every record has a memory_type. Episodic
is the default: a specific observation or event ("we decided X today"). Semantic
is generalized, durable knowledge distilled from episodes. Procedural captures
how to do something — steps, conventions, runbooks. The type nudges ranking and is
the unit consolidation promotes (episodic → semantic).
Importance. Each record carries an importance in [0, 1] that boosts ranking
in recall. It defaults to a transparent, content-derived heuristic (type, decision
keywords in RU/EN, length) and can be set explicitly. No machine learning, no
hidden signals.
Supersession. Facts go stale. memory_supersede(old_id, new_content, reason)
writes the replacement as a new record and marks the old one superseded_by the
new one. The old record is kept for history and audit but excluded from recall
by default (pass include_superseded to see it).
Consolidation. memory_consolidate finds clusters of similar, older episodic
records (greedy agglomeration over their vectors by cosine similarity) and returns
them with sample contents. The server performs no summarization and no
network calls — the client decides what to summarize and stores the result as a
semantic record. This keeps the "no network at runtime" boundary intact.
Search
Hybrid: FTS5 for lexical matching + sqlite-vec for semantic similarity,
combined via Reciprocal Rank Fusion (RRF), then adjusted by importance and a
recency boost. If the embedding model is not present (or you opt out), recall
degrades gracefully to FTS5-only — nothing breaks, you just lose the semantic leg.
Benchmark
npm run bench compares the legacy FTS-only search() against the v2 hybrid
recall() over a mixed RU/EN dataset (6 cases, 24 records, 22 queries). Results
with paraphrase-multilingual-MiniLM-L12-v2:
| Query type | v1 recall@5 | v2 recall@5 | Δ |
|---|---|---|---|
| lexical | 100.0% | 100.0% | +0.0 п.п. |
| synonym | 44.4% | 100.0% | +55.6 п.п. |
| concept | 57.1% | 100.0% | +42.9 п.п. |
MRR on synonym queries rises from 0.333 to 0.861. As expected, lexical queries are
unchanged (FTS already nails exact words); the win is on paraphrased and conceptual
queries — exactly where a key-value/FTS store falls short for an AI agent. Raw
results are in benchmark-results/.
Programmatic API
import {
MemoryStore,
TaskPlanner,
AgentCoordinator,
AuditLogger,
} from "safeflow";
const audit = new AuditLogger(process.cwd());
const memory = new MemoryStore(process.cwd(), audit);
const planner = new TaskPlanner(process.cwd(), audit);
const coord = new AgentCoordinator(process.cwd(), audit);
await memory.store("project.notes", "decision-1", "Use SQLite for memory", {}, {
memoryType: "semantic",
});
const hits = await memory.recall({
namespace: "project.notes",
query: "which database did we choose",
});
const plan = planner.createPlan("Add authentication");
const step = planner.addStep(plan.id, {
title: "Design schema",
description: "users, sessions",
dependsOn: [],
});
const agent = coord.register("researcher", "Survey auth libraries");
Trade-offs and limitations
- First model load requires the network. Semantic search relies on the
paraphrase-multilingual-MiniLM-L12-v2model (~120MB), downloaded once from Hugging Face into./.safeflow/models/. Until then, search is FTS5-only. You can opt out of embeddings entirely and stay FTS-only. See SECURITY.md. - Native modules.
better-sqlite3andsqlite-vecare native; they need prebuilt binaries or a toolchain for your platform. - Scale. This is a local, single-file SQLite design. Past ~100k records you want a dedicated vector database and a different architecture; SafeFlo is built for a project's working memory, not a data lake.
Uninstall
node /path/to/safeflow/dist/cli.js uninstall --yes
This removes:
./.safeflow/— all local databases, model cache, and audit log./.claude/commands/safeflow-*.md
SafeFlo uses no global paths whatsoever, so there is nothing to clean up outside the project. Genuinely nothing. Verify for yourself: grep -rn "homedir\|os\.home" src/ returns no results.
Security
The full threat model and guarantees are in SECURITY.md. Quick summary:
- No install scripts in
package.json(CI checks this automatically). - No network calls during memory operations. One-time exception: the embedding model (~120MB) is downloaded on first use; opt out to stay FTS5-only. Documented in SECURITY.md.
- No modification of files outside the project — all data in
./.safeflow/. - Parameterized SQL everywhere, Zod validation on every input.
- Protection against path traversal (including
....//bypasses), prototype pollution, SQL injection. - Transparent MCP descriptions — no hidden directives to the LLM. Audited automatically in CI.
- Idempotent migrations with automatic backups to
./.safeflow/backups/before any schema change. - Complete uninstall with a single command.
- Pinned dependencies — 5 packages with exact versions (
@modelcontextprotocol/sdk,better-sqlite3,sqlite-vec,@xenova/transformers,zod). - Provenance — npm packages are published with cryptographic attestation via GitHub Actions.
Vulnerabilities — through private security advisory, not through public issues. See SECURITY.md.
Contributing
See CONTRIBUTING.md. In short:
- For bugs — issue → fork → PR with a test.
- For features — issue first, then PR.
- For vulnerabilities — private security advisory, not a public issue.
Code of Conduct — CODE_OF_CONDUCT.md.
License
MIT, see LICENSE.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。