dcg 统一 Robot Mode API 设计解析:为 AI Agent 打造稳定、可解析的命令行接口
2026/9/17 18:37:03 网站建设 项目流程

dcg 统一 Robot Mode API 设计解析:为 AI 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_guard

dcg(Destructive Command Guard)以 hook 形式嵌入 Claude Code、Gemini CLI 等 AI 编码代理,拦截危险的 git 与 shell 命令。本文基于仓库 docs/adr-002-robot-mode-api.md 展开,剖析其提出的统一Robot Mode(机器人模式)API设计:全局--robot标志、标准化退出码、统一OutputFormat枚举与纯 JSON 输出契约。读完你将掌握 dcg 为机器消费设计的完整接口约定、各子命令在 robot 模式下的行为差异,以及如何在自己的脚本或 Agent 工作流中可靠地消费 dcg 的输出。

背景:Agent 集成为何需要统一接口

dcg 作为 hook 被 AI 编码代理调用时,代理需要以编程方式解析 dcg 的输出。但在 ADR-002 提出之前,CLI 存在一系列不一致,使集成变得复杂:

  1. 格式标志不统一:不同命令混用-f-F-o--json布尔标志;
  2. 默认值不统一:部分命令默认pretty,部分默认jsontext
  3. 缺少统一机器人模式:每条命令都要单独配置机器输出;
  4. 退出码不统一:各命令没有文档化的标准退出码;
  5. stderr 行为混杂:即使在 CI 环境,某些命令也会输出装饰性内容;
  6. JSON 字段命名不一致:hook 输出使用 camelCase(协议要求),其他输出使用 snake_case。

Agent 的核心需求

AI 代理需要的是:

  • stdout 上是纯 JSON(无 ANSI 码、无装饰文本);
  • stderr保持静默(至少不干扰 stdout 解析);
  • 可预测的退出码用于决策;
  • 稳定的 JSON schema,版本升级不破坏;
  • 单一标志即可在所有命令上启用“机器模式”。

ADR-002 的决策正是围绕这六点展开,并已在仓库中落地实现。

全局--robot标志:一份配置、处处生效

ADR-002 设计了一个全局--robot布尔标志,并支持通过环境变量DCG_ROBOT启用。在 src/cli.rs 中可以看到它的实际定义:

/// Enable robot/machine mode for AI agent integration /// /// When enabled: /// - All output is JSON on stdout /// - stderr is completely silent (no rich output, no human messages) /// - Exit codes follow standardized values (see docs/adr-002-robot-mode-api.md) /// - Human-friendly decorations are suppressed #[arg(long, global = true)] pub robot: bool,

注意实现细节:ADR 草案中曾设计env = "DCG_ROBOT"直接挂在 clap 参数上,而落地实现将其移到了输出层统一处理。在 src/output/mod.rs 的robot_mode_enabled中:

pub fn robot_mode_enabled(explicit_robot_flag: bool) -> bool { explicit_robot_flag || env_flag_enabled("DCG_ROBOT") }

关键语义:显式--robot始终优先DCG_ROBOT环境变量遵循与其他输出标志一致的布尔解析——0falsenonoff及空值都视为未启用,而非“只要设置了就算启用”。env_flag_value_enabled的实现验证了这一点(src/output/mod.rs 中test_env_flag_value_enabled_boolean_semantics测试覆盖了这些取值)。

在 src/main.rs 中,robot 模式被纳入“强制纯文本输出”的判定:

let robot_mode = destructive_command_guard::output::robot_mode_enabled(cli.robot); let force_plain_output = cli.legacy_output || cli.no_color || robot_mode;

即 robot 模式下自动禁用颜色渲染,并同时禁用建议(suggestion)输出(init_suggestions(!cli.no_suggestions && !robot_mode))。

启用方式

# 方式一:命令行标志 dcg --robot test "rm -rf /" # 方式二:环境变量(支持 true/false 语义) DCG_ROBOT=1 dcg test "rm -rf /"

行为对照表

维度普通模式Robot 模式
stdoutJSON 或 pretty始终 JSON
stderrRich 彩色输出静默
退出码各命令各异标准化
ANSI 码视 TTY从不输出
进度指示显示隐藏
建议(suggestions)显示仅在 JSON 中
警告输出到 stderr编码进 JSON

标准化退出码:让$?直接可决策

ADR-002 提议创建独立的退出码模块。仓库中 src/exit_codes.rs 已完整落地,且比 ADR 草案增加了两个实战常量:

