关于 celmis
Celmis 是供团队跨仓库使用的可自托管代码智能平台。它构建共享符号图,用于代码问答、依赖审计、PR 审查和从告警到 PR 的工作流,并提供访问控制与审计。
主要功能
- 01带引用的跨仓库问答
- 02结合符号图的 PR 审查
- 03依赖审计与 CycloneDX SBOM
- 04将告警和发现转为 PR
- 05工作区知识包
- 06按人发放 MCP 令牌并审计调用
适用场景
- 01追踪跨仓库调用链
- 02结合下游调用者审查代码变更
- 03生成 SBOM 和可复核的证据包
- 04从告警或依赖问题启动修复
MCP 相关
Celmis 通过 MCP 提供 51 个工具,并为编辑器提供精简的 `/mcp/dev` 配置。MCP 调用使用共享代码索引,并遵循仓库访问规则和审计要求。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm ghcr.io/celmis-labs/celmis-api:v0.1.30本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/celmis-labs/celmis-api:v0.1.30Streamable HTTP工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
你运行的某项服务发来告警。Celmis 已经知道该服务属于哪个代码仓库以及由谁负责,因此修复从这里开始:嵌入式 Claude Code 会话使用你的订阅,在你的安装环境中编辑代码;运行器随后提交更改、推送分支并创建拉取请求。在一项经过测量的发现中,从告警首先抵达的设备开始,整个过程耗时 220 秒。
这个闭环之所以成立,是因为所有内容都位于同一个索引中:它根据你的代码仓库一次性构建符号图,构建时不涉及任何模型。其他所有界面都读取同一索引。
功能
| 从这里修复 | 告警或依赖项发现会启动嵌入式会话,然后创建分支,最后生成拉取请求。由人工审核并合并;Celmis 从不合并。从这里修复 · 告警 |
| 拉取请求审核 | Agent 会读取差异,并在图谱涵盖的范围内,了解其他代码仓库中还有谁调用了变更内容。通过 @celmis 与它对话,使用 remember 教会它;没有内容可说时,它会保持安静。审核 |
| 询问代码 | 针对多个代码仓库提问,答案会在调用关系两端提供 file:line 引用。询问代码 |
| 代码库与 MCP | 通过 MCP 提供 51 个工具、供编辑器使用的精简 /mcp/dev 配置、Claude Code 插件,以及团队成员已经口头讲解过的技能版本化知识包。MCP · 知识包 |
| 证据 | 依赖项审计、CycloneDX SBOM,以及第三方可重新计算清单的证据包。SBOM 与证据 |
| 可辩护的访问控制 | 代码仓库默认关闭访问;MCP 令牌按人员发放;每次调用都会记录审计日志;机密信息在源头就会被屏蔽;还可以将代码仓库限时共享给其他工作区。谁能看到什么 · 共享 |
安装
git clone https://github.com/Celmis-labs/Celmis.git celmis && cd celmis
./scripts/init-env.sh # writes .env and fills every secret
docker compose --env-file .env up -d
然后打开 http://localhost,在 Settings → LLM Setup 下粘贴一个模型提供商密钥。
在全新服务器上,从克隆到六项服务正常运行只需 197 秒。内置 Postgres 和 Qdrant;约需 4 GB 内存。详情请见快速开始。 未提供许可证的安装最多允许五人使用;请参阅许可。
v3 新增内容
- 值得留下评论的审查。 低于你的评论级别的问题不会出现在拉取请求中;没有问题可提的审查会直接批准。评论会说明问题、原因和修复方法,并使用仓库所用的语言(3.1)。
- 可以交流的审查者。 可在讨论串中向
@celmis发送命令和问题;设置remember规则;从团队驳回的内容中学习;对每次推送进行增量审查;在总结中检查 Jira 验收标准(2.3)。 - 知识包。 按工作区管理版本化技能、API 示例和检查清单,可在应用中查看,也可供编码助手通过
brief和skills使用;由celmis-pack发布(3.0)。 - 默认关闭访问权限。 未配置规则的仓库不可见;MCP 令牌归个人所有;每次调用都会记录审计日志(2.3.7)。3.0.2 进一步加强了秘密信息隐藏。
- 跨工作区共享。 可用于研究,设定固定期限,并隐藏路径、限制读取者人数(3.1)。
- 面向开发者的 MCP 配置文件和 Claude Code 插件,专为编辑器设计(2.3.7)。
每个版本的内容都记录在变更日志中。
日志,以及职责边界
Celmis 不会监控你的服务;Grafana 或你现有的其他工具会负责这项工作。 应用本身不会采集任何日志,而是从告警开始处理。仓库提供了一个可选的可观测性覆盖层(Prometheus、Loki、Promtail、Grafana),用于采集日志,覆盖整个平台,而不仅是 Celmis:
docker compose -f docker-compose.yml -f docker-compose.observability.yml up -d
所有端口都绑定到 127.0.0.1,并通过 SSH 隧道访问,因为 Loki 没有身份验证。必须设置 GRAFANA_ADMIN_PASSWORD。
这能带来什么,是仅查看差异的工具做不到的
提出一个跨两个仓库的问题,答案会引用两个仓库:

