kimi-code-memory-mcp-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +144 -0
- package/CHANGELOG.md +26 -0
- package/LICENSE +21 -0
- package/README.md +227 -0
- package/README.zh-CN.md +227 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.js +63 -0
- package/dist/config.js.map +1 -0
- package/dist/context/wire-context.d.ts +171 -0
- package/dist/context/wire-context.js +586 -0
- package/dist/context/wire-context.js.map +1 -0
- package/dist/dao/index.d.ts +76 -0
- package/dist/dao/index.js +490 -0
- package/dist/dao/index.js.map +1 -0
- package/dist/dao/memory-store.d.ts +24 -0
- package/dist/dao/memory-store.js +112 -0
- package/dist/dao/memory-store.js.map +1 -0
- package/dist/refined-manager.d.ts +70 -0
- package/dist/refined-manager.js +369 -0
- package/dist/refined-manager.js.map +1 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.js +71 -0
- package/dist/server.js.map +1 -0
- package/dist/theme-manager.d.ts +40 -0
- package/dist/theme-manager.js +88 -0
- package/dist/theme-manager.js.map +1 -0
- package/dist/tools/context-tools.d.ts +56 -0
- package/dist/tools/context-tools.js +332 -0
- package/dist/tools/context-tools.js.map +1 -0
- package/dist/tools/index.d.ts +835 -0
- package/dist/tools/index.js +370 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/memory-tools.d.ts +62 -0
- package/dist/tools/memory-tools.js +292 -0
- package/dist/tools/memory-tools.js.map +1 -0
- package/dist/tools/system-tools.d.ts +37 -0
- package/dist/tools/system-tools.js +195 -0
- package/dist/tools/system-tools.js.map +1 -0
- package/dist/tools/theme-tools.d.ts +34 -0
- package/dist/tools/theme-tools.js +186 -0
- package/dist/tools/theme-tools.js.map +1 -0
- package/dist/types.d.ts +93 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +10 -0
- package/dist/utils/frontmatter.js +61 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/mutex.d.ts +11 -0
- package/dist/utils/mutex.js +17 -0
- package/dist/utils/mutex.js.map +1 -0
- package/dist/utils/paths.d.ts +19 -0
- package/dist/utils/paths.js +54 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/validation.d.ts +15 -0
- package/dist/utils/validation.js +40 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/version.d.ts +9 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/docs/ARCHITECTURE.md +144 -0
- package/docs/CONTRIBUTING.md +83 -0
- package/docs/CONTRIBUTING.zh-CN.md +83 -0
- package/docs/search-logic.md +157 -0
- package/docs/search-logic.zh-CN.md +157 -0
- package/examples/README.md +34 -0
- package/examples/sample-workspace/essence/essence.md +26 -0
- package/examples/sample-workspace/index.json +36 -0
- package/examples/sample-workspace/memory/decisions/sample-decision.md +30 -0
- package/examples/sample-workspace/memory/knowledge/sample-knowledge.md +24 -0
- package/examples/sample-workspace/memory/reference/sample-reference.md +20 -0
- package/examples/sample-workspace/memory/rules/sample-rule.md +31 -0
- package/examples/sample-workspace/themes/cache-design.json +15 -0
- package/package.json +72 -0
- package/skills/memory-manage/SKILL.md +43 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
This document explains how Kimi Code Memory MCP Server is structured, how data flows, and why we made the key design choices.
|
|
4
|
+
|
|
5
|
+
## Design Principles
|
|
6
|
+
|
|
7
|
+
1. **Markdown is the source of truth**
|
|
8
|
+
- Every memory is a `.md` file with YAML frontmatter.
|
|
9
|
+
- `index.json` is a rebuildable cache, not the database.
|
|
10
|
+
- Users can edit files directly; running `sync_workspace_index` repairs the cache.
|
|
11
|
+
|
|
12
|
+
2. **Local-first, offline, zero external dependencies**
|
|
13
|
+
- No vector database, no graph database, no cloud API.
|
|
14
|
+
- Works entirely on the local filesystem.
|
|
15
|
+
|
|
16
|
+
3. **Structured before fuzzy**
|
|
17
|
+
- Memories are written into typed folders (`decisions/`, `knowledge/`, `rules/`, `reference/`).
|
|
18
|
+
- Keyword search + tags + theme tracing are the default retrieval model.
|
|
19
|
+
- Optional embedding/LLM layers can be added later as plugins.
|
|
20
|
+
|
|
21
|
+
4. **Cross-session context recovery**
|
|
22
|
+
- The server reads Kimi Code CLI's `wire.jsonl` to rebuild recent conversation context.
|
|
23
|
+
- This is intentionally Kimi-specific; other CLI adapters can be added later.
|
|
24
|
+
|
|
25
|
+
## Data Flow
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
|
29
|
+
│ Kimi Code CLI │────▶│ wire.jsonl │────▶│ wire-context.ts │
|
|
30
|
+
│ (conversation) │ │ (event stream) │ │ (parser) │
|
|
31
|
+
└─────────────────┘ └──────────────────┘ └────────┬────────┘
|
|
32
|
+
│
|
|
33
|
+
▼
|
|
34
|
+
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
|
35
|
+
│ Agent tools │◀────│ MCP server │◀────│ context-tools │
|
|
36
|
+
│ remember/ │ │ src/server.ts │ │ │
|
|
37
|
+
│ search/ │ │ │ │ │
|
|
38
|
+
│ trace_theme/ │ │ │ │ │
|
|
39
|
+
└─────────────────┘ └────────┬─────────┘ └─────────────────┘
|
|
40
|
+
│
|
|
41
|
+
┌─────────────────────┼─────────────────────┐
|
|
42
|
+
│ │ │
|
|
43
|
+
▼ ▼ ▼
|
|
44
|
+
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
|
45
|
+
│ memory-tools │ │ theme-tools │ │ system-tools │
|
|
46
|
+
│ CRUD memory │ │ tag/trace/ │ │ organize/ │
|
|
47
|
+
│ files │ │ refine │ │ sync/bootstrap│
|
|
48
|
+
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
|
|
49
|
+
│ │ │
|
|
50
|
+
▼ ▼ ▼
|
|
51
|
+
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
|
52
|
+
│ memory-store │ │ theme-manager │ │ refined- │
|
|
53
|
+
│ (.md I/O) │ │ (themes/*.json)│ │ manager │
|
|
54
|
+
└───────┬───────┘ └───────────────┘ │ (refined/ │
|
|
55
|
+
│ │ refined.sqlite)│
|
|
56
|
+
▼ └───────────────┘
|
|
57
|
+
┌───────────────┐
|
|
58
|
+
│ IndexDao │
|
|
59
|
+
│ (index.json) │
|
|
60
|
+
└───────────────┘
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Module Responsibilities
|
|
64
|
+
|
|
65
|
+
| File | Responsibility |
|
|
66
|
+
|------|----------------|
|
|
67
|
+
| `src/server.ts` | MCP server entry, registers tools, starts stdio transport. |
|
|
68
|
+
| `src/config.ts` | Default paths, environment variable handling (`MEMORY_STORE_ROOT`, `MEMORY_SESSIONS_ROOT`, `KIMI_CODE_HOME`). |
|
|
69
|
+
| `src/tools/index.ts` | Tool schemas, validation, and dispatch. |
|
|
70
|
+
| `src/tools/memory-tools.ts` | `remember`, `recall`, `recall_recent`, `search`, `list`, `list_tags`, `delete`, `move`. |
|
|
71
|
+
| `src/tools/context-tools.ts` | `load_workspace_context`, `load_more_context`, `search_context`, `load_turn_context`. |
|
|
72
|
+
| `src/tools/theme-tools.ts` | `tag_theme`, `trace_theme`, `list_themes`, `refine_session_turns`. |
|
|
73
|
+
| `src/tools/system-tools.ts` | `organize_memories`, `sync_workspace_index`, `bootstrap_workspace`, `get_current_workspace`. |
|
|
74
|
+
| `src/dao/index.ts` | `index.json` v3-kv DAO with structure-hash consistency check. |
|
|
75
|
+
| `src/dao/memory-store.ts` | Markdown file read/write and frontmatter handling. |
|
|
76
|
+
| `src/context/wire-context.ts` | Parses Kimi Code CLI `wire.jsonl` into conversation rounds. |
|
|
77
|
+
| `src/theme-manager.ts` | Reads/writes `themes/<theme>.json`. |
|
|
78
|
+
| `src/refined-manager.ts` | Stores refined turn summaries in `refined/refined.sqlite`. |
|
|
79
|
+
| `src/utils/frontmatter.ts` | YAML frontmatter parser and serializer. |
|
|
80
|
+
| `src/utils/paths.ts` | Path helpers and storage root resolution. |
|
|
81
|
+
| `src/utils/validation.ts` | Input sanitization (`sanitizeKey`, `sanitizeFolder`). |
|
|
82
|
+
|
|
83
|
+
## `index.json` v3-kv
|
|
84
|
+
|
|
85
|
+
`index.json` is a fast cache over the Markdown files on disk.
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"version": "v3-kv",
|
|
90
|
+
"meta": {
|
|
91
|
+
"structureHash": "sha256-of-directory-tree",
|
|
92
|
+
"updatedAt": "2026-06-24T12:00:00.000Z"
|
|
93
|
+
},
|
|
94
|
+
"index": {
|
|
95
|
+
"memory/decisions/choose-sqlite.md": {
|
|
96
|
+
"key": "choose-sqlite",
|
|
97
|
+
"folder": "memory/decisions",
|
|
98
|
+
"title": "Choose Sqlite",
|
|
99
|
+
"tags": ["decision", "database"],
|
|
100
|
+
"createdAt": "...",
|
|
101
|
+
"updatedAt": "..."
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"folderComments": {
|
|
105
|
+
"memory/decisions": "Architecture and product decisions"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- `structureHash` is computed from the file tree.
|
|
111
|
+
- If the hash changes (e.g., external edit), the index is rebuilt on next access.
|
|
112
|
+
- The DAO also supports migration from older index formats.
|
|
113
|
+
|
|
114
|
+
## Memory Lifecycle
|
|
115
|
+
|
|
116
|
+
1. **Capture** — Agent writes a memory via `remember`.
|
|
117
|
+
2. **Index** — `IndexDao` updates `index.json` and writes the `.md` file.
|
|
118
|
+
3. **Recall** — Agent uses `search`, `recall`, or `recall_recent` to retrieve memories.
|
|
119
|
+
4. **Distill** — `organize_memories` condenses `memory/` into `essence/essence.md` (≤15 KB).
|
|
120
|
+
5. **Trace** — `tag_theme` and `trace_theme` connect memories and conversation turns into evolving themes.
|
|
121
|
+
6. **Archive/Move** — `move` renames or relocates a memory; `delete` removes it.
|
|
122
|
+
|
|
123
|
+
## Why No Vector Database by Default?
|
|
124
|
+
|
|
125
|
+
Vector search is excellent for:
|
|
126
|
+
- Fuzzy "something like this" queries
|
|
127
|
+
- Synonym matching
|
|
128
|
+
- Large corpora where keyword recall is insufficient
|
|
129
|
+
|
|
130
|
+
For a coding assistant, however, the most valuable memories are usually:
|
|
131
|
+
- Exact decisions (`decisions/`)
|
|
132
|
+
- Explicit conventions (`rules/`)
|
|
133
|
+
- Known project facts (`knowledge/`)
|
|
134
|
+
|
|
135
|
+
These are best retrieved by **path + tags + keywords + theme links**, which is fast, deterministic, and fully explainable.
|
|
136
|
+
|
|
137
|
+
We keep the door open for optional embedding plugins, but the default path is intentionally lightweight.
|
|
138
|
+
|
|
139
|
+
## Security Notes
|
|
140
|
+
|
|
141
|
+
- `sanitizeKey` and `sanitizeFolder` reject path traversal attempts.
|
|
142
|
+
- `move` refuses to overwrite an existing target.
|
|
143
|
+
- Writes use temp-file + rename for atomicity.
|
|
144
|
+
- Sensitive files (`.env`, SSH keys, etc.) are never read by the server.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in improving Kimi Code Memory MCP Server!
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/Zehee/kimi-code-memory-mcp-server.git
|
|
9
|
+
cd kimi-code-memory-mcp-server
|
|
10
|
+
npm install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Scripts
|
|
14
|
+
|
|
15
|
+
| Script | Purpose |
|
|
16
|
+
|--------|---------|
|
|
17
|
+
| `npm test` | Run integration tests |
|
|
18
|
+
| `npm run lint` | Run ESLint |
|
|
19
|
+
| `npm run lint:fix` | Run ESLint with auto-fix |
|
|
20
|
+
| `npm run format` | Format code with Prettier |
|
|
21
|
+
| `npm start` | Start the MCP server |
|
|
22
|
+
|
|
23
|
+
## Before Submitting a Pull Request
|
|
24
|
+
|
|
25
|
+
1. **Run tests**
|
|
26
|
+
```bash
|
|
27
|
+
npm test
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
2. **Run linting**
|
|
31
|
+
```bash
|
|
32
|
+
npm run lint
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
3. **Format code**
|
|
36
|
+
```bash
|
|
37
|
+
npm run format
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
4. **Update documentation** if your change affects user-facing behavior.
|
|
41
|
+
|
|
42
|
+
5. **Update `CHANGELOG.md`** under the `Unreleased` section.
|
|
43
|
+
|
|
44
|
+
## Code Style
|
|
45
|
+
|
|
46
|
+
- We use ESLint and Prettier. Run `npm run format` before committing.
|
|
47
|
+
- Use JSDoc comments for public functions.
|
|
48
|
+
- Keep functions small and focused.
|
|
49
|
+
- Prefer explicit error messages over silent failures.
|
|
50
|
+
|
|
51
|
+
## Commit Messages
|
|
52
|
+
|
|
53
|
+
Use clear, descriptive commit messages in English or Chinese. For example:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
feat: add search_context tool test
|
|
57
|
+
docs: update README quick start example
|
|
58
|
+
fix: handle missing frontmatter in recall
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Reporting Bugs
|
|
62
|
+
|
|
63
|
+
Use the [bug report issue template](../.github/ISSUE_TEMPLATE/bug_report.md).
|
|
64
|
+
|
|
65
|
+
Include:
|
|
66
|
+
- Node.js version
|
|
67
|
+
- Operating system
|
|
68
|
+
- Steps to reproduce
|
|
69
|
+
- Expected vs actual behavior
|
|
70
|
+
- Relevant logs or error messages
|
|
71
|
+
|
|
72
|
+
## Proposing Features
|
|
73
|
+
|
|
74
|
+
Use the [feature request issue template](../.github/ISSUE_TEMPLATE/feature_request.md).
|
|
75
|
+
|
|
76
|
+
Explain:
|
|
77
|
+
- The problem you want to solve
|
|
78
|
+
- Your proposed solution
|
|
79
|
+
- Why it fits the project's design principles
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
By contributing, you agree that your contributions will be licensed under the MIT License.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# 贡献指南
|
|
2
|
+
|
|
3
|
+
感谢你对 Kimi Code Memory MCP Server 的兴趣!
|
|
4
|
+
|
|
5
|
+
## 开发环境
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/Zehee/kimi-code-memory-mcp-server.git
|
|
9
|
+
cd kimi-code-memory-mcp-server
|
|
10
|
+
npm install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 脚本
|
|
14
|
+
|
|
15
|
+
| 脚本 | 用途 |
|
|
16
|
+
|------|------|
|
|
17
|
+
| `npm test` | 运行集成测试 |
|
|
18
|
+
| `npm run lint` | 运行 ESLint |
|
|
19
|
+
| `npm run lint:fix` | 自动修复 ESLint 问题 |
|
|
20
|
+
| `npm run format` | 用 Prettier 格式化代码 |
|
|
21
|
+
| `npm start` | 启动 MCP 服务器 |
|
|
22
|
+
|
|
23
|
+
## 提交 Pull Request 前
|
|
24
|
+
|
|
25
|
+
1. **运行测试**
|
|
26
|
+
```bash
|
|
27
|
+
npm test
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
2. **运行 lint**
|
|
31
|
+
```bash
|
|
32
|
+
npm run lint
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
3. **格式化代码**
|
|
36
|
+
```bash
|
|
37
|
+
npm run format
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
4. **更新文档**(如果你的改动影响用户可见行为)
|
|
41
|
+
|
|
42
|
+
5. **更新 `CHANGELOG.md`**(在 `Unreleased` 区域添加条目)
|
|
43
|
+
|
|
44
|
+
## 代码风格
|
|
45
|
+
|
|
46
|
+
- 使用 ESLint 和 Prettier。提交前运行 `npm run format`。
|
|
47
|
+
- 公共函数使用 JSDoc 注释。
|
|
48
|
+
- 保持函数小而聚焦。
|
|
49
|
+
- 优先给出明确的错误信息,而不是静默失败。
|
|
50
|
+
|
|
51
|
+
## 提交信息
|
|
52
|
+
|
|
53
|
+
使用清晰、描述性的提交信息,英文或中文均可。例如:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
feat: add search_context tool test
|
|
57
|
+
docs: update README quick start example
|
|
58
|
+
fix: handle missing frontmatter in recall
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 报告 Bug
|
|
62
|
+
|
|
63
|
+
使用 [Bug 报告 issue 模板](../.github/ISSUE_TEMPLATE/bug_report.md)。
|
|
64
|
+
|
|
65
|
+
请包含:
|
|
66
|
+
- Node.js 版本
|
|
67
|
+
- 操作系统
|
|
68
|
+
- 复现步骤
|
|
69
|
+
- 预期行为 vs 实际行为
|
|
70
|
+
- 相关日志或错误信息
|
|
71
|
+
|
|
72
|
+
## 提议新功能
|
|
73
|
+
|
|
74
|
+
使用 [功能请求 issue 模板](../.github/ISSUE_TEMPLATE/feature_request.md)。
|
|
75
|
+
|
|
76
|
+
请说明:
|
|
77
|
+
- 想解决什么问题
|
|
78
|
+
- 你的方案
|
|
79
|
+
- 为什么它符合项目的设计原则
|
|
80
|
+
|
|
81
|
+
## 许可证
|
|
82
|
+
|
|
83
|
+
通过贡献代码,你同意你的贡献采用 MIT 许可证。
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Search Logic
|
|
2
|
+
|
|
3
|
+
The project provides two search tools with different scopes and implementations:
|
|
4
|
+
|
|
5
|
+
- `search` — searches across persisted Markdown memories.
|
|
6
|
+
- `search_context` — searches across Kimi Code CLI session wires (`wire.jsonl`).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. `search` — Memory Search
|
|
11
|
+
|
|
12
|
+
Source: `src/tools/memory-tools.ts` (`handleSearch`)
|
|
13
|
+
|
|
14
|
+
### Flow
|
|
15
|
+
|
|
16
|
+
```mermaid
|
|
17
|
+
flowchart TD
|
|
18
|
+
A[Receive query + optional folder] --> B[Load index.json via IndexDao]
|
|
19
|
+
B --> C[Iterate over .md entries]
|
|
20
|
+
C --> D{Folder filter?}
|
|
21
|
+
D -->|Yes| E[Skip entries outside folder]
|
|
22
|
+
D -->|No| F[Build haystack: title + key]
|
|
23
|
+
E --> F
|
|
24
|
+
F --> G{Haystack contains needle?}
|
|
25
|
+
G -->|Yes| H[Return title match]
|
|
26
|
+
G -->|No| I[Open .md file and search body]
|
|
27
|
+
I --> J{Body contains needle?}
|
|
28
|
+
J -->|Yes| K[Collect up to 3 matching lines]
|
|
29
|
+
J -->|No| L[Skip entry]
|
|
30
|
+
H --> M[Return items]
|
|
31
|
+
K --> M
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Key behavior
|
|
35
|
+
|
|
36
|
+
- The query is converted to lowercase and matched against a lowercased haystack.
|
|
37
|
+
- Matching is **title/key first, body fallback**.
|
|
38
|
+
- When the body matches, up to 3 matching lines are returned as snippets.
|
|
39
|
+
- Results are not ranked by score; they appear in `index.json` iteration order.
|
|
40
|
+
|
|
41
|
+
### Example result
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"items": [
|
|
46
|
+
{
|
|
47
|
+
"key": "use-sqlite-cache",
|
|
48
|
+
"folder": "memory/decisions",
|
|
49
|
+
"title": "Use SQLite for Cache",
|
|
50
|
+
"matches": ["We chose SQLite over Redis because..."]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 2. `search_context` — Cross-Session Wire Search
|
|
59
|
+
|
|
60
|
+
Sources:
|
|
61
|
+
|
|
62
|
+
- Entry point: `src/tools/context-tools.ts` (`handleSearchContext`)
|
|
63
|
+
- Core search: `src/context/wire-context.ts` (`searchWireContext`)
|
|
64
|
+
- Refined storage: `src/refined-manager.ts` (`searchRefinedTurns`)
|
|
65
|
+
|
|
66
|
+
### Flow
|
|
67
|
+
|
|
68
|
+
```mermaid
|
|
69
|
+
flowchart TD
|
|
70
|
+
A[Receive query + options] --> B{Refined SQLite
|
|
71
|
+
has matches?}
|
|
72
|
+
B -->|Yes| C[Load original turns from wire.jsonl]
|
|
73
|
+
B -->|No| D[Full scan all workspace sessions]
|
|
74
|
+
C --> E{Wire file exists?}
|
|
75
|
+
E -->|Yes| F[Build matches & hits]
|
|
76
|
+
E -->|No| G[Build match from refined summary]
|
|
77
|
+
D --> F
|
|
78
|
+
F --> H[Group hits by session]
|
|
79
|
+
G --> M[Return refined-only matches]
|
|
80
|
+
H --> I[Expand clusters around hits]
|
|
81
|
+
I --> J[Refine unrefined turns in clusters]
|
|
82
|
+
J --> K[Save refined turns to SQLite]
|
|
83
|
+
K --> L[Return matches, clusters, skippedSessions]
|
|
84
|
+
M --> L
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Two-phase search
|
|
88
|
+
|
|
89
|
+
#### Phase 1 — Refined SQLite index
|
|
90
|
+
|
|
91
|
+
`searchWireContext` first queries `refined/refined.sqlite` through `RefinedManager.searchRefinedTurns`:
|
|
92
|
+
|
|
93
|
+
- Splits the query into lowercase terms.
|
|
94
|
+
- Uses SQL `LIKE` to match all terms against `summary`, `facts`, and `notes` columns.
|
|
95
|
+
- Returns matches sorted by keyword frequency score.
|
|
96
|
+
- For each refined match, it tries to load the original turn from the session's `wire.jsonl`.
|
|
97
|
+
- If the wire still exists, the full turn content is used for the match and the turn becomes a hit for clustering.
|
|
98
|
+
- If the wire is missing, the refined record itself is returned as a match. Its `summary` becomes the `agent` text and `snippet`, so the key information is preserved even without the original wire.
|
|
99
|
+
- If matches are found, it returns early.
|
|
100
|
+
|
|
101
|
+
#### Phase 2 — Full wire scan fallback
|
|
102
|
+
|
|
103
|
+
If refined search returns nothing, `searchWireContext` falls back to scanning every workspace session:
|
|
104
|
+
|
|
105
|
+
- `findAllWorkspaceSessions()` discovers all `wire.jsonl` files for the current workspace.
|
|
106
|
+
- Each wire is parsed into turns.
|
|
107
|
+
- Each turn is scored by keyword presence in `user` + `agentText`.
|
|
108
|
+
- Matching turns become hits.
|
|
109
|
+
|
|
110
|
+
### Clustering & refinement
|
|
111
|
+
|
|
112
|
+
Back in `handleSearchContext`:
|
|
113
|
+
|
|
114
|
+
1. **Group hits by session**. Only hits backed by an existing wire participate in clustering; refined-only matches are returned as standalone results.
|
|
115
|
+
2. **Expand clusters**: for each hit, absorb nearby turns within `cluster_gap_seconds` (default 90s), up to `max_cluster_size`.
|
|
116
|
+
3. **Refine missing turns**: turns inside clusters that are not yet in SQLite are passed to `refinedManager.refineTurn()` and saved in batch.
|
|
117
|
+
4. **Return** `matches`, `clusters`, `skippedSessions`, and `refinedCount`.
|
|
118
|
+
|
|
119
|
+
### Example result
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"query": "SQLite cache",
|
|
124
|
+
"totalMatches": 2,
|
|
125
|
+
"matches": [
|
|
126
|
+
{ "sessionId": "session_xxx", "turnId": 5, "score": 3, "user": "...", "agent": "..." }
|
|
127
|
+
],
|
|
128
|
+
"clusters": [
|
|
129
|
+
{ "sessionId": "session_xxx", "hitTurnId": 5, "memberCount": 3, "members": [...] }
|
|
130
|
+
],
|
|
131
|
+
"skippedSessions": [],
|
|
132
|
+
"refinedCount": 1
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Comparison
|
|
139
|
+
|
|
140
|
+
| Dimension | `search` | `search_context` |
|
|
141
|
+
|-----------|----------|------------------|
|
|
142
|
+
| Target | Markdown memory files | Kimi Code CLI `wire.jsonl` sessions |
|
|
143
|
+
| Index | `index.json` v3-kv | `refined/refined.sqlite` + full scan fallback |
|
|
144
|
+
| Matching | Substring in title/key/body | Substring in refined summary/facts/notes, or turn text |
|
|
145
|
+
| Ranking | None | Score by keyword frequency |
|
|
146
|
+
| Clustering | No | Yes, around hits |
|
|
147
|
+
| Side effect | None | Writes refined turns to SQLite |
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Environment variables that affect search
|
|
152
|
+
|
|
153
|
+
| Variable | Impact |
|
|
154
|
+
|----------|--------|
|
|
155
|
+
| `MEMORY_STORE_ROOT` | Changes where `index.json` and `refined/refined.sqlite` are located. |
|
|
156
|
+
| `MEMORY_SESSIONS_ROOT` | Changes where `search_context` looks for `wire.jsonl` files. |
|
|
157
|
+
| `KIMI_CODE_HOME` | Alternative to `MEMORY_SESSIONS_ROOT`; sessions are read from `<KIMI_CODE_HOME>/sessions`. |
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# 搜索逻辑
|
|
2
|
+
|
|
3
|
+
本项目提供两个搜索工具,作用域和实现各不相同:
|
|
4
|
+
|
|
5
|
+
- `search` —— 在持久化的 Markdown 记忆文件中搜索。
|
|
6
|
+
- `search_context` —— 在 Kimi Code CLI 的会话 wire(`wire.jsonl`)中搜索。
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. `search` —— 记忆搜索
|
|
11
|
+
|
|
12
|
+
源码:`src/tools/memory-tools.ts`(`handleSearch`)
|
|
13
|
+
|
|
14
|
+
### 流程
|
|
15
|
+
|
|
16
|
+
```mermaid
|
|
17
|
+
flowchart TD
|
|
18
|
+
A[接收 query + 可选 folder] --> B[通过 IndexDao 加载 index.json]
|
|
19
|
+
B --> C[遍历所有 .md 条目]
|
|
20
|
+
C --> D{是否指定 folder?}
|
|
21
|
+
D -->|是| E[跳过不在该 folder 的条目]
|
|
22
|
+
D -->|否| F[构造 haystack: title + key]
|
|
23
|
+
E --> F
|
|
24
|
+
F --> G{haystack 包含 needle?}
|
|
25
|
+
G -->|是| H[返回 title 匹配]
|
|
26
|
+
G -->|否| I[打开 .md 文件搜索正文]
|
|
27
|
+
I --> J{正文包含 needle?}
|
|
28
|
+
J -->|是| K[收集最多 3 行匹配片段]
|
|
29
|
+
J -->|否| L[跳过该条目]
|
|
30
|
+
H --> M[返回 items]
|
|
31
|
+
K --> M
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 关键行为
|
|
35
|
+
|
|
36
|
+
- query 被转小写,与同样小写化的 haystack 做子串匹配。
|
|
37
|
+
- 匹配策略是**标题/key 优先,正文兜底**。
|
|
38
|
+
- 正文命中时,返回最多 3 行包含关键词的片段。
|
|
39
|
+
- 结果没有打分排序,按 `index.json` 的遍历顺序返回。
|
|
40
|
+
|
|
41
|
+
### 返回示例
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"items": [
|
|
46
|
+
{
|
|
47
|
+
"key": "use-sqlite-cache",
|
|
48
|
+
"folder": "memory/decisions",
|
|
49
|
+
"title": "Use SQLite for Cache",
|
|
50
|
+
"matches": ["We chose SQLite over Redis because..."]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 2. `search_context` —— 跨会话历史搜索
|
|
59
|
+
|
|
60
|
+
源码:
|
|
61
|
+
|
|
62
|
+
- 入口:`src/tools/context-tools.ts`(`handleSearchContext`)
|
|
63
|
+
- 核心搜索:`src/context/wire-context.ts`(`searchWireContext`)
|
|
64
|
+
- 精炼存储:`src/refined-manager.ts`(`searchRefinedTurns`)
|
|
65
|
+
|
|
66
|
+
### 流程
|
|
67
|
+
|
|
68
|
+
```mermaid
|
|
69
|
+
flowchart TD
|
|
70
|
+
A[接收 query + options] --> B{Refined SQLite
|
|
71
|
+
有命中?}
|
|
72
|
+
B -->|是| C[从 wire.jsonl 加载原始 turn]
|
|
73
|
+
B -->|否| D[全量扫描当前工作区所有 session]
|
|
74
|
+
C --> E{wire 文件存在?}
|
|
75
|
+
E -->|是| F[构建 matches & hits]
|
|
76
|
+
E -->|否| G[从 refined summary 构建 match]
|
|
77
|
+
D --> F
|
|
78
|
+
F --> H[按 session 分组 hits]
|
|
79
|
+
G --> M[返回 refined-only matches]
|
|
80
|
+
H --> I[围绕命中点扩展 cluster]
|
|
81
|
+
I --> J[精炼 cluster 中未精炼的 turn]
|
|
82
|
+
J --> K[将精炼结果写入 SQLite]
|
|
83
|
+
K --> L[返回 matches, clusters, skippedSessions]
|
|
84
|
+
M --> L
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 两阶段搜索
|
|
88
|
+
|
|
89
|
+
#### 第一阶段 —— Refined SQLite 索引
|
|
90
|
+
|
|
91
|
+
`searchWireContext` 首先通过 `RefinedManager.searchRefinedTurns` 查询 `refined/refined.sqlite`:
|
|
92
|
+
|
|
93
|
+
- 把 query 拆成小写关键词。
|
|
94
|
+
- 用 SQL `LIKE` 要求所有关键词都匹配 `summary`、`facts`、`notes` 列。
|
|
95
|
+
- 按关键词出现频次打分并排序返回。
|
|
96
|
+
- 对每个 refined 命中,尝试从对应 session 的 `wire.jsonl` 加载原始 turn。
|
|
97
|
+
- 如果 wire 仍存在,使用完整 turn 内容构建 match,并作为 hit 参与 cluster 扩展。
|
|
98
|
+
- 如果 wire 已不存在,直接用 refined 记录本身作为 match 返回。其 `summary` 会作为 `agent` 文本和 `snippet`,即使没有原始 wire,关键信息也不会丢失。
|
|
99
|
+
- 如果有命中,直接返回,不再走全量扫描。
|
|
100
|
+
|
|
101
|
+
#### 第二阶段 —— 全量 wire 扫描兜底
|
|
102
|
+
|
|
103
|
+
如果 refined 搜索没有结果,`searchWireContext` 会回退到扫描当前工作区的所有 session:
|
|
104
|
+
|
|
105
|
+
- `findAllWorkspaceSessions()` 发现当前工作区的所有 `wire.jsonl`。
|
|
106
|
+
- 逐个解析为 turns。
|
|
107
|
+
- 对每个 turn 的 `user` + `agentText` 做关键词打分。
|
|
108
|
+
- 命中的 turns 成为 hits。
|
|
109
|
+
|
|
110
|
+
### 聚类与精炼
|
|
111
|
+
|
|
112
|
+
回到 `handleSearchContext`:
|
|
113
|
+
|
|
114
|
+
1. **按 session 分组 hits**。只有存在 wire 的 hit 才会参与 cluster;纯 refined 命中作为独立结果返回。
|
|
115
|
+
2. **扩展 cluster**:对每个命中点,吸收 `cluster_gap_seconds`(默认 90 秒)内的相邻 turn,最多 `max_cluster_size` 个。
|
|
116
|
+
3. **精炼缺失 turn**:cluster 中尚未写入 SQLite 的 turn 会批量传给 `refinedManager.refineTurn()` 并保存。
|
|
117
|
+
4. **返回** `matches`、`clusters`、`skippedSessions`、`refinedCount`。
|
|
118
|
+
|
|
119
|
+
### 返回示例
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"query": "SQLite cache",
|
|
124
|
+
"totalMatches": 2,
|
|
125
|
+
"matches": [
|
|
126
|
+
{ "sessionId": "session_xxx", "turnId": 5, "score": 3, "user": "...", "agent": "..." }
|
|
127
|
+
],
|
|
128
|
+
"clusters": [
|
|
129
|
+
{ "sessionId": "session_xxx", "hitTurnId": 5, "memberCount": 3, "members": [...] }
|
|
130
|
+
],
|
|
131
|
+
"skippedSessions": [],
|
|
132
|
+
"refinedCount": 1
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 对比
|
|
139
|
+
|
|
140
|
+
| 维度 | `search` | `search_context` |
|
|
141
|
+
|------|----------|------------------|
|
|
142
|
+
| 搜索对象 | Markdown 记忆文件 | Kimi Code CLI `wire.jsonl` 会话 |
|
|
143
|
+
| 索引 | `index.json` v3-kv | `refined/refined.sqlite` + 全量扫描兜底 |
|
|
144
|
+
| 匹配方式 | title/key/正文子串匹配 | refined summary/facts/notes 或 turn 文本子串匹配 |
|
|
145
|
+
| 排序 | 无 | 按关键词频次打分排序 |
|
|
146
|
+
| 聚类 | 无 | 围绕命中点扩展 cluster |
|
|
147
|
+
| 副作用 | 无 | 将精炼 turn 写入 SQLite |
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 影响搜索的环境变量
|
|
152
|
+
|
|
153
|
+
| 变量 | 影响 |
|
|
154
|
+
|------|------|
|
|
155
|
+
| `MEMORY_STORE_ROOT` | 改变 `index.json` 和 `refined/refined.sqlite` 的位置。 |
|
|
156
|
+
| `MEMORY_SESSIONS_ROOT` | 改变 `search_context` 查找 `wire.jsonl` 的位置。 |
|
|
157
|
+
| `KIMI_CODE_HOME` | `MEMORY_SESSIONS_ROOT` 的替代方案;会话从 `<KIMI_CODE_HOME>/sessions` 读取。 |
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
This directory contains a sample workspace that demonstrates the storage layout and content conventions used by Kimi Code Memory MCP Server.
|
|
4
|
+
|
|
5
|
+
## sample-workspace/
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
sample-workspace/
|
|
9
|
+
├── index.json # v3-kv index cache
|
|
10
|
+
├── essence/
|
|
11
|
+
│ └── essence.md # workspace digest
|
|
12
|
+
├── memory/
|
|
13
|
+
│ ├── decisions/ # architecture and product decisions
|
|
14
|
+
│ ├── knowledge/ # project-specific knowledge
|
|
15
|
+
│ ├── rules/ # conventions and guardrails
|
|
16
|
+
│ └── reference/ # external references
|
|
17
|
+
├── notes/ # scratch notes
|
|
18
|
+
└── themes/ # theme associations
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## How to Use
|
|
22
|
+
|
|
23
|
+
1. Copy `sample-workspace/` to your own location.
|
|
24
|
+
2. Set `MEMORY_STORE_ROOT` to the parent directory of `sample-workspace/`.
|
|
25
|
+
3. Or rename `sample-workspace/` to match your workspace ID and place it under `~/.kimi-code-memory/`.
|
|
26
|
+
|
|
27
|
+
## Files
|
|
28
|
+
|
|
29
|
+
- `memory/decisions/choose-sqlite-cache.md` — example decision record
|
|
30
|
+
- `memory/knowledge/project-tech-stack.md` — example knowledge record
|
|
31
|
+
- `memory/rules/no-plaintext-secrets.md` — example rule
|
|
32
|
+
- `memory/reference/mcp-spec.md` — example external reference
|
|
33
|
+
- `essence/essence.md` — example workspace digest
|
|
34
|
+
- `themes/cache-design.json` — example theme association
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
key: 'essence'
|
|
3
|
+
title: 'Workspace Essence'
|
|
4
|
+
tags:
|
|
5
|
+
- essence
|
|
6
|
+
- workspace-memory
|
|
7
|
+
updatedAt: '2026-06-20T10:20:00.000Z'
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Workspace Essence: Sample Project
|
|
11
|
+
|
|
12
|
+
## Decisions
|
|
13
|
+
|
|
14
|
+
- Use SQLite for the cache layer to keep deployment simple.
|
|
15
|
+
|
|
16
|
+
## Knowledge
|
|
17
|
+
|
|
18
|
+
- Runtime: Node.js >= 18, MCP over stdio, Markdown + JSON index storage.
|
|
19
|
+
|
|
20
|
+
## Rules
|
|
21
|
+
|
|
22
|
+
- No plaintext secrets in memory.
|
|
23
|
+
|
|
24
|
+
## References
|
|
25
|
+
|
|
26
|
+
- MCP specification at https://modelcontextprotocol.io/.
|