dcg 的 TOON 结构化输出集成:让安全决策以最小 Token 成本被 Agent 消费

dcg 的 TOON 结构化输出集成:让安全决策以最小 Token 成本被 Agent 消费 dcg 的 TOON 结构化输出集成让安全决策以最小 Token 成本被 Agent 消费【免费下载链接】destructive_command_guardThe Destructive Command Guard (dcg) is for blocking dangerous git and shell commands from being executed by agents.项目地址: https://gitcode.com/GitHub_Trending/de/destructive_command_guarddcgdestructive_command_guard是用于拦截 AI 编程 Agent 执行危险 git / shell 命令的 Rust CLI。本文围绕 docs/planning/RESEARCH_FINDINGS.md 及其配套的 docs/planning/TOON_INTEGRATION_BRIEF.md系统梳理 dcg 的两类机器接口Hook 协议与 Robot 模式、TOON 输出格式的引入范围与落地路径以及它如何在不破坏既有集成契约的前提下让 Agent 以更低的 Token 开销消费 dcg 的安全决策。读完本文你将掌握 dcg 输出格式的全景、--format toon的实际用法、格式优先级设计以及 crate 化编码方案的源码级实现细节。为什么 dcg 需要第三种结构化输出dcg 的核心使命是“在危险命令真正执行之前将其拦截”。它天然面对两类消费者人类开发者需要可读、带高亮与建议的输出和 AI Agent / CI 脚本需要稳定、可解析的结构化数据。为此dcg 从一开始就设计了两条面向机器的契约Hook 协议Claude CodePreToolUse等从 stdin 读 JSON向 stdout 输出JSONcamelCase 字段这是 Agent Hook 协议本身的硬性约束Robot 模式--robot或DCG_ROBOT1stdout 输出JSONstderr 静默采用标准化退出码。当 JSON 成为唯一的结构化载体时一个现实问题浮出水面JSON 的语法噪声引号、冒号、花括号、逗号会占用大量 LLM 上下文 Token。对于高频调用 dcg 的 Agent 工作流每次命令评估都要解析一次决策JSON 的冗余会让成本随调用量线性放大。TOONToken-Optimized Object Notation正是为此而生的一种紧凑编码它保留 JSON 的全部语义信息但通过精简语法把结构化数据的 Token 开销压缩到接近纯文本的水平。RESEARCH_FINDINGS 的核心结论是TOON 支持应限定在“CLI 专有、且已经支持--format json”的结构化输出上并通过toon_rustcrate 实现绝不使用 Node.js 版toonCLI。现状盘点JSON 在哪里被产生、被消费Hook 协议必须保持 JSON 的契约面Hook 协议是 dcg 与 Claude Code 之间的集成契约散落在两个文件中src/hook.rs定义HookInput/ToolInputstdin JSON 解析与HookOutput/HookSpecificOutputstdout JSON 序列化。序列化时通过#[serde(rename ...)]强制输出 camelCase 字段例如hookSpecificOutput、permissionDecision、permissionDecisionReason、allowOnceCode、ruleId、packId、systemMessage等反序列化侧则通过#[serde(alias ...)]兼容sessionId、toolName、toolInput、toolArgs等各家 Agent 的命名差异src/cli.rsHookCommand { batch, parallel, workers, continue_on_error, with_packs }定义dcg hook子命令其中--batch模式按 JSONL每行一个 JSON 对象读入、按 JSONL 输出行级 schema 是BatchHookOutput含index、decision、可选的mode/rule_id/pack_id/error字段。这两处是协议约束区无论环境变量如何设置Hook 协议的输入输出都必须是 JSON / JSONL。TOON 在此完全不适用——改变字段命名或编码方式都会直接破坏 Claude Code 等 Agent 的 Hook 解析器。Robot 模式默认保持 JSON 的契约面Robot 模式在 src/cli.rs 的Cli结构中以全局参数--robot声明其语义在文档注释中写得很清楚所有输出为 stdout JSON、stderr 完全静默、退出码标准化0 允许 / 1 拒绝或不确定 / 2 警告配合--fail-on warn/ 3 配置错误 / 4 解析错误 / 5 IO 错误。底层判定逻辑位于 src/output/mod.rs 的robot_mode_enabled显式--robot始终优先DCG_ROBOT环境变量沿用与其他输出开关一致的布尔解析规则0、false、no、off均视为关闭并有对应单元测试test_robot_mode_enabled_explicit_flag_wins保证“显式标志优先于环境变量”。Robot 模式的 JSON 契约是为了不破坏既有 Agent 集成如 docs/adr-002-robot-mode-api.md 所定义的 API。因此 RESEARCH_FINDINGS 建议Robot 模式默认仍输出 JSON即使未来支持 TOON也必须显式 opt-in例如显式传--format toon并且 Hook 协议要持续忽略环境变量的格式覆盖。CLI JSON 输出TOON 的候选目标除协议区外dcg 有大量 CLI 子命令自带本地Format枚举通常是{Pretty, Json}二选一这些才是 TOON 的候选落点dcg testsrc/cli.rsTestFormat::{Pretty, Json, Toon}TestOutput为输出 schematest_command(...)中Json分支用serde_json::to_string_pretty打印Toon分支用toon::encode编码后打印dcg packsPacksFormat::{Pretty, Json}与PacksOutputdcg config/dcg doctor/dcg explain/dcg simulate/dcg corpus/dcg suggest-allowlist等各自拥有本地Format枚举src/scan.rsScanFormat::{Pretty, Json, Markdown, Sarif}是唯一真正产出 SARIF 2.1.0 报告的命令。值得注意的现状是TOON 已经不止停留在规划层面。在 src/cli.rs 中TestFormat已经包含Toon变体并配套了 CLI 解析测试test_cli_parse_test_with_format_toon与编码往返测试test_toon_roundtrip_for_test_output_payloadCargo.toml 中tru 0.2.2就是该 crate 的实际依赖。README 的输出格式表中也已列出dcg test接受pretty别名text、json别名sarif、structured、toon三种格式——这说明 RESEARCH_FINDINGS 中“Phase 1给已有 JSON 输出的 CLI 命令加 TOON”已被实现规划文档与代码现状是互相印证的。推荐的作用域与分阶段计划RESEARCH_FINDINGS 给出的非回归约束Non-regression constraints是一切设计的红线Hook 协议无论环境变量如何始终 JSON / JSONLRobot 模式默认始终 JSON不受环境变量影响。Phase 1最小、安全只给“已有 JSON 输出、且不属于 Hook 协议”的 CLI 命令增加 TOON 输出dcg test --format toon已落地可选dcg scan --format toon——scan 报告可能体积较大是否启用取决于 payload 对 LLM 的实际价值。Phase 2可选若未来要在 Robot 模式中支持 TOON必须要求显式 opt-in如显式--format toon并确保 Hook 模式继续忽略任何环境变量覆盖。这样既给了希望省 Token 的 Agent 一条出路又不破坏默认契约。格式与环境变量的优先级设计对 CLI 专有命令非 Hook 模式RESEARCH_FINDINGS 提出了如下优先级从高到低显式--format ...参数DCG_OUTPUT_FORMAT新增推荐或沿用现有DCG_FORMATTOON_DEFAULT_FORMAT跨工具共享约定命令自身默认值通常是pretty。对 Hook 协议与 Robot 模式Hook 协议无论环境变量如何始终 JSON / JSONLRobot 模式默认 JSON无视环境变量。从当前代码看--format与DCG_FORMAT的结合已经在多数子命令上实现——例如dcg test、dcg packs、dcg config、dcg doctor、dcg explain、dcg simulate、dcg corpus、dcg suggest-allowlist的参数都声明了env DCG_FORMATclap 会以环境变量作为默认值、显式参数覆盖之。--format是命令级专属的每个子命令只接受自己的一组取值传入未识别值会直接报用法错误退出码 2DCG_FORMAT只对有--format标志的命令生效对没有该标志的命令静默忽略。另外有一个细节除dcg scan外sarif在所有命令上都是 JSON 的别名dcg test与dcg packs的枚举中均有#[value(alias sarif)]这样全局设置DCG_FORMATsarif时dcg scan产出真正的 SARIF 报告其余命令则优雅降级为结构化 JSON 而非报错。而--robot会无视--format强制输出 JSON。DCG_OUTPUT_FORMAT/TOON_DEFAULT_FORMAT属于规划中的建议项尚未在源码中出现属于“提案”性质读者可按需自行评估。实现方案crate 化编码杜绝 subprocessRESEARCH_FINDINGS 与 TOON_INTEGRATION_BRIEF 一致强调必须直接依赖toon_rustcrate绝不通过子进程调用 Node.js 的toonCLI /toon-format/cli。原因很实际子进程方案引入运行时依赖、IO 开销与二进制分发问题而纯 crate 方案零外部进程、零网络、可静态链接对 dcg 这种“要在 Agent 每次命令评估时被高频调用”的守护进程尤为重要。依赖声明规划文档给出两种声明方式开发期用本地路径、发布期切 git 依赖# 本地开发路径 toon_rust { path ../toon_rust } # 或发布用 git 依赖 toon_rust { git https://github.com/Dicklesworthstone/toon_rust }实际仓库已经演进了一步包名toon-rust在 0.1.3 之后被改名为trucrate 库名toon当前 Cargo.toml 中声明的是tru 0.2.2详见 docs/planning/UPGRADE_LOG.md 的迁移记录。编码 API 也从旧版的toon_rust::encode(json, None).expect(...)可失败变为新版的toon::encode(json, None)不可失败直接返回String。编码辅助函数TOON_INTEGRATION_BRIEF 给出的辅助函数设计如下——它接受任意serde::Serialize值先序列化为serde_json::Value再交给toon_rust::encodepub fn encode_toonT: serde::Serialize(value: T) - ResultString, anyhow::Error { let json serde_json::to_value(value)?; Ok(toon_rust::encode(json, None)) }随后在每个支持--format toon的命令中复用与 JSON 完全相同的 payload 结构体编码后打印到 stdout。这保证 TOON 与 JSON 承载同一份决策数据只是编码不同。源码中的真实实现在 src/cli.rs 中dcg test的实际输出分支与规划完全吻合match format { TestFormat::Json { println!({}, serde_json::to_string_pretty(output).unwrap()); } TestFormat::Toon { let json serde_json::to_value(output).expect(TestOutput should serialize); let encoded toon::encode(json, None); println!({encoded}); } TestFormat::Pretty unreachable!(handled above), }TestFormat::is_structured()将Json与Toon同视为结构化格式TestFormat枚举上还有#[value(alias text)]与#[value(alias sarif)]别名与 README 输出格式表的描述一致。dcg test的 payload 形状TOON 与 JSON 共享同一 schemadcg test的结构化输出由 src/cli.rs 的TestOutput定义字段包括schema_version当前为 1、dcg_version来自env!(CARGO_PKG_VERSION)、robot_mode、command、decisionallow/deny/ask/warn/log/indeterminate、可选的mode、rule_id、pack_id、pattern_name、reason、explanation、sourceconfig_override/pack/heredoc_ast等、matched_span、severitycritical/high/medium/low、allowlist、agent以及仅在“全方言评估并拒绝”时出现的dialect_divergence。可选字段统一用#[serde(skip_serializing_if Option::is_none)]省略保持 payload 精简。TOON_INTEGRATION_BRIEF 给出的两个 fixture 就是 TOON 输出的 JSON 等价物二者字段完全一致允许示例git status{ schema_version: 1, dcg_version: X.Y.Z, robot_mode: false, command: git status, decision: allow, agent: { detected: unknown, trust_level: medium, detection_method: none } }拒绝示例rm -rf /{ schema_version: 1, dcg_version: X.Y.Z, robot_mode: false, command: rm -rf /, decision: deny, rule_id: core.filesystem:rm-rf-root, pack_id: core.filesystem, pattern_name: rm-rf-root, reason: Refusing to remove root directory, source: pack, severity: critical, agent: { detected: unknown, trust_level: medium, detection_method: none } }TOON 输出就是对同一 payload 执行toon::encode(json, None)的结果。由于TestOutput实际还包含mode、explanation、matched_span、allowlist、dialect_divergence等可空字段命中时才出现真实输出会比上述最小示例更丰富但字段名与语义完全一致。测试设计验证契约不被破坏TOON_INTEGRATION_BRIEF 的测试计划分为三层源码中已经落地了大部分1. 单元测试——格式优先级验证 CLI 专有命令上--formatDCG_OUTPUT_FORMAT或DCG_FORMATTOON_DEFAULT_FORMAT 命令默认值。目前代码中--format与DCG_FORMAT的结合已通过 clap 的env机制实现DCG_OUTPUT_FORMAT与TOON_DEFAULT_FORMAT尚属规划项。2. 单元测试——Hook 输出稳定性在DCG_ROBOT1环境下Hook 输出形状仍保持 camelCase JSON。这与 src/output/mod.rs 中“显式--robot始终优先”的布尔解析逻辑呼应——Hook 模式是协议区不受格式环境变量干扰。3. 单元测试——TOON 编码往返源码 src/cli.rs 的test_toon_roundtrip_for_test_output_payload已经实现构造一个 deny 语义的TestOutputpayloadrm -rf /、rule_id core.filesystem:rm-rf-root、severity critical序列化为 JSONtoon::encode编码再用toon::try_decode解码回serde_json::Value做规范性比较。测试还专门处理了一个真实约束tru0.2.2 在解码往返中会把整数规范化为 f64整数/浮点差异在 decode 时有损因此比较前先对两侧做canon归一化数字统一转 f64再断言相等。CLI 解析测试test_cli_parse_test_with_format_toon则验证dcg test --format toon rm -rf /tmp能被正确解析为TestFormat::Toon。4. E2E 脚本规划避免副作用只用dcg test# 1. 以 JSON 测试一个危险命令 dcg test rm -rf / --format json # 2. 以 TOON 测试同一命令 dcg test rm -rf / --format toon # 3. 将 TOON 解码回 JSON 并比较 payload 等价性实战用法在 Agent / CI 管线中消费 TOONTOON 的定位是“agent-to-agent / tool pipeline”的高效数据通道。在 README.md 中dcg test的三种输出格式被如此定义pretty人类可读输出含命令上下文、命中规则信息与建议json面向脚本/CI 的结构化 payload含schema_version、dcg_version、command、decision及命中时的 rule/pack 字段、allowlist/agent 上下文toon与json同一 payload 的 Token 高效编码适合 Agent 之间的工具管线。典型用法与 JSON 完全平行只是换一个格式名# 允许场景 dcg test git status --format toon # 拒绝场景 dcg test rm -rf / --format toon # 通过 DCG_FORMAT 环境变量设定默认格式 DCG_FORMATtoon dcg test git status由于--format是命令级专属toon目前只在dcg test上生效dcg scan若要支持需要走 Phase 1 的可选项。CI 集成可以沿用 JSON 的失败快速判定模式例如dcg test --format json rm -rf / /tmp/dcg.json jq -e .decision allow /tmp/dcg.json当 Agent 管线需要反复读取决策时把json换成toon即可在保持相同字段语义的前提下降低上下文占用。注意保持 stdout 纯数据、stderr 只放诊断信息的原则Robot 模式下 stderr 按契约完全静默。命名与边界提醒TOON_INTEGRATION_BRIEF 最后给出几条易混淆点tru是toon_rust的 CLI 二进制名不要与 Unix 的tr或 Node 的toon混淆本仓库不应 shell out 调用外部工具一律使用 cratetru 0.2.2库名为toon保持 stdout 纯数据输出stderr 仅承载诊断信息Robot 模式下按契约静默。小结从 RESEARCH_FINDINGS 的规划到当前源码TOON 集成遵循一条清晰的主线在 Hook 协议与 Robot 模式这两条机器契约保持 JSON 不动摇的前提下为 CLI 专有的结构化输出dcg test增加 TOON 编码用 crate 内联编码替代子进程调用并以“同 payload、双编码”的方式保证 TOON 与 JSON 语义完全等价。对 LLM 驱动的 Agent 工作流而言dcg test --format toon是在不牺牲决策信息完整性的前提下压缩 Token 成本的直接手段而对集成方而言Hook 协议与 Robot 模式的 JSON 契约仍然是最稳定的集成锚点。进一步阅读TOON 方案的详细计划与 sample payload 见 docs/planning/TOON_INTEGRATION_BRIEF.mddcg 机器接口的整体设计见 docs/adr-002-robot-mode-api.md输出格式与DCG_FORMAT的完整对照表见 README.mdtrucrate 的迁移记录见 docs/planning/UPGRADE_LOG.md。【免费下载链接】destructive_command_guardThe Destructive Command Guard (dcg) is for blocking dangerous git and shell commands from being executed by agents.项目地址: https://gitcode.com/GitHub_Trending/de/destructive_command_guard创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考