常量含义
0EXIT_SUCCESS成功 / 放行(allowed、passed、healthy)
1EXIT_DENIED命令被安全规则拒绝/拦截
2EXIT_WARNING警告(配合--fail-on warn
3EXIT_CONFIG_ERROR配置错误(配置文件无效、缺少必需配置)
4EXIT_PARSE_ERROR解析/输入错误(无效 JSON、畸形命令)
5EXIT_IO_ERRORIO 错误(文件未找到、权限拒绝、网络错误)
141EXIT_BROKEN_PIPEstdout/stderr 读取方提前离开(EPIPE),是干净退出而非信号死亡
2EXIT_HOOK_BLOCK仅 hook 模式:deny/ask/indeterminate 裁决无法写入 stdout 时,以退出码承载拦截

EXIT_BROKEN_PIPE(141)的由来

EXIT_BROKEN_PIPE对应128 + SIGPIPE(13),让dcg … | head -1set -o pipefail下与cat … | head -1表现完全一致。dcg 通过 broken-pipe panic 兜底(issue #389)走干净的process::exit到达该码——永远不会因信号死亡,因此无 core dump、无SIGABRT,且SIGPIPE本身保持忽略(详见output::emit的注释:hook 二进制不能在 stderr 写入时死亡,因为其 stdout 上的裁决可能仍有读者)。

EXIT_HOOK_BLOCK(2)与EXIT_WARNING(2)的共存

两个常量数值相同(都是 2),但永远不会出现在同一进程中

  • EXIT_WARNING属于 robot 模式子命令(如dcg --robot test --fail-on warn);
  • EXIT_HOOK_BLOCK属于 hook 模式(无子命令)。当 stdout 写入本身失败(EPIPE,宿主在裁决写入前关闭了管道)时,退出 0 且无 JSON 会被宿主解读为“放行”,从而把 deny 变成 allow——这是不可接受的,因此拦截结果改由退出码 2 承载,理由写到 stderr。每个 hook 协议的“裁决无法送达时的退出码”映射表定义在HookProtocol::undeliverable_block_exit_code上。

各协议对“退出 2 + 空 stdout”的解读(来自 docs/agents.md):

协议效果
Claude Code 及兼容宿主(Posit Assistant、Augment)拦截;stderr 作为理由反馈给模型
Gemini CLI拦截(退出 2 即其阻断错误)
Copilot CLI拦截(preToolUse钩子退出 2 拒绝调用)
Crush拦截;stderr 即理由
Grok拦截(退出 2 是文档化的显式拒绝)
Codex CLI、Hermes、Antigravity(agy记为 hook 失败后 fail-open——与退出 0 无 JSON 效果相同,但可见

hook 模式绝不会因其他原因退出 2,也从不退出 141(hook 模式的每次写入都容忍关闭的管道)。

辅助 API

exit_codes模块还提供to_exit_code(i32) -> ExitCode(供main()返回)、exit_with(code) -> !(便捷退出包装)以及ToExitCodetrait(将求值结果转换为退出码)。模块内测试(exit_codes_are_distinctexit_codes_are_valid_rangesuccess_is_zero等)保证这些常量互不冲突且落在 0–255 合法区间。

统一OutputFormat枚举:消灭各自为政的格式类型

ADR-002 设计了跨命令共享的OutputFormat枚举,落地实现位于 src/cli.rs:

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, clap::ValueEnum, serde::Serialize)] #[serde(rename_all = "lowercase")] pub enum OutputFormat { /// Human-readable colored output (default for interactive use) #[default] #[value(alias = "text", alias = "human")] Pretty, /// Structured JSON output (for agents and scripting) #[value(alias = "sarif", alias = "structured")] Json, /// JSON Lines format (one JSON object per line, for streaming) #[value(name = "jsonl")] Jsonl, /// Compact single-line output (for specific commands) Compact, }

该枚举提供两个实用谓词:

  • is_json()JsonJsonl均为真——用于判断输出是否可被 JSON 解析器消费;
  • is_human_readable()PrettyCompact均为真。

Robot 模式下的格式默认值:当--robot启用时,格式强制默认Json,无论命令自身的默认值是什么。因此下面两条命令等价:

dcg --robot test "cmd" dcg --robot --format json test "cmd"

可用的格式别名

  • pretty/text/human—— 人类可读(无--robot时的默认);
  • json/sarif/structured—— JSON 输出(--robot时的默认);
  • jsonl—— JSON Lines(每行一个对象,适合流式处理);
  • compact—— 紧凑单行输出(用于explain等特定命令)。

从源码结构看,除统一枚举外,各子命令仍保留了自己的强类型格式枚举(TestFormatCorpusFormatStatsFormatClassifyFormatConfigFormatPacksFormatDoctorFormat等),它们大多以Pretty/Json二元结构为主,并通过DCG_FORMAT环境变量统一驱动默认值——这印证了 ADR 中“先加统一枚举、逐步淘汰零散类型”的迁移思路。

Robot 模式 JSON 输出:稳定、可解析的响应契约

ADR-002 设想的响应信封包含dcg_versionschema_versioncommand_namesuccessdatametadata等字段。实际落地为每个子命令输出稳定的 JSON,例如dcg test的 deny 结果(tests/golden/robot/deny_filesystem.json):

{ "schema_version": 1, "dcg_version": "<DYNAMIC_VERSION>", "robot_mode": true, "command": "rm -rf /", "decision": "deny", "mode": "deny", "rule_id": "core.filesystem:rm-rf-root-home", "pack_id": "core.filesystem", "pattern_name": "rm-rf-root-home", "reason": "rm -rf on root or home paths is EXTREMELY DANGEROUS. ...", "explanation": "This command would recursively delete files starting from the root filesystem (/) ...", "source": "pack", "matched_span": [3, 6], "severity": "critical", "agent": { "detected": "unknown", "trust_level": "medium", "detection_method": "none" } }

allow 结果的字段更精简(tests/golden/robot/allow_git_status.json):

{ "schema_version": 1, "dcg_version": "0.4.1", "robot_mode": true, "command": "git status", "decision": "allow", "agent": { "detected": "unknown", "trust_level": "medium", "detection_method": "none" } }

Agent 元数据字段

输出中的agent对象承载代理检测信息:detected(代理标识,如claude-code)、trust_levelhigh/medium/low,默认medium)、detection_method(如environment_variable)。检测优先级为:显式--agent标志 > 环境变量 > 父进程检查 > unknown(详见 docs/agents.md)。trust_level建议性标签,本身不改变规则触发,行为差异全部来自disabled_packsextra_packsadditional_allowlistdisabled_allowlist等配置项。

