ConfigLens:一款用于排查 AI 编程工具为何忽略配置的 Rust CLI
ConfigLens: Figure out why your AI tool is ignore your settings
ConfigLens 是一款本地只读的 Rust CLI,可追踪 Claude Code 和 OpenCode 的配置键,展示实际生效的值及其来源文件、行号和原因,包括被覆盖的配置项。
找出你的 AI 编程工具为何忽略你的配置。
ConfigLens 是一个小巧、本地、只读的 Rust CLI,它会针对 Claude Code 和 OpenCode,在受支持的配置来源中追踪某个受支持的配置键,并显示观察到的胜出者——包括每个贡献项所在的文件、行号和原因,也包括那些落败的贡献项。
它从不执行你的配置,从不运行客户端二进制文件,不打开任何套接字,也不读取任何凭据。除非适配器明确将其列入允许列表,否则值都会被脱敏处理。
预发布版,
0.1.0-beta.3。 这是一个可用的原型,而非成品:两个适配器都经过固定样本验证,而非运行时一致性验证,无法读取的层会被报告为缺口,而不是靠猜测填补。状态准确说明了这意味着什么。
安装
每个版本都附带了预编译二进制文件。目前提供三个目标平台:
| 平台 | 发布归档 |
|---|---|
| Windows (x86-64) | configlens-<tag>-x86_64-pc-windows-msvc.zip |
| macOS (Apple Silicon) | configlens-<tag>-aarch64-apple-darwin.tar.gz |
| Linux (x86-64, glibc) | configlens-<tag>-x86_64-unknown-linux-gnu.tar.gz |
每个版本还附带一个 SHA256SUMS 文件以及每个目标平台的 CycloneDX SBOM。这些二进制文件未签名,也没有安装程序或包管理器;请将下面的 <tag> 替换为你想要的版本(当前为 v0.1.0-beta.3)。
验证下载
Linux 和 macOS:
tag=v0.1.0-beta.3 target=x86_64-unknown-linux-gnu # or aarch64-apple-darwin base=https://github.com/ob4cl/configlens/releases/download/$tag curl -LO $base/configlens-$tag-$target.tar.gz curl -LO $base/SHA256SUMS sha256sum -c --ignore-missing SHA256SUMS # macOS: use shasum -a 256 -c tar xzf configlens-$tag-$target.tar.gz ./configlens-$tag-$target/configlens --version
Windows (PowerShell):
$tag = 'v0.1.0-beta.3' $repo = 'ob4cl/configlens' # With the GitHub CLI: gh release download $tag --repo $repo --pattern '*windows-msvc.zip' gh release download $tag --repo $repo --pattern 'SHA256SUMS' # Without it: download both files from the release page in a browser. $zip = Get-ChildItem *windows-msvc.zip | Select-Object -First 1 $expected = (Get-Content .\SHA256SUMS | Select-String $zip.Name).Line.Split()[0] $actual = (Get-FileHash -Algorithm SHA256 $zip.FullName).Hash.ToLower() if ($actual -ne $expected) { throw 'SHA256 mismatch - do not run this file' } Expand-Archive $zip.FullName -DestinationPath unpacked & .\unpacked\configlens-*\configlens.exe --version
预期得到 configlens 0.1.0-beta.3。在 macOS 上,归档文件未经公证,因此 Gatekeeper 会在首次运行时发出警告:右键点击 → 打开,或 xattr -d com.apple.quarantine <binary>。
从源码安装
任何装有 Rust 1.85 或更新版本的平台:
cargo install --locked --git https://github.com/ob4cl/configlens
或者从代码检出目录安装:cargo build --locked --release,这会将二进制文件留在 target/release/configlens。
尚不可用:macOS Intel、Linux arm64、crates.io、Homebrew、Scoop/winget。没有强制性的 curl-to-shell 安装程序,而且这里的一切在运行时都不会访问网络。
你的第一条命令
configlens explain /model --client claude --client-version 2.1.296
这会打印出 model 的观察到的胜出者,以及每个贡献项所在的文件、行号和原因。一个真实的终端示例展示了完整输出以及如何解读它。
这能回答的问题
你设置了一个模型、一项权限、一个 MCP 标志。工具却忽略了它。现在你有五个可能的文件、一个环境变量、一个会话标志和一项可能都牵涉其中的托管策略——而工具只是说“正在使用另一个”。ConfigLens 回答了随之而来的四个问题:
- 哪个值胜出了? 在它能读取的所有内容中观察到的胜出者。
- 每个值来自哪里? 每个贡献项所在的文件、行号和列号,按优先级顺序排列,包括那些被替换或跳过的定义。
- 我应该编辑哪个文件? 胜出的来源会被指明,因此你可以编辑正确的那个。
- 我能把这个粘贴到 issue 里吗? 报告会对受保护的值进行脱敏,
--paths share会减少可识别细节;configlens support-report --preview正是为此构建共享模式报告。在分享之前,请查看输出和下方的隐私限制;脱敏报告并不保证匿名。
快速开始(从源码)
在软件包发布之前,请从此代码检出目录构建。无需安装任何客户端,运行时也不需要网络访问。
cargo build --locked --release ./target/release/configlens --help
如果你更想从代码检出目录将二进制文件安装到你的 PATH:
cargo install --locked --path .运行隔离演示
demo/demo.sh 不读取任何真实配置。它会在临时目录下创建一个一次性的 home 和项目,只写入明显虚假的值,清空环境,并针对该沙盒运行 CLI。临时目录之外的任何内容都不会被写入,也不会使用网络或客户端子进程。
cargo build --locked --release ./demo/demo.sh
一个真实的终端示例
截取自上文中的隔离演示(仅使用合成值)。较长的覆盖行和末尾的两条 trust_unknown 诊断信息被省略——该工具会打印每一个缺口和每一条诊断信息。
$ configlens explain /model --client claude --client-version 2.1.296 /model = "local-model" (observed) Observed winner: $PROJECT/.claude/settings.local.json:1:12 "local-model" observed_winner Losers: "project-model" $PROJECT/.claude/settings.json:2:12 replaced_by_later_layer Rule: claude.scalar.layer-override Coverage: partial — cc.managed.hkcu — registry_not_read (expected_unobservable); … (3 more gaps) Support: fixture_verified; confidence: evidence_class:fixture_verified Conclusion: "local-model" wins among the observed applicable sources; effective value withheld. Next inspection: - supply the managed settings file with --input-context to include it - remote/MDM layers are not observable here; re-run where the managed source is readable
这样理解:项目文件集 model 到 "project-model",后面的某一层将其替换为 "local-model",而 "local-model" 是 ConfigLens 观察到胜出的值。它有意不将其称为运行时值,因为某个它无法读取的更高层仍可能改变它——参见 有界语义。
命令
configlens <command> [options]
| 命令 | 示例 | 作用 |
|---|---|---|
clients |
configlens clients |
列出已实现的适配器及其测试过的版本、始终不完整的层,以及明确不支持的客户端。 |
scan |
configlens scan --client claude |
清点候选来源及其适用性和可读性,外加覆盖缺口。不进行递归爬取。 |
explain |
configlens explain /model --client claude --client-version 2.1.296 |
解释一个 RFC 6901 JSON Pointer:有序追踪、观察到的胜出者(或未解析的结果)以及覆盖缺口。 |
doctor |
configlens doctor --client opencode --format json --strict |
解析 / schema / 适用性 / 覆盖诊断。绝不将配置认证为安全。 |
snapshot |
configlens snapshot --client claude --output before.json |
将脱敏后的报告 JSON 写入显式路径。默认创建新文件;使用 --overwrite 进行替换。 |
diff |
configlens diff before.json after.json |
比较来自同一客户端和 schema 的两份报告;受保护的值按 unknown_redacted 比较。 |
schema |
configlens schema --kind report |
打印内置的报告 JSON Schema。无网络。 |
support-report |
configlens support-report --preview |
构建用于粘贴到 issue 中的分享模式报告。始终为分享模式(无论 --paths 如何)。--preview 将其打印到 stdout 且不写入任何内容;--output <PATH> 将其写入(在 Unix 上为 0600)。没有上传。 |
completions |
configlens completions --shell bash |
为 bash、zsh 或 fish 打印 shell 补全脚本,由实时命令树生成。不向磁盘写入任何内容。 |
运行 configlens --help(以及 configlens <command> --help)以获取当前权威列表——上表涵盖核心命令。
选项
解析需要 --client <opencode|claude>。共享选项:--cwd <PATH>(默认 .)、--client-version <VERSION>(一个声称的版本——ConfigLens 从不读取客户端二进制文件)、--format text|json、--strict、--no-env、--input-context <PATH>、--color auto|always|never、--paths local|share、--allow-read-root <PATH>(可重复)、--project-root <PATH>。此外,一个全局 --quiet(在每个子命令上以 configlens <cmd> --quiet 形式接受)仅抑制信息性 stderr 提示——即快照 wrote N bytes 行和支持报告的写入/--preview 提示。错误始终打印到 stderr,stdout 保持机器可读(JSON),退出码不变。snapshot 添加 --output/--overwrite;doctor 添加 --fail-on warning|error;support-report 接受 --preview 或 --output <PATH>;两者都不提供属于用法错误(退出码 2),如果两者都给出,则 --preview 胜出且不写入任何内容;completions 接受 --shell bash|zsh|fish。
退出码
| 代码 | 含义 |
|---|---|
0 |
已生成报告。允许存在非致命发现。 |
1 |
doctor 发现达到或高于 --fail-on(默认 error)。 |
2 |
用法错误或输入/报告不兼容。 |
3 |
请求的键/客户端语义不受支持,或 --strict 发现上下文不完整。 |
4 |
所需文件无法访问、格式错误或超出资源限制。 |
当多个条件适用时,优先级为 2 → 4 → 3 → 1 → 0。
“胜出”究竟意味着什么
每个报告中有三个术语承载着关键含义:
- 观察到的胜出者——在 ConfigLens 能够读取的来源中优先级最高的定义。
- fixture_verified——该规则已针对本项目的 fixtures 和上游文档进行了核对,而非针对正在运行的客户端。
- 覆盖缺口——某个来源存在但无法读取,因此有效值被保留不给出。
ConfigLens 是一个针对其能够读取的输入的静态分析器。它不检查正在运行的会话,也从不假设不可读的层不存在。这有三个可见的后果:
- 已观察,但未生效。当存在更高优先级的层但不可观察时(服务器管理的策略、MDM/注册表设置、OpenCode 远程默认值)——或者项目信任状态未知——结果会被标记为
partial,胜出者被标记为已观察胜出者,而有效值则与覆盖缺口列表一起被暂不披露。 - 清点,而非猜测。未知键会作为不透明清单保留,绝不会被赋予凭空发明的合并规则。未知或未经测试的客户端版本会以临时方式报告;
--strict随后以3退出。 - 来源,而非授权。对于 Claude 权限列表,ConfigLens 会展示列表条目如何组合,并明确提示这不是一项授权决定。
因此退出码 0 意味着“已生成报告”,而不是“这就是你的工具将使用的值”。
兼容性
目前提供两个有边界的适配器。两者最多都只是 fixture_verified——依据项目自身的测试夹具和当前上游文档进行验证,而非依据上游加载器,因此没有任何规则声称 upstream_conformance_verified。支持状态以 inventory_only < documented < fixture_verified < upstream_conformance_verified 运行。
| 客户端 | 适配器修订版 | 已测试/已记录版本 | 最大支持 | 始终不完整的层 |
|---|---|---|---|---|
| OpenCode | 0.1.0 | 已测试 1.18.35 / 已记录 1.19.0 | fixture_verified |
远程默认值、.opencode 目录、macOS 托管偏好设置 |
| Claude Code | 0.1.0 | 2.1.296 | fixture_verified |
MDM 策略存储、服务器管理的设置、HKCU 注册表、托管文件缺失 |
逐键详情、证据 URL、检索日期和规则→测试 ID 位于适配器的注册表中:
compatibility/opencode/registry.md 和
compatibility/claude/registry.md。
OpenCode 的 @opencode/cli 2.x 系列是一个单独的测试版,具有不同的已记录合并模型(目录遍历至文件系统根目录;每个 .opencode 配置覆盖每个直接配置)。它尚未实现;声称的版本若不在受支持集合内,会以 unsupported 报告,而不是凭猜测解析。请参阅适配器注册表。
这些客户端尚未实现,并被标记为 unsupported——不会仅凭共享文件名做出兼容性声明:Codex 和 Gemini(0.2 待办)、Aider(待办),以及 Cursor、Copilot CLI、Cline、Roo 和 Hermes(未调查)。运行 configlens clients 以获取当前矩阵。
隐私与注意事项
- 离线且只读。无网络、无子进程、不执行客户端二进制文件;一项测试会扫描
src/以保持这一状态。$schema引用永远不会被获取。 - 除非列入允许列表,否则一律脱敏。只有脱敏投影会生成可报告的值;机密会显示为
{"redacted": true, "reason": "..."}。 - 两种路径模式。
--paths local(默认)显示配置位置和键名,以便你进行诊断;--paths share会对路径进行假名化,将未知键名替换为不透明 ID,并剥离 URL 用户信息、查询和片段。 - 快照。以创建新文件的方式原子写入,在 Unix 上使用
0600仅所有者权限。在 Windows 上没有0600等价物:快照会作为同目录临时文件写入,然后重命名,因此它继承目标文件夹的 ACL——ConfigLens 无法收紧它。报告会说明这一点(redaction.snapshot_acl = "not_implemented"),而不是声称一种并不存在的保护。 - 已知的 0.1 差距 / Windows 指南。 Windows 快照 ACL 限制未实现。
限制性 DACL 需要通过
unsafeFFI 或新依赖来调用 Win32 安全 API,而这两者都被本 crate 的unsafe_code = "forbid"及其最小依赖策略排除,因此不在 0.1 的范围内。请将快照保存在私有的、用户控制的目录中(例如%USERPROFILE%,而不是共享或全局可读的文件夹),这样继承的 ACL 才是你想要的。 - 报告仍会描述你的项目结构。切勿将原始凭据文件粘贴到 issue 中。
状态
0.1.0-beta.3,预发布版。诚实的总结:
- 随附两个适配器——Claude Code 和 OpenCode——两者最多为
fixture_verified。没有任何规则 声称与上游一致,因为测试中未执行任何上游加载器。 - 某些层始终被报告为覆盖缺口,而不是猜测;它们按客户端列在 Compatibility 中。
- Windows 快照 ACL 限制未实现,报告如实说明,而不是暗示存在 实际并不存在的保护。
- 引擎在键数量上是二次方的;真实配置只有几十个键,此时耗时
为亚毫秒级。实测的扩展性见
docs/implementation-status.md。 - 已实现、已验证和未验证的内容逐项记录在
docs/implementation-status.md中,实际运行的命令见docs/verification-log.md。
要求
Rust,2021 版。rust-version = "1.85" 在 Cargo.toml 中声明并已验证:
cargo +1.85.0 check --locked --all-targets --all-features 退出 0(docs/verification-log.md 的 §8.1),CI 的 msrv 任务运行相同的检查。
本地开发使用 1.99.0。确切命令和结果见验证日志。
贡献
适合初次贡献的内容包括合成夹具、更清晰的诊断信息和特定版本的规则 证据。每次适配器变更都需要一手来源、声明的兼容范围和 正/负测试——绝不能使用真实密钥或专有指令。开发 检查包括:
cargo fmt --all -- --check cargo clippy --locked --all-targets --all-features -- -D warnings cargo test --locked --no-fail-fast python -m unittest discover -s scripts -p "test_*.py"
在打开拉取请求之前,请在本地运行这些检查。回归工作流见
CONTRIBUTING.md,维护者侧流程见
docs/maintaining.md。安全问题的报告方式见 SECURITY.md。
文档
docs/getting-started.md— 构建、首次运行以及如何阅读输出。docs/maintaining.md— 验证、添加规则和发布检查清单。docs/implementation-status.md— 已实现、已验证和未实现的内容。docs/verification-log.md— 实际运行的命令。docs/decisions.md— 工程权衡和被否决的替代方案。docs/spec/ConfigLens_Technical_Specification.md— 它所依据的设计。
许可证
以下任一许可证下授权
- Apache License, Version 2.0(
LICENSE-APACHE) - MIT 许可证(
LICENSE-MIT)
由你选择。
除非你明确声明 otherwise,否则你有意提交以纳入本项目的任何贡献, 如 Apache-2.0 许可证所定义,应按上述方式双重授权,且不附加 任何额外条款或条件。
来源:Hacker News · github.com