关于 Glasir
Glasir 为工程工具和编码 Agent 构建本地、可查询的代码库图谱,记录定义、引用、依赖和变更影响。其确定性 MCP 工具提供有证据支撑的结构化答案,索引和查询过程均不使用模型或网络。
主要功能
- 01构建代码关系图谱
- 02追踪调用方和符号路径
- 03评估变更影响与风险
- 04将差异映射到受影响定义
- 05通过监视模式保持图谱更新
- 06导出并浏览代码库图谱
适用场景
- 01修改符号前查找调用方
- 02识别依赖代码和潜在影响
- 03为未提交的变更选择测试
- 04追踪请求如何到达某个组件
MCP 相关
Glasir 通过 stdio 或 Streamable HTTP 提供十五种 MCP 工具,包括图查询、影响分析、符号路径和代码片段。安装程序会将服务注册到检测到的编码助手,并保持代码库图谱更新。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm ghcr.io/attackwave/glasir:v0.13.2本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/attackwave/glasir:v0.13.2stdio工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Glasir
为代码仓库提供确定性的代码智能。 Glasir 在本地构建可查询的定义、 引用、依赖关系和变更影响图谱,然后通过 MCP 提供有界证据。它能为工程工具提供结构化答案,而不是未经筛选的文件转储: 是什么调用了它、它变更后会影响什么,以及两个符号如何关联。
Glasir 是一棵长着金叶、矗立在 Valhalla 前的树,是“众神与世人中最美的”—— 一棵从地面就能看清每根枝条的树。
一个 Rust 二进制文件。不需要 Python、Node、数据库或 GPU,而且索引或查询 流程中完全不涉及模型——同一棵树和同一个问题,始终会得到相同的答案。
生产部署将 Core 与 Glasir Control 配套使用,以实现租户策略、 mTLS 边界、经审计的管理、跨仓库审查,以及提供方的拉取请求检查。
快速入门
使用你已经在用的包管理器安装:
brew install attackwave/glasir/glasir # macOS, Linux
scoop bucket add glasir https://github.com/Attackwave/scoop-glasir
scoop install glasir # Windows
或者从 Releases 下载适用于你平台的
归档文件,通过旁边的 .sha256 文件或构建来源证明进行校验(gh attestation verify <archive> --repo Attackwave/glasir),并将 glasir 放到你的 PATH 中:
| 平台 | 归档文件 |
|---|---|
| Linux x86_64 | glasir-<version>-linux-x86_64.tar.gz |
| Linux ARM64 | glasir-<version>-linux-arm64.tar.gz |
| macOS Apple Silicon | glasir-<version>-macos-arm64.tar.gz |
| macOS Intel | glasir-<version>-macos-x86_64.tar.gz |
| Windows x86_64 | glasir-<version>-windows-x86_64.zip |
Linux 二进制文件采用静态链接,可在任何发行版上运行,包括 Alpine 和较旧的企业版发行版。
在 macOS 上手动下载的二进制文件尚未经过公证,因此 macOS 会阻止它首次启动;
检查校验和后,运行一次 xattr -d com.apple.quarantine glasir 清除标记。
Homebrew 安装不受影响。
读取 MCP registry 的客户端会将 Glasir
列为 io.github.Attackwave/glasir;该条目会运行容器镜像,并以只读方式挂载仓库。
接下来,在你想要查询的仓库中:
glasir install .
这会查找你机器上已安装的编码助手——通过它们在 PATH 中的程序、主目录中的设置,
或项目中的文件——并在项目自己的配置中为每个助手注册 Glasir:
| 助手 | 文件 |
|---|---|
| Claude Code | .mcp.json |
| Codex | .codex/config.toml |
| Gemini CLI | .gemini/settings.json |
| Qwen Code | .qwen/settings.json |
| Antigravity | .agents/mcp_config.json |
| Cursor | .cursor/mcp.json |
| VS Code (Copilot) | .vscode/mcp.json |
| OpenCode | opencode.json |
它注册的服务以 --watch 运行,因此助手运行期间,图谱会随你的编辑实时更新。它还会安装 Git 钩子,确保每次拉取、检出或变基后图谱都保持最新。对于 Claude Code,它会在 .claude/settings.local.json 中添加一个 SessionStart 钩子:在已分析的代码树中,会话启动时会提示加载图谱工具,因为 Claude Code 会延迟加载 MCP 工具,而尚未加载这些工具的助手会改为搜索文本。--no-hook 会跳过这两类钩子。它创建的注册文件包含你机器上的绝对路径,因此会添加到 .gitignore;如果团队已跟踪某个注册文件,则会合并到该文件中,而不会替换它,也不会改动你主目录中的任何内容。如果未检测到助手,它会写入一个通用的 glasir-mcp.json,供任何 MCP 客户端使用。--platform <name> 可显式指定平台。 |
同一棵代码树上的多个助手共用一个服务。客户端启动的是一个通往该代码树后端的小型中继;如果后端尚未运行,中继会将其启动:一张图谱、一个监视器,不论打开多少个助手都一样。最后一个客户端关闭一分钟后,后端会结束;有客户端重新连接时,它会再次启动。十分钟没有请求后,它会释放图谱并停止监视;下一个请求会重新加载图谱(--sleep-after <minutes>,设为 0 则保持运行)。客户端忘记关闭的中继只会占用几 MB 内存,不会占用 CPU。glasir servers 会列出正在运行的服务;--stop-replaced 会结束被客户端替换但未关闭的服务。在 Windows 上,每个客户端都会保留自己的服务。
大多数助手在启动新服务前都会征求许可:Claude Code 和 Qwen Code 需要先批准该服务;Codex 和 Gemini CLI 只会读取你已信任的文件夹中的项目设置;Antigravity 则会在首次使用 MCP 工具前征求许可。install 会输出针对每个已写入配置的助手所需的操作步骤。
在 Claude Code 中,只要将 glasir 放入 PATH,插件就能以相同方式工作,无需为每个代码库单独执行操作:
/plugin marketplace add Attackwave/glasir
/plugin install glasir@glasir
它会为会话启动时所在的 Git 代码库提供服务,不会在其他位置启动任何服务。它生成的文件会写入 .git/info/exclude,因此不会更改任何受跟踪文件。请在一棵代码树中使用插件或 glasir install,不要同时使用:两者各自会带有一份独立的服务副本。
重启助手,然后询问它一些有关代码的问题,例如:“如果我更改 parse_config,会影响什么?”、“请求如何到达数据库?”。答案来自 impact、query_graph、shortest_path 以及更多工具,详见服务内容。
glasir status . # what is registered, what the graph holds
glasir why "your question" # what the search saw, when an answer surprises you
glasir view . # the graph as a map in the browser, one region per subsystem
glasir review # the uncommitted change as a Markdown review: risk, dependents, tests
glasir export . > graph.json # the graph as node-link JSON, for another tool
glasir servers # running servers; --stop-replaced ends those a client replaced
glasir uninstall . # remove the registration and the hooks
索引范围
索引所有未被各级目录中的 .gitignore 文件排除的内容,但不包括构建产物和依赖项(target、node_modules、点目录)。
同级的 .glasirignore 使用相同语法,并且优先级更高,因此既可以排除更多内容,也可以重新纳入 Git 忽略的内容:
# .glasirignore
!plan.md # untracked, but worth asking about
!/reference/ # git ignores the whole directory ...
/reference/scans/ # ... of which only this part stays out
如果目录树中包含自身的副本,例如合并后的头文件或供应商快照,那么每个名称都会有两个定义,对有歧义的名称的调用不会建立链接。
overview 会列出此类目录;请在此处排除副本。
与 Git 一样,被忽略目录中的文件只有在目录本身重新纳入后才会重新纳入(如上面的 !/reference/)。
只有目录树中的忽略文件会生效——全局排除文件和 .git/info/exclude 均不生效——因此,无论各个开发者在本地忽略了什么,同一个提交在每台机器上都会生成相同的图。
默认不纳入面向编码助手的指令文件(AGENTS.md、CLAUDE.md、GEMINI.md 及其 .local.md 变体、COPILOT.md、OPENAI.md、CHATGPT.md)以及 CONTRIBUTING.md、CHANGELOG.md、CODE_OF_CONDUCT.md:这些文件使用提问时所用的语言描述如何处理代码,其优先级高于它们所描述的代码。希望纳入其中某个文件的项目,可以在 .glasirignore 中指定,例如 !AGENTS.md。对任一文件的更改会在下一次分析时生效;启用 --watch 时则会立即生效。
在 .github 中,工作流、本地操作和 scripts/ 都会被索引,尽管它是点目录:工作流的作业是符号,needs 会将它们连接起来,而 uses: ./… 和步骤运行的脚本会将作业与这些文件连接起来,因此,对脚本执行 impact,以及对工作流执行 review,都能看到彼此。
为什么使用图
搜索可以查找文本。图则保留了让代码仓库作为一个系统运行的关系。
例如,若要回答“authorize 发生变化会影响什么?”,使用搜索需要先找到候选文件、解读每个调用点,并反复重建传递依赖。impact 会沿着存储的带来源标注的边进行遍历,并按距离对受影响的符号分组。同样,shortest_path 会展示两个符号之间有证据支持的路径,而不是要求调用方根据互不相关的文件摘录自行推断。
| 需求 | 搜索和阅读文件 | Glasir |
|---|---|---|
| 查找提及某个名称的文本 | 有用 | 有用 |
| 查找直接调用者 | 需要手动解读 | 直接查询图 |
| 评估传递影响 | 需要反复重建依赖 | 有界遍历并提供边的来源信息 |
| 说明 A 如何到达 B | 根据摘录推断路径 | 返回具体路径 |
该图并不声称能够翻译任意自然语言。搜索使用确定性的标识符和文本匹配;未解析或有歧义的符号会保持可见并标明状态,而不会被猜测。
基准测试
Glasir 提供的是回归基准测试,而非与供应商比较的结论。这些基准测试会将检入的语料库与有文档说明的 grep-and-read 基线进行比较,并在配置的召回率下限出现回退时失败。随着语料库、问题和实现发生变化,结果也会变化,因此本 README 不发布固定的百分比或 token 数量。
glasir benchmark .
glasir benchmark . --check
python3 bench/scale.py target/release/glasir --check # 100k vs 1M lines
基准测试方法定义了语料库、基线、token 估算、限制和结果解读。文档还解释了为什么本仓库的结果不能替代针对客户代码进行的评估。
性能
索引和查询延迟取决于源代码形态、解析器层级、存储、硬件以及请求的图遍历方式。analyse 命令会报告仓库实测的冷启动索引时间和图大小;再次运行则会测量快照复用情况。请使用生产环境中实际采用的版本、仓库形态和部署限制来评估性能。
快照存储在源代码树旁边,并在复用前进行验证。如果源代码和提取配置仍然匹配,热启动时会映射已存储的图,而不是重新解析整个代码树。
提供的功能
十五个 MCP 工具,可通过 stdio 为本地编辑器提供服务,也可通过 Streamable HTTP 为远程 Agent 提供服务:
overview— 展示不熟悉的代码树中的子系统,以及进入各子系统的方式query_graph— 返回与问题相关的子图;给定文件路径时,返回该文件中的所有定义shortest_path— 展示一个符号如何到达另一个符号explain_node— 展示一个符号的调用方、被调用方和所属子系统impact— 按距离分组,展示更改后会造成哪些影响cycles— 展示依赖环;默认仅包含由编译器解析的边get_code_snippet— 返回符号所指向的源代码,范围取自解析器记录的内容,因此无需打开文件或猜测行号;对于 Markdown,返回指定章节,而非整个文档;following: N会继续读取后续 N 个定义。对于会分支跳转或落入其他位置的汇编例程,会说明后续执行位置find_callers— 将某个符号的直接调用方列为一个列表,并列出按名称使用该符号但未调用它的定义(例如签名中的类型、读取的常量或基类)detect_changes— 将 git diff 映射到其触及行所在的定义(文档则映射到相应章节,也包括新文件),并展示依赖这些定义的内容及风险级别 以及风险原因:更改的代码有调用方且没有测试覆盖时为high;存在依赖项,或历史记录显示通常会一同更改的文件未包含在内时为medium;其他情况为low
其中三个工具用于回答提交前该做什么;此时采取行动成本最低:
-
affected_tests— 返回覆盖某个符号或未提交 diff 的测试,按距离从近到远排列,并列出要运行的文件。可识别各语言的测试惯例(tests/、spec/、__tests__/、x_test、x.spec、FooTest、#[test]和@Test等测试属性);仅test_x这类名称时,只有在测试运行器会按名称收集测试的 Python 和 Ruby 中才算测试 -
co_changes— 根据 git 历史,列出与某个文件在同一提交中更改的文件,并标记图中没有边相连的文件:这些是隐藏耦合项——模板、迁移文件、另一种语言中的客户端——由于没有代码引用它们,impact无法发现 -
check_architecture— 根据图检查glasir-rules.txt中的架构约定(deny <path> -> <path>、no-cycles),并列出每条被违反的规则及违规边;可临时传入规则,以便在编写边界约定前测试它。在serve --watch模式下,图会跟随工作树变化,因此更改可以在提交前得到检查 -
find_unused— 查找代码树中没有被引用的定义,并对照每个文本文件逐一确认,而不只是检查调用图;排除测试、带注释的代码和生成代码、重载项及框架惯例。在五种语言的六个真实仓库中,报告的每个名称都只出现在其自身定义中;每条回答都会说明它无法发现的内容,例如库的公共 API 或运行时构造的名称 -
change_history— 按时间倒序列出更改过某个定义的提交及其说明:在代码更改前,了解代码为何如此编写。如果某次提交更改的行落在当时文件中的该定义内(而非嵌套于其中的定义内),就会被计入。按需从 git 读取;提交说明不会进入搜索索引,因为实测发现它们会挤占其所描述的代码 其中一个用于连接不同树: -
http_surface— 该树声明的 HTTP 路由及其处理程序,以及它发送的请求及其发送方,均作为可匹配的片段。在一棵树内,find_callers和impact已能沿请求追踪到其处理程序;Glasir Control 用它在工作区的各个仓库之间执行相同操作,因为客户端和服务端分处不同仓库
每个工具都声明自身为只读、幂等且封闭世界(readOnlyHint、openWorldHint: false),因此处于规划或只读模式的客户端可以调用所有工具。四个会列出不限数量结果的工具——impact、find_callers、find_unused 和 overview——接受 limit 和 offset,并在还有结果时返回 next_offset;排序稳定,因此分页结果合起来就是完整答案。
“没有任何调用方”会根据源代码核查。 图会记录调用;签名中的类型、读取的常量,或在模板中绑定的处理程序,都是它没有对应边的用法。因此,对于树中恰好只定义一次的每个名称,impact、find_callers 和 affected_tests 还会列出文本中提及该符号、但没有边与之相连的文件(named_elsewhere)——这样,注入到三个控制器中的接口就不会再被报告为毫无影响。
每个答案都同时以两种形式提供:说明文字和 structuredContent。 文本以便于人阅读的方式排版;结构化部分将相同事实作为数据返回,并遵循每个工具声明的架构,因此 Agent 可以解析字段,而不必匹配可能改写的措辞。文本由该值生成,因此两者不会相互矛盾。
GET /health 无需令牌即可返回 {"status":"ok",...},因此容器编排器可以探测服务是否存活;其他所有请求都需要令牌。
在 serve --watch 模式下,GET 会打开一个事件流;树重新索引时,该事件流会推送 notifications/resources/updated,这样持有缓存答案的客户端就能知道,这些答案描述的是一棵已经发生变化的树。
同一提交在任何机器上都会给出相同答案。 索引过程不使用模型,也不进行采样:嵌入签名会经过哈希处理,每种排序都会按节点 ID 打破平局,而 glasir selfcheck 会从冷启动状态对一个测试样例分析两次,并要求 ID、边、分区、嵌入、布局和搜索排名完全一致。这使检索到的答案可以引用,而不只是看起来合理。
每条边都会说明它是如何解析的。 extracted 表示经过编译器验证(SCIP/LSP),inferred 表示由原生扫描器根据语法推断,ambiguous 表示名称匹配。对类型未知的值调用方法也属于 ambiguous,无论方法名多么唯一:x.is_empty() 可能来自标准库。因此,答案可以被引用:调用方能分辨工具掌握的信息与推测的信息。在 Python、Go 和 JavaScript/TypeScript 中,通过导入进行的调用——util.Do()、from pkg.b import helper as h; h()、import * as x from './x'——会解析到导入所指向的文件或包,因此即使名称在多个位置定义,也仍会链接到正确位置,而不是不链接到任何位置。Erlang 和 Elixir 会通过模块解析调用;Java 会通过变量解析调用,指向其声明类型所命名的类。Rust 会以相同方式处理 use crate::…、super::… 和 self::…,而对有类型的值调用方法时,无论定义它的 impl 位于何处,都能找到它;树外的类型(HashMap)则保持其自身的解析结果。
请求会到达其处理程序。 客户端的 HTTP 调用会形成一条指向相应路由所命名的服务端处理程序的边:路由可来自 Spring 注解、NestJS 装饰器、ASP.NET 控制器和最小 API、Express 风格及 Go 注册方式、Python 装饰器和 OpenAPI 文档(paths、动词、operationId);请求可来自 Angular 的 HttpClient、fetch、.NET 的 HttpClient、Spring 的 RestTemplate、MockMvc 和 Go 的 http.NewRequest,URL 可由常量、模板或 + 拼接而成。find_callers、impact 和 affected_tests 会沿这些边追踪,因此调用端点的测试或前端都会计为其调用方。
语言
parsers/ 中注册了 148 种语言,均配有原生扫描器,且不依赖外部语法。其中包括 Rust、Python、JavaScript、
TypeScript、Go、Java、C、C++、C#、Ruby、PHP、Swift、Scala、Kotlin、Bash、Lua、
Elixir、Dart、Haskell、Zig、Perl、SQL、HCL、R、Julia、OCaml、Solidity、
Erlang 和汇编语言(Motorola 68000、GNU as 和 NASM:标签、EQU
常量、宏——包括定义自身名称的宏——以及通过 JSR/BSR/BRA/call 发起的调用、例程落入下一个
标签的情况,以及间接调用:通过 DC.L 表,或通过其他位置写入表的字段,例如 MOVE.L MN_OPS(A1),A2 / MOVE.L OP_READ(A2),A2 /
JSR (A2),到达每个此类表中偏移量为 OP_READ 的入口。值会沿寄存器、分支、调用以及传递给它们的例程进行跟踪,且可跨文件追踪。无法追踪间接调用时,impact 和 find_callers 会列出最近的调用,而不是悄无声息地停止;通过 A6 中基址发起的库调用(JSR _LVOOpen(A6))则单独统计)。仓库内的语言测试样例会验证每种受支持语言变体的提取下限,因此扫描器为空或提取结果明显退化时,构建会失败,而不会悄悄返回空结果。Markdown 也会作为独立的源代码进行索引——章节是节点,反引号括起的名称是指向其所命名代码的边。
内置提取规则无需配置即可使用。目前,公开的覆盖接口仅支持 Go、Rust 和 Ruby;其他内置规则文件属于内部实现细节,不保证兼容性。要显式替换受支持语言的规则:
glasir analyse . --language-rules /path/to/rules
glasir serve . --watch --language-rules /path/to/rules
规则会在索引前验证,重启前保持不变,并参与快照有效性判断。有关架构、示例、测试和当前提取限制,请参阅语言规则维护。
使用其他语言提问
提问时优先使用英语。 代码名称几乎总是英语,而 query_graph 会将问题中的词语与标识符和文档进行匹配——它不会翻译。
所有结构性工具都与语言无关:impact、find_callers、
shortest_path、explain_node、cycles 和 overview 都基于符号和边工作;任何语言的文档和注释也都会被索引。
如果问题中的技术词汇与代码中的词有相同词干,用其他语言提问仍然可以找到英语代码——技术词汇通常确实如此:
server、serveur、servidor;compaction、compactage、compactación;
德语 Konfiguration 会匹配 configuration,Aktion 会匹配 action,因为德语中的 k 和 z 会与英语中的 c 匹配。用
德语、法语和西班牙语提问时,关于此仓库的同一个问题都能找到正确的文件,不过英语会将完全匹配的符号排在最高位。
无法奏效的是没有共同词干的词对——Raum 和 room、
Leinwand 和 canvas。要弥合这类差异,需要词典或语言模型,而 Glasir 在查询路径中刻意不使用它们,因此相同的问题总会返回相同的答案。问题未命中时,回复会列出仓库自身使用的词汇,方便助手换用这些词再次提问。
| 提问语言 | 状态 |
|---|---|
| 英语 | 首选;所有基准测试均以英语为参照 |
| 德语 | 支持:会过滤问题中的词语,并弥合与英语的拼写差异 |
| 其他拉丁字母语言 | 通过相同的技术词干实现匹配;comment 或 qué 等问题词不会被过滤,会计入搜索词 |
| 其他文字体系(西里尔文字、CJK 等) | 未测量;自由文本问题不太可能匹配英语代码,结构性工具不受影响 |
在实际使用中,无论你用哪种语言提问,Glasir 前面的助手通常都会使用代码本身的词汇来构造工具调用。
面向团队运行
glasir serve /srv/repo --http 0.0.0.0:8899 # refuses to start: no auth
glasir token add anna --days 90 # prints the token once
glasir serve /srv/repo --http 0.0.0.0:8899 --watch
- 每用户令牌,仅以 SHA-256 形式存储。撤销后会在下一个请求时生效,无需重启。
- JSONL 审计日志:记录时间戳、身份、工具、问题和结果大小;日志写入不在请求处理路径上,因此磁盘写满只会丢失记录,不会影响请求。
- 非回环地址未配置身份验证时会拒绝启动。 回环地址仍保持开放——适用于单机使用。
- 按照 MCP 传输规范进行
Origin验证,并使用有界连接池。
部署边界
对于企业部署,请在公共边缘运行独立的 Glasir Control 服务。该服务提供 OIDC 资源服务器验证、仓库路由、代码托管权限镜像、集中式审计和公共 TLS 边界。 Glasir Core 仍是单个源代码树的私有数据平面,本身不会公开这些控制平面功能。运行每个 Core 进程时都不要配置公共共享密钥:
cd /srv/alpha && CONTROL_TOKEN="$(glasir token add control)"
glasir serve /srv/alpha --http 7001 --behind-control-plane --watch
# rights.tsv in glasir-control contains the one-time CONTROL_TOKEN for alpha.
--behind-control-plane 会拒绝 --token 或缺少每服务令牌的情况;除非提供下方明确的 CIDR 门控,否则它仅绑定回环地址。公共代理会验证浏览器来源,并在转发前将其移除;
Core 则保留其回环 DNS 重绑定防护。
对于 Kubernetes,只有设置明确的网络边界后,Core 才能绑定到 Pod 接口。将 Core 的 Service 与默认拒绝的 NetworkPolicy 配对,并传入控制平面的确切 Pod CIDR:
glasir serve /srv/alpha --http 0.0.0.0:7001 --behind-control-plane \
--control-plane-cidr 10.1.0.0/16 \
--tls-cert /run/tls/core.crt --tls-key /run/tls/core.key \
--control-plane-client-ca /run/tls/ca.crt --watch
CIDR 是额外的连接门控,并不能替代身份验证: 每服务令牌仍是必需的。来自范围之外的连接会在 HTTP 解析前被丢弃,且不会收到任何探测响应。此首个联网数据平面模式有意不接受 IPv6。
对于生产环境中的控制平面,CIDR 加每服务令牌只能作为第一道边界:请使用双向 TLS。只有在使用 --behind-control-plane 且配置了服务器证书/密钥时,才接受 --control-plane-client-ca。随后,Core 会要求转发请求的控制平面客户端证书链能追溯至该 CA;证书名称必须与 Core Service DNS 名称匹配。请将 CA、服务器证书/密钥和控制平面客户端证书保存在工作负载密钥中(或外部密钥提供方中),分别轮换它们,不要在明文 sidecar 处终止此连接。
Core 的独立部署范围不包括公共身份管理和跨仓库编排。独立使用时可启用 TLS(--tls-cert / --tls-key),也可在反向代理处终止 TLS。当前 Core 的边界和保证记录在 docs/architecture.md 中。
构建
带标签的版本会向 GHCR 发布已签名的多架构(linux/amd64、
linux/arm64)Core 镜像。版本资源包括 CycloneDX SBOM;
版本工作流还会为每个归档文件和已发布的镜像清单生成构建来源证明,并为后者生成无密钥 Cosign 签名。请按摘要部署,而不要使用可变标签。CI 还会在每次变更时重新构建生产 Dockerfile,并验证其非 root 运行时。
cargo build --release
cargo test # root checks and CLI integration tests
cargo test --manifest-path parsers/Cargo.toml --target-dir target/parser-tests
glasir selfcheck # the same checks in one pass, in order
glasir benchmark . --check # recall against bench/baseline.txt
glasir langcheck bench/langs --check # extraction against bench/languages.txt
glasir langcheck bench/langs --anomalies --check # names no fixture may show
基准测试是一个门槛,而非报告:任何集合低于其下限都会导致构建失败。
langcheck 负责守护另一半。召回率下限会读取本仓库,而本仓库使用 Rust,因此它无法发现某个扫描器是否已停止从 Julia 中提取内容;此工具会报告每种语言每 1,000 行代码中的定义和边数量,以及归属于文件而非外围定义的引用比例——当某个语言关键字不再被识别时,这个数值会从 3% 跳到 99%。
--anomalies 会读取计数无法揭示的内容:名称类似关键字或其规则文件赋予某个角色的单词的定义(fun ref charge 会被读作 ref)、包含空白字符或引号的名称,以及不可能存在的范围,并指出需要检查的位置。用于真实代码时,它会生成分流报告;用于测试夹具时,则会导致构建失败。
运行
/health 无需凭据即可响应,用于检查存活状态。/ready 是部署探针:它会确认图已加载,并返回其 indexed_at、发布 generation 以及最近一次重新索引错误。/metrics 无需凭据即可响应,提供 Prometheus 计数器——各工具的调用次数、错误数和耗时、拒绝次数、延迟直方图,以及图的大小。无论如何,/mcp 都需要令牌才能访问。
在受监控的生产服务上设置 --max-index-age 900,当已加载的图超过约定的 15 分钟 SLO 时,/ready 就会返回 503。编排器替换或修复实例期间,最后一个有效图仍可用。
同时处理多个代码仓库
客户端及其通信的服务通常位于两个代码仓库中。提供同时包含两者的目录,它们就会成为同一张图:
cd ~/work # holds shop-web/ and shop-api/, each a git repository
glasir install . # registers the server for this directory, hooks in each repository
一个代码仓库中的 HTTP 请求会到达另一个代码仓库中的处理程序,因此 find_callers、impact 和 affected_tests 无需控制平面即可跨越边界。符号会将代码仓库作为路径的第一个部分(shop-api/src/orders.rs#create)。需要查询 git 的工具——detect_changes、affected_tests、co_changes、change_history、review——会分别查询每个代码仓库,并为结果加上前缀;如果某个修订版本仅存在于一个代码仓库中,就只会对该代码仓库生成差异。对于自身及其子目录中都没有代码仓库的目录,系统会拒绝处理,而不会将其报告为未发生变化。
拉取请求
glasir review [rev] 会以 Markdown 格式输出 detect_changes 和 affected_tests 对变更的分析:风险级别及其原因、变更的符号、按距离排列的依赖项、能够到达该变更的测试,以及图未覆盖的文件。设置 --fail-on medium 可将其作为门禁。
该代码仓库提供了一个复合 GitHub Action,可在每个拉取请求上运行,并持续更新同一条评论:
on: pull_request
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0 # the base commit has to be in the clone
- uses: Attackwave/[email protected]
with:
fail-on: high # optional: block the merge at this risk
图会在运行器上根据已检出的代码树构建;不会有任何源代码离开运行器。该 Action 会下载其自身标签指定的发布版本,并校验归档是否与已发布的 SHA-256 和构建来源相符(早于 0.11.0 的发布版本不包含这些信息,因此会被拒绝)。将 Action 固定到某个提交的代码仓库应写为 Attackwave/glasir@<commit of the tag> # v0.11.5;随后,该 Action 会下载该版本的发布包。
许可证
Apache-2.0。请参阅 LICENSE 和 NOTICE。
所有链接到二进制文件中的依赖均采用宽松许可证——MIT、Apache-2.0、ISC、BSD-3-Clause、Unicode-3.0 或 Unlicense——不含任何著佐权许可证。每个发布归档都包含其版权声明和许可证文本,位于 THIRD-PARTY-LICENSES.txt 中;该文件由 cargo about 根据打标签的 Cargo.lock 生成。about.toml 列出了接受的许可证,发布流程遇到其他许可证时会失败。CI 还会在每次运行时生成 CycloneDX SBOM,因此这项声明可以核查,而非仅仅声称。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。