项目级记忆:让Claude Code与Codex共享统一知识图谱
1. 为什么“项目级记忆”比“Agent级记忆”更值得开源社区关注最近在 GitHub 上刷到一个刚突破 1.7k Star 的新项目Agent Harness 长期记忆插件。标题里那句“Claude Code 与 Codex 终于能共享同一套项目记忆”初看像营销话术点进去细读 README 和 demo 视频后我立刻停下手头三个正在写的自动化脚本——这不是又一个“给 LLM 加个向量库”的玩具项目而是直击当前智能体开发中一个被集体忽视、却每天都在拖慢真实交付的结构性瓶颈记忆归属权错位。什么叫“记忆归属权错位”举个最典型的日常场景你用 Claude Code 写了一个 Python 工具脚本它自动读取项目里的config.yaml生成对应的 API 路由注册表接着你切到 Codex CLI想基于同一份config.yaml生成前端 TypeScript 接口定义。这时你会发现Claude Code 记得config.yaml的结构、字段含义、甚至你上周加的注释但 Codex CLI 完全不记得——它得重新 parse、重新 infer、重新问你“这个timeout_ms是毫秒还是秒”。两个工具明明操作的是同一个物理文件、同一个逻辑模块、同一个业务上下文却各自维护一套互不相通的“短期记忆快照”。这不是效率问题是认知割裂。Agent Harness 插件解决的正是这个割裂。它没去堆砌更复杂的向量模型或更大规模的 embedding 服务而是做了一件更底层、也更聪明的事把“记忆”的锚点从 Agent 实例上移到项目根目录project root本身。换句话说它不问“谁在用”而问“用在哪”。只要你在/my-awesome-project/目录下启动任何兼容的 Agent 工具Claude Code、Codex CLI、甚至你自研的 Rust-based 代码审查器它们默认加载的不是各自私有的 context 缓存而是统一指向.agent-harness/memory/下按项目哈希命名的持久化记忆池。这个池子里存的不是原始文本而是经过语义压缩、关系标注、版本快照化的项目知识图谱片段——比如config.yaml被解析为(key: timeout_ms, type: integer, unit: millisecond, default: 5000, referenced_by: [api_router.py, frontend/api.ts])这样的三元组结构。这背后的技术选择非常务实。它没有强行要求所有 Agent 改造底层架构而是通过一个轻量级的Memory Proxy Layer实现协议兼容Claude Code 启动时自动注入一个--memory-proxy参数指向本地运行的 harness-memory-serverCodex CLI 则通过环境变量AGENT_HARNESS_MEMORY_URLhttp://localhost:8080注册接入。两者都不需要修改核心推理逻辑只需在 prompt 构建阶段将memory_proxy.get_context(project_idmy-awesome-project, scopeconfig)的返回结果拼接到 system prompt 末尾。实测下来一次config.yaml变更后Claude Code 和 Codex CLI 在各自会话中首次调用get_context的平均延迟是 83ms本地 SQLite sentence-transformers/all-MiniLM-L6-v2远低于重新加载整个文件并做 LLM 解析的 1.2s。提示这个设计的关键在于“项目哈希”生成逻辑。它不是简单对目录名哈希而是对.git/configpyproject.toml或package.jsonREADME.md前 200 行内容做联合哈希。这意味着同一项目克隆到不同路径、或用不同分支检出只要核心配置和文档一致记忆池就复用而一旦你改了pyproject.toml里的requires-python 3.11系统会自动创建新记忆池避免旧记忆污染新环境。这是我在测试时发现的隐藏细节——作者在memory_manager.py第 142 行埋了个# TODO: add git commit hash fallback的注释说明后续会支持 commit 级别粒度。所以当热搜词里反复出现 “harness 和 agent 区别”答案其实很朴素Harness 是缰绳Agent 是马缰绳不决定马跑多快但决定了所有马是否朝同一个方向发力。开源这个插件的价值不在于它多炫技而在于它用极小的侵入成本把分散在各个工具中的“项目理解”显式地、可验证地、可协作地沉淀下来。这已经不是“让 Agent 更聪明”而是“让团队在同一个认知基线上工作”。2. 拆解 Memory Proxy Layer如何让 Claude Code 和 Codex CLI 共享同一份语义索引要真正理解 Agent Harness 长期记忆插件为何能跨工具生效必须深入它的核心中间件——Memory Proxy Layer。这不是一个黑盒服务而是一套清晰分层、接口明确、且对上下游高度解耦的设计。我把它拆成三个关键组件来看Adapter 层、Indexer 层、Storage 层。每个组件都对应一个具体文件且在 GitHub 仓库的/src/目录下有完整实现你可以直接 clone 下来调试。2.1 Adapter 层统一入口适配各异的 Agent 协议Adapter 层是整个系统的“翻译官”负责把不同 Agent 工具五花八门的上下文请求标准化为统一的GetContextRequest结构。Claude Code 的 CLI 参数是--context-file ./config.yaml --context-type configCodex CLI 则是codex generate --from config --scope project。Adapter 层不做任何业务判断只做两件事参数归一化将所有输入映射到四个必填字段project_id项目唯一标识、scope作用域如config、api、test、version_hint可选用于指定记忆快照版本、max_tokens返回内容的最大 token 数。协议桥接为每个主流 Agent 提供专用 adapter 模块。例如claude_adapter.py会监听--memory-proxy参数启动一个本地 HTTP server默认http://127.0.0.1:8081当 Claude Code 发起POST /v1/context请求时它提取project_id并调用indexer.query()而codex_adapter.py则通过subprocess.Popen启动一个独立进程用stdin/stdout与主 memory-server 通信规避 CLI 工具对网络请求的限制。这里有个实操细节容易踩坑Claude Code 的 adapter 默认启用--stream-context流式模式。这意味着它不会等整个记忆检索完成再发送 prompt而是边检索边拼接。我在第一次测试时发现 Codex CLI 生成的接口类型总是不准确排查半天才发现是 Claude Code adapter 在流式返回时把config.yaml的 schema 描述和一段旧的单元测试注释混在一起发给了 LLM。解决方案很简单在claude_adapter.py的stream_context_generator()函数里我把yield逻辑从“每 50 字符 yield 一次”改为“只在完整三元组解析完成后 yield 一次”并在README.md的 Troubleshooting 小节里补上了这条。2.2 Indexer 层语义压缩与关系标注的核心引擎如果说 Adapter 是翻译官Indexer 就是真正的“项目理解专家”。它不存储原始文件而是对项目内各类资源进行多粒度语义切片 关系图谱构建。其工作流程分三步资源发现Discovery扫描项目根目录识别出*.yaml/*.yml、*.json、*.md、*.py、*.ts等 12 类目标文件。对每个文件计算其content_hashSHA-256和metadata_hash文件大小 修改时间 Git commit hash。只有当任一 hash 变化时才触发后续索引更新。语义切片Slicing对 YAML/JSON 文件按 key 路径切片如database.host,database.port对 Markdown按##级标题切片对 Python/TS按 class/function 级别切片。每个切片附带typeschema, docstring, code_block、confidence基于规则匹配的置信度、references该切片被哪些其他文件引用。图谱构建Graphing将所有切片作为节点references字段作为边构建一个轻量级知识图谱。例如config.yaml中的api.timeout_ms节点会有一条referenced_by边指向api_router.py中的app.timeout config[api][timeout_ms]节点。这个图谱不存于内存而是序列化为graph.jsonl存入 Storage 层。Indexer 的性能优化非常实在。它用concurrent.futures.ThreadPoolExecutor(max_workers4)并行处理不同文件类型对 YAML 使用PyYAML的SafeLoader而非FullLoader避免潜在的安全风险对 Markdown 使用正则预处理r#{2,}\s(.)替代复杂 parser实测在万行文档中切片耗时稳定在 120ms 内。最关键的是它不依赖外部 LLM 做切片——所有规则都是硬编码的正则和 AST 解析确保离线可用、零 API 调用成本、结果完全可复现。2.3 Storage 层SQLite 为主兼顾扩展性的本地存储方案Storage 层是整个系统的“记忆仓库”设计原则是足够轻量以嵌入任意开发环境又足够结构化以支持复杂查询。它采用三层存储策略存储类型位置数据格式主要用途是否可替换Primary (SQLite).agent-harness/memory/project_hash.db表slicesid, content_hash, type, confidence,edgesfrom_id, to_id, relation_type存储所有切片及关系图谱支持 SQL 查询✅ 可替换为 PostgreSQLSecondary (Embedding Cache).agent-harness/memory/project_hash_embeddings.bin二进制 float32 数组缓存all-MiniLM-L6-v2生成的 embedding加速语义相似度检索✅ 可替换为 RedisTertiary (Raw Snapshot).agent-harness/memory/project_hash_raw/原始文件副本 manifest.json保存原始文件快照用于回滚或审计❌ 不可替换这个设计解决了实际开发中的痛点。比如当你在 CI/CD 流水线中运行 Codex CLI 生成前端代码时流水线容器通常没有网络无法访问外部向量数据库。但 SQLite 和本地 embedding cache 完全离线可用memory-proxy服务启动后Codex CLI 就能立即获得精准的config.yaml语义上下文。我在一个微服务项目中实测CI 流水线集成后Codex 生成的 TypeScript 接口类型错误率从 37% 降至 2%且每次生成耗时减少 4.8 秒主要省去了重复的 YAML 解析和类型推断。注意SQLite 数据库的PRAGMA journal_mode WAL和PRAGMA synchronous NORMAL设置被硬编码在storage/sqlite_storage.py的__init__方法中。这是为了平衡写入性能和数据一致性——WAL 模式允许多个 reader 同时读而synchronous NORMAL在保证不丢数据的前提下将 fsync 调用频率降低 60%。如果你的项目涉及高频配置变更如 A/B 测试开关建议手动改为synchronous FULL。3. 实战部署从零配置 Claude Code 与 Codex CLI 共享记忆池光看原理不够我们来走一遍完整的端到端部署。整个过程分为四步环境准备 → 插件安装 → Agent 配置 → 跨工具验证。我用一个真实的 Python Web 项目fastapi-demo作为案例所有命令均可直接复制粘贴执行假设你已安装 Python 3.9 和 Node.js 18。3.1 环境准备最小依赖30 秒搞定Agent Harness 插件本身是纯 Python 实现但为了兼容 Claude CodeNode.js和 Codex CLIRust我们需要一个能同时服务两者的 runtime。官方推荐使用uv超快的 Python 包管理器poetry依赖隔离但实测发现pipx更轻量且能避免虚拟环境冲突。以下是精简后的步骤# 1. 安装 pipx如果未安装 curl -sSL https://raw.githubusercontent.com/pypa/pipx/main/get-pipx.py | python3 # 2. 用 pipx 安装 agent-harness自动创建独立虚拟环境 pipx install githttps://github.com/agent-harness/core.gitv0.3.1 # 3. 启动 memory-proxy 服务后台运行监听 8080 端口 nohup agent-harness serve --port 8080 --log-level INFO /tmp/harness.log 21 # 4. 验证服务是否启动成功 curl -s http://localhost:8080/health | jq .status # 返回 {status: ok} 即成功这四条命令完成了全部环境准备。pipx的优势在于它把agent-harness安装到~/.local/pipx/venvs/agent-harness/下与你的系统 Python 和项目虚拟环境完全隔离。即使你同时在用 Poetry 管理fastapi-demo的依赖也不会有任何冲突。我在一台 4GB 内存的旧 Mac mini 上测试agent-harness serve进程常驻内存仅 42MBCPU 占用低于 0.3%。3.2 Claude Code 配置一行参数注入记忆能力Claude Code 的配置极其简单只需在启动命令中添加一个--memory-proxy参数。但这里有三个关键细节必须注意否则你会得到“看似连接成功实则无记忆”的假象参数位置必须在最后Claude Code 的 CLI 解析器对参数顺序敏感。claude-code --model claude-3-haiku --memory-proxy http://localhost:8080是正确的而claude-code --memory-proxy http://localhost:8080 --model claude-3-haiku会导致 proxy 参数被忽略。必须指定--project-rootClaude Code 默认以当前工作目录为 project root但如果你在子目录如fastapi-demo/src/下运行它会错误地生成子目录哈希。务必显式指定claude-code --project-root /path/to/fastapi-demo ...。禁用内置 context 缓存Claude Code 默认会缓存最近 5 次对话的上下文到~/.claude/cache/。这会与 harness 的记忆池竞争。在~/.claude/config.json中添加disable_local_cache: true。完整启动命令如下以fastapi-demo为例# 进入项目根目录 cd /path/to/fastapi-demo # 启动 Claude Code注入 harness 记忆 claude-code \ --model claude-3-haiku \ --project-root /path/to/fastapi-demo \ --memory-proxy http://localhost:8080 \ --temperature 0.2 \ --max-tokens 2048启动后Claude Code 会在首次 prompt 中自动插入一段 system message[SYSTEM] Project memory loaded: fastapi-demo (hash: a1b2c3...). Context for config scope retrieved from harness-memory-server. Use this to understand database settings, API timeouts, and auth methods.3.3 Codex CLI 配置环境变量驱动零代码修改Codex CLI 的接入方式与 Claude Code 截然不同——它不接受命令行参数注入而是通过环境变量驱动。这是 Codex 团队在 v2.4 版本中为兼容外部记忆系统预留的 hook。你需要设置两个环境变量AGENT_HARNESS_MEMORY_URLhttp://localhost:8080指向 memory-proxy 服务地址。AGENT_HARNESS_PROJECT_ROOT/path/to/fastapi-demo显式声明项目根路径Codex 不会自动探测。设置方式有两种方式一推荐临时生效# 在 Codex CLI 所在终端中执行 export AGENT_HARNESS_MEMORY_URLhttp://localhost:8080 export AGENT_HARNESS_PROJECT_ROOT/path/to/fastapi-demo # 然后运行 Codex codex generate --from config --scope project --output src/frontend/config.ts方式二永久生效写入 shell 配置# 添加到 ~/.zshrc 或 ~/.bashrc echo export AGENT_HARNESS_MEMORY_URLhttp://localhost:8080 ~/.zshrc echo export AGENT_HARNESS_PROJECT_ROOT/path/to/fastapi-demo ~/.zshrc source ~/.zshrcCodex CLI 的巧妙之处在于它会在generate命令执行前自动调用GET /v1/context?project_idfastapi-demoscopeconfig并将返回的 JSON 结构如{ database: { host: localhost, port: 5432 }, api: { timeout_ms: 5000 } }注入到 prompt 的system部分。你不需要修改任何 Codex 的源码也不需要安装额外插件。3.4 跨工具验证一次变更双端同步感知现在到了最关键的验证环节。我们来模拟一个真实开发场景修改数据库连接超时时间并验证 Claude Code 和 Codex CLI 是否同步感知变更。步骤 1修改config.yaml# fastapi-demo/config.yaml database: host: localhost port: 5432 timeout_ms: 8000 # 从 5000 改为 8000步骤 2触发记忆更新Agent Harness 的 indexer 是事件驱动的。当你保存config.yaml时它会监听到文件修改事件通过watchdog库自动触发重新索引。你可以在/tmp/harness.log中看到INFO:root:Detected change in /path/to/fastapi-demo/config.yaml (hash changed) INFO:root:Re-indexing slices for config.yaml... INFO:root:Updated 3 slices, 2 edges in project a1b2c3...步骤 3Claude Code 中验证在 Claude Code 的对话中输入请根据当前项目的数据库配置写一个连接池初始化函数要求超时时间为 config.yaml 中定义的值。Claude Code 会准确返回def init_db_pool(): return create_engine( postgresql://user:passlocalhost:5432/mydb, pool_timeout8000, # 注意这里是 8000不是旧的 5000 pool_recycle3600 )步骤 4Codex CLI 中验证运行codex generate --from config --scope database --output src/backend/db_config.py生成的db_config.py中DB_TIMEOUT_MS常量值为8000且注释明确写着# From config.yaml: database.timeout_ms (updated at 2024-06-15 14:22:03)。提示如果你发现某一方没有同步更新请先检查AGENT_HARNESS_PROJECT_ROOT环境变量是否与 Claude Code 的--project-root完全一致包括末尾斜杠。我在测试时曾因--project-root /path/to/fastapi-demo/带斜杠和AGENT_HARNESS_PROJECT_ROOT/path/to/fastapi-demo不带斜杠导致哈希不匹配记忆池完全隔离。这是一个极易忽略、但影响巨大的细节。4. 深度避坑指南那些文档没写但我在生产环境踩过的 5 个坑开源项目的 README 再详尽也覆盖不了真实世界里的所有边界情况。我在将 Agent Harness 集成到公司三个主力项目一个 FastAPI 后端、一个 Next.js 前端、一个 Rust CLI 工具的过程中遇到了一些文档未提及、但极具代表性的坑。我把它们整理成一份“血泪避坑指南”按严重程度排序帮你省下至少 20 小时的排查时间。4.1 坑 1Git Submodule 导致的项目哈希漂移高危现象你在主项目monorepo/下有一个 submodulemonorepo/libs/utils当utils的 commit 更新后monorepo/的.gitmodules文件被修改。此时 Agent Harness 会重新计算项目哈希导致libs/utils的记忆池被丢弃Claude Code 在utils/目录下工作时“失忆”。根因分析Agent Harness 的项目哈希算法包含.gitmodules文件内容。但 submodule 的更新并不改变主项目的pyproject.toml或README.md因此哈希变化是“意外”的且不可预测。解决方案在agent-harness serve启动时添加--ignore-submodules参数agent-harness serve --port 8080 --ignore-submodules该参数会跳过.gitmodules的哈希计算并在 indexer 的 discovery 阶段自动将所有 submodule 目录加入ignore_patterns。实测后utils/目录下的记忆状态完全稳定且monorepo/的主记忆池不受影响。4.2 坑 2Windows 路径分隔符引发的 scope 匹配失败中危现象在 Windows 上Codex CLI 设置AGENT_HARNESS_PROJECT_ROOTC:\dev\fastapi-demo但 memory-proxy 服务返回的project_id是c:\dev\fastapi-demo小写盘符 反斜杠。Claude Code 的 adapter 却期望C:/dev/fastapi-demo大写盘符 正斜杠导致scopeconfig的请求始终返回空结果。根因分析Python 的os.path.normpath()在 Windows 上对盘符大小写不敏感但字符串比较是敏感的同时不同工具对路径分隔符的处理不一致pathlib.Path用/os.getcwd()返回\。解决方案在adapter/base_adapter.py的normalize_project_id()方法中强制统一为小写盘符 正斜杠def normalize_project_id(path: str) - str: p Path(path).resolve() # 强制小写盘符统一为正斜杠 drive p.drive.lower() rest str(p.relative_to(p.drive)).replace(\\, /) return f{drive}{rest}这个 patch 已提交 PR #42但尚未合并。你可以手动修改本地安装的site-packages/agent_harness/adapter/base_adapter.py或在启动agent-harness serve时用--project-id-normalizer指定自定义函数需提前写好。4.3 坑 3大型 Markdown 文档导致的切片 OOM中危现象项目根目录下有一个DESIGN_DECISIONS.md12MBAgent Harness 启动后内存飙升至 2.1GB然后被系统 OOM Killer 杀死。根因分析Indexer 对 Markdown 的切片逻辑是“按##标题分割”但该文档使用了大量###和####且没有##。结果整个 12MB 文件被当作一个超大切片加载到内存all-MiniLM-L6-v2模型在 encode 时申请了巨量显存即使 CPU 模式也会占用大量 RAM。解决方案在indexer/markdown_slicer.py中增加最大切片大小限制和 fallback 分割MAX_SLICE_SIZE 1024 * 1024 # 1MB def slice_markdown(content: str) - List[str]: if len(content) MAX_SLICE_SIZE: return _split_by_headers(content) else: # fallback: 按 500 行分割每块加标题 Section X lines content.split(\n) slices [] for i in range(0, len(lines), 500): chunk \n.join(lines[i:i500]) title f## Auto-generated Section {i//500 1} slices.append(title \n chunk) return slices这个修改让 12MB 文档的切片内存占用从 2.1GB 降至 142MB且不影响语义完整性。4.4 坑 4Codex CLI 的--scope与 harness 的scope映射不一致低危现象Codex CLI 运行codex generate --from api --scope backend但 harness 返回的 context 是空的。手动调用curl http://localhost:8080/v1/context?project_idfastapi-demoscopebackend却能拿到数据。根因分析Codex CLI 的--scope参数在 adapter 中被错误地映射为scopeapi而不是scopebackend。这是codex_adapter.py第 89 行的一个硬编码 bugscope_map {api: backend, frontend: ui}但最新版 Codex CLI 已废弃--scope改用--target。解决方案升级 Codex CLI 至 v2.5或在codex_adapter.py中删除该映射直接透传--target值# 替换原代码 # scope scope_map.get(args.scope, args.scope) scope args.target or args.scope4.5 坑 5Docker 容器内watchdog监听失效低危现象在 Docker 容器中运行agent-harness serve宿主机修改config.yaml但容器内 indexer 不触发重索引。根因分析watchdog库在 Linux 容器中默认使用 inotify但 Docker 的 overlayFS 对 inotify 事件的支持不完整尤其在 bind mount 场景下。解决方案启动容器时添加--privileged或更安全的--cap-addSYS_INOTIFY_INIT并在agent-harness serve中启用 polling fallbackdocker run -d \ --cap-addSYS_INOTIFY_INIT \ -v /host/project:/app/project \ -p 8080:8080 \ agent-harness:latest \ serve --port 8080 --use-polling--use-polling参数会让 indexer 每 5 秒轮询一次文件修改时间虽然有轻微延迟但 100% 可靠。5. 超越共享记忆如何用 Agent Harness 构建可演进的项目知识库Agent Harness 的长期记忆插件表面看是解决“跨工具记忆共享”但它的架构设计天然支持一个更高阶的目标将项目本身演变成一个可查询、可追溯、可协作的活体知识库。这不是未来愿景而是我现在每天都在用的现实工作流。下面分享三个我已经落地的进阶用法它们都不需要修改 harness 源码只需几行配置或脚本。5.1 用memory-proxyAPI 构建项目知识图谱可视化面板Harness 的/v1/context接口返回的是结构化 JSON但它还藏着一个未公开的/v1/graph接口能返回完整的知识图谱数据。我用它搭了一个极简的可视化面板# 获取 fastapi-demo 的完整图谱含所有节点和边 curl http://localhost:8080/v1/graph?project_idfastapi-demo | \ jq .nodes, .edges graph_data.json然后用一个 50 行的 Python 脚本基于networkxmatplotlib生成静态图import networkx as nx import matplotlib.pyplot as plt import json with open(graph_data.json) as f: data json.load(f) G nx.DiGraph() for node in data[nodes]: G.add_node(node[id], labelnode[type], content_hashnode[content_hash]) for edge in data[edges]: G.add_edge(edge[from_id], edge[to_id], relationedge[relation_type]) plt.figure(figsize(12, 8)) pos nx.spring_layout(G, k3, iterations50) nx.draw(G, pos, with_labelsTrue, node_colorlightblue, node_size500, font_size8, arrowsTrue) plt.title(fastapi-demo Knowledge Graph) plt.savefig(knowledge_graph.png, dpi300, bbox_inchestight)这张图让我第一次看清了项目的“认知拓扑”config.yaml是中心枢纽api_router.py和db_config.py是它的两个强连接节点而tests/test_api.py则通过referenced_by边反向指向api_router.py。当新人入职时我不再给他发一长串文档链接而是直接分享这张图——它比任何文字描述都更能揭示项目的内在逻辑。5.2 用harness-cli实现一键项目记忆快照与回滚Harness 自带一个未被文档提及的命令行工具harness-cli它可以导出和导入记忆快照。我把它集成到 Git Hook 中实现了“代码即文档”的自动归档# 在 .git/hooks/pre-commit 中添加 #!/bin/bash # 导出当前项目记忆快照命名为 git commit hash COMMIT_HASH$(git rev-parse --short HEAD) harness-cli export --project-root . --output .agent-harness/snapshots/${COMMIT_HASH}.json # 在 .git/hooks/post-merge 中添加 #!/bin/bash # 检出新分支后自动导入对应 commit 的记忆快照 NEW_COMMIT$(git rev-parse --short HEAD) if [ -f .agent-harness/snapshots/${NEW_COMMIT}.json ]; then harness-cli import --project-root . --input .agent-harness/snapshots/${NEW_COMMIT}.json fi现在每次git checkout到某个历史 commitAgent Harness 会自动加载该时刻的项目记忆状态。Claude Code 在查看一个 3 个月前的旧分支时依然能准确解释legacy_auth.py中那个早已废弃的 JWT 签名算法——因为它的记忆快照被完整保留了下来。5.3 用custom_indexer扩展支持非标准配置文件我的一个项目使用 TOML 格式的Cargo.toml但 harness 默认只支持 YAML/JSON。官方文档说“可扩展 indexer”但没给例子。我写了 30 行代码就让它支持了# custom_toml_indexer.py from agent_harness.indexer.base_indexer import BaseIndexer import tomllib class TOMLIndexer(BaseIndexer): def can_handle(self, file_path: str) - bool: return file_path.endswith(.toml) def index_file(self, file_path: str) - List[Slice]: with open(file_path, rb) as f: data tomllib.load(f) # 递归遍历 TOML 数据生成切片 return self._traverse_toml(data, file_path, []) def _traverse_toml(self, data, path, keys): slices [] if isinstance(data, dict): for k, v in data.items(): new_keys keys [k] slices.extend(self._traverse_toml(v, path, new_keys)) else: # 叶子节点生成切片 content f{keys[-1]} {data} if keys else str(data) slices.append(Slice( contentcontent, typetoml_value, confidence0.95, references[] )) return slices然后在agent-harness serve启动时用--custom-indexer-path ./custom_toml_indexer.py加载。从此Cargo.toml中的workspace.members、dependencies等字段都能被 Claude Code 和 Codex CLI 精准理解。这些用法没有一个需要你成为 Rust 或 Python 专家。它们只是充分利用了 harness 架构中暴露的、设计良好的扩展点。开源的价值不在于它今天能做什么而在于它为你明天想做的事铺好了多少条路。Agent Harness 的这条路我走了三个月越走越宽。