这不是搜索结果。网关和支付服务是两个独立的仓库,没有共享代码;答案会追踪它们之间的调用链,然后还会主动发现,Kafka 主题名称在两边都被硬编码,修改其中一处会悄无声息地导致另一处出错。
只读取差异的审查者在结构上无法做到这一点,因为它从未打开过另一个仓库。
人们用它做的九件事
| 你是产品经理、交付负责人或客户,想了解一组项目的进展,或弄清某件事的实际运作方式 | 直接询问。随时随地、使用任何设备,不必预约工程师,也不必参加一场最终只产出一段文字的会议 → 询问代码 |
| 新工程师提出了一个需要资深工程师解答的问题 | 每个这样的问题都会让有经验的人在已经身兼多职时脱离工作状态。代码库会直接作答,并附上文件:行号引用 → 询问代码 |
| 两个团队共用一项集成,但双方都无法读取对方的代码仓库 | 加载代码仓库,授予提问权限,并拒绝访问必须保密的路径。他们可以得到答案;凭据会在源头被拒绝 → 谁能看到什么 |
| 客户或审计人员要求提供你的 SBOM | 按一个按钮即可生成 CycloneDX,以及一份证据包;他们可以自行重新计算其中的清单,并与发布在证据包之外的哈希值进行核对 → 依赖项、SBOM 和证据包 |
| 某个依赖项出现漏洞 | 从这里修复会将代码仓库、软件包和发现的问题交给嵌入式会话。会话负责修改,运行器推送分支并创建 PR → 从这里修复 |
| 需要审查一个拉取请求 | Agent 会阅读差异;如果已构建依赖图,还会查看其他哪些代码调用了正在修改的内容,包括来自其他代码仓库的调用 → 拉取请求审查 |
| 四十个服务都需要完成同一件事 | 输入一句话。Celmis 会显示匹配到的代码仓库,并等待你再次按下按钮;不用从四十个仓库里逐个寻找,再按四十次按钮 → 跨代码仓库安排工作 |
| 凌晨 02:00 收到警报,而你不在办公桌前 | 警报会出现在 Celmis 中,并发送到工作区的聊天频道;从这里修复会打开一个已载入警报内容的会话。运行器会创建拉取请求 → 警报,以及用手机修复问题 |
| 你自己的 Agent 或编辑器需要了解代码库 | 将其指向 /mcp/。通过同一个索引提供 51 个工具,其中 35 个为只读,并遵循相同的访问规则——无需在任何地方再保存一份代码 → 连接 Claude Code 和其他 MCP 客户端 |
前三件事是代码审查工具完全无法做到的,也是本项目成为平台而非审查工具的原因:只需建立一次索引,就能从工作中的任何一方读取该索引。
三个数字
| 197 秒 | 从 git clone 到六项服务健康运行,在干净的服务器上测得 |
| $0.118 | 每个经审查的拉取请求的成本,按本项目随附模型计算 |
| 50 项中排名第 17 | 在 Martian Code Review Bench 离线测试集上,综合三位评审者的结果 |
最后一个数字刻意不讨喜,我们也会保留它。它衡量的是下文中的某项功能——针对彼此隔离的单代码仓库拉取请求进行审查——而该测试集里没有可供符号使用者所在的关联服务,因此,本产品围绕其构建的核心能力并未体现在这个数字中。结果表、对所有被判定为误报的发现所做的审计,以及可复现这两项结果的命令,都在结果中。
目录
- 功能介绍
- v3 新内容
- 相比仅支持差异的工具,它能为你带来什么
- 人们用它做的九件事
- 三个数字
- 快速入门
- 首位用户和管理员
- 连接代码仓库
- 向代码提问
- 拉取请求审查
- 依赖项、SBOM 和证据包
- 从这里修复
- 告警,以及通过手机修复
- 跨代码仓库请求工作
- 谁能查看哪些内容
- 语言和格式
- 确定性检查——无需模型,不会产生误报
- 连接 Claude Code 和其他 MCP 客户端
- 结果
- 误报审计
- 测试代码仓库
- 配置
- 运维
- 本地开发
- CLI 参考
- 架构
- 故障排除
- 项目布局
- 来源和权利
快速入门
所需条件
| Docker | 24+,带 Compose v2 | macOS/Windows 上的 Docker Desktop,Linux 上的原生引擎 |
| 模型 API 密钥 | 以下任一项 | Google Gemini、Anthropic、OpenAI、OpenRouter、Groq 或 Mistral。免费 Gemini 密钥即可用于评估:https://aistudio.google.com/app/apikey |
| RAM | 约 4 GB 可用 | 在实际索引运行中测得:五个容器合计峰值 1.1 GB,静置时为 565 MB |
Postgres 和 Qdrant 已捆绑——无需配置外部集群。Docker 流程无需安装 Python 或 Node.js。
启动
git clone https://github.com/Celmis-labs/Celmis.git celmis
cd celmis
# Generates .env and fills every secret in the format each one needs.
# Idempotent: run it again after a pull and it fills only the new blanks.
./scripts/init-env.sh
docker compose --env-file .env up -d
# Wait for healthy — first boot pulls three images and applies migrations
docker compose ps
打开 http://localhost。
这里不会构建任何内容。三个镜像会从 CELMIS_REGISTRY 指定的注册表中拉取,
使用 CELMIS_TAG 指定的标签,支持 linux/amd64 和
linux/arm64——Apple Silicon 和 ARM 服务端都会获得原生镜像。
在运行它们的机器上构建镜像时,仅 api 就实测耗时 485 秒,并占用 4.2GB
磁盘空间,因此安装不再意味着编译。
端口是 80,而不是 3000:反向代理会让应用和 API 共用一个源,并通过
/backend 提供 API。这并非部署偏好——浏览器包请求的是相对路径,这是让一个已发布的
镜像能够服务所有安装实例,而不只是构建它的那个实例的唯一方式。
若要在 Celmis 上进行开发,而不是运行它,请添加开发覆盖配置,即可恢复本地 构建:
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build
init-env.sh --check 会报告哪些项目仍为空,但不会写入任何内容。
这是对捕获会话的渲染,不是屏幕录像——其中的数字是该次运行于 2026 年 8 月 26 日产生的结果,Compose
输出则逐字取自安装报告中的 logs/03-up.log。之所以采用绘制而非截图,是因为无法在正在运行的服务栈旁再启动另一个服务栈:docker-compose.yml 固定了
container_name,因此容器名称会冲突。
停止
docker compose down # stop, keep your data
docker compose down -v # stop and DELETE every volume
首位用户与管理员
只要服务栈运行正常,/login 上的注册表单就可以使用。该账户是普通用户——注册不会授予任何管理员权限,即使是第一个注册的人也不例外。
全局管理员权限来自环境变量:使用 .env 中的 CELMIS_MASTER_EMAIL 和 CELMIS_MASTER_KEY(作为密码)登录。运行此系统的人就是管理员,这正是可自托管安装所需的模式,而不是由第一个访问注册表单的人担任管理员。只有同时设置这两个变量时,此登录方式才会生效,每次使用都会记录到审计日志中。
要将普通账户提升为管理员:
docker compose exec api analyzer auth make-admin [email protected]
被提升为管理员的账户(或由 OIDC_ADMIN_ROLE 设为管理员的账户)是全局管理员:可以查看系统状态、运维、合规信息以及所有工作区。但它不是超级管理员——只有主账户才是超级管理员,且只有超级管理员能授予下文所述的高权限角色。
工作区角色
每个工作区都是一个租户,每个人在不同工作区中可以拥有不同角色——在一个工作区担任管理员,在另外两个工作区担任编辑者。
| 角色 | 在该工作区中可以执行的操作 |
|---|---|
viewer | 查看 |
member | 查看;更改审核问题的状态 |
editor | 提示词编辑器:Agent 系统提示词、每个代码仓库的审核策略(提示词模板、文件夹规则、每个 Agent 的提示词覆盖设置)、分析。不能管理成员、邀请、团队、大模型密钥、Git 连接或许可证 |
admin | 拥有编辑者权限,此外还可管理成员和查看者、邀请、团队、大模型密钥、Git 连接 |
owner | 拥有管理员权限,此外还可删除工作区 |
谁可以授予哪些角色:
- owner、admin、editor — 只有超级管理员可以授予、更改为这些角色或从这些角色更改为其他角色,以及移除这些角色。工作区管理员不能将所有者或其他管理员降级。
- member、viewer — 超级管理员,或该工作区的所有者/管理员可以授予(直接授予或通过邀请授予;邀请中只能包含邀请创建者有权授予的角色,且接受邀请时会再次检查)。只有当你与某个现有账户共享工作区时,才能直接将其添加进来;其他人会收到必须接受的邀请。
- 密码重置链接 工作区管理员创建的密码重置链接,其适用范围涵盖该用户所属的所有工作区,而不只是当前工作区。在多租户模式下,每个人都拥有自己的个人工作区,因此实际上只有超级管理员可以创建此类链接。没有任何路由可以为主账户创建链接。
- 共享工作区 由超级管理员创建。每个人注册时都会获得自己的个人工作区,并成为该工作区的所有者。
超级管理员通过 管理 → 用户(/admin/users)跨工作区管理用户;无论在哪个页面进行成员资格变更,都会将操作者、用户、工作区以及变更前后的角色写入审计日志。其中的 无团队访问权限 筛选器会列出仅拥有个人工作区的账户(无论他们通过何种方式登录),并按注册时间从新到旧排序。
获取访问权限:邀请和访问请求
邀请没有账户的人。 邀请一个尚无账户的电子邮件地址,会创建一个与该邮箱绑定、只能使用一次的链接。邀请者可以查看该链接(从团队页面复制);配置 SMTP 后,系统也会通过电子邮件发送该链接。用户退出登录后打开 /invite/<token>,页面会显示工作区、角色和邀请者,并提供登录、注册(AUTH_PASSWORD_LOGIN 允许时)、Google 和公司 SSO(启用时)选项;完成后都会返回该链接以接受邀请。接受邀请时,系统会重新检查邀请者是否仍有权授予该角色、记录审计日志,并使链接失效。链接过期、已撤销或已使用时,页面会说明具体情况。其他账户打开与邮箱绑定的链接时,系统会拒绝访问。
自动接受邀请——仅限已验证的邮箱地址。 用户通过 Google 或公司 SSO 登录,且身份提供商将其邮箱标记为已验证(email_verified)时,系统会在登录时接受发送至该邮箱的待处理邀请,使用相同的接受流程(重新检查授予权限、记录审计日志、仅可使用一次)。密码账户绝不会通过邮箱地址自动接受邀请:Celmis 不会验证注册时填写的邮箱,因此任何人都可以注册他人的邮箱。密码账户需要打开收到的链接并在那里接受邀请;拥有密码且关联了 Google/SSO 的账户也一样,因为设置密码的人仍然可以登录。自动接受流程只会添加成员:如果用户已加入某个工作区,该工作区的邀请会被使用,但不会更改其角色;移除成员时,系统会撤销发送给该成员、针对该工作区的有效邀请。
访问请求。 已登录用户若只有个人工作区,会在仪表板和 /access-request 看到 “你尚未获得任何团队工作区的访问权限——发送请求”,并可填写可选备注(最多 1000 个字符)。同一时间只能有一个待处理请求;用户可以取消请求,被拒绝后也可以重新发送。请求不会指定工作区,在批准之前,请求者也不会看到任何工作区。只有 superadmin 可以通过管理 → 访问请求(/admin/access-requests)作出决定:批准时提供一个或多个(工作区,角色)配对——要么全部应用,要么全部不应用,并为每项成员关系记录审计日志,via="access_request";或者填写拒绝理由,供请求者查看。通过其他方式授予访问权限(用户页面、接受邀请)会将待处理请求标记为已批准。已决定的请求会保留在列表中作为历史记录。请求者可在 /access-request 查看决定,也会在下次访问时收到提示;已批准的工作区无需退出登录便会出现在切换器中。配置 SMTP 后,系统也会通过电子邮件将决定发送给请求者,并将新请求通知主邮箱地址;没有其他通知渠道。
POST /api/access-requests {comment?} | 发送请求(已有待处理请求或账户已拥有团队访问权限时返回 409) |
GET /api/access-requests/me | 查看申请资格和最新请求 |
DELETE /api/access-requests/me | 取消待处理请求 |
GET /api/admin/access-requests?status= | superadmin:列出请求,待处理项优先 |
POST /api/admin/access-requests/{id}/approve {grants:[{workspace_id, role}]} | superadmin:一个或多个,不重复,必须存在且不能是个人工作区 |
POST /api/admin/access-requests/{id}/reject {reason} | superadmin:必须填写理由 |
对已不处于待处理状态的请求作出决定时,会返回 409。
连接代码库
- Settings → LLM Setup — 粘贴提供商密钥。密钥在写入数据库前会使用
CREDENTIAL_MASTER_KEY加密,之后 UI 只会显示首尾各四个字符。 - Connections — 添加 GitHub、GitLab 或 Bitbucket 令牌。请使用机器 账户,而不是你自己的账户:个人令牌可以访问你能看到的所有代码库,而且令牌最终会出现在备份、日志和屏幕截图中。
- Repositories → Add — 从提供商中选择代码库,或粘贴克隆 URL。索引任务会加入队列;任务状态会显示在同一页面上。
索引会从同一次检出中构建两样内容:符号图(定义、调用、导入——审查 Agent 推理所依据的内容)和 Qdrant 中的嵌入向量(问答检索的内容)。一个包含 120k 个符号的代码库在四核机器上大约需要一分钟。
23 种语言可以解析到图中。对于没有解析器的语言,会明确说明,而不是悄悄跳过——analyzer graph-stats 会列出已读取和未读取的内容。
询问代码
在聊天中提问,即可获得基于你指定的任意多个代码库、带有文件:行号引用的回答。回答会边生成边流式显示。
将代码库归入一个项目,即可针对整个代码库组提问:

