{"id":51488837,"url":"https://github.com/bbingz/engram","last_synced_at":"2026-07-07T09:31:57.868Z","repository":{"id":354611489,"uuid":"1168270130","full_name":"bbingz/engram","owner":"bbingz","description":"Cross-tool AI session aggregator: TypeScript MCP server and macOS menu bar app","archived":false,"fork":false,"pushed_at":"2026-07-06T00:44:02.000Z","size":19335,"stargazers_count":0,"open_issues_count":8,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-06T01:13:57.339Z","etag":null,"topics":["ai-coding","local-first","macos","mcp","raspberry-pi","sqlite","typescript","web-ui"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bbingz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/SECURITY.md","support":null,"governance":null,"roadmap":"docs/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-02-27T07:36:45.000Z","updated_at":"2026-07-05T23:52:07.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bbingz/engram","commit_stats":null,"previous_names":["bbingz/engram"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/bbingz/engram","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbingz%2Fengram","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbingz%2Fengram/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbingz%2Fengram/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbingz%2Fengram/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bbingz","download_url":"https://codeload.github.com/bbingz/engram/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbingz%2Fengram/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35223382,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-07T02:00:07.222Z","response_time":90,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-coding","local-first","macos","mcp","raspberry-pi","sqlite","typescript","web-ui"],"created_at":"2026-07-07T09:31:57.688Z","updated_at":"2026-07-07T09:31:57.825Z","avatar_url":"https://github.com/bbingz.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Engram\n\n\u003e Native Swift MCP helper + macOS App：聚合 14 个默认启用来源 + 3 个归档默认关闭来源的 AI 编程助手历史会话，实现跨工具上下文共享、关键词搜索和项目迁移。\n\n在 Codex 里做了半天，切到 Claude Code 继续时，AI 不需要你手动解释之前做了什么——它可以直接调用 `get_context` 查询你的历史。\n\n**Current product state (2026-07-06):** shipped runtime is the native Swift\nmacOS app + bundled Swift MCP helper. The active MCP surface has 27 tools,\nsearch is keyword-only in the Swift product path, and session ingestion defaults\nto 14 active sources plus 3 archived default-off sources. `docs/TODO.md` and\n`docs/roadmap.md` have no open engineering/product items; low-priority\nverification and cleanup follow-ups live in `docs/followups.md`. Latest\nCI-verified main: `24cc4562` (Tests + CodeQL success after PR #113).\n\n```\n┌─────────┐ ┌───────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐\n│  Codex  │ │Claude Code│ │Gemini CLI│ │  Cursor  │ │ Cline …│\n│ sessions│ │ projects  │ │   tmp    │ │  vscdb   │ │  tasks  │\n└────┬────┘ └─────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬────┘\n     └────────────┴──────┬─────┴─────────────┴────────────┘\n                         ▼\n              ┌──────────────────────┐\n              │       engram         │\n              │  Swift MCP + App UI  │\n              │    ~/.engram/        │\n              │    index.sqlite      │\n              └──────────┬───────────┘\n                    ┌────┴────┐\n                    ▼         ▼\n                MCP Tools   macOS App\n              (AI 调用)   (桌面 UI)\n```\n\n## 目录\n\n- [支持的工具](#支持的工具)\n- [适配器与显示一致性](#适配器与显示一致性)\n- [快速上手](#快速上手)\n- [注册为 MCP Server](#注册为-mcp-server)\n- [macOS App](#macos-app)\n- [MCP Tools 参考](#mcp-tools-参考)\n- [搜索现状](#搜索现状)\n- [项目别名](#项目别名)\n- [配置](#配置)\n- [添加新适配器](#添加新适配器)\n- [数据存储与隐私](#数据存储与隐私)\n- [开发](#开发)\n\n## 支持的工具\n\n| 工具 | 日志路径 | 状态 |\n|------|---------|------|\n| [Codex CLI](https://github.com/openai/codex) | `~/.codex/sessions/` | ✅ 完整支持 |\n| [Claude Code](https://claude.ai/code) | `~/.claude/projects/` | ✅ 完整支持 |\n| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | `~/.gemini/tmp/` | ✅ 完整支持 |\n| [Antigravity](https://idx.google.com) | CLI brain `~/.gemini/antigravity-cli/brain/` + legacy cache when present | ✅ 完整支持 |\n| [Windsurf](https://codeium.com/windsurf) | `~/.engram/cache/windsurf` cache only; live gRPC sync is disabled | ⚠️ cache-only |\n| [Cursor](https://cursor.sh) | `~/Library/Application Support/Cursor/…/state.vscdb` | ✅ 完整支持 |\n| [VS Code Copilot](https://code.visualstudio.com) | `~/Library/Application Support/Code/…/chatSessions/` | ✅ 完整支持 |\n| [GitHub Copilot](https://github.com/features/copilot) | `~/.copilot/session-state/\u003cuuid\u003e/events.jsonl` | ✅ 完整支持 |\n| [iflow](https://iflow.ai) | `~/.iflow/projects/` | 归档默认关闭，可在 Sources \u003e Archived 启用 |\n| [Qwen Code](https://qwen.ai) | `~/.qwen/projects/` | ✅ 完整支持 |\n| Qoder | `~/.qoder/projects/` | ✅ 完整支持 |\n| [OpenCode](https://opencode.ai) | `~/.local/share/opencode/opencode.db` | ✅ 完整支持 |\n| [Kimi](https://kimi.moonshot.cn) | `~/.kimi/sessions/` | ✅ 完整支持 |\n| [MiniMax](https://minimax.chat) | Claude Code-derived sessions under `~/.claude/projects/` | ✅ 完整支持 |\n| [Lobster AI](https://lobster.ai) | Claude Code-derived sessions under `~/.claude/projects/` | 归档默认关闭，可在 Sources \u003e Archived 启用 |\n| Command Code | `~/.commandcode/projects/` | ✅ 完整支持 |\n| [Cline](https://github.com/cline/cline) | `~/.cline/data/tasks/` | 归档默认关闭，可在 Sources \u003e Archived 启用 |\n\n## 适配器与显示一致性\n\nEngram 的产品解析路径在 Swift 侧：`macos/Shared/EngramCore/Adapters/Sources/` 负责读取各工具原始日志，`macos/EngramCoreWrite/Indexing/` 负责写入索引库。TypeScript 适配器保留为 dev/reference/fixture tooling，用于生成和校验 fixture parity。\n\n会话详情只把 `user` / `assistant` 消息作为可见正文展示；tool/event/system-like 数据用于索引、工具统计或诊断，不作为普通对话气泡混入正文。分页 offset 按 adapter 原始消费位置推进，避免隐藏消息造成可见消息漏页或重复页。\n\nAntigravity CLI、Command Code、Qoder 是重点覆盖来源。Antigravity CLI 使用 `~/.gemini/antigravity-cli/brain/` 下的 CLI transcript，并兼容旧 gRPC cache；Qoder 覆盖顶层 session 与 nested `subagents/` 父子关系；Command Code 覆盖 `tool-call` 的 `input` / `args` 形态。发布前的 parser/parity smoke：\n\n```bash\nnpm run check:adapter-parity-fixtures\nnpm test -- tests/adapters\nxcodebuild test -project macos/Engram.xcodeproj -scheme EngramCoreTests -destination 'platform=macOS' -only-testing:EngramCoreTests/AdapterParityTests/testSwiftAdaptersMatchNodeParityGoldensForAllProviders\nxcodebuild test -project macos/Engram.xcodeproj -scheme Engram -destination 'platform=macOS' -only-testing:EngramTests/MessageParserTests\n```\n\n当前 fixture/parity gate 覆盖 15 个独立产品适配器：Antigravity CLI、Claude Code、Cline、Codex CLI、Command Code、GitHub Copilot、Cursor、Gemini CLI、iflow、Kimi、OpenCode、Qoder、Qwen Code、VS Code Copilot、Windsurf。其中 Cline 和 iflow parser/fixture 继续保留，但作为归档来源默认不扫描，需在 Sources \u003e Archived 手动启用；MiniMax 保持默认启用。MiniMax 和 Lobster AI 作为 Claude-compatible derived sources 走 Claude Code parser，但会以独立 source 写入索引；Lobster AI 同样保留 parser/fixture 并默认归档关闭。Swift/Node 回归测试覆盖该派生分类。Swift App、Swift MCP、Swift Service export 都只展示非空 `user` / `assistant` 可见正文；tool/system/event-like 行保留给索引、工具统计和诊断，不混入普通对话气泡。provider parser parity 由 `tests/fixtures/adapter-parity/**` 约束；Swift/MCP/export 的可见消息一致性由 Swift service/core 测试覆盖。如果出现同一会话在两端解析或显示不同，先补对应 fixture，再改 adapter 或可见消息过滤逻辑。\n\n最近一次完整 provider/parser ship 记录见 [`docs/verification/provider-parser-parity-2026-05-20.md`](docs/verification/provider-parser-parity-2026-05-20.md)，其中包含两轮 Polycli review 与最终验证命令。\n\n## 快速上手\n\n**前置要求：** 已安装 `Engram.app`，或从源码构建 macOS App。\n\n```bash\n# 源码构建\ngit clone https://github.com/bbingz/engram\ncd engram\nmacos/scripts/build-release.sh --local-only\n\n# 2. 安装到 /Applications\nmacos/scripts/deploy-local.sh macos/build/EngramExport/Engram.app\n\n#    如果没有 Developer ID 证书，--local-only 会生成\n#    macos/build/EngramExport/Engram-local-only.app，只能本机安装，不能分发/公证。\n\n# 3. 重启 AI 工具，在对话中调用：\n# get_context cwd=/your/project/path\n```\n\n首次启动 `Engram.app` 时，`EngramService` 会自动扫描所有会话文件并建立索引（存储在 `~/.engram/index.sqlite`）。之后通过文件监听增量更新，无需手动维护。\n\n## 注册为 MCP Server\n\n### Claude Code\n\n```bash\nclaude mcp add --scope user engram /Applications/Engram.app/Contents/Helpers/EngramMCP\n```\n\n或者手动编辑 `~/.claude/settings.json`：\n\n```json\n{\n  \"mcpServers\": {\n    \"engram\": {\n      \"command\": \"/Applications/Engram.app/Contents/Helpers/EngramMCP\",\n      \"args\": []\n    }\n  }\n}\n```\n\n### Codex\n\nCodex 会在会话启动时持有 MCP stdio 子进程。为了避免发布时替换\n`/Applications/Engram.app` 影响已经打开的 Codex 会话，建议先创建一个稳定\nshim：\n\n```bash\nmkdir -p ~/.engram/bin\ncat \u003e ~/.engram/bin/engram-mcp \u003c\u003c'EOF'\n#!/bin/sh\nset -eu\n\nHELPER=\"/Applications/Engram.app/Contents/Helpers/EngramMCP\"\nif [ ! -x \"$HELPER\" ]; then\n  echo \"Engram MCP helper is not executable at $HELPER\" \u003e\u00262\n  exit 127\nfi\n\nexec \"$HELPER\" \"$@\"\nEOF\nchmod 755 ~/.engram/bin/engram-mcp\n```\n\n编辑 `~/.codex/config.toml`：\n\n```toml\n[mcp_servers.engram]\ncommand = \"/Users/\u003cyou\u003e/.engram/bin/engram-mcp\"\nargs = []\n```\n\n### 其他支持 MCP 的客户端\n\n任何支持 MCP stdio transport 的客户端均可使用。将以下内容加入对应的 MCP 配置：\n\n```json\n{\n  \"command\": \"/Applications/Engram.app/Contents/Helpers/EngramMCP\",\n  \"args\": []\n}\n```\n\n## macOS App\n\nEngram 的产品 UI 是原生 macOS App。`Engram.app` 启动后会管理 `EngramService`，并通过 Swift/GRDB 读取索引库。\n\n侧边栏按四个分区组织页面，并支持 `⌘K` 命令面板在页面/操作间快速跳转：\n\n- **OVERVIEW**\n  - **Today**：默认入口工作台，聚合 Continue、Follow-ups、Changed Repos、Service State，面向继续工作和收口\n  - **Search**：SQLite FTS5 trigram 关键词搜索，支持中英文、UUID 直查和结果高亮；project/source/time 等低层过滤收在 Advanced filters 里\n- **MONITOR**\n  - **Sessions**：按来源/项目/时间筛选，多选过滤、分页；Claude Code → Codex/Gemini 等派发子会话自动归组到父会话下，可展开查看\n  - **Favorites / Timeline / Activity**：收藏列表、时间线、按天/工具的活动视图\n  - **Hygiene**：索引健康体检，列出空会话、待确认的父子建议、孤儿会话等可处理项\n  - **Observability**：日志流 / 错误面板 / 性能 / 追踪 / 系统健康等开发诊断，默认收在「Settings → General → Show Developer Tools」开关后（普通用户侧边栏不显示）\n- **WORKSPACE**\n  - **Projects**：项目 rename / move / archive / undo，走 Swift service single-writer pipeline\n  - **Sources / Repos / Work Graph**：来源状态、Git 仓库工作量、跨会话工作图\n- **CONFIG**\n  - **Agents / Memory**：子代理与记忆条目配置一览\n\n其他贯穿全局的能力：\n- **会话详情**：完整对话内容、Markdown 渲染、收藏、导出，工具栏含 Handoff / Replay / Resume\n- **价值提示**：索引时计算 `quality_score`，列表/搜索结果用高/中/低 value band 做快速判断\n- **用量与成本**：按来源/项目/天/周分组的用量统计、模型成本、工具调用、文件活动，以及费用洞察建议\n- **今日父会话 badge**：菜单栏徽标显示今天的顶层父会话数量，而不是全部子任务总数\n\n历史 TypeScript Web/API 入口已删除；当前 macOS 产品路径通过 Swift App、Swift Service 和 Swift MCP 提供功能。TypeScript 搜索代码仅作为 retained tooling/reference，不代表 Swift App/MCP 当前已启用语义搜索。\n\n## MCP Tools 参考\n\nEngram 的 Swift MCP runtime 当前暴露 27 个工具，覆盖上下文获取、搜索、记忆管理、统计分析、会话整理和项目迁移等场景：\n\n| 工具 | 说明 |\n|------|------|\n| `get_context` | 🔑 **核心工具** — 自动提取当前项目的历史上下文，开始新任务时调用 |\n| `search` | FTS 关键词搜索；旧客户端传 `semantic`/`hybrid` 会降级为 keyword 并返回 warning |\n| `list_sessions` | 列出历史会话，支持按来源/项目/时间过滤 |\n| `get_session` | 读取单个会话完整对话，支持分页 |\n| `save_insight` | 保存重要知识片段，跨会话持久化 |\n| `delete_insight` | 删除已保存的 insight |\n| `get_memory` | 检索已保存的记忆和知识 |\n| `project_timeline` | 查看项目跨工具的操作时间线 |\n| `stats` | 用量统计（按来源/项目/天/周分组） |\n| `get_costs` | Token 用量和费用统计 |\n| `tool_analytics` | 分析各工具（Read/Edit/Bash 等）调用频率 |\n| `file_activity` | 项目中最常编辑/读取的文件 |\n| `handoff` | 生成项目交接简报 |\n| `export` | 导出会话为 Markdown/JSON |\n| `generate_summary` | AI 生成会话摘要 |\n| `link_sessions` | 在项目目录创建会话文件软链接 |\n| `manage_project_alias` | 管理项目别名（目录移动后保持关联） |\n| `live_sessions` | MCP mode 下返回明确 unavailable 结果；App/service IPC 路径有本地活跃会话扫描 |\n| `get_insights` | 获取费用优化建议 |\n| `hide_session` | 隐藏或恢复指定会话 |\n| `project_move` | 移动项目目录并保持 AI 会话历史可达 |\n| `project_archive` | 将项目归档到 `_archive/` 分类目录 |\n| `project_undo` | 回滚已提交的 project move |\n| `project_move_batch` | 批量执行 project move/archive |\n| `project_list_migrations` | 查看 project move 迁移记录 |\n| `project_recover` | 诊断失败或卡住的迁移 |\n| `project_review` | 扫描迁移后的旧路径残留引用 |\n\n**快速示例：**\n\n```json\n// 获取项目上下文\n{ \"cwd\": \"/Users/me/my-project\", \"task\": \"重构认证模块\" }\n\n// 搜索历史\n{ \"query\": \"JWT 认证\", \"mode\": \"keyword\" }\n\n// 保存知识\n{ \"content\": \"项目使用 Hono 作为 HTTP 框架\", \"wing\": \"engram\" }\n```\n\n\u003e 完整参数文档见 [MCP Tools Reference](docs/mcp-tools.md)。\n\n---\n\n## 搜索现状\n\n当前 Swift 产品路径使用 SQLite FTS5 trigram 关键词搜索。MCP、App service 读路径和会话详情展示共用同一套 Swift 索引库与可见消息规则。\n\n- **keyword**：已上线。覆盖用户消息、助手回复、摘要和索引文本；支持中英文、代码片段、函数名、UUID 直查。\n- **semantic / hybrid**：Swift service 当前没有 embedding provider，也没有 sqlite-vec KNN 查询链路。旧客户端传 `semantic`、`hybrid` 或 `both` 会被兼容接收，但实际降级为 keyword，并返回 warning。\n- **insights memory**：`save_insight` / `get_memory` 当前以 FTS/recent fallback 为主；embedding 字段保留在 schema 中，尚不是产品可用的语义检索能力。\n\n搜索覆盖范围：用户消息 + 助手回复 + 会话摘要 + 部分 adapter 归一化后的工具/诊断文本。\n\n搜索还支持**直接粘贴会话 UUID** 进行精确查找，无需关键词或语义匹配。\n\n### Embedding 配置状态\n\n`~/.engram/settings.json` 仍可能包含旧版 TypeScript/reference tooling 使用过的 embedding 字段：\n\n| 字段 | 当前状态 |\n|------|----------|\n| `ollamaUrl` / `ollamaModel` / `embeddingDimension` | 兼容保留；Swift service 不会因此启用语义搜索 |\n| `aiApiKey` / `titleApiKey` | 分别用于用户触发的 AI summary / title generation；不代表 Swift semantic search 已启用 |\n| `session_embeddings` / `vec_sessions` | schema/backfill 兼容表；FTS 版本或向量版本变化时可能被清空重建 |\n\n## 项目别名\n\n当你移动了项目目录（例如从 `~/Code/wechat-decrypt` 移到 `~/Code/wechat-decrypt-bing`），AI 助手会找不到旧路径下的历史会话。通过项目别名，可以声明两个项目名是同一个项目，所有查询自动展开。\n\n### 添加别名\n\n**通过 MCP 工具（在 AI 对话中）：**\n\n```json\n{ \"name\": \"manage_project_alias\", \"arguments\": { \"action\": \"add\", \"old_project\": \"wechat-decrypt\", \"new_project\": \"wechat-decrypt-bing\" } }\n```\n\n历史 TypeScript Web/API 入口已删除；当前产品路径优先使用 Swift MCP 工具。macOS App 暂未提供 Project Aliases 管理 UI。\n\n添加后，在任意路径下调用 `get_context`、`search`、`list_sessions` 等工具，两个项目名的会话都会出现。别名是双向的——查哪个名字都能找到另一个。\n\n### 管理别名\n\n```json\n// 列出所有别名\n{ \"action\": \"list\" }\n\n// 删除别名\n{ \"action\": \"remove\", \"old_project\": \"wechat-decrypt\", \"new_project\": \"wechat-decrypt-bing\" }\n```\n\n\u003e **注意：** 项目别名解决的是 Engram 层面的查询问题。各 AI 工具自身的 `/resume` 等功能仍然依赖原始路径，这不在 Engram 的控制范围内。\n\n## 远程会话卸载（可选，默认关）\n\n可选功能：把冷/归档会话的**可再生索引产物**（`sessions_fts` 正文 + summary，AES-GCM 加密）卸载到**你自托管的服务器**以回收本地磁盘，原始 transcript 文件绝不移动；卸载的会话保留一条 keyword shadow 仍可搜索，打开时透明回填。默认关闭，需在 `~/.engram/settings.json` 显式开启并配置服务器。\n\n```json\n{\n  \"remoteOffloadEnabled\": false,\n  \"remoteOffloadBackend\": \"http\",\n  \"remoteOffloadServerURL\": \"https://100.x.x.x:8443\",\n  \"remoteOffloadColdAgeDays\": 365\n}\n```\n\n\u003e 注意：卸载跑在后台 helper 进程里，受 macOS 本地网络隐私限制——`remoteOffloadServerURL` 要用 **Tailscale IP / tailnet 名**，不能用局域网 IP。部署与运维见 [`docs/remote-offload.md`](docs/remote-offload.md)，隐私说明见 [`docs/PRIVACY.md`](docs/PRIVACY.md)。\n\n## 配置\n\n配置文件路径：`~/.engram/settings.json`\n\n```json\n{\n  \"aiProtocol\": \"openai\",\n  \"aiApiKey\": \"@keychain\",\n  \"aiModel\": \"gpt-4o-mini\",\n  \"titleProvider\": \"ollama\",\n  \"titleModel\": \"qwen2.5:3b\"\n}\n```\n\n| 字段 | 类型 | 默认值 | 说明 |\n|------|------|--------|------|\n| `aiProtocol` | string | `\"openai\"` | AI 摘要协议；当前 Swift service 支持 OpenAI-compatible chat completions |\n| `aiApiKey` | string | — | AI 摘要 API Key；优先存在 macOS Keychain，JSON 中可能是 `@keychain` |\n| `aiModel` | string | `\"gpt-4o-mini\"` | AI 摘要模型 |\n| `titleProvider` | string | `\"ollama\"` | 标题生成 provider：`ollama`、`openai` 或 `custom` |\n| `titleApiKey` | string | — | 标题生成 API Key；非 Ollama provider 使用，优先存在 macOS Keychain |\n| `titleModel` | string | `\"qwen2.5:3b\"` | 标题生成模型 |\n| `ollamaUrl` | string | `\"http://localhost:11434\"` | 旧版 embedding 兼容字段；Swift service 当前不使用 |\n| `ollamaModel` | string | `\"nomic-embed-text\"` | 旧版 embedding 兼容字段；Swift service 当前不使用 |\n| `embeddingDimension` | number | `768` | 旧版 embedding 兼容字段；Swift service 当前不使用 |\n\n旧版 peer-sync settings keys (`syncNodeName`, `syncEnabled`, `syncIntervalMinutes`, `syncPeers`) 可能仍存在于旧配置中；Swift service 兼容保留但不会读取、启用或触发 peer sync。\n\n## 添加新适配器\n\n产品适配器优先在 Swift 中实现；TypeScript 适配器保留为 dev/reference/fixture material。\n\n**Swift 产品路径：**\n\n- 适配器：`macos/Shared/EngramCore/Adapters/Sources/`\n- 索引与 backfill：`macos/EngramCoreWrite/Indexing/`\n- 服务命令：`macos/EngramService/Core/`\n- MCP 路由：`macos/EngramMCP/Core/MCPToolRegistry.swift`\n\nTypeScript reference 接口（`src/adapters/types.ts`）：\n\n```typescript\ninterface SessionAdapter {\n  readonly name: SourceName          // 工具标识符\n  detect(): Promise\u003cboolean\u003e         // 检测该工具是否已安装\n  listSessionFiles(): AsyncGenerator\u003cstring\u003e                   // 枚举所有会话文件路径\n  parseSessionInfo(filePath: string): Promise\u003cSessionInfo | null\u003e  // 解析文件元数据\n  streamMessages(filePath: string, opts?: StreamMessagesOptions): AsyncGenerator\u003cMessage\u003e  // 流式读取消息\n}\n```\n\n**步骤：**\n\n1. 先在 Swift adapter/indexer/backfill 路径实现产品行为\n2. 补 Swift fixture/parity tests\n3. 仅当 retained TypeScript fixture tooling 需要时，再同步 `src/adapters/**`\n4. 参照现有测试编写对应 Swift/TypeScript 回归测试\n\n**实现参考：** Swift adapters 是产品实现；`src/adapters/codex.ts` 仍可作为历史/reference 参考。\n\n## 数据存储与隐私\n\n- **索引库位置：** `~/.engram/index.sqlite`，存储元数据（会话 ID、时间、路径、摘要）、FTS 全文搜索索引和兼容保留的 embedding 表\n- **原始文件：** 完整消息内容始终从 AI 工具的原始日志文件流式读取，不做额外拷贝\n- **隐私脱敏：** 导出和 Web 预览使用内置敏感内容脱敏；索引库按原始本地日志建立 FTS，不支持用户配置的索引时正则替换\n- **数据不离本机：** `EngramService`、`EngramMCP` 和 macOS App 本地运行，不向任何远程服务发送数据（除非你显式配置并使用远程 AI 摘要/标题 provider）\n\n### Restoring user data\n\n`EngramService` periodically writes small user-data backups to\n`~/.engram/backups/user-data-\u003cUTC yyyyMMdd-HHmmss\u003e.sqlite`. These are not whole\ndatabase snapshots and they are not project-directory file backups. They contain\nonly user-authored Engram rows: `insights`, manual/hidden/named session columns,\n`session_local_state` without `local_readable_path`, `project_aliases`, and\n`migration_log`, plus favorites and manually curated related-session links.\n\nTo restore after rebuilding `~/.engram/index.sqlite`, first let Engram re-index\nthe original AI-tool session files so `sessions.id` rows exist again. Then quit\nEngram and run a manual SQLite restore using the backup file:\n\n```sql\nATTACH DATABASE '/Users/\u003cyou\u003e/.engram/backups/user-data-YYYYMMDD-HHMMSS.sqlite' AS backup;\n\nINSERT OR IGNORE INTO insights(\n  id, content, wing, room, source_session_id, importance, has_embedding,\n  created_at, insight_type, superseded_by, last_accessed_at, access_count\n)\nSELECT id, content, wing, room, source_session_id, importance, has_embedding,\n  created_at, insight_type, superseded_by, last_accessed_at, access_count\nFROM backup.insights;\n\nUPDATE sessions\nSET parent_session_id = COALESCE(\n      (SELECT parent_session_id FROM backup.sessions b WHERE b.id = sessions.id AND b.link_source = 'manual'),\n      parent_session_id\n    ),\n    link_source = COALESCE(\n      (SELECT link_source FROM backup.sessions b WHERE b.id = sessions.id AND b.link_source = 'manual'),\n      link_source\n    ),\n    hidden_at = COALESCE((SELECT hidden_at FROM backup.sessions b WHERE b.id = sessions.id), hidden_at),\n    custom_name = COALESCE((SELECT custom_name FROM backup.sessions b WHERE b.id = sessions.id), custom_name)\nWHERE id IN (SELECT id FROM backup.sessions);\n\nINSERT OR IGNORE INTO session_local_state(session_id, hidden_at, custom_name)\nSELECT session_id, hidden_at, custom_name FROM backup.session_local_state;\nUPDATE session_local_state\nSET hidden_at = COALESCE((SELECT hidden_at FROM backup.session_local_state b WHERE b.session_id = session_local_state.session_id), hidden_at),\n    custom_name = COALESCE((SELECT custom_name FROM backup.session_local_state b WHERE b.session_id = session_local_state.session_id), custom_name)\nWHERE session_id IN (SELECT session_id FROM backup.session_local_state);\n\nINSERT OR IGNORE INTO project_aliases(alias, canonical, created_at)\nSELECT alias, canonical, created_at FROM backup.project_aliases;\n\nINSERT OR IGNORE INTO migration_log(\n  id, old_path, new_path, old_basename, new_basename, state, files_patched,\n  occurrences, sessions_updated, alias_created, cc_dir_renamed, started_at,\n  finished_at, dry_run, rolled_back_of, audit_note, archived, actor, detail, error\n)\nSELECT id, old_path, new_path, old_basename, new_basename, state, files_patched,\n  occurrences, sessions_updated, alias_created, cc_dir_renamed, started_at,\n  finished_at, dry_run, rolled_back_of, audit_note, archived, actor, detail, error\nFROM backup.migration_log;\n\nCREATE TABLE IF NOT EXISTS favorites (\n  session_id TEXT PRIMARY KEY,\n  created_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\nINSERT OR IGNORE INTO favorites(session_id, created_at)\nSELECT session_id, created_at FROM backup.favorites;\n\nCREATE TABLE IF NOT EXISTS session_relations (\n  a_id TEXT NOT NULL,\n  b_id TEXT NOT NULL,\n  created_at TEXT NOT NULL DEFAULT (datetime('now')),\n  PRIMARY KEY (a_id, b_id)\n);\nINSERT OR IGNORE INTO session_relations(a_id, b_id, created_at)\nSELECT a_id, b_id, created_at FROM backup.session_relations;\n\nDETACH DATABASE backup;\n```\n\nDo not restore derived tables such as `insights_fts`, `insight_embeddings`,\n`session_tools`, analytics tables, `session_local_state.local_readable_path`, or\nlegacy `memory_insights`; FTS, embedding state, and local readable paths are\nregenerated from the source rows when maintenance runs.\n\n## 开发\n\n```bash\nnpm test              # 运行测试\nnpm run test:watch    # 监听模式\nnpm run test:coverage # 覆盖率报告\nnpm run build         # 编译 TypeScript dev/reference tooling -\u003e dist/\nnpm run check:adapter-parity-fixtures # 校验 provider parser parity fixtures\n```\n\nmacOS 应用（Menu Bar）：\n\n```bash\ncd macos\nxcodegen generate     # 从 project.yml 生成 Xcode 项目\nopen Engram.xcodeproj # 在 Xcode 中构建和运行\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbingz%2Fengram","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbbingz%2Fengram","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbingz%2Fengram/lists"}