Golden 文件测试保障 schema 稳定

仓库用 golden 文件锁定 robot 模式 JSON,路径 tests/golden/robot/ 下含allow_git_status.jsonallow_simple.jsondeny_filesystem.jsondeny_git_force_push.jsondeny_git_reset.json五个快照。配合dcg_version字段支持版本占位符(如<DYNAMIC_VERSION>),测试可在版本更新时动态替换,从而验证“schema 不因版本而破坏”这一 ADR 目标。

Hook 模式 vs Robot 模式:两条契约的分工

这是理解 dcg 接口的关键——hook 模式与 robot 模式是两套不同的退出码/输出契约(docs/agents.md):

  • Hook 模式(无子命令时默认):裁决写在 stdout JSON 上,allow 时为空 stdout;进程退出 0,无论命令是允许、警告、送审还是拒绝。仅当阻断裁决无法送达时退出 2(EXIT_HOOK_BLOCK)。Codex CLI 使用严格 hook 解析,dcg 输出最小化的hookSpecificOutput拒绝负载并退出 0。
  • Robot 模式(带子命令,如dcg --robot test):deny 时退出 1(便于脚本直接判断$?),stdout 纯 JSON,stderr 静默。

stdout / stderr 分离原则

dcg 将面向 Agent 的输出与面向人类的输出放在不同流上,这是 rich 格式化兼容性的根基:

用途Hook 模式内容Robot 模式内容
stdoutAgent 与脚本解析拒绝时为协议 JSON,放行为空仅 JSON
stderr人类可见诊断Rich 或纯文本警告框静默

Rich 输出纯属展示用途,绝不允许被 Agent 解析,也绝不允许写入 stdout。Unicode 边框、颜色、高亮命令、建议面板全部归属 stderr。

实战:在 Agent 工作流中消费 robot 模式

场景一:脚本按退出码决策

#!/bin/bash # Script for AI agent to check commands before execution check_command() { local cmd="$1" local result # Use robot mode for predictable output result=$(dcg --robot test "$cmd" 2>/dev/null) local exit_code=$? if [ $exit_code -eq 0 ]; then echo "Command allowed: $cmd" return 0 elif [ $exit_code -eq 1 ]; then echo "Command BLOCKED: $cmd" echo "Reason: $(echo "$result" | jq -r '.reason')" return 1 else echo "Error checking command (exit code: $exit_code)" return $exit_code fi } # Usage check_command "git status" # Allowed check_command "rm -rf /" # Blocked

场景二:包装器同时保留两条流

