harness - 自定义命令
2026年7月4日 下午1:09:28
自定义命令是一种把"常用提示词模板"固化为可复用指令的能力(兼容 Claude Code 的 Custom Commands 规范)。命令本质是带参数占位的 Markdown 模板,执行时替换参数后作为 Agent 任务运行。
1、命令定义文件
命令以 Markdown 文件定义,放在 {harnessHome}/commands/ 目录下:YAML Front Matter 描述元数据,正文即提示词模板。
---
description: 生成一条 git 提交信息
argument-hint: [message]
model: deepseek-v4-flash
---
请根据当前暂存区的变更,生成一条简洁的提交信息。
补充说明:$ARGUMENTS
元数据字段:
| 字段 | 描述 |
|---|---|
description | 命令描述 |
argument-hint | 参数提示(用于补全提示) |
model | 指定执行该命令的模型(可选) |
2、参数占位符
模板正文支持两种占位符(兼容 Claude Code):
$1、$2、$3…:按位置取单个参数。$ARGUMENTS:把所有参数拼接为一个字符串。
替换顺序为"先位置参数、后 $ARGUMENTS"。例如模板 部署 $1 到 $2 环境($ARGUMENTS),传入 ["web", "prod"] 后得到 部署 web 到 prod 环境(web prod)。
3、命名空间(子目录)
commands/ 支持子目录递归扫描,子目录会成为命令的命名空间(用冒号分隔)。例如:
commands/deploy/staging.md→ 命令名deploy:stagingcommands/git/commit.md→ 命令名git:commit
4、命令接口(Command)
命令系统由 Command 接口、CommandRegistry 注册中心和 CommandContext 执行上下文共同构成。Command 接口定义:
public interface Command {
String name(); // 命令名(不含 / 前缀)
String description(); // 命令描述
String[] examples(); // 示例
default String model() { return null; } // 使用模型(可选)
default boolean cliOnly() { return false; } // 是否仅 CLI 可用
void execute(CommandContext ctx) throws Exception; // 执行命令
}
CommandContext 提供命令执行所需的环境信息:
| 方法 | 描述 |
|---|---|
getSession() | 获取当前会话 |
getEngine() | 获取 Agent 运行时 |
getRawInput() | 获取用户原始输入 |
getCommandName() | 获取命令名(不含 / 前缀) |
getArgs() | 获取命令参数列表 |
argAt(index) | 按索引获取参数,越界返回 null |
argCount() | 参数数量 |
getArgsJoined() | 全部参数拼接为单个字符串 |
println(text) | 输出一行文本(不同端有不同实现) |
supportsAnsi() | 是否支持 ANSI 颜色(CLI=true,Web=false) |
color(text) | ANSI 友好的颜色输出 |
runAgentTask(prompt, model) | 运行 Agent 任务(CLI 阻塞,Web 返回 Flux 流) |
5、注册与查找
命令由 CommandRegistry 管理,可从目录加载,也可用代码注册:
CommandRegistry registry = engine.getCommandRegistry();
// 从目录加载(递归扫描 .md)
registry.load(Paths.get(engine.getWorkspace(), engine.getHarnessCommands()));
// 注册 Java 命令(实现 Command 接口)
registry.register(new MyCommand());
// 查找与列举
Command cmd = registry.find("git:commit");
List<Command> all = registry.all(); // 排序后的全部命令
List<String> names = registry.names(); // 命令名列表(用于 Tab 补全)
同名命令只会注册一次,重复注册会被忽略并打印告警。
6、MarkdownCommand 执行流程
MarkdownCommand 是基于 Markdown 模板的命令实现,执行流程如下:
- 解析 Markdown 文件,提取 Front Matter 元数据和正文模板。
- 调用
getResolvedPrompt(args)将参数占位符替换为实际值。 - 调用
ctx.runAgentTask(prompt, model)将替换后的文本作为 Agent 任务执行。
7、多端支持
命令系统设计为 CLI 和 Web 共用:
- CLI 端:
runAgentTask阻塞等待返回;supportsAnsi返回true,支持彩色输出。 - Web 端:
runAgentTask返回 Flux 流;supportsAnsi返回false,自动去除 ANSI 转义序列。 - 标记为
cliOnly()=true的命令在 Web 端不展示也不执行。