回答会引用真实代码,而且只引用提问者有权查看的代码——因此可以安全地让代码库所有团队之外的人提问。请参阅谁能看到什么。
Pull request 审查
Agent 会读取差异,并将审查结果发布到 GitHub、GitLab 或 Bitbucket。我们不会在此界面的屏幕截图中展示审查结果,而是将它们保留在发布的位置——在真实项目的 50 个 pull request 中,评论仍附在对应的代码行上。它们列在测试代码库下,其中的输出未经编辑,包括下文审计标记为错误的结果。
构建了图的代码库,其审查结果还会包含差异中看不到的信息:还有哪些位置调用了正在修改的符号,包括来自其他代码库的调用。未构建图的代码库仍会运行审查——只是回答的问题范围更窄,而这正是基准测试衡量的内容。
与审查者交流,以及它会学到什么
完成首次审查后,审查者会在拉取请求中继续工作:
- 评论命令。
@celmis help、start-review、review --force、remember: <rule>,以及可在同一讨论串中获得回答的自由文本问题 (PR 命令)。 - 增量审查与频率控制。 新推送的内容会从上次审查的提交开始审查;仓库可以在短时间内大量推送后暂停自动审查、按关键词跳过标题,并将概述写入描述中 (审查设置)。
- 团队记忆与学习。 团队提出的规则和驳回的发现会影响后续审查,并提供影子模式以便先评估效果 (记忆与学习)。
- 问题待办列表。 系统会在后续推送及合并后持续跟踪发现的问题;当代码表明缺陷已消失时,会自动解决这些问题 (问题待办列表)。
- Jira 任务上下文。 业务逻辑 Agent 会根据拉取请求中指定的任务检查变更,并提供验收标准清单 (Jira)。
- 生产力指标。 根据拉取请求历史记录,为负责人和管理员提供周期时间及四项 DORA 指标 (生产力)。
- 谁能查看哪些内容。 角色与访问权限。所有这些功能都只会为有权读取仓库的人读取仓库,规则与 MCP 相同 (MCP 访问权限);聊天回复和 Jira 检查绝不会引用提问者无权查看的代码。
- 与另一个工作区共享仓库。 可用于研究,可设定固定时限,仅限开发者令牌中注明该仓库的少数人员访问;路径会隐藏,且默认关闭提问功能,除非所有者允许 (共享)。
- 面向编码助手的精简 MCP 配置。
/mcp/dev提供 11 个适用于编辑器的只读工具,包括用于回答“此服务如何进行身份验证”的howto、用于访问工作区自有知识包的brief和skills,以及 Claude Code 插件 (开发者配置,howto)。
基准测试判定为误报的每条发现,都已在源代码中核查并公布了判定结果。79 条中有 33 条最终证实是真实缺陷,而这些缺陷并未包含在金标准集中。相关工作见误报审计,其中列出了每条发现对应的代码和永久链接,你可以对任何一条提出异议。
依赖项、SBOM 和证据包
依赖项审计是确定性的:工具已安装时使用原生审计器,其他情况一律使用 OSV,不涉及模型。如果你提供密钥,大模型会撰写摘要,但不会判断哪些内容存在漏洞。