# Hook integration: preserve both streams. dcg < hook-input.json >hook-stdout.json 2>human-warning.txt # Scripting integration: use robot mode and parse stdout only. dcg --robot test "rm -rf /" >decision.json 2>/dev/null

对于 Codex 和 Claude 兼容的 hook 集成:stdout 非空时解析 stdout;stdout 为空且退出 0 视为 allow。Codex 的拒绝负载是最小化的,且有意省略 dcg 专属元数据。

场景三:作为其他工具的底层调用

从源码结构看,dcg 自身的集成组件也依赖 robot 模式:OMP 扩展通过dcg --robot test --stdin --agent omp --format json做每命令预检(见 docs/agents.md),并以--dialect posix指定 shell 方言。这说明 robot 模式是 dcg 生态内部组件的通用机器接口,而不仅是外部脚本的便利开关。

Rich 输出降级控制:机器人环境的兜底保障

--robot外,以下任一条件都会让 dcg 回退到纯文本/静默输出(src/output/mod.rs 的should_use_rich_output_with_env):

控制项效果
DCG_NO_RICH=1禁用 rich 格式化,保持正常命令行为
--legacy-output/DCG_LEGACY_OUTPUT=1强制 legacy/纯文本渲染路径
NO_COLOR=1/DCG_NO_COLOR=1禁用彩色输出
TERM=dumb使用 dumb 终端安全输出
CI=1CI 下抑制 rich 交互格式化
stdout 非 TTY偏好纯文本,利于管道
--robot/DCG_ROBOT=1机器可读 stdout + stderr 静默

判定的完整顺序是:显式强制纯文本 →DCG_NO_RICH/NO_COLOR/DCG_NO_COLORCI环境变量 → stdout 是否为 TTY →TERM=dumb。这些开关共同保证:无论 Agent 宿主环境如何(CI、管道、无 TTY 子进程),stdout 始终可安全解析。

迁移策略与影响评估

ADR-002 规划的迁移分三个阶段推进:

  1. Phase 1(非破坏):新增--robot标志与DCG_ROBOT环境变量、新增exit_codes模块、新增OutputFormat枚举、在 AGENTS.md 中记录 robot 模式——均已落地;
  2. Phase 2(弃用期):弃用命令各自的--json布尔标志与不一致的格式枚举;旧标志继续工作并发出弃用警告;
  3. Phase 3(未来):在下一个大版本移除已弃用标志;考虑 gRPC/MCP 原生协议(注:仓库已提供dcg mcp-server子命令,以 stdio 方式暴露check_commandscan_fileexplain_pattern工具,是这一方向的先行实现)。

影响总结

正面:单一--robot标志即可配置一切,Agent 集成更简单;行为可预测;JSON schema 版本化防止破坏性变更;golden 文件测试可验证 robot 输出;Agent 开发者有集中、清晰的文档。

负面:CLI 新增一个全局标志;现有使用--json的脚本最终需要更新;需要同时维护人类与机器两条输出路径。

中性:完全向后兼容,所有既有行为继续工作;robot 模式是 opt-in,默认仍是人类友好的 pretty 输出。

最佳实践清单

  1. 脚本集成一律使用 robot 模式:需要稳定可解析输出时,用--robot而非命令各自的--format json
  2. 简单判定只看退出码:allow/deny 直接读$?(0/1),无需解析 JSON;需要理由再jq -r '.reason'
  3. 永远丢弃 stderr:robot 模式下 stderr 应为空;脚本中建议2>/dev/null防御性隔离;
  4. 不要解析 rich 输出:人类可读的装饰内容属于 stderr,只用于展示;
  5. CI 中审计 Agent 行为:用--format json审计哪些 Agent 在访问代码库(配合agent元数据字段);
  6. 检查schema_version:消费方应对输出中的schema_version做校验,防止 schema 变更时静默破坏;
  7. hook 集成遵循协议语义:hook 模式退出 0 携带裁决 JSON,空 stdout + 0 = allow;阻断裁决无法送达时退出 2,切勿把退出 2 误读为“警告”。

延伸阅读

  • 设计原文:docs/adr-002-robot-mode-api.md
  • Agent 配置与集成指南:docs/agents.md
  • 退出码常量实现:src/exit_codes.rs
  • --robot标志与OutputFormat枚举:src/cli.rs
  • robot 模式启用判定:src/output/mod.rs
  • Robot 模式 golden 输出快照:tests/golden/robot/
  • 相关测试:tests/robot_mode.rs、tests/golden_json_tests.rs
  • 相邻设计:MCP 服务器集成见 docs/pi-integration.md 与dcg mcp-server子命令

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询