news 2026/9/13 13:02:43

Archon 变量替换完全指南:Workflow 与命令中的占位符系统详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Archon 变量替换完全指南:Workflow 与命令中的占位符系统详解

Archon 变量替换完全指南:Workflow 与命令中的占位符系统详解

【免费下载链接】ArchonThe first open-source harness builder for AI coding. Make AI coding deterministic and repeatable.项目地址: https://gitcode.com/GitHub_Trending/archon3/Archon

导读

Archon 在命令文件(command files)与工作流(workflow)提示词中通过$VARIABLE形式的占位符在执行时完成文本替换,这是把用户输入、运行上下文、上游节点输出与后续 AI 步骤衔接起来的核心机制。本文以官方 Variable Substitution Reference 为骨架,结合仓库源码梳理全部内置变量、替换发生的时机与位置、bash:/script:节点特有的注入防护与环境变量通道,以及 DAG 模式下的节点输出引用($nodeId.output)与 Artifact 指针契约。读完后你将能准确设计可安全传递用户输入、跨节点传递结构化数据的工作流模板,并规避静默失效与 Shell 注入两类常见陷阱。

变量总览

所有变量都遵守「执行时替换」的同一原则:它们在节点真正运行前被解析,解析结果取决于当次运行的触发消息、git 状态与配置。

变量作用域说明
$ARGUMENTS所有模式触发工作流的用户原始消息
$USER_MESSAGE所有模式$ARGUMENTS等价,二者都解析为用户消息
$WORKFLOW_ID所有模式唯一的工作流运行 ID(用于追踪与日志关联)
$ARTIFACTS_DIR所有模式本次运行预先创建好的产物目录,节点输出请写在这里
$BASE_BRANCH所有模式基础分支名。优先从 git 自动检测,或由配置worktree.baseBranch指定;被引用但无法解析时直接抛错
$DOCS_DIR所有模式文档目录(配置docs.path,默认docs/)。永不抛错
$CONTEXT所有模式GitHub issue/PR 上下文(平台可用时才有);不可用时为空字符串
$EXTERNAL_CONTEXT所有模式$CONTEXT的别名
$ISSUE_CONTEXT所有模式$CONTEXT的别名
$LOOP_USER_INPUT循环 / loop_group 提示词交互式循环门(/workflow approve <id> <text>)中的用户反馈。只在恢复后的第一次迭代填充,其余位置均为空字符串
$LOOP_PREV_OUTPUT循环提示词上一轮迭代清理后的输出(已剥掉 completion 标签)。第 1 轮为空。是fresh_context: true循环获知「上一轮做了什么」的关键工具
$LOOP_PREV.<nodeId>.output[.field]loop_group 正文提示词与when:条件上一轮迭代中某个正文节点的输出。第 1 轮为空。字段访问遵循下面的严格契约(真正缺失的先前输出→'');在正文when:中它是类型化条件引用而非文本替换
$REJECTION_REASON旧式approval.on_reject提示词来自/workflow reject <id> <reason>的评审反馈。其他位置均为空字符串;新式门读取$gate.output.text
$nodeId.output仅 DAG某个已完成的上游节点的完整文本输出;未知或被跳过的生产者 →''
$nodeId.output.field仅 DAGJSON 字段访问——严格模式:字段无法解析会使消费节点失败(见下文)

仓库完整版参考文档还额外补充了两个引擎级变量,见 reference/variables.md:

  • $STATE_DIR:预创建的跨运行状态目录(~/.archon/workspaces/<project>/state/),按项目(而非按运行)共享,供相互协作的工作流共享记忆(如去重账本、last processed游标)。它在仓库与 worktree 之外,worktree 拆除后依然存活,也永不进入git status。与$BASE_BRANCH一样,被引用但无法解析时抛错而非替换为空串。引擎对其不做任何锁,跨运行并发写需自行按$STATE_DIR/<name>/命名空间隔离。
  • $ADOPTED_RUN_DIR(源码 executor-shared.ts):仅在显式--adopt <run-id>采纳前序运行时可用,用于按引用读取先前运行的产物目录,未启用采纳时引用会抛错。