每次审计都会生成两个文件,二者都不需要 LLM 密钥:
-
SBOM — 一份 CycloneDX 清单,列出每个依赖项、其版本、包 URL,以及已知的相关漏洞。这就是人们说“把 SBOM 发给我们”时所指的文件。
-
证据包 — 作为存档整理的审计记录:每份 SBOM、每项发现、过往运行的时间线,以及每个文件的 sha256。这些哈希可证明存档内部一致;但它们本身不能证明这就是从这里发出的存档,因为清单没有记录自身的哈希,而且任何编辑文件的人都可以改写相应条目。导出时会在
X-Celmis-Manifest-SHA256中返回清单自身的 sha256——把它发布在证据包之外,第三方就可以根据你没有随文件一同交给他们的值进行核验,而无需信任我们。一个内容日后可以更改的文件夹什么也证明不了;让它成为证据的是清单。以前,最后这句话只是一种无法落实的说法:要核验证据包,就得克隆这个仓库,并在 Python 3.13 下安装 40 个依赖项——为了检查产出物,必须安装生产方的整套工具链。现在,核验器已独立打包,不需要依赖项,也不会发起网络请求:
pip install celmis celmis verify evidence-pack.zip任何 Python 3.9 或更高版本都可以离线运行,即使机器从未运行过 Celmis 也可以。它会重新计算清单列出的每个 sha256,并报告清单中列出但文件缺失、哈希不匹配,以及文件存在但未列入清单的情况;无问题时退出码为 0,发现问题时为 1。它只是核验器——平台本身由 docker compose 下的六项服务组成,不能通过 pip 安装;不带参数运行时,该包会明确说明这一点。
此外,还有从代码生成的技术文档——模块 PRD、功能文档和集成指南——这些都由你保存,且即使任何订阅到期后仍可继续使用。
为什么现在要做这件事。 自 2026 年 9 月 11 日起,欧盟《网络弹性法案》要求制造商在 24 小时内向 ENISA 报告遭到主动利用的漏洞。正式的 SBOM 强制要求将于 2027 年 12 月生效,但要回答这项 24 小时要求,首先必须了解组件层面的情况——要报告哪些内容受到影响,就必须知道产品包含什么。
Celmis 不声称能够确保合规,也不会这样做。 它会生成备案所需的材料。备案是否充分,需要由律师判断;暗示并非如此的工具,只是在兜售虚假的安全感。
审计页面还会直言一件事,因为这是一种无人留意的失败情况:从未扫描过的生态系统,报告的漏洞数量为零,和干净的生态系统完全一样。 页面会在发现结果旁显示覆盖情况——每项结果由哪个审计器生成,以及更重要的,哪些内容未经过检查、原因是什么。
从这里修复
发现问题只是一个循环的一半。嵌入式 Claude Code 会话会在安装环境内部运行、编辑检出目录;运行器则会提交更改、推送分支并创建拉取请求。
它运行在你的订阅上、你的机器上
我们不出售密钥,也不捆绑任何模型。你连接自己的 Claude 订阅,就像 Cursor 那样:在自己的笔记本电脑上运行一次 claude setup-token,然后将令牌粘贴到 Settings 中。令牌会加密后存储在凭据库中,之后运行的会话会使用它。
两个槽位,按以下顺序解析:
| 个人 | 你自己的订阅,其他人不可见 |
| 工作区 | 管理员与工作区共享的一个订阅——需明确选择加入 |
除非有人启用,否则工作区槽位默认关闭;保存前,界面会说明原因:**多人共用一个人的订阅可能违反 Anthropic 的消费者条款。**是否这样做由订阅持有人决定,产品不会悄悄替你做这个决定。
而且,会话并不运行在别人的云端。它运行在你自己的安装环境中,每个会话都在独立的工作区内运行。这样做带来的并不是“云访问权限”,而是存放你代码的机器由你掌控;无论你是在办公室用笔记本电脑,还是在火车上用手机,都能访问它,原因和你访问自己运行的任何服务一样:因为它属于你,而且一直在线。
这就是告警,以及用手机修复问题的全部内容——收到告警后,无论你当时在哪里看到它,都可以开始修复。
依赖项审计中的一个漏洞会显示一个从此处修复按钮。它不会打开一个空白聊天,而是直接向会话提供仓库、软件包、两个版本以及任务范围,所有内容都已填写:

下面是这样一个完整的工作流,针对一个真实发现——存在已知漏洞的 lodash 4.17.11。从开始会话到创建打开的拉取请求,220 秒,共五轮:
Read package.json
→ "Only package.json has lodash; no requirements.txt/pyproject/go.mod exist here."
Edit package.json: "lodash": "4.17.11" → "4.18.0"
mcp__exec__run: cat package.json | grep -A2 lodash; ls
→ "Confirmed no other manifest files exist, so no other changes were needed."
它推送的分支以及在 GitHub 上创建的拉取请求:

看看这个差异中没有什么。axios 0.21.1、minimist 1.2.0、node-fetch 2.6.0 就在上下几行——都已过时,都在同一次审计中被标记,但都没有改动。任务要求只修改清单;如果 Agent 顺手再整理另外三个依赖,结果只会更难审核,而不会更好。
这是一个真实的拉取请求,不是截图:
celmis-demo-gateway#6
——分支 celmis-agent/b8960e01,一个提交,+1/-1。

