内容
# 底层 🌱
**不断增长的记忆。**
在您的代理之下:一个自我连接的纯 Markdown 记忆。您的代理学习的每个事实都被记录为一个 Markdown 概念,交叉链接到一个活跃的知识图谱中,并由代理本身保持健康——可搜索、可差异化且完全属于您。在本地模型上运行良好。
软件包遵循 [开放知识格式(OKF)v0.1 规范](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)——带有 YAML 前置信息的纯 Markdown 文件,人类可读,可在 git 中差异化,可在工具之间移植。
**三种方式,一个代理:**
- **MCP 服务器** — 通过 stdio 或可流式 HTTP 提供 `memory_query` / `memory_add` / `memory_update` / `memory_status` / `memory_maintain` 工具。每个调用都驱动一个内部 LLM 代理,其系统中使用 OKF 规范。
- **Web UI** — 浏览软件包(树、概念查看器、更新日志、一致性徽章),将记忆视为类似 Obsidian 的 **力导向图**(可拖拽、可平移、可缩放,按类型着色,按连接大小,孤立节点红色环绕),并与同一个代理聊天以测试它。工具调用内联渲染,以便您可以观察其工作过程。
- **查询路径重放** — 每个代理运行(查询/变异/聊天)都记录其遍历(搜索 → 读取 → 写入)为紧凑符号,保存在 `<bundle>/.traces/` 下。列出最近的选择一个重放路径为编号的有向跳跃图过的概念环绕结果虚线显示,其他内容淡化。
- **CLI**pnpm agent:query / `pnpm agent: "..."` 烟雾测试。
**设计规则:一致性在代码中强制执行,而不是在提示** 确定性软件前置信息(需要`),重新生成 ` 文件,追加 `log 条目(最新优先,规范 §7),并将所有路径化到软件包。LLM 决定 *更改内容*;代码保证结果的软件包。
## 快速入门(Docker)
无需——镜像是公开的。将以下内容保存为 `docker-compose.yml`:
```yaml
services:
understory:
image: ghcr.io/thecodacus/understory:latest
ports:
- "3800:3800"
volumes:
# 您的记忆在此以纯 Markdown 形式存在 - 命名卷或指向
# 绑定挂载(例如 ./my-memory:/bundle)在任何 OKF 软件包。
- understory-memory:/bundle
environment:
BUNDLE_ROOT: /bundle
# 选择一个提供商:
# 1).cpp / llama-swap(模型自动发现;使用 --jin llama-server)
LLM_PROVIDER: llamacpp
LLAMACPP_BASE_URL: http://your-inference-box:808 # 2)Anthropic
#LLM anthropic
#ROPIC_API_KEY: sk-ant-...
# 3)OpenRouter
#LLM_PROVIDER: openrouter
#OPEN_API_KEY: sk-or restart: unless-stopped
volumes understory-memory:
```
```bash
docker compose up -d
```
然后:
- **Web UI** → http://localhost:3800 — 浏览记忆,查看图表,与代理- **MCP 端点** → `http://localhost:380cp`(可流式 HTTP)— 在任何 MCP 客户端中注册它:
```bash
claude mcp add --transport http ustory http://localhost:3800/mcp
```
- 您的代理现在具有 `memory_query` / `memory_add` / `memory_update` / `memory_status` / `memory_maintain`,并且在每次会话开始时获得内存的种子概述。
教它一些东西(`memory_add`:“我们在星期五部署,从不星期一”),然后打开图表并观察概念如何连接起来。使用 Portainer 部署?使用 [docker-compose.portainer.yml](docker-compose.portainer.yml) 作为存储库堆栈。
## 堆栈
pnpm monorepo:
| 软件包 | 描述 |
|---|---|
| `packages/core` | OKF 软件包层(零 LLM)+ 代理(Vercel AI SDK 工具循环:搜索/读取/列出/写入/修补/删除)+ 提供商注册表 |
| `packages/server` | Express:在 `/mcp` 处提供流,在 `/api/*` REST 浏览 APIapi/chat` 处提供流式聊天,在 `/mcp提供 stdio 二进制 `packages/web` | Vite + React + TS +:软件包浏览器 + 代理聊天(`useChat`提供商(,可按聊天更换):thropic**(默认),**OpenRouter**,**llamacpp**(llamallama-server` / llama-swap — 模型从 `/v1/models` 自动发现,首选已加载模型),**(任何其他 OpenAI 兼容端点)。
### llama.cpp
```bash
# 在推理框上 — --jinja 启用 样式的工具调用
llama-server -m model.gguf --jinja --host 0.0.0 --port 8080 在此处 — 不需要模型 ID,它会被发现
LL=llamacpp LLPP_BASE_URL=http://-box:8080 \
_ROOT=./sample-bundle node/dist/index.js
```
llama-swap:发现优先使用当前 **已加载**,因此查询不会触发多模型交换。使用 `LLM_MODEL=` 固定特定模型。
## 从源代码
```bash
pnpm install
pnpm build .env.example . # 添加您的 API 密钥
BUNDLE_ROOT=./sample-bundle ANTHROPIC_APIsk-... node packages/server/dist/index.js
# →localhost:3800 UI + /api +cp)
```
或者自己:`docker compose up -- (存储库的 [.yml](docker-compose.yml)代码构建并挂载 `./sample-bundle`)。
开发模式(服务器在 :380Vite HMR 在0 带有代理):
```bash
BUNDLE_ROOTsample-bundle pnpm --understory/server dev
--filter @understory/web dev
```
## MCP 注册aude Code / Desktop)
```bash
claude mcp add ustory \
-e BUNDLE_ROOT=/path/to/your/bundle \
-THROPIC_API_KEY-... \
--path/to/understory/packages/mcp/stdio.js或将 HTTP MCP 客户端指向 `host:3800/mcp`。
### 种子记忆
仅看到四个裸工具名称的客户端 LLM 永远不会产生检查记忆的直觉。因此,在 **会话开始** 时,服务器通过两个通道将知识库内容的紧凑概述注入到模型中:
1. MCP 初始化 **`instructions`** 字段(客户端如 Claude 将其放入系统),以及
2. **`memory_query` 工具描述** — 每个工具调用客户端加载备用程序。
种子为每个新会话重新生成。在长期)会话中进行 `` / `memory_update,工具描述通过 `tools/list_changed` 刷新,因此看到自己的写入。带外编辑(手动编辑,其他会在下一个会话中被拾取。
### 图表健康与维护
记忆是一张图,而不是一堆笔记,图会腐烂:概念会 **孤立**(没有任何链接到它们),链接会 **断裂**。两种机制保持其健康:
- **写入时链接** — 新知识要么丰富所属概念(现有实体的属性被修补,而不是单独归档),要么当它是独立实体时,创建 *并* 从反向链接。矛盾地被取代,与旧值并存。
- **`memory_maintain`** — 一个确定性 lint( + 断裂链接,在_status` 下的 `graph` 中显示)驱动,将孤立节点连接到相关概念并修复悬空定期运行以对抗漂移;当图已经健康时,它是无操作的。
该设计镜像了 Karpathy 的 [LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) 中的模式(index.md + log.md,创建-vs-丰富,孤立节点的 lint)。从该模式延期,直到规模需要:显式页面类型模式和混合 FTS5 + 嵌入(`search.ts简单扫描对于少量概念来说。
## 测试
pnpm test # core: 18 tests §5/§67/§9, sandbox, search, concurrency)
pnfilter @understory/server exec tsx scripts/mcp-smoke.mts # MCP std-trip (需要 SMOKE_BUNDLE + API 密钥)
```
## 环境
请参env.example](.example)。`BUNDLE_ROOT` 是必需的;`GIT_AUTOCOMMIT=true` 会提交每次变更。