变量在哪些位置被替换

  • 命令文件.archon/commands/*.md)——核心集合($ARGUMENTS/$USER_MESSAGE$WORKFLOW_ID$ARTIFACTS_DIR$BASE_BRANCH$DOCS_DIR$CONTEXT家族),以及当该命令作为 DAG 节点运行时额外的$nodeId.output[.field]。被loop.commandloop_group正文引用的命令文件,与内联循环提示词一样获得填充好的循环变量;普通 DAG 命令节点对循环/拒绝类变量拿到''$REJECTION_REASON只在approval.on_reject提示词中填充。
  • 内联prompt:字段——DAG 提示词节点、循环提示词、loop_group 正文提示词。
  • bash:脚本——特殊:用户可控变量($ARGUMENTS$USER_MESSAGE$LOOP_USER_INPUT$LOOP_PREV_OUTPUT$REJECTION_REASON$CONTEXT做文本替换(Shell 注入防护),而是作为环境变量传入:ARGUMENTSUSER_MESSAGELOOP_USER_INPUTLOOP_PREV_OUTPUTREJECTION_REASONCONTEXT,外加ARTIFACTS_DIRLOG_DIRBASE_BRANCH——用"$ARGUMENTS"按普通 Shell 环境变量读取即可。$nodeId.output引用被替换且自动加 Shell 引号;超过 32KB 的值会溢出写入文件并替换为$(cat <path>)
  • script:正文——与bash:相同:用户可控变量做文本替换(注入防护,见 issue #2115),以环境变量形式到达——ARGUMENTSUSER_MESSAGELOOP_USER_INPUTLOOP_PREV_OUTPUTREJECTION_REASONCONTEXT(外加EXTERNAL_CONTEXT/ISSUE_CONTEXT),以及ARTIFACTS_DIRLOG_DIRBASE_BRANCH和受管的项目级环境变量——通过process.env.ARGUMENTS(bun)或os.environ['ARGUMENTS'](uv/python)读取。源码中留在正文里的字面$ARGUMENTS/$USER_MESSAGE/$CONTEXT不再解析,并会记录一条「单版本迁移」警告。$nodeId.output值仍以原始文本替换(不加 Shell 引号)。

这一「引擎变量文本替换 + 用户可控变量环境变量传递」的双通道设计,在源码 executor-shared.ts 中可以看到:$WORKFLOW_ID$ARTIFACTS_DIR$STATE_DIR$BASE_BRANCH$DOCS_DIR无条件替换(即便shellSafe开启),而$USER_MESSAGE/$ARGUMENTS/$LOOP_USER_INPUT/$REJECTION_REASON/$LOOP_PREV_OUTPUT只在非 shell 分支替换——这正是为了防止把不可信输入拼进可执行源码。

bash 与 script 节点的安全取值姿势

由于bash:/script:对用户可控变量走环境变量通道,读取方式如下:

# bash 节点:环境变量即参数,正常加引号 echo "用户消息: $ARGUMENTS" mkdir -p "$ARTIFACTS_DIR"
// script 节点(runtime: bun) const args = process.env.ARGUMENTS ?? ''; const base = process.env.BASE_BRANCH ?? '';
# script 节点(runtime: uv) import os args = os.environ.get('ARGUMENTS', '')

$nodeId.output则按节点类型不同处理:bash:自动 Shell 引号(小值内联单引号;>32KB 写入引擎所有的$ARTIFACTS_DIR/.archon/node-output-spills/<node>[.<field>].nodeoutput并替换为$(cat '<path>')),而script:原样嵌入(不引号化)。因此对 script 节点,要把替换值当不可信输入用语言特性解析(如JSON.parse),而不是插进 Shell 语法。

直接赋值有前提const data = $nodeId.output;只有runtime: bun生产者声明了output_format时才安全;JSON 布尔值与 null 不是合法的 Python 字面量,所以runtime: uv的脚本应改用with: { data: "$nodeId.output" }绑定,再从os.environ['INPUTS_DATA']json.loads解析。对任意文本生产者(bash/script 的 stdout 或散文输出)同样建议走环境变量绑定,仅在确认文本含 JSON 时才防御性地解析。不要把$nodeId.output包进String.raw模板字面量——当输出含反引号(AI 生成的 markdown 与output_format载荷中很常见)时会静默破坏。

bash 节点双重引号陷阱

bash:的替换自带引号,再套一层双引号会引入字面单引号,导致条件判断静默失败:

# 错误——小值场景下 $emit.output.status 被注入为 'ok'(单引号), # status="$emit.output.status" 实际变成 status="'ok'",引号变成数据 status="$emit.output.status" [ "$status" = "ok" ] && echo pass # → 静默失败($status 是 'ok',不是 ok) # 正确——保持替换不带引号;Archon 的引号就是引号 status=$emit.output.status # → status='ok' → bash 赋值:ok [ "$status" = "ok" ] && echo pass # → 通过

大输出(>32KB)的替换形态是$(cat '/path')var="$(cat ...)"在 bash 里正确——但作者无法在编写时预知大小,所以规则是无条件的:始终用var=$node.output.field,绝不用var="$node.output.field"。数字与布尔字段以裸值注入(无引号),双引号对它们「碰巧」有效,这让 bug 变得时有时无。

替换顺序

  1. 标准工作流变量($WORKFLOW_ID$ARGUMENTS$ARTIFACTS_DIR$BASE_BRANCH$DOCS_DIR$CONTEXT、循环/拒绝类变量)
  2. 节点输出引用($nodeId.output$nodeId.output.field$LOOP_PREV.*)——仅 DAG 模式

完整版参考文档进一步细分为三步(reference/variables.md):工作流变量 → 上下文变量($CONTEXT家族)→ 节点输出引用;且loop_group正文中$LOOP_PREV.<nodeId>.output引用最先解析(先于$LOOP_USER_INPUT拼接,保证用户文本不会被二次当作工作流引用处理),随后再执行该节点正常的替换流程。

上下文自动追加(Context Auto-Append)

如果提示词模板中完全没有出现$CONTEXT/$EXTERNAL_CONTEXT/$ISSUE_CONTEXT,但上下文确实存在(例如来自 GitHub issue),则该上下文会在---分隔符之后自动追加到提示词末尾。这条规则有两个目的:其一,避免命令显式使用$CONTEXT时上下文被重复发送;其二,在无 issue 上下文时把三个别名替换为空串,避免把字面$CONTEXT文本发给 AI。

转义美元符号

在命令文件中用\$产生字面$(阻止变量替换)。

明确不支持:$1$9位置参数

尽管旧文档曾暗示支持,工作流引擎替换位置参数$1$9——命令文件与提示词只通过$ARGUMENTS/$USER_MESSAGE接收完整消息,不存在按空白拆分成编号槽位的机制(直接命令调用与工作流节点皆如此)。代码库中存在一个遗留的位置替换辅助函数,但未接入执行路径。需要结构化输入时,在提示词内部解析$ARGUMENTS,或用bash:/script:节点处理。

节点输出细节(仅 DAG)

$nodeId.output解析为上游节点的完整文本输出。若节点使用了output_format:(结构化输出),输出是经校验的 JSON 字符串化结果;无output_format的 bash/script 输出则是去掉尾部换行的 stdout;有output_format时 stdout 必须在同一结果契约下被认证为 JSON(见 node-reference.md 的 Result contracts 一节)。loop/loop_group 输出是剥掉完成信号标签后的最终迭代输出。带作者自定approval.decisions的门总是输出 JSON{decision, text},读取其字段用$gate.output.decision$gate.output.text;未自定决策的旧式门保持旧行为——只有capture_response: true时才输出其审批评论,否则为''。未知或被跳过的生产者解析为空串(并记录警告)。

字段访问的严格契约(no-silent-drop)

$nodeId.output.field严格的:要么解析成功,要么让消费节点失败

  • 生产者声明了output_format:模式中已声明的字段解析为其值,若缺失则解析为''(声明为可选);未在模式中声明的字段会使消费者失败(防拼写错误)。
  • 无模式生产者(生产节点未声明output_format):输出必须是包含该键的 JSON 对象——非 JSON 输出、键缺失都会使消费者失败。
  • 生产者被跳过或未决:消费者失败——用when:或宽松的trigger_rule保护引用。

取值规则:字符串原样通过;数字/布尔字符串化;对象/数组 JSON 字符串化。

workflow:子运行结果,这些字段规则使用子运行returns:节点的模式——字段名随值一同传递并能在冷恢复后存活;调用方不能增删契约。include:别名在展平后直接使用其选中的生产者。

源码中对应注释亦印证了「未知输入名 THROWS,而非替换''」的严格性——拼错的输入静默变空比加载可见的错误更糟(executor-shared.ts)。

实战示例

nodes: - id: classify command: classify-issue output_format: type: object properties: type: { type: string, enum: [BUG, FEATURE] } required: [type] - id: fix prompt: | The issue was classified as: $classify.output.type Full classification: $classify.output User's original request: $USER_MESSAGE depends_on: [classify]

命令/脚本节点的with:绑定

命令文件与命名脚本对内联文本替换是不透明的——引擎从不改写其正文。with:command:/script:节点上按名字把上游值绑定到这些正文已经会读取的通道:命令文件读$INPUTS.<name>,脚本读INPUTS_<UPPER_SNAKE>环境变量。

nodes: - id: validate prompt: Run validation and report the verdict. output_format: type: object properties: green: { type: boolean } required: [green] - id: record script: record-verdict # 命名脚本——读取 process.env.INPUTS_GREEN runtime: bun depends_on: [validate] with: green: $validate.output.green

绑定值有三种形态:非字符串字面量(true42[a, b])按自身逻辑类型传递;恰好是一个完整$node.output/$node.output.field/$INPUTS.<name>引用的字符串按逻辑值传递(布尔字段到达时就是布尔,对象就是对象;环境变量投递用其规范文本:字符串原样、其余 JSON);其他字符串当作文本模板,按input:的规则替换(先工作流变量,再$node.output引用)。绑定指令对象{ from, if_skipped }可在生产者被跳过时提供回退值——被跳过且无if_skipped会直接失败节点,绑定永不静默解析为空串。每个被引用的生产者都必须是depends_on的上游依赖(否则加载器拒绝),保证绑定永远不会与生产者竞态。

Artifact 指针:大文件结果的标准通道

当机器消费方需要文件结果时,在结果中返回一个包含指针的小型 JSON 值。保留形状:

{"type":"archon_artifact","run_id":"<producing run id>","path":"review/report.md"}

run_id必须使用实际的WORKFLOW_ID值(而非字面变量名)。生产者必须先把自己的文件写到$ARTIFACTS_DIR之下。允许指针上携带兄弟键。在持久化结果前,引擎会针对生产运行校验带标签的指针:自身的 run id、非空相对路径且不含..段或 NUL 字节、词法包含、且必须是存在的常规文件。绝对路径/越界路径、目录、缺失文件、其他运行的 id 都会使生产者失败。

校验规则(reference/variables.md):

规则拒绝的情形
自有运行run_id非生产运行自身($WORKFLOW_ID)。当前结果只能指向自身运行的产物
可寻址运行输出位置从未记录,或记录在 Archon home 目录之外
相对路径绝对路径、..段或 NUL 字节
包含性词法上解析到运行产物目录之外
真实文件目标缺失,或是目录

workflow:父运行与扇出聚合原样转发指针而不针对父运行重新校验。事件与恢复保留 run id 与相对路径。引擎不会把指针展开为绝对路径、不会把文件内容读进提示词,也不提供工作流内解析器——生产运行内部的提示词交接请继续使用$ARTIFACTS_DIR/<path>(磁盘上是同一个文件)。

读侧(谁可以看该运行、路径经符号链接跟随后的 realpath 包含性)由读取方自持授权与校验责任:GET /api/artifacts/<run_id>/<path>目前只做词法包含校验,读时 realpath 解析尚未实现(跟踪于 #3160)。

各上下文中的变量可用性

变量工作流节点直接命令调用when:条件
$ARGUMENTS/$USER_MESSAGE是(两个别名均可)
$WORKFLOW_ID
$ARTIFACTS_DIR
$STATE_DIR
$BASE_BRANCH
$DOCS_DIR
$CONTEXT/ 别名
$LOOP_USER_INPUT是(循环节点)
$REJECTION_REASON是(仅on_reject
$LOOP_PREV_OUTPUT是(循环节点)
$LOOP_PREV.<nodeId>.output是(loop_group 正文节点)是(loop_group 正文节点)
$nodeId.output是(DAG 节点)

此外,systemPrompt:agents.<id>.prompt/agents.<id>.description中,工作流变量与$nodeId.output引用均可解析(这些文本直接进入 provider,与prompt:一样经过两轮替换;三者中任何一处出现悬空的$nodeId.output都是加载错误)。

常见误区速查

  • $1$9不可用:在提示词内解析$ARGUMENTS,或交给bash:/script:节点处理。
  • bash:中不要对$node.output.field套双引号:替换已自带引号,嵌套引号会让引号字符变成数据(数字/布尔字段会掩盖此问题,使其间歇性出现)。
  • script:中不要直接嵌入$nodeId.output到源码:对任意文本生产者优先走with:环境变量绑定,再防御性解析;bun 下直接赋值仅限生产者声明了output_format的场景。
  • 不要把$nodeId.output包进String.raw模板字面量:输出含反引号时会静默破坏。
  • $BASE_BRANCH$STATE_DIR会 fail-fast:被引用却无法解析时直接抛错,而非静默替换为空串——「响亮的失败」优于「静默写错位置」。
  • 位置参数未接入执行路径:代码库中的遗留辅助函数不参与执行,不要依赖它。

深入阅读

  • 本主题的完整版参考:reference/variables.md(含$STATE_DIR并发与命名冲突讨论、with:绑定三形态、环境读取的静态词法检查等扩展内容)
  • 节点类型与结果契约:node-reference.md
  • 工作流编写指南(DAG、when:trigger_rule、持久会话等):guides/authoring-workflows.md
  • 变量替换核心实现:executor-shared.ts(substituteWorkflowVariablesbuildPromptWithContext,含shellSafe双通道逻辑与 fail-fast 校验)
  • 相关测试与校验逻辑:packages/workflows/src/executor-shared.test.tspackages/workflows/src/dag-executor.tspackages/workflows/src/validator.ts(可用bun test在仓库内运行验证行为)

【免费下载链接】ArchonThe first open-source harness builder for AI coding. Make AI coding deterministic and repeatable.项目地址: https://gitcode.com/GitHub_Trending/archon3/Archon

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 13:01:09

OCC+Gmsh+OSG集成:从网格建模到三维可视化的工程实践

简介&#xff1a;面向 CAD 领域开发者&#xff0c;这份集成 OCC、Gmsh 与 OSG 的测试程序&#xff0c;把几何建模、网格划分与三维可视化串联为完整工作流&#xff0c;适合需要快速搭建 CAD 原型&#xff0c;或研究三者在 CAE 前处理与后处理中协同工作的工程师。压缩包共 40 个…

作者头像 李华
网站建设 2026/9/13 12:59:07

软考网管初级计算机硬件基础:高频考点与备考攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 12:59:00

STM32F3xx DDS信号发生器工程解析与实战

简介&#xff1a;本资源为2023年全国大学生电子设计竞赛实战代码合集&#xff0c;面向备赛本科生及嵌入式开发初学者&#xff0c;聚焦STM32平台下的高频考点实现与工程化落地。包内含177个文件&#xff0c;以49个头文件&#xff08;h&#xff09;和25个C源码&#xff08;c&…

作者头像 李华
网站建设 2026/9/13 12:56:40

K-means聚类算法原理与Python实现详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华