这段记录中有两处细节比差异本身更值得关注。Agent 没有假设不存在其他清单,而是在沙盒中运行命令进行检查。任务要求“仅修改清单,不要改动无关依赖”,因此最终恰好只改了一行。
运行器允许做什么,不允许做什么
这由运行器决定,而不是由提示词决定——在授予 Agent 任何权限之前,值得先了解这一点:
- 没有自己的 Shell。
Bash、WebFetch、WebSearch和笔记本编辑均不允许。命令通过沙箱容器运行;这是一个独立服务,拥有自己的 uid 和只读根文件系统。 - Git 由运行器负责。 Agent 不会提交或推送。工作完成后,或者你按下 Finish & push 时,运行器会创建提交、推送分支并创建 PR。绝不会推送到默认分支。
- 达到提供商限制时会暂停,而不是丢失会话。 上面的运行首次尝试时,在会话中途遇到了每周账户限额。会话并未终止:它转为
paused状态,工作可在十四天内恢复,并显示提供商自己的消息,而不是通用错误。第二个密钥完成了任务。 - 会话可供查看。 输出通过支持重放的 SSE 流式传输,因此重新连接后会从中断处继续,而不是显示空白。
连接使用设置令牌,按用户或工作区保存。保存后,API 不会再返回令牌本身,只会告知令牌是否存在以及是否仍然有效。
告警,以及通过手机修复问题
上述流程从依赖项发现开始,也可以从生产环境开始。
将任何监控系统指向工作区的接收 URL,告警就会进入 Celmis:
POST /webhook/alerts/{workspace_id}.{secret}
Grafana 的统一告警 Webhook 会按原样解析;其他任何内容都可以发送 {"title", "body", "severity", "repo"}。密钥部分会按工作区使用 Fernet 加密存储,并以恒定时间进行比较。此端点按设计无需身份验证——监控系统无法使用 OAuth;而且在结构上与租户绑定:令牌只能写入其所属的工作区。
这样就能实现不需要笔记本电脑的处理流程:
- 告警触发。它到达 Celmis 后,会直接发送到工作区绑定的任意渠道——Slack、Discord、Google Chat 或普通 Webhook——因此会在你本来就会查看的地方找到你,而不是出现在一个你必须记得打开的页面上。
- 你打开告警。告警会附带其代码仓库,因为
route_incident可以接收堆栈跟踪,并指出它所属的代码仓库和负责人。 - 你按下 Fix from here。会话打开时已载入告警,而不是空白聊天。
- 运行器创建提交、推送分支并创建拉取请求。

