Residue:为AI编程对话建立可追溯的代码考古学
1. 项目概述为AI编程对话建立可追溯的“代码考古学”如果你和我一样日常开发中已经离不开像Claude Code、Cursor、Windsurf这类AI编程助手那你一定遇到过这个场景看着一段几天前写的、逻辑有点绕的代码死活想不起来当时为什么要这么设计。你隐约记得是和AI助手来回讨论了几个回合才定下的方案但具体讨论了什么AI给出了哪些建议你又是基于什么考虑选择了最终这个实现这些记忆就像沙滩上的字迹被后续的代码浪潮冲刷得干干净净。Residue 就是为了解决这个“记忆断层”而生的。它是一个开源、自托管的工具链核心使命就一句话自动捕获AI编程对话并将其与最终的Git提交精准关联。你可以把它想象成给每一次“人机结对编程”过程安装了一个黑匣子。每次你执行git pushResidue 都会将促成这次代码变更的完整对话记录一并上传在你的代码仓库旁建立一个可搜索、可追溯的“决策上下文档案馆”。这不仅仅是简单的日志记录。在团队协作中它的价值会指数级放大。新同事接手一个模块不再需要凭空猜测“前辈们当时是怎么想的”他可以直接查看某次提交关联的完整对话理解每个设计决策背后的权衡。进行代码审查时审查者能直接看到作者与AI讨论的备选方案和取舍理由让审查从“猜意图”变成“验证逻辑”。对于个人开发者它则是一个强大的知识管理工具让你能随时回溯任何一段代码的“诞生记”。整个系统由两部分组成一个用Bun编写的命令行工具CLI和一个部署在Cloudflare Workers上的轻量级后端。CLI负责在本地拦截事件AI对话开始/结束、Git提交/推送后端则负责存储和提供查询界面。最妙的是它的设计极其克制——Git钩子即使出错也绝不阻塞你的正常提交流程数据上传采用直接写入对象存储R2的方式避免对Worker造成性能压力。接下来我会带你从零开始完整部署一套属于你自己的Residue系统并分享在实际集成和使用中积累的一系列实战经验。2. 核心架构与设计哲学解析在动手部署之前深入理解Residue的设计思路能帮助你在后续使用和可能的问题排查中事半功倍。它的架构清晰地反映了几个关键的设计决策这些决策共同确保了工具的轻量、可靠与实用。2.1 事件驱动的双流模型连接对话与提交Residue的核心工作流程建立在两个独立的事件源上AI代理适配器和Git钩子。理解它们如何协作是理解整个系统的钥匙。AI代理流当你启动一个支持Residue的AI编程助手如Claude Code并开始对话时适配器会调用residue session start命令生成一个唯一的会话ID。随着对话进行所有的消息你的提问、AI的回复、工具调用结果都会被适配器实时或分批发送给CLI暂存。当对话窗口关闭或你明确结束会话时适配器调用residue session end标记该会话已准备就绪。关键在于此时会话数据仅存在于你本地机器的暂存区尚未与任何代码变更关联。Git提交流这是建立关联的桥梁。当你执行git commit后由residue init安装的post-commit钩子会自动触发。这个钩子执行residue capture命令其逻辑是“找到所有当前处于‘已结束’但尚未关联提交的本地会话给它们都打上刚刚生成的这个Commit SHA标签。” 这意味着一次提交可能关联多个对话会话如果你在提交前和AI聊了好几次而一个长时间的对话也可能跨越多次提交最终关联到多个SHA上。数据同步流最后当你执行git push时pre-push钩子触发residue sync。这个命令将所有已被标记即关联了提交SHA的本地会话数据打包并上传到你自托管的Cloudflare Worker后端。上传成功后本地暂存数据被清空完成一个完整的生命周期。设计精妙之处这种“先本地暂存提交时打标签推送时同步”的设计完美适应了开发工作流的不确定性。你可以在一次编码会话中多次保存文件、多次与AI交流最后一次性提交。Residue不会在你每说一句话时就慌乱记录而是在一个自然的边界Git提交处建立关联这使得最终的记录单元既有意义又整洁。2.2 存储策略元数据与内容分离Residue采用了清晰的数据存储分离策略这直接影响了其扩展性和成本。会话原始数据 (R2对象存储)AI对话的完整原始数据通常是JSON格式包含所有消息、时间戳、元数据被直接上传到Cloudflare R2。R2是一个兼容S3 API的对象存储服务价格低廉且与Workers集成极佳。Residue通过让Worker生成预签名URL允许CLI直接将数据PUT到R2完全绕开了Worker本身对请求体大小的限制。这意味着即使你有一个长达数小时的、包含大量代码块的对话上传也畅通无阻。搜索索引数据 (R2对象存储)直接对庞大的原始JSON文件进行全文搜索是不现实的。因此在同步时CLI会做一项额外工作从原始数据中提取出“人类消息”、“AI的文本回复”以及“工具调用的摘要”等纯文本内容生成一个轻量级的.txt文件并将其上传到R2中一个专门的search/目录下。后端的搜索功能实际上是对这些文本文件进行操作效率极高。关联关系与元数据 (D1数据库)Commit SHA、会话ID、仓库信息、分支、作者、时间戳等结构化关系数据则被存储在Cloudflare D1一个基于SQLite的服务器less数据库中。D1非常适合存储这种轻量的、关系型的数据并且支持在Worker中直接进行SQL查询。Web界面中展示的提交时间线、按仓库/分支/作者的筛选功能都依赖于D1中的数据。2.3 无侵入与高可靠性的工程实践作为一款开发工具Residue严格遵守了“不影响主体工作”的原则Git钩子永不阻塞所有residue命令在Git钩子中调用时都被包裹在错误处理中。即使上传失败、网络中断或CLI自身出错钩子脚本也会以退出码0结束确保你的git commit和git push永远不会因为Residue而失败。捕获和同步是“尽力而为”的。适配器透明集成residue setup命令所做的只是向AI代理的配置目录如Claude Code的.claude/settings.json添加几行配置告诉代理“在对话生命周期的特定时刻去调用这个本地命令”。它不修改代理的核心行为也不影响其与AI服务的通信。配置即代码项目的Residue配置使用--local参数登录时保存在项目根目录的.residue/config文件中并且该目录被自动加入.gitignore。这意味着你的Residue服务器地址和令牌不会误提交到代码库但配置本身可以作为项目环境的一部分进行管理。3. 从零开始部署你的Residue后端现在我们进入实战环节。我将带你走通手动部署的每一步并解释每个操作背后的原因。虽然项目提供了便捷的安装器installer但手动部署能让你更透彻地理解系统各个组件是如何连接起来的。3.1 前期准备工具与账户确保你的开发环境已就绪Node.js环境Residue使用Bun作为运行时。请先安装Bun。如果你习惯用npm或yarn后续的pnpm命令大多可以类比。Bun的优势在于其极快的启动速度和与Node.js生态的良好兼容这对CLI工具至关重要。Cloudflare账户你需要一个Cloudflare账户。Residue的后端运行在Cloudflare Workers无服务器平台上数据存储在R2和D1中。Workers的免费额度对于个人或小团队使用Residue来说完全足够这几乎是零成本部署。3.2 第一步创建R2存储桶与API凭证R2将存储所有会话的原始数据和搜索文本。我们需要创建存储桶并获取访问密钥。登录Cloudflare仪表板进入你希望使用的账户。创建R2存储桶在侧边栏找到“R2”点击“创建存储桶”。桶名称可以设为residue-sessions或其他有意义的名称。区域选择建议选一个离你主要开发地较近的例如apac亚太或enam北美东部。创建后记下你的Bucket名称。创建S3兼容API令牌在R2页面找到“API令牌”选项卡点击“创建API令牌”。令牌名称residue-worker-upload权限选择“编辑”权限这包含了读写操作。资源访问选择“特定存储桶”然后选中你刚创建的存储桶。点击“创建”后务必立即妥善保存弹出的Access Key ID和Secret Access Key。Secret Key只显示这一次。此外你还需要找到你的Cloudflare账户ID它通常在仪表板首页的右下角或账户概览页面。至此你手头应该有这四个关键信息请将它们保存在一个临时文件里R2_ACCESS_KEY_IDR2_SECRET_ACCESS_KEYR2_ACCOUNT_IDR2_BUCKET_NAME3.3 第二步部署Worker应用Worker是Residue的大脑它提供API和Web界面。我们采用“手动部署”方式以获得最大控制权。# 1. 克隆代码库并安装依赖 git clone https://github.com/butttons/residue.git cd residue pnpm install # 使用项目约定的pnpm包管理器 # 2. 进入Worker目录 cd packages/worker # 3. 登录Wrangler (Cloudflare的官方CLI工具) npx wrangler login # 按照提示在浏览器中完成Cloudflare账户授权。 # 4. 创建D1数据库 npx wrangler d1 create residue-db # 成功后会输出数据库ID形如 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx。复制这个ID。 # 5. 配置wrangler.jsonc # 用编辑器打开当前目录下的 wrangler.jsonc 文件。 # 你需要更新以下几处 # a. 在 d1_databases 部分将 database_id 替换为你刚复制的ID。 # b. 在 vars 部分添加或更新以下环境变量 # R2_ACCESS_KEY_ID: 你的Access Key ID, # R2_ACCOUNT_ID: 你的Cloudflare账户ID, # R2_BUCKET_NAME: 你的R2存储桶名称, # ADMIN_USERNAME: admin # 设置一个管理员用户名如admin # c. 在 r2_buckets 部分确保 binding 是 RESIDUE_SESSIONSbucket_name 是你的存储桶名。 # 6. 应用数据库迁移 npx wrangler d1 migrations apply residue-db --remote # 这会在远程D1数据库中创建所需的表结构。 # 7. 设置密钥Secrets # 这些敏感信息不会写在配置文件中而是通过命令注入。 # 生成一个强随机字符串作为AUTH_TOKEN用于CLI认证 echo 你的强随机CLI认证令牌 | npx wrangler secret put AUTH_TOKEN # 设置一个安全的ADMIN_PASSWORD用于Web界面管理员登录 echo 你的管理员密码 | npx wrangler secret put ADMIN_PASSWORD # 设置R2_SECRET_ACCESS_KEY echo 你的R2 Secret Access Key | npx wrangler secret put R2_SECRET_ACCESS_KEY # 8. 部署Worker npx wrangler deploy部署成功后命令行会输出你的Worker域名例如https://residue.your-subdomain.workers.dev。记下这个Worker URL和刚才设置的AUTH_TOKEN。注意事项wrangler.jsonc中的vars是明文环境变量而secret是通过wrangler secret put设置的加密环境变量。R2_SECRET_ACCESS_KEY必须设为secret因为它是高度敏感的凭证。ADMIN_PASSWORD也同理。3.4 第三步安装与配置CLICLI是连接你本地开发环境和远程Worker的桥梁。# 全局安装CLI需要先安装Bun bun add -g residue/cli # 使用上一步获得的URL和Token进行登录 residue login --url https://residue.your-subdomain.workers.dev --token YOUR_AUTH_TOKEN这条命令会在你的用户主目录下创建~/.residue/config文件保存凭证。如果你想为某个特定项目使用不同的Residue实例比如公司项目和个人项目分开可以在项目根目录下使用--local参数residue login --url https://company-residue.example.com --token COMPANY_TOKEN --local这会在当前目录创建.residue/config文件优先级高于全局配置。4. 项目集成与AI代理配置实战后端和CLI就绪后就可以在你具体的代码仓库中启用Residue了。这个过程是“按项目”进行的。4.1 初始化Git仓库跟踪进入你想要跟踪AI对话的Git仓库根目录执行residue init这个命令做了三件事在.git/hooks/目录下创建或修改post-commit和pre-push两个钩子脚本在其中调用residue capture和residue sync。确保项目根目录的.gitignore文件中包含了.residue/防止本地缓存数据被误提交。在本地初始化Residue的项目状态。你可以检查一下.git/hooks/post-commit文件会发现其内容类似#!/bin/sh # 调用residue捕获当前提交关联的会话 residue capture /dev/null 21 || true末尾的|| true确保了即使residue capture命令失败钩子也会返回成功状态不阻塞Git操作。4.2 配置AI代理适配器这是让Residue自动捕获对话的关键。Residue目前官方支持几种流行的AI编程助手1. 配置 Claude Code (Cursor内置或独立版)residue setup claude-code这个命令会定位到 Claude Code 的配置目录通常是~/.cursor或~/.claude并修改其中的settings.json文件添加一个钩子配置。配置内容大致是告诉Claude Code“在会话开始时执行residue session start在会话结束时执行residue session end并在每次发送消息时将消息内容通过标准输入传递给residue hook claude-code”。配置后你需要重启Claude Code或Cursor使其生效。2. 配置 Windsurf (或原Cursor AI)residue setup pi对于使用“Pi”代理模式的编辑器如Windsurf此命令会在项目或用户全局的扩展目录中安装一个小的适配器脚本。原理与Claude Code类似。3. 配置 OpenCode (或其他兼容LSP的代理)residue setup opencode此命令会安装一个OpenCode插件通过LSP协议的事件来触发Residue的会话记录。实操心得执行setup命令后务必检查对应AI工具的日志或设置界面确认钩子已成功加载。有时因为权限问题或配置路径不同可能需要手动调整。一个简单的验证方法是配置完成后在对应编辑器中新建一个对话然后去终端执行residue status你应该能看到一个状态为active的会话。4.3 验证全链路工作流完成以上步骤后你可以进行一次完整的测试开始对话在已配置的编辑器中如Cursor新建一个文件开启AI对话例如Claude Code讨论几句关于代码的问题。进行修改根据AI的建议对代码做一些修改并保存。提交代码git add . git commit -m feat: add user authentication module with AI assistance提交后post-commit钩子触发。你可以通过residue status查看刚才的会话应该已经从active变为ended并且关联上了刚才的提交SHA。推送代码git push origin mainpre-push钩子触发执行数据同步。观察终端输出应该能看到上传进度。如果没有报错数据就已发送至你的Worker。查看结果打开你的Worker URL如https://residue.your-subdomain.workers.dev/app用设置的管理员账号登录。你应该能在界面上看到你的仓库、刚刚的提交以及旁边一个“对话”图标或链接。点击即可查看完整的、与此次提交关联的AI对话记录。5. 日常使用、查询与运维技巧Residue在后台默默工作但你也需要通过一些命令来管理它或者从中挖掘价值。5.1 常用CLI命令详解除了基础的login,init,setup以下命令在日常开发中非常有用residue push手动触发数据同步。如果你禁用了pre-push钩子或者想在推送前提前上传会话可以使用此命令。residue status显示当前仓库的Residue状态。包括是否有活跃会话、等待关联的已结束会话列表、以及最近同步的状态。这是最快速的健康检查工具。residue clear [--id SESSION_ID]清除本地队列中的会话。如果某个会话数据损坏或你不想上传它可以用此命令清理。使用--id参数清除指定会话。residue read session-id将本地存储的某个会话的原始转录内容输出到标准输出。这可以用于将对话内容通过管道传递给其他文本处理工具或AI进行分析。residue context输出一份面向AI代理的文档。这份文档实际上是在“教”AI如何更好地与Residue协作例如在对话中如何引用之前的会话。你可以将此命令的输出作为系统提示词的一部分喂给AI。查询命令这些命令会调用Worker APIresidue query sessions列出所有已同步的会话。支持丰富的过滤器# 查找特定仓库、特定分支、最近7天的会话 residue query sessions --repo my-org/my-repo --branch feat/auth --since 7d # 查找特定AI代理如claude-code产生的会话 residue query sessions --agent claude-coderesidue query commits列出所有关联了会话的提交。residue query session id/residue query commit sha获取会话或提交的详细信息包括完整的关联关系。5.2 Web管理界面使用指南Worker提供的Web界面是你查看数据的主要窗口。登录与模式首次访问/app路径你会被引导至登录页。使用部署时设置的ADMIN_USERNAME和ADMIN_PASSWORD登录。在“设置”中你可以将实例切换为公开模式这样任何人拥有链接即可查看对话适合开源项目或者保持私有模式需要登录。浏览结构界面通常以组织(Org) / 仓库(Repo)的层级展示。组织和仓库名是从你Git仓库的远程URL如github.com/my-org/my-repo中自动解析出来的。时间线视图进入一个仓库后你会看到一个提交时间线。每个旁边有“对话”图标的提交都意味着有相关联的AI会话。点击提交SHA可以进入详情页看到具体的文件变更和关联的对话。会话查看与搜索点击对话图标会以侧边栏或新页面的形式展示完整的对话记录。消息通常被渲染成易于阅读的格式代码块有高亮。顶部通常有搜索框可以在当前仓库的所有会话内容中进行全文搜索。用户管理管理员可以在“设置” “用户”中创建新的用户账号并为其设置密码。新用户登录后即可查看会话在私有模式下。5.3 运维与故障排查常见问题1R2上传失败提示SignatureDoesNotMatch这是最常见的问题根本原因是Worker用于给预签名URL签名的R2_SECRET_ACCESS_KEY与实际R2存储桶的密钥不匹配。原因你在Cloudflare控制台重新生成了R2的API令牌但Worker上的Secret没有更新。解决# 进入worker目录 cd /path/to/residue/packages/worker # 更新Secret echo 你的新R2_SECRET_ACCESS_KEY | npx wrangler secret put R2_SECRET_ACCESS_KEY # 如果Access Key ID也变了还需要更新wrangler.jsonc中的R2_ACCESS_KEY_ID变量然后重新部署 npx wrangler deploy常见问题2Git钩子未执行检查钩子文件权限确保.git/hooks/post-commit和pre-push有可执行权限chmod x .git/hooks/post-commit。检查Git配置有些Git配置或GUI工具可能会禁用钩子。在命令行中执行git commit和git push通常能确保钩子运行。手动测试钩子直接运行./.git/hooks/post-commit看是否有错误输出。常见问题3Web界面无法显示会话内容检查R2桶权限确保Worker使用的API令牌对R2存储桶至少有读取和写入权限。检查D1数据库通过npx wrangler d1 execute residue-db --remote --commandSELECT COUNT(*) FROM sessions检查数据是否正常写入。查看Worker日志在Cloudflare仪表板的Workers部分找到你的Residue Worker查看其实时日志排查API错误。定期维护更新关注Residue GitHub仓库的Release。更新CLI只需bun update -g residue/cli。更新Worker则需要重新拉取代码运行pnpm install和npx wrangler deploy。项目也提供了便捷的更新页面install.residue.dev/update。数据清理目前Residue没有自动清理旧数据的机制。如果R2中存储的会话数据过多你可以通过Cloudflare控制台或S3 API手动制定生命周期规则例如自动删除30天前的对象。D1中的数据也可以通过自定义Worker API端点来清理。6. 深入原理数据流与扩展可能性要真正玩转Residue甚至基于它进行二次开发就需要深入其数据流转的细节。6.1 一次完整的数据流转剖析假设我们使用Claude Code编辑一个api.js文件。会话开始你在编辑器按CmdK激活Claude Code。Claude Code适配器调用residue session start。CLI在本地创建一个临时文件例如在~/.residue/cache/下生成一个UUID作为session_id并记录开始时间、编辑器类型等元数据。会话状态为active。对话进行你输入“如何用Express实现一个简单的JWT认证中间件”。Claude Code在发送此消息给AI服务前会先调用residue hook claude-code并将消息以JSON格式通过stdin传入。CLI将此条消息追加到该会话的临时文件中。AI回复后回复内容同样被捕获并追加。这个过程持续进行。会话结束你关闭对话窗口。Claude Code适配器调用residue session end。CLI将本地临时文件标记为已完成状态改为ended并计算哈希等摘要信息。此时数据仍在本地。提交关联你编写了中间件代码并提交git commit -am add auth middleware。post-commit钩子执行residue capture。CLI获取到最新的提交SHA如abc123然后扫描本地所有状态为ended且commit_sha为空的会话将它们都与abc123这个SHA关联起来并更新本地索引。推送同步你执行git push。pre-push钩子执行residue sync。CLI开始处理所有已关联提交的会话准备数据读取会话原始JSON文件。生成搜索文本解析JSON提取出所有user和assistant角色的text内容拼接成一个纯文本文件。获取上传URL向你的Worker发送请求携带会话元数据。Worker验证Token后生成两个针对R2存储桶的预签名PUT URL一个用于原始数据sessions/{session_id}.json一个用于搜索文本search/{session_id}.txt。直接上传CLI使用这两个URL通过HTTP PUT请求将两个文件直接上传到Cloudflare R2。这步不经过Worker速度快且不受Worker体积限制。提交元数据文件上传成功后CLI再次调用Worker API提交会话的元数据session_id, 关联的commit_sha, 仓库、分支、作者、时间戳等以及文件在R2中的存储路径。Worker将这些信息存入D1数据库。清理本地所有步骤成功后CLI删除本地的临时会话文件。6.2 扩展与定制化思路Residue的架构为扩展提供了可能支持新的AI代理如果你用的工具不在官方支持列表你可以为其编写一个适配器。核心是让该工具在对话开始、结束和每次消息交换时调用对应的residue session start/end/hook命令。residue hook命令设计为接收标准输入的JSON格式可以自定义你只需要在Worker端添加对应的解析器Mapper即可。自定义数据处理器residue read命令的输出可以接入其他流程。例如你可以写一个脚本定期将对话内容导出用于训练团队内部的代码风格模型或者分析高频问题来优化开发文档。增强Web UIWorker的UI部分是用Hono JSX构建的。你可以克隆代码库修改packages/worker/src/ui下的组件添加你需要的功能比如更强大的数据看板、统计图表然后重新部署你自己的Worker。集成到CI/CD你可以通过Worker提供的API (/api/query/commits) 在CI流水线中获取当前构建对应提交的AI对话记录将其作为代码审查报告的一部分自动附加到Pull Request中。Residue解决的是一个非常具体但痛点十足的“上下文丢失”问题。它没有试图打造一个庞杂的AI开发平台而是巧妙地利用现有的Git工作流和云原生服务做了一个精准、轻量、自托管的“缝合器”。这种克制和专注正是它在众多开发者工具中显得独特而实用的原因。