这四个步骤都不需要检出代码、使用终端,也不需要一台你信任的机器。工作在你自己的安装中进行;手机只是用来查看的屏幕。
同一页面会列出工作区收到的所有告警,因此无人处理的告警也会清晰可见,不会淹没在某个渠道中。
此过程中记录的内容。 会生成两种不同的记录,它们回答不同的问题:
- 审计记录 — 仅追加的 JSONL 文件,按大小轮换,可按时间、模式、操作和代码仓库筛选,并可导出为 CSV。它回答的是谁在何时对哪个代码仓库做了什么。默认保留 90 天,当前文件绝不会删除,只会轮换归档文件。
- 资源历史记录 — 对安装本身进行采样和汇总,可导出为 CSV,用于制定容量规划表。它回答的是运行这项服务花费了多少资源。
凌晨两点,有人通过手机启动 Agent 会话并修改代码仓库——这正是事后必须能够还原的事件类型。此处可以做到。
跨仓库请求工作
上面每个入口一次只处理一件事:这个仓库、这个拉取请求、这个发现。这适合作为按钮的操作方式,却不适合处理按条件定义的一组对象。
为每个没有文档的服务生成文档是一句话。通过界面操作,就得从 40 个服务中找出符合条件的服务,再按 40 次按钮。审计 acme-ai 下所有 30 天内未审计的内容需要筛选器、已保存的选择和批量操作——也就是一个子系统——或者只需一句话。
因此,我们提供了一个输入句子的文本框,以及一份刻意精简的动词目录。处理单个对象的工作仍由按钮完成,各得其所。
第一次按下按钮时不会启动任何操作。 对意图的理解只是猜测,而这些动词会消耗金钱和时间——构建知识库、调度一组审查 Agent、审计一组仓库。因此,对一句话的响应不是直接开始工作,而是列出这句话匹配到的仓库,并在列表下方提供第二个按钮。你确认的是范围,而不是意图。
范围会在你确认时重新检查,而不是在你提出请求时检查。 如果某个仓库在你提问后的几秒内注册,它就不能悄悄加入一个声称涵盖“所有内容”的集合。整个产品遵循同一条规则——在工作实际发生的地方进行检查——此处也不例外。
自动化调用方永远无法将无界的扇出任务加入队列。 动词数量有限、限定在工作区范围内,并且要求显式指定操作者:这里的任何操作都不会读取隐式请求上下文,因为处理队列的连接器没有请求上下文,而猜测工作区的函数会让一个租户的自动化操作触及另一个租户的仓库。
目前有三个调用方正汇聚到这些相同的动词上——通过 MCP 接入的外部 Agent、嵌入式 Agent,以及将审计这四个服务转化为工作并回传结果的工单连接器。它们有意共享同一套实现:第二套“启动审计”逻辑,就意味着第二套关于正在运行的任务、去重和强制重启的规则,而无人维护的那套代码最终会破坏队列。
谁能看到什么
访问权限按仓库和团队解析,并且会同时应用于所有入口——问答、图谱、代码搜索、生成的文档和 MCP:
| 设置 | 效果 |
|---|---|
visibility: none | 该仓库不会出现在研究范围内 |
visibility: metadata | 仅限文档和架构说明 |
visibility: code | 可以读取源代码 |
deny_globs | 即使设置为 code 也优先生效——凭据、加密、数据库连接、密钥验证 |
allow_globs | 设置后即为允许列表;拒绝规则仍会从中排除路径 |
这正是相邻团队协作场景能够真正实现,而不只是承诺的原因:加载仓库,授予另一个团队提问的权限,并拒绝读取不得访问的路径。他们可以获得答案;这些文件会在源头被拒绝读取,而不是从已包含这些内容的响应中过滤掉。
语言和格式
17 个图谱模块,另有一条通用路径,通过 tree-sitter 标签查询支持尚无专用模块的语言:
代码——Python、TypeScript、JavaScript、Go、Java、C#、C++、PHP、Vue 等均可通过通用路径支持。
基础设施——Dockerfile、docker-compose、Helm、Kubernetes 清单、Terraform 和 CI 工作流。这是大多数代码智能工具会忽略的部分,也正因如此,提问才能从某个函数延伸到运行该函数的服务定义。
确定性检查——不使用模型,不产生误报
以下每项检查都通过读取文件来判定。没有任何大模型参与判断问题所在,因此误报率从原理上来说就是零,而非通过调优得到。
这一点正是关键所在。误报率达到约 20% 时,开发者就会完全不再看工具的评论——一次误报会耗费几秒注意力,一千次误报就会让整个团队学会跳过工具说的一切。这里使用大模型来解释和确定优先级,而不是检测。
| 检查 | 读取内容 | 捕获的问题 |
|---|---|---|
install_script | package.json 生命周期钩子 | 安装时运行代码的依赖 |
python_build_hooks | pyproject.toml / setup.py | Python 包在构建时执行代码 |
cargo_build_script | Cargo.toml | 带有 build.rs 的 crate |
non_registry | 清单和锁定文件 | 从 git URL 或 tarball 拉取,而非从注册表获取的依赖 |
suspect_name | 依赖列表 | 仿冒包——与热门包名称仅差一个字符 |
lock_drift | 清单与锁定文件 | 不再与清单声明相符的锁定文件 |
cross_repo_drift | PR 差异,然后是同级仓库 | 在一个仓库中更改、却未同步到其他仓库的常量 |
普通的 CVE 扫描有意不在此列表中。OSV-Scanner 已能完成这项工作,而且它免费,也是事实上的标准——Celmis 会运行它(以及各生态系统自己的审计工具:pip-audit、npm audit、govulncheck、cargo audit),并将结果作为输入,而非功能。
关于合规。 Celmis 会生成审计所需的材料——CycloneDX SBOM、依赖清单、带时间戳的发现历史记录,以及每项发现所依据的证据。它不会声称你的申报符合要求,坦白说,没有任何工具能做到这一点:审计人员接受什么,取决于你的行业、司法管辖区和自身控制措施。生成材料;由负责评估的人来审核。
连接 Claude Code 和其他 MCP 客户端
Celmis 通过 MCP 提供其索引,因此 Agent 无需检索自己无法访问的代码库,就能搜索符号、读取 API 接口并查找使用方。
通过 HTTP(运行中的服务栈通过 /mcp/ 提供服务):
# A token is per person and names the repositories it may read. The
# superadmin issues it (Administration, MCP tokens) or on the server:
docker compose exec api analyzer mcp issue-token \
--user [email protected] --workspace acme --repos 'acme/shop-*' --days 30
令牌永远不会触达持有者无权读取的代码库,且每次调用都会经过审计。对于没有任何成员访问规则的代码库,成员无法访问。关于访问权限、令牌和审计的工作方式,请参阅 MCP 访问。
// ~/.claude.json (or .mcp.json in a project)
{
"mcpServers": {
"celmis": {
"type": "http",
"url": "http://localhost:8000/mcp/",
"headers": { "Authorization": "Bearer <the token you just minted>" }
}
}
}
供外部客户端访问单个项目。 超级管理员可以在项目页面创建项目令牌(cmcp_...,有效期为 1 小时至 90 天,仅显示一次,可撤销)。该令牌只能访问此项目的代码库,并受项目文件范围限制,可通过两个工具 search_project 和 ask_project 访问。详情和 claude mcp add 命令见归档和项目令牌。
通过 stdio,无需经过 HTTP:
{
"mcpServers": {
"celmis": {
"command": "docker",
"args": ["compose", "exec", "-T", "api", "analyzer", "mcp", "serve"]
}
}
}
Agent 可以询问什么
HTTP 挂载提供 51 个工具,客户端不一定能看到所有工具。其中 35 个为只读;另外 16 个会写入——add_repo、
start_dep_audit、cancel_dep_audit、generate_docs、set_auto_review、
migrate_consumers、ack_alert、retry_job、cancel_job、set_budget、
update_review_setting、propose_review_rules、generate_review_rules、
review_pr、index_repo、update_issue——
需要写入作用域(write:repos、write:config、write:reviews),而默认令牌不包含这些作用域,因此它们不会出现在只读客户端的工具列表中,按名称调用时也会被拒绝。只读工具可以回答以下问题,而这些问题是 grep 无法回答的:
list_workspace_repos | 有哪些代码仓库、哪些已建立索引、哪些已有文档、哪些已开启自动审查 |
search_symbols | 某个函数或端点在整个项目中的定义位置 |
find_consumers | 哪些代码仓库调用了某个符号——包括你从未克隆过的代码仓库 |
get_api_surface | 某项服务实际公开了哪些 HTTP 处理程序 |
get_owner · list_deprecations | 谁负责某个文件;哪些内容即将弃用,以及谁仍在使用它们 |
route_incident | 给定堆栈跟踪后,它属于哪个代码仓库、由谁负责 |
bootstrap_client · start_integration_walk | 客户端需要什么才能调用其他团队的服务 |
get_dep_audit · list_dep_findings | 上次审计及其发现,按严重程度从高到低排列 |
get_review · get_review_policy | 某个 PR 的最新审查,以及哪些 Agent 会在何处运行 |
list_reviews · get_review_run | 最新的审查运行记录,以及某次运行的发现(通过运行 ID,或代码仓库 + PR 编号查询) |
list_issues | 已跟踪的审查问题,按严重程度从高到低排列,并按状态统计数量 |
ask_code · search_code | 关于代码的文字回答(一次模型调用,计入问答);可查询符号、用法、负责人和架构 |
HTTP 挂载还可通过 review_pr(将一个 PR 或所有开放的 PR 加入审查队列)、index_repo 和 update_issue(设置问题状态)进行写入;这些操作都需要 write:repos。
| get_review_settings | 当前生效的审查设置,以及每个值的来源 |
| get_spend · get_usage · get_budget | 按模型、接口和日期统计的大模型开支;审查用量;每月上限 |
| list_alerts · list_jobs | 收到的警报;后台作业及按状态统计的数量 |
| audit_delta · export_sbom | 与上次审计相比的变更;SBOM 下载 URL |
| list_members | 工作区成员及其角色和团队 |
| howto | 某个代码仓库如何完成一项操作(db、auth、config、http_client、logging、messaging、cache):代码片段、它读取的环境变量和设置名称,以及这些值的来源,但绝不提供实际值;在 /mcp/ 上需要 read:graph,在 /mcp/dev/ 上需要 read:code |
两种传输方式提供的工具集并不相同。 通过标准输入/输出运行 analyzer mcp serve 会提供 13 个较早的、以图为核心的工具(find_symbol、find_callers、
query_graph);HTTP 挂载则提供 35 个只读工具(包括两个项目令牌工具 search_project 和 ask_project)。两者互不包含——请根据需要的工具选择传输方式。
.claude/skills/celmis-mcp/SKILL.md 中提供了分步指南,说明各工具所需的作用域和可能的故障情况。
当此代码仓库处于打开状态时,Claude Code 会自动加载该指南。
Agent 可以请求什么
一次 search_symbols 调用、一个契约符号,结果来自两个使用不同语言的代码库——而客户端一个都没有检出。差异对比永远无法跨越的边界,在这里成了寻常之事。
下表列出了 stdio 服务的图形工具集(analyzer mcp serve,共 13 个工具)。/mcp/ 上的 HTTP 挂载总共提供 51 个工具(35 个读取、16 个写入),通过 Streamable HTTP 提供服务,采用与 /api/ 相同的身份验证方式,并且令牌只能访问其作用域允许的工具。图查询工具:
| 工具 | 回答的问题 |
|---|---|
list_repos | 索引了哪些代码库,以及每个索引有多新 |
list_groups | 哪些代码库归为一组,以便为跨代码库问题设定范围 |
find_symbol | 某个名称在哪里定义,涵盖所有已索引的代码库 |
get_symbol | 定义本身,以及其文件和行范围 |
find_callers | 什么在调用此项——这是 grep 很难回答、而图能精准回答的问题 |
find_callees | 此项调用了什么,向外查找一跳 |
cross_repo_edges | 跨越代码库边界的调用 |
query_graph | 只读 Cypher,用于回答上述七个工具未涵盖的问题 |
cross_repo_edges 值得重点了解,因为它正是本产品构建符号图的原因。仅查看差异的审查工具——包括上方基准测试表中的所有工具,以及图为空时的这个工具——都能告诉你函数签名发生了变化。但它们无法告诉你,另一个代码库中的服务仍在调用旧接口,因为它们从未打开过那个代码库。只需将代码库分组一次,这个问题便可以得到解答:
> which services outside this repo call PaymentGateway.charge?
这也正是我们的基准排名低估了产品能力,而非如实反映它的原因:基准测试集采用彼此隔离的单代码库拉取请求,因此没有可供边跨越的关联代码库。这项能力确实存在,而基准测试看不到它——这说的是基准测试的局限,并非要求你盲信的说法。让 MCP 客户端连接到你自己的分组并亲自验证。
结果
Celmis 在 Martian Code Review Bench
离线集上运行:其中包含 50 个精选拉取请求和 173 条人工编写的黄金评论,由 LLM 评审员对照黄金集进行评分。使用 gemini-3.6-flash,温度为 0.1,不启用推理 token,在 e0db376 上测得。
| 评审员 | F1 | 精确率 | 召回率 | 排名 |
|---|---|---|---|---|
| claude-opus-4.5 | 47.5% | 52.4% | 43.4% | 17 / 50 |
| claude-sonnet-4.5 | 44.9% | 48.0% | 42.2% | 17 / 50 |
| gpt-5.2 | 42.7% | 46.0% | 39.9% | 17 / 50 |
F1 会因评审员不同而相差 4.8 个百分点。排名则完全不变——三位评审员给出的排名都是第 17。
整轮运行费用为 $5.88——每个拉取请求 $0.118——共生成 153 条发现,每个 PR 3.06 条(缺陷 114 条、安全问题 27 条、契约问题 6 条、结构问题 6 条)。
为什么这个比较公平。 Martian 在基准测试仓库中公布了对 49 个工具的评估,使用相同的三位评审员,对照相同的黄金评论评审相同的 50 个 PR。我们没有重新评分任何工具:其他工具的数据行均照原样采用,并在末尾附上我们的数据行。使用以下命令即可复现整张表:
python3 autoloop/offline_table.py anthropic_claude-sonnet-4-5-20250929
离线榜单并非公开排行榜。 Martian 运行两种基准测试。公开排行榜采用的是在线测试——根据开发者实际修复的内容,对 200,000 个真实拉取请求评分。这张表采用的是离线测试——针对 50 个精选 PR,以黄金集为依据评分。两者衡量的内容不同,数据不可互换。诸如“工具 X 在 Martian 上排名第一”的说法,通常指的是在线排行榜、不同的指标,或不同的评审员。
这项数据不包含什么。 在全部 50 个 PR 中,图谱均为空(每个 PR 的 graph_status 均为 null,drift 也为空),因为基准测试集由彼此隔离的单仓库拉取请求组成——没有可供某个符号拥有消费者的关联服务。跨仓库漂移,也就是本产品借助符号图谱处理的问题,对上述分数的贡献恰好为零。这项能力无法在此衡量,我们也不会依据这张表宣称其效果。要观看它如何处理真实代码,请参阅测试仓库。
误报审计
基准测试评分存在结构性上限:评审员会将我们的评论与一份有限的人工编写黄金评论列表进行匹配,因此,标注者没有写下来的正确发现,必然会被判为错误。我们在测量所用的提交中检查了全部 79 条发现,并逐一给出判定。
在被评分为误报的 79 条发现中,33 条是真实缺陷,但不在黄金集中;38 条确实有误;另有 8 条无法根据代码得出结论。因此,这轮运行的真实精确率介于 69.7% 至 75.0% 之间,而非测得的 48.0%——但这个修正后的数字不能与上表中的任何数字比较,因为我们没有以相同方式审计其他工具,而且它们的误报中很可能也有相近比例的真实缺陷;若要与其他工具比较,测得的 48.0% 才是诚实的数字,因为它是对所有工具采用相同方法得出的。
38 条确实有误的发现中,有 24 条源自四个共同原因,而且没有一个原因是“模型能力不足”——这四个原因都与模型看到的内容有关。最常见的情况是:标识符在同一文件中声明,但位于 Agent 收到的代码片段之外,例如上移 26 行的方法参数、位于第 3 行的导入语句,以及位于第 18 行的 attr_reader。
完整报告 列出了每条发现的主张、该提交中的代码、判定、理由和永久链接,方便你依据同一组证据对任意判定提出异议。
测试仓库
上文运行中的所有审查仍然在线且公开。它们是真实项目中的真实拉取请求,连同历史记录一起分叉,并包含 Celmis 写下的行内评论:
| Fork | PR |
|---|---|
| celmis-bench/keycloak | 9 |
| celmis-bench/grafana | 10 |
| celmis-bench/discourse-graphite | 10 |
| celmis-bench/cal.diy | 10 |
| celmis-bench/sentry | 6 |
| celmis-bench/sentry-greptile | 4 |
建议先查看:
- keycloak#17 — Keycloak 测试存储提供程序中的空值解引用,以及恢复代码索引问题
- grafana#16 — 针对 Legacy 指标记录的 Storage 故障;该文件中同一错误共有三处
- cal.diy#11 — 使用带异步回调的
forEach,因此删除操作会即发即弃,外围的try什么也捕获不到 - sentry#11 — 针对一个 Kafka 消费者 PR 的七条行内评论
你看到的是未经编辑的输出,包括上文审计判定为错误的发现。评分后没有删除任何内容。
配置
./scripts/init-env.sh 会根据 .env.example 写入 .env,并生成所有密钥。示例文件有意将每个密钥留空:之前的版本把生成命令放在变量旁边,但 dotenv 文件不支持行内注释,结果每个复制该文件的安装都使用了一个打印在仓库中的主密码。
设置只有通过 docker-compose.yml 中的 environment: 区块才能传入容器——镜像中不包含 .env。未在此处命名的变量,无论 .env 中写了什么,都会采用代码默认值。
GET /healthz 会报告进程实际解析出的审查时限,这可以用来检查哪些设置已生效。
.env.example 中集中记录了这些时限,并注明了它们必须满足的不变量:
REVIEW_LLM_TIMEOUT_SECONDS × (1 + RETRY_FACTOR) ≤ REVIEW_TIMEOUT_SECONDS
提高其中一个时,另一个也必须随之提高;有测试会对此进行验证。
| 变量 | 默认值 | |
|---|---|---|
REVIEW_TIMEOUT_SECONDS | 900 | 单次审查的实际运行时限;超时后,后续阶段会停止,并在评论中说明 |
REVIEW_LLM_TIMEOUT_SECONDS | 300 | 单次模型调用的时限。对于推理较慢的模型,可提高到约 600 |
REVIEW_LLM_TIMEOUT_RETRY_FACTOR | 2.0 | 超时后重试时限的延长倍数;设为 1.0 可禁用延长 |
REVIEW_MAX_DIFF_SIZE_BYTES | 500000 | 超过此大小的差异会被拒绝,而非截断 |
REVIEW_VERIFIER_ENABLED | false | 用于否决 LLM 误报的功能 |
REVIEW_VERIFIER_MIN_FINDINGS | 1 | 启用否决功能后,触发它所需的最少非确证发现数 |
REVIEW_AGENT_CONCURRENCY | 3 | 每次审查中同时进行的提供商调用数 |
CELMIS_JOB_LEASE_SECONDS | 600 | 工作任务可能被重新领取前,工作进程允许无响应的最长时间 |
CELMIS_DEPLOYMENT_MODE | single_tenant | multi_tenant 会隔离各个工作区 |
运维
docker compose logs -f api # follow the API
docker compose exec api analyzer graph-stats <repo> # what parsed, what did not
./scripts/backup.sh # Postgres + volumes
./scripts/restore.sh <archive>
Admin → Monitoring 会显示队列深度、各工作区的支出,以及每个 Agent 的模型设置。Usage & cost 会按使用场景细分支出,因此批量文档构建不会被统计为聊天。
在服务器上运行 ./scripts/deploy-on-server.sh v0.1.0 即可部署:它会拉取已发布的镜像,在 Caddy 后启动整个服务栈,并标记 AGPL 页脚链接指向的构建版本。该机器之外无需提供凭据。请参阅
docs/ORACLE_CICD.md,或查看适用于普通 VM 的
docs/HETZNER.md。
本地开发
# Postgres and Qdrant from compose, everything else on the host
docker compose up -d postgres qdrant
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
alembic upgrade head
uvicorn src.api.main:app --reload --port 8000
cd web && npm install && npm run dev # http://localhost:3000
pytest -q # the suite
ruff check . # lint, ratcheted at zero
cd web && npx tsc --noEmit
CLI 参考
analyzer 通过 pip install -e . 安装;在 Docker 中使用
docker compose exec api analyzer …。每条命令都支持 --help。
analyzer init | 创建工作区布局 |
analyzer index <path|url> | 将代码库解析到图中 |
analyzer ask "<question>" | 提出一个问题,获取带引用的回答 |
analyzer chat | 交互式会话 |
analyzer review <provider> <repo> <pr> | 审查拉取请求;--post 会发布审查结果 |
analyzer generate | 构建文档库 |
analyzer refresh | 重新索引发生变更的内容 |
analyzer graph-stats <repo> | 查看各语言的解析情况 |
analyzer serve | 不使用 Docker 运行 API |
analyzer review-serve | 单独运行 Webhook 接收器 |
分组子命令:analyzer repo、analyzer group、analyzer auth、
analyzer mcp、analyzer scip。
架构
┌──────────────┐
GitHub / GitLab ──▶│ webhook │──┐
Bitbucket └──────────────┘ │
▼
Browser ──▶ web (Next.js) ──▶ api (FastAPI) ──▶ Postgres jobs, policies, audit
│ Qdrant embeddings
│ sandbox untrusted execution
▼
model provider
(direct, or via a LiteLLM gateway)
- Postgres 保存作业、策略、运行历史、支出和审计日志。持久化作业队列由一个表构成——出队操作使用
SELECT … FOR UPDATE SKIP LOCKED, 工作器会在工作期间续租,而不是预先猜测一个时长。 - Qdrant 保存嵌入向量,每个安装使用一个集合,并通过筛选器强制隔离工作区。
- sandbox 会以独立的用户 ID 和网络运行任何不受信任的操作——例如测试套件或构建,且不提供数据库、密钥,根文件系统也为只读。
- LiteLLM 为可选组件。一起设置
LITELLM_PROXY_URL和LITELLM_MASTER_KEY, 所有调用都会通过网关路由;任一项留空,则直接使用提供商密钥。
故障排除
容器无法启动。 使用 docker compose logs <service>。API 会在启动时说明哪些可选功能不可用及其原因,而不是悄无声息地失败。
审查没有任何结果。 检查 GET /healthz,查看解析后的时钟,然后运行
docker compose logs api | grep agent_。每个 Agent 都会记录耗时、使用的模型和故障代码。
只是超时,并非服务中断。 local_timeout 表示此安装自身的截止时间先于提供商响应而到期——请调高
REVIEW_LLM_TIMEOUT_SECONDS。此情况不会被报告为提供商故障,这是有意为之。
问答没有引用。 代码库可能尚未建立索引,或建立索引时没有生成嵌入向量。代码库页面会显示每个代码库的状态;analyzer graph-stats <repo> 会显示解析情况。
沙箱一直处于忙碌状态。 SANDBOX_SLOTS 表示可同时运行的作业数,也是影响内存消耗的调节项。SANDBOX_SLOT_WAIT 表示调用方在收到稍后重试的提示前排队等待的时长。
项目布局
src/
api/ FastAPI app, routers, schemas
review/ PR review — agents, orchestrator, providers, policies
indexing/ parsers, symbol graph, embeddings
qa/ retrieval and answer composition
generation/ documentation vault
llm/ provider clients, error taxonomy, cost ledger
sync/ git providers, the durable job queue, workers
sandbox/ the isolated execution server
mcp_server/ the MCP surface
security/ redaction, patterns, log filtering
web/ Next.js UI (App Router, 16 locales)
tests/ 5200+ tests
deploy/ Caddy overlay and the LiteLLM gateway config
docs/ deploy guides and the end-to-end walk-through
bench/ benchmark harness and results
来源与权利
此仓库只有一个根提交,包含约十万行代码——对于来源不明的代码包,来源扫描器会将其视为这种情况,而这需要解释,不能一笔带过。这里提供了解释: PROVENANCE.md 说明了许可立场和代码来源——开发工作在此提交之前以私有方式完成,而这些信息无助于构建、审计或分叉此处的内容。
该文件记录的是事实,而非许可证。许可证是
AGPL-3.0,但有一项例外:ee/ 下的所有内容,以及文件名包含 .ee. 的任何文件,均改由 LICENSE_EE 许可。
LICENSING.md 完整说明了这一界限——LICENSE 本身是未经修改的 AGPL 正文,因为在许可证正文前加上序言的文件不会被视为该许可证。
目前有三项企业功能受此界限保护——单点登录(OIDC /
Keycloak)、评审分析,以及创建仓库共享(共享的其余部分采用 AGPL 许可),位于 src/ee/ 和 web/ee/ 中,并通过离线许可证密钥启用(参见 ee/README.md)。这一界限在第一个标签创建之前就已划定,因为事后再添加,就意味着要重新征求每一位已在不附加限制的 AGPL 许可下提交代码的贡献者的同意。
此处发布的其他所有内容均采用 AGPL 许可,包括看起来偏商业化的部分:审计控制台、使用量与支出、合规性检查、安装指标。 安全控制绝不会只面向企业版——审计日志采用 AGPL 许可,并且将始终如此。新代码应放在何处,请参阅 CONTRIBUTING.md。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。