跳到主要内容

AW 原生 Agent 接入参考

本页用于组件接入与维护。安装和日常使用请阅读用户指南。 公共 Hook、MCP 与策略更新支持情况见能力矩阵。

AW 将工具策略和 Hook 命令接入 Agent,同时保留它原有的交互界面。在 aw.yaml 中声明程序和事件后,AW 启动或复用本地服务,接通受支持的原生 Hook,并在 Agent 会话结束后继续保存执行记录。

当前 Linux 源码版本支持 Qoder CLI >=1.1.64、OpenClaw 2026.9.6、 QwenPaw 2.2.2.post1 / AgentScope 2.0.10、Hermes 官方提交 952c941e,以及显式接入的 Claude SDK 0.2.88 worker(bundled CLI 2.1.161),以及 Pi Coding Agent/Core SDK 0.84.2 worker, 以及在前台 Python worker 中通过显式公共工厂接线的 AgentScope SDK 2.0.6。 Qoder SDK 1.0.56 / Worker 1.1.78 使用受管 daemon 与 Query 工厂。 其他首批 Adapter 独立交付。AW 不安装 Agent,也不配置模型账号;继续使用框架 原有的模型与认证配置。

安装请从 Preview 包指南开始;源码构建与无需模型的策略验证见 组件接入教程。随后使用下方共用配置验证 原生工具行为。字段定义集中在配置参考。

可选生命周期观测参见通过 aw run 接入 AgentSight。

安装 Preview​

使用 Preview 包 安装并演示 AW + sec-core,无需编译。 下方源码构建说明面向开发者;Preview 尚非稳定发行。

当前支持范围​

能力状态
校验一份包含全部 16 个事件名的配置✅ 识别事件不代表安装 Hook
通过 AW 启动 Qoder CLI✅ 交互和 print 入口
工具前运行结构化 Provider✅ observe、block
工具后运行结构化 Provider✅ observe;成功、失败及阻断尝试的覆盖随框架而异
工具前后执行原生脚本和命令✅ 回调输入保持不变,转交字节输出与退出状态
保留 Qoder 已有 Hook 及其调度✅ 默认配置和显式传入的附加配置文件
复用共享服务并持久保存执行元数据✅ 按需启动或外部启动服务
通过 AW 启动 Hermes✅ 显式安装原生插件后的本地 chat
通过 AW 启动 OpenClaw✅ 新 Gateway 中的 Agent 工具 Hook
通过 AW 启动 QwenPaw✅ 官方 App/API 入口
启动 Pi SDK 0.84.2 worker✅ 公共 SDK 工厂;见worker 指南
启动 Claude SDK 0.2.88 worker✅ 显式公共工厂 Bridge;见 worker 指南
启动 Qoder SDK 1.0.56 worker✅ 受管 daemon 与 Query 工厂;见 worker 指南
通过 AW 启动 AgentScope SDK✅ 单个前台 Python worker 中显式接线的公共工厂
启动其他首批框架❌ 相应 Adapter 独立交付;QwenPaw 与 Qwen Code 分别识别
其他事件、跨框架 ask、输入改写或 OS 执行约束❌ 当前结构化 Provider 路径不予准入
安装 Preview 包并生成 Qoder/sec-core 配置✅ Preview 指南,尚非稳定发行

对于 Qoder,tool.after 映射到成功调用后的 PostToolUse。Qoder 的 PostToolUseFailure 是独立事件,本 Adapter 尚未接入。原生 Hook 命令仍按 Qoder 的响应语义处理。 透传原生审批响应不代表 AW 已提供跨框架审批支持;交互式审批不在本期验收范围内。

四框架使用同一份配置​

共用 YAML与 布尔脚本让四个目标共用工具前 阻断、工具后观察策略。按教程复制文件、 替换绝对路径并验证 Provider。这里沿用其 AW_BIN、AW_CONFIG 和 AW_DEMO 变量。包安装用户也可使用这两个文件,将 AW_BIN 指向已安装的二进制;Python 3 是该示例脚本的依赖。

先准备各 Agent 的受支持版本与原生模型配置。运行时只需安装所选目标。各框架使用 独立原生 profile,显式选择工具工作目录,并从 $AW_DEMO/workspace 启动。 共用 YAML 不修改模型凭据或原生权限,起步时逐个测试目标。

目标原生前置条件启动差异
Qoder支持原生命令 Hook 的 CLI >=1.1.64,已登录交互或 print 入口;可选 --native-settings
OpenClaw2026.9.6,已配置的 JSON 和现有状态目录;先停止使用该 profile 的 GatewayAW 新启 gateway run,须传入两个原生路径
QwenPaw2.2.2.post1 / AgentScope 2.0.10,已初始化 App 工作目录与模型设置 QWENPAW_WORKING_DIR,使用 App/API,不使用 ACP/TUI
Hermes干净的官方提交 952c941e、已安装的 Python console script 和已初始化的本地 chat profile在该 profile 中安装一次 AW 插件,运行时使用同一 profile

启动 Qoder:

cd "$AW_DEMO/workspace"
"$AW_BIN" run --config "$AW_CONFIG" --agent qoder

使用已有原生绝对路径启动 OpenClaw:

"$AW_BIN" run --config "$AW_CONFIG" --agent openclaw \
--native-settings /absolute/openclaw.json --native-state-dir /absolute/openclaw-state

使用已初始化目录启动 QwenPaw:

QWENPAW_WORKING_DIR=/absolute/qwenpaw-home "$AW_BIN" run \
--config "$AW_CONFIG" --agent qwenpaw -- --host 127.0.0.1 --port 8096

阅读 Hermes 的 profile 要求后,安装并启动:

"$AW_BIN" install --config "$AW_CONFIG" --agent hermes \
--native-profile /absolute/hermes-profile
"$AW_BIN" run --config "$AW_CONFIG" --agent hermes \
--native-profile /absolute/hermes-profile

OpenClaw 和 QwenPaw 的服务终端保持运行,等 AW 输出原生 Hook 就绪信息后,再向 对应 Gateway 或 App 发起请求。OpenClaw 使用连接该 Gateway 的客户端,不使用 agent --local;QwenPaw 使用 App UI/API,不改用其他 CLI 入口。Qoder 和 Hermes 使用已启动的原生 chat。下方各框架章节说明共存方式与支持的生命周期范围。

验证原生行为​

在另一个终端恢复教程中的 AW_BIN、AW_CONFIG 和 AW_DEMO,将 AW_TARGET 设为正在测试的目标。开始时标记文件应不存在;重复测试时换一个新名称。打印下述 两个提示词,分两轮发送到该目标的原生界面:

export AW_TARGET=qoder
printf 'Use your shell tool exactly once to run `printf AW_OK > "%s/%s.allowed"`. Report the result; do not retry or use another tool.\n' "$AW_DEMO/workspace" "$AW_TARGET"
printf 'Use your shell tool exactly once to run `printf AW_DENY_TEST > "%s/%s.blocked"`. Report the result; do not retry or use another tool.\n' "$AW_DEMO/workspace" "$AW_TARGET"

这些命令即使执行也只写入演示标记。第二条输入包含策略的拒绝标记。完成两轮后检查:

cat "$AW_DEMO/workspace/$AW_TARGET.allowed"
test ! -e "$AW_DEMO/workspace/$AW_TARGET.blocked"
"$AW_BIN" status --config "$AW_CONFIG"
ls "$AW_DEMO/state/journal"

预期读到 AW_OK,第二轮收到 AW 策略拒绝,且 blocked 标记不存在。通过 AW 读取对应 journal:从列出的目录选择文件,将去掉 .jsonl 的 64 字符文件名作为 AW_AUDIT_KEY。

export AW_AUDIT_KEY=REPLACE_WITH_EVENT_KEY
printf '{"method":"audit","key":"%s"}\n' "$AW_AUDIT_KEY" | \
"$AW_BIN" request --socket "$AW_DEMO/state/aw.sock"

目录同时包含准备与事件 journal。事件的 result.records[0].record.plan 中, kind 为 event,instance 和 binding 应与启动时输出的 AW instance 对应。before 拒绝调用应有 policy_block: true;完成的 after 步骤应指向 Provider check-tool 且 status: ok。审计保存元数据,不保存原始输入/结果或效果的原因 文本。已闭合事件有 terminal: true。以下检查共同组成验收记录:

检查项证据
允许工具工具已执行、allowed 标记存在、before 及受支持的 after 步骤成功
策略阻断AW 返回拒绝、blocked 标记不存在、before 审计记录策略命中
Provider 失败停止旧会话/服务后,使用 before 脚本路径不存在的配置副本启动;调用失败,on_error: block 阻止标记生成,审计记录故障而非策略命中
共存保留一个已有原生 Hook/插件,确认其预期行为与 AW 一起生效
重启退出 Agent、停止 AW、使用原配置重新启动;新工具仍受检查,旧审计键仍可查询

记录框架版本、AW 提交、实际命令与审计键。合成 Host 测试与启动就绪不能替代该表。 模型拒绝、未调用工具或原生权限拒绝不算 AW 阻断。各框架的 after 覆盖不同,例如 Qoder 仅报告成功工具,不应要求为每次被拒绝的调用补造 after 事件。

停止与清理​

退出 Qoder/Hermes,在自己启动的 OpenClaw/QwenPaw 服务终端按 Ctrl-C。等待这些 进程退出后,再停止共享 AW 服务:

"$AW_BIN" stop --config "$AW_CONFIG"

停止响应只确认收到请求;等待记录的 daemon PID 退出且 aw.sock 消失。 QwenPaw 正常退出时删除自己的临时插件。Hermes 保留已安装插件;没有 AW 绑定的 普通 Hermes 启动不会启用 AW 回调。撤销安装时,停止 Hermes 与原生配置写入, 核对安装时报告的 backup 和 displaced 文件,将 plugins/aw-native-hooks 移到 profile 的 plugins 目录之外,再恢复选定的安装前配置。保留安装后有意 进行的原生修改,不要盲目整文件覆盖。AW 没有原生插件卸载命令。

保留审计证据后,按教程的清理步骤 删除演示目录。框架 profile 单独保留。包卸载见 Preview 指南。

构建并启动 Qoder​

AW 尚未通过 anolisa install 或 RPM 发布。开发者可以在 Linux 上用 rustup 和 仓库固定的工具链构建。另行安装 Qoder CLI 并核对版本。从仓库根目录执行:

cd src/aw
cargo build --locked -p aw-cli --bin aw
qodercli --version
target/debug/aw validate --config crates/aw-service/examples/aw.qoder.yaml
target/debug/aw run --config crates/aw-service/examples/aw.qoder.yaml --agent qoder

Qoder 示例使用 argv: [qodercli]。若需选择特定安装,将该项改为对应可执行文件的绝对路径。 --agent qoder 选择 spec.agents 下的命名对象;名称可以自定, adapter: qoder 才是框架类型。

AW 要求 CLI 的语义版本 >=1.1.64,以此前测试基线为下限,不再固定一个版本。 --version 输出去掉首尾空白后,必须是 1.1.66 这样的裸 SemVer,长度为 1–128 个 UTF-8 字节。不接受前导 v、产品名、尾部说明或额外行。格式错误会明确说明 这个要求,并显示实际输出。AW 记录去掉首尾空白后的原文,不从中搜索版本号。 旧版本或非法版本文本在绑定前拒绝;1.1.64 的预发布版低于下限,构建信息仍保留。 使用相同原生 Hook 合同的 CLI 无需在 YAML 填版本,也无需降级。该合同包括 --settings、通过字面 args 执行的命令 Hook、PreToolUse/PostToolUse、 回调 ID/输入,以及退出码 2 阻断。 版本文本本身不能证明兼容;关闭 Hook 的配置、不支持的启动模式及非法回调仍会 失败。旧 AW 构建若要求 1.1.64,需更新 AW 才能使用这个行为。

例如,将目标命名为 qodercli,并选择已安装的可执行文件:

agents:
qodercli:
adapter: qoder
argv: [/absolute/path/to/qodercli]

将该段合入完整配置的 spec 下,再运行 aw run --config /absolute/aw.yaml --agent qodercli。目标名与原生可执行文件名、 版本号分别定义。

示例在工具前后消费 Hook 输入并返回 {},不增加限制,也不是安全策略。可以让 Qoder 执行一个无副作用的只读工具,触发前后两个回调;没有工具调用的回答不会 触发它们。-- 后的参数传给 Qoder,例如:

target/debug/aw run --config crates/aw-service/examples/aw.qoder.yaml --agent qoder -- -p 'Read the current directory name with a tool.'

AW 打开 Qoder 的原生终端界面,Qoder 退出后回到原 shell,并释放本次会话的绑定 与未完成工作。共享 daemon 继续运行,供使用同一配置的后续会话复用。

target/debug/aw status --config crates/aw-service/examples/aw.qoder.yaml
target/debug/aw stop --config crates/aw-service/examples/aw.qoder.yaml

启动 AgentScope SDK​

使用安装了 agentscope==2.0.6 的 Python 环境;这与 QwenPaw 已验证的 AgentScope 2.0.10 运行时分开。argv 指定 SDK 环境的 Python 和 .py 应用或 -m MODULE。AW 校验该 SDK 版本,提供 aw_agentscope 与受保护的运行配置, 等待真实公共工厂安装 middleware 后生成的回执。

在 src/aw 中,将该环境的 python3 放到 PATH 后执行:

target/debug/aw run --config crates/aw-service/examples/aw.agentscope.yaml --agent agentscope
target/debug/aw status --config crates/aw-service/examples/aw.agentscope.yaml
target/debug/aw stop --config crates/aw-service/examples/aw.agentscope.yaml

示例使用确定性的离线 model 与本地 Echo 工具,无需凭据。before 布尔 Hook 返回 false(没有 block 命中),after 返回 true(observe)。把 before 命令改为 printf true 即可拒绝工具;原生 final response 为 denied,after 观察该拒绝。 修改配置之前先停止服务。

已有应用在每个公共工厂中使用 AwBridge().create_agent(...),原样传入已有 middleware 列表。可信参数注入应先于追加的 AW middleware。readiness 回执只 覆盖所构造的 Agent,不覆盖其他工厂或直接 dispatch 路由。 工厂合同说明顺序、预算、 调用身份与覆盖边界。

before 等待并可在工具副作用前阻断;after 等待一次 final ToolResponse,保留 success/error/interrupted,不重复中间 stream chunk。on_acting 之前的原生 参数/权限拒绝、直接 Toolkit 调用和外部执行请求需要另接。launcher 支持单个 前台 worker;fork 型 Gunicorn supervisor、多 worker 和远端部署不在此合同内。 常驻进程必须显式管理 service 每实例 1024 个事件关联的容量限制。

接入 PreTool 重试建议和最终 PostTool 压缩时,复制 SDK 生命周期示例, 替换所有路径,并在 sec-core 映射 Toolkit 的准确工具名和参数指针。示例先做安全检查, 再执行 Tokenless PreTool;工具完成后先观察原始结果,再压缩一个成功的文本槽。 custom/native after Hook 放在最终压缩步骤之前;启用替换后 AW 按声明顺序执行此链。 native 和观察 Hook 不替换响应;只有最后一个已准入的结构化替换步骤可以修改模型 可见文本。Hook 故障按 report 处理后,后续步骤仍收到原始输入。 只有观察的链保持原生逆序退出。

PreTool 拒绝原始调用,向模型返回完整重试参数;每次新尝试重新经过原生权限和 sec-core。带 RTK 归属的重试即使使用新 call ID 也不会重复压缩。PreTool 需独立安装 RTK,PostTool 不依赖 RTK。文本槽适用条件、故障处理和遥测配置见 Tokenless 行为。无效的最终响应替换指令会报告故障并保留原结果。

启动 QwenPaw​

安装 QwenPaw 2.2.2.post1 与 AgentScope 2.0.10,通过 QwenPaw 初始化模型配置。示例 使用 argv: [qwenpaw, app]。将 QWENPAW_WORKING_DIR 指向已初始化的绝对目录。 AW 只添加自身临时插件,保留已有插件和原生配置,App 退出后删除自身插件。

普通启动会检查每个已构造 Agent 实际安装的 resident middleware,并创建已确认的 任务作用域。Before 正序执行、After 逆序展开,原生工具并发由宿主决定。Offload 工具 保留作用域直到生成器、原生 Hook 和后台完成回调全部结束;已完成调用及时回收状态, 长会话按活跃调用容量准入。

后台 HTTP 输出和下一轮提示在全部必要原生回调成功后才发布;拒绝结果保留策略说明及 Tokenless 重试参数。脱敏函数必须幂等,以支持多个交付及 Hook 边界重复检查。 After Hook 接收脱敏后的终结 ToolResponse,包括 AW 拒绝结果。应用凭据扩展提供 每次 Agent reply 一个私有执行租约,由该 reply 的工具共享,并负责清理;见 私有执行租约。 授权所依据的工具参数保持原样。on_error: report 保持配置的 回调故障报告策略,工具前 block 拒绝执行。结构化 Provider 和布尔 Hook 的工具后 withhold_result 阻止未核验结果交付及后续派发,仅普通 resident 启动准入该动作。 严格 After 路径暂扣匹配工具的流式 chunk;任务私有执行也会暂扣中间 chunk,直到终态脱敏。 原生 Hook 或生命周期故障会封锁 Agent,包括 AW 步骤配置为 report 的情况; 修复原因后重启失败的 Agent。清理超时或 finish/release 确认状态不明会在进程范围内 封锁新请求,须重启 worker;凭据保留至原生工作确认排空。Shutdown 与嵌套清理 共用十秒预算,包含取消后的排空。 事件预算为 1..55,000 ms,ask/approve 指令尚不支持。 原生权限检查在这些回调之前执行;外部执行工具和此前的权限拒绝沿各自原生路径处理。

Startup 回执确认插件加载,每个 Agent 在请求开始前另行通过实际安装检查。看到原生 Hook 就绪信息后使用 App/API;ACP/TUI、多 worker 启动继续被拒绝。--reloadable 保留独立的请求空闲更新合同;普通启动提供 resident 子作用域、长会话回收,以及 reply 完整排空后的显式更新。复用的 Agent 在每轮新 reply 预留任务后读取活动策略。 App startup 在首个 reply 前确认更新就绪;启动策略持续生效,直到更新成功。共享 子作用域尚无原生证据采集合同,普通 resident 启动会拒绝该配置。

QWENPAW_WORKING_DIR=/absolute/qwenpaw-home target/debug/aw run \
--config crates/aw-service/examples/aw.qwenpaw.yaml --agent qwenpaw \
-- --host 127.0.0.1 --port 8096

QwenPaw 中性示例 在工具前后执行命令,不安装安全策略。受支持的适配器可复用同一份 aw-provider/v1alpha1 策略配置;原生 Hook 的输出格式与事件覆盖仍按框架分别说明。

零 Provider、零事件步骤的普通配置也会安装 resident 准入与清理 middleware。

启动 OpenClaw​

另行安装 OpenClaw 2026.9.6。示例使用 argv: [openclaw, gateway, run],必要时 改为可执行文件的绝对路径。显式传入已有原生 JSON 配置和已存在的绝对 state 目录。 AW 生成私有配置 overlay,保留该目录中的认证和会话;发现 Gateway 所有权冲突时 拒绝启动,不接管正在运行的实例。 AW 对受管 Gateway 禁用 Node 编译缓存,避免启动器重启子进程改变就绪 PID; 自定义包装器必须 exec Gateway。

每个 AW 步骤注册为一个原生插件 handler。OpenClaw 按原生优先级串行执行 before, 并发执行 after;其他插件的优先级保留。事件预算范围为 1..12,000 ms。被阻断的尝试 也可能带错误产生 after,因此 after 不代表执行成功。当前覆盖新 Gateway 内的 Agent 工具执行,operator tools.invoke 不属于完整前后接线入口。原生 Gateway startup 回调完成后才报告 Hook 已就绪,该状态与 AW 服务可连接分开判断。

target/debug/aw run --config crates/aw-service/examples/aw.openclaw.yaml --agent openclaw \
--native-settings /absolute/openclaw.json --native-state-dir /absolute/openclaw-state

OpenClaw 中性示例 在工具前后执行命令,不安装安全策略。受支持的适配器可复用同一份 aw-provider/v1alpha1 策略配置;原生 Hook 的输出格式与事件覆盖仍按框架分别说明。

升级服务​

本版本使用本地协议 aw-service/v1alpha7。旧版 daemon 会在 Agent 绑定和回调前 被拒绝,返回 protocol_version。替换可执行文件前,先退出其 Agent 会话,再用 旧版 aw stop --config FILE(或 --socket ABSOLUTE_PATH)停止每个旧服务; 随后一起更新 CLI 和 daemon,再次启动。不要删除仍在使用的 socket 或审计历史。 AW 配置和 Provider 协议仍分别为 aw/v1alpha1、aw-provider/v1alpha1。

布尔判断脚本​

简单规则只需从 stdin 读取一个标准化事件 JSON,在 stdout 输出 JSON 布尔值 true 或 false,然后以退出码 0 结束。true 表示命中规则,AW 请求配置中的 effect;false 不请求 effect,也不覆盖原生权限。诊断可写 stderr,不进入 Provider 回复或审计。自定义 Hook 默认只在事件触发时调用:省略 Provider 的 protocol 和步骤的 operation 即可。AW 在本地校验配置和效果准入,不调用脚本的 describe 或 validate_config,只对已准入事件执行脚本。脚本不接收 method、 request ID 或摘要,也不用构造 response 对象。显式声明 protocol: aw-provider/v1alpha1 仍走完整结构化 Provider 握手。

例如,将以下规则保存为 $AW_DEMO/check.py。Python 是这个自选脚本的依赖, 不是 AW core 的依赖:

import json
import sys

def contains(value):
if isinstance(value, str):
return "12345" in value
if isinstance(value, list):
return any(contains(item) for item in value)
if isinstance(value, dict):
return any(contains(item) for item in value.values())
return False

event = json.load(sys.stdin)
print(json.dumps(contains(event["tool"]["input"])))

沿用安装指南中的前缀与路径,由工具生成完整 YAML,无需手工拼装 Provider 和步骤。只提供所需 Agent 入口;本例声明两个框架:

"$AW_PREVIEW_PREFIX/bin/aw" config init --prefix "$AW_PREVIEW_PREFIX" \
--config "$AW_DEMO/aw-command.yaml" --state-dir "$AW_DEMO/command-state" \
--qoder "$AW_QODER" --node "$AW_NODE" --openclaw "$AW_OPENCLAW" \
--provider command --check /usr/bin/python3 --effect block \
--reason-code parameter_contains_12345 -- "$AW_DEMO/check.py"
"$AW_PREVIEW_PREFIX/bin/aw" validate --config "$AW_DEMO/aw-command.yaml"
"$AW_PREVIEW_PREFIX/bin/aw" run --config "$AW_DEMO/aw-command.yaml" --agent qoder

无需 sec-core 包或 daemon。同一份生成配置可配合 --agent openclaw 及其已有原生 profile 参数使用。两个框架向脚本提供相同的标准化工具字段,由 AW 将 block 翻译为 各自的原生 Hook 回复。生成的 transport 直接执行用户命令。 在 spec 内可这样声明自定义 Hook:

providers:
command:
transport:
type: stdio
location: agent
argv: [/usr/bin/python3, /absolute/path/check.py]
timeout_ms: 1000
max_output_bytes: 32
events:
tool.before:
enabled: true
required: true
steps:
- id: check-command
provider: command
effects: [block]
reason_code: parameter_contains_12345
on_error: block

省略 protocol 等同 aw-hook/v1alpha1,省略 operation 等同 invoke,也可 显式声明这两个值。Hook 的 config 省略或填空对象,脚本选项通过字面 argv 传入。 true 请求该步骤 effects 列表中的全部效果,可携带步骤的 reason_code; false 不请求效果。效果仍须满足 Adapter 能力。block 只用于工具前, observe 也可用于工具后。完整 Provider 步骤的 effects 仍是准入上限,由 Provider 选择实际返回的效果。

生成器创建一个必需的工具前步骤,设置 on_error: block 和 1,000 ms 命令超时。 非零退出、超时、输出超限、stdin 未完整交付或非布尔响应均为执行错误,不当作 false;按步骤的失败策略处理。布尔 stdout 含空白上限为 max_output_bytes 和 32 字节中的较小值,服务将 stderr 限为 65,536 字节。AW 不插入隐式 shell。 准备阶段在本地校验配置和 Adapter 能力,不执行用户脚本。 aw validate 离线检查期望配置文档。

已有 aw policy 桥接配置仍受支持,保留私有 config.on_true 的效果映射和完整 Provider 协议,无需迁移。切换自定义规则时,将 transport argv 指向布尔脚本, 省略 protocol、config 和 operation,将命中后的 effects 和可选 reason code 放到步骤中。切换配置前退出旧 Agent 会话并停止旧服务。旧 AW 二进制不接受新的 缺省形式,回滚时保留原配置。

aw config init 只新建私有文件,不覆盖已有文件。移除策略时,不传 --provider (或传 --provider none)生成新的基础文档,退出旧 Agent、停止其服务后显式切换 配置。Provider 与关联步骤一起移除;修改运行服务的文件不会触发重新加载。 通用的已有 YAML 编辑不属于此命令。

启动 Hermes​

使用官方 Hermes 提交 952c941e741e922a9be8fc403c8944c6e96318bb。安装与启动 均拒绝已跟踪文件的已暂存或未暂存修改;重试前提交或 stash 本地修改,并恢复到 固定提交。 父环境与 profile dotenv 均须取消 GIT_DIR、GIT_COMMON_DIR,让 Git 正常发现 当前 checkout。跳过的优先 PATH 名称也须防止他人替换或创建,包含 sticky 可写 父目录。两个环境中的非空 GIT_CONFIG_SYSTEM、GIT_CONFIG_GLOBAL、 XDG_CONFIG_HOME 及已设置的 HOME 均须为绝对路径;取消不支持的相对值或改用 绝对路径。工作目录、profile、venv、editable checkout、AW 执行文件和启动状态路径须为 UTF-8。 Git 在工作目录与 checkout 中须解析为同一规范可执行文件。两个目录分别核验 各自的有效配置,包括 local 配置和条件 include;拒绝外部 filter 命令与 fsmonitor helper。示例为 argv: [hermes, chat],请指向该安装的 Python console script,例如 /absolute/hermes/venv/bin/hermes,且使用绝对 Python shebang。显式路径和 PATH 查找均要求可执行普通文件;FIFO、目录及不可执行文件在原生探测前被拒绝。不支持 shell wrapper 或 python -m 入口。AW 使用该解释器进入同一个原生 CLI 进程,保留参数与工作 目录。原生 profile 加载决定生效的 HERMES_SAFE_MODE,包括 profile .env 的 覆盖;AW 拒绝 safe mode,并在 chat 调度工具前要求插件完成注册。先通过 Hermes 初始化 profile 与模型账号。aw agent connect 是显式的一次性原生 AW 插件安装:启用前备份原始配置, 保留未知配置字段,拒绝覆盖同名非 AW 插件。原生 YAML 写入器修改私有候选文件, AW 再与真实配置原子交换。命令报告初始字节备份 backup 与永久保留的 displaced 文件(<backup>.displaced);后者保留原 inode,包括已打开描述符 后续写入的内容。安装与回退期间停止原生配置写入,恢复前核对两份恢复文件。 写入器失败或发布前检测到冲突时,真实配置保持不变;在交换边界检测到冲突时, 命令报错,候选文件已经发布,被置换内容保留以供核对。 成功还要求删除配置暂存目录并同步其父目录。清理或同步失败会报告配置已发布 及两份恢复文件的路径,不返回成功或自动回退。该交换不向忽略 AW 锁的 写入器提供 compare-and-swap 保证。安装不会热加载或重启既有 Hermes 服务。 规范化后的 profile 目录、配置及随附插件文件必须属于当前用户,且其他用户不可写。 各级上级目录 须属于当前用户或 root,并禁止组或其他用户写入;像 /tmp 这样以 sticky bit 保护子目录的情况除外。已有 profile .env 同样必须是当前用户所有、组或其他用户不可写的普通文件 (接受 0600 或 0644)。AW 在任何原生探测前检查它且不跟随符号链接,包括 --version,因为导入 CLI 就会加载该文件。AW 拒绝不安全路径,不修改其权限。Ctrl-C 或 SIGTERM 会 取消安装的原生探测及写入进程、删除暂存副本,并保留信号退出状态。 安装与启动探测的错误会在信号退出前输出,包括无法确认进程组清理的错误。 安装在探测或修改 profile 前按启动时相同的本地 chat 限制校验已配置的原生参数。 仍支持只包含执行文件的 argv;此时在 aw run 的 -- 后提供 chat 及其选项。 chat 的 --help/-h 会在插件就绪前退出,因此 AW 会在原生探测或修改 profile 前 拒绝配置参数及 aw run 追加参数中的这两个选项。查看原生帮助请直接运行 hermes chat --help。--query=--help 这类字面量查询值仍受支持。

AW 升级可能改变随附插件的字节内容。启动或安装报告插件不匹配或缺少文件时,先停止 Hermes 会话与插件写入者,检查 <profile>/plugins/aw-native-hooks,并将该目录 移到 <profile>/plugins 之外备份。重新执行相同的 aw agent connect 命令安装匹配文件; 保留的目录可用于检查或回退。

当 providers 和 events 为空时,AW 注册零个回调并正常启动。已有原生 Hook 仍会执行;AW 记录会话生命周期,不表示执行了每工具策略检查或工具审计。 仍须先显式安装插件。

后续 aw run 保留该 profile 的认证、历史与工作目录。原生 before/after 按 Hermes 注册顺序执行,before 阻断不会跳过后续已注册的回调;post 也可观察被阻断和失败的 尝试。AW 保留原生 Hook 返回解析和 Agent 自身审批,尚不支持通用 AW ask。 配置了 AW before 回调时,原生 Hook 和 tool-execution middleware 的参数改写 会被拒绝,包含 execute_code 内部调用:Hermes 可能在这些回调完成后才应用 改写,修改后的参数未经检查。仅观察的执行 middleware 仍可使用;空策略和 仅 after 路由保留原生改写行为。配置 AW 回调时,before 检查或工具执行期间的强制插件重载 会在卸载前被拒绝,以保留待执行的审计回调;工具之间仍使用原生重载。 当前入口为以 --cli 固定的本地 chat,不含原生 TUI、Gateway 或 ACP。 请使用完整 chat 参数;不支持 profile/worktree/恢复会话切换与选项缩写。事件预算最多 55,000 ms, 同时必须留在原生回调超时范围内。

target/debug/aw agent connect --config crates/aw-service/examples/aw.hermes.yaml --agent hermes \
--native-profile /absolute/hermes-profile
target/debug/aw run --config crates/aw-service/examples/aw.hermes.yaml --agent hermes \
--native-profile /absolute/hermes-profile

Hermes 中性示例 在工具前后执行命令,不安装安全策略。受支持的适配器可复用同一份 aw-provider/v1alpha1 策略配置;原生 Hook 的输出格式与事件覆盖仍按框架分别说明。

接入自己的程序​

spec.providers 中的每个命名对象描述一个程序,事件步骤通过 provider 引用 它。根据现有程序选择协议:

协议输入与结果步骤字段
aw-hook/v1alpha1(缺省)命令读取一个标准化事件并返回 JSON true/false,AW 在命中时投影配置的效果,不执行脚本握手effects、on_error;可选 reason_code;省略 operation 或填 invoke
aw-provider/v1alpha1AW 执行 describe、validate_config、invoke,响应包含经校验的候选效果operation、effects、on_error
native-hook/v1alpha1命令收到所选框架的原始回调 stdin,stdout、stderr 和退出状态按该 Adapter 合同处理native: {}、on_error;不填 operation、effects

接入原生 Hook 时,将示例的 transport.argv 换成脚本的可执行文件及字面量参数。 AW 不插入 shell;使用 shell 语法时明确指定 /bin/sh -c ...。这种协议保留 config: {},不执行 Provider 配置交互。Qoder 专用的原生输出不会自动转换成其他 框架的响应。

原生命令使用回调进程的实际环境,包括框架加载的 profile 变量;结构化 Provider 使用绑定时固定的启动环境。环境内容不写入事件或审计。

统一策略使用 aw-provider/v1alpha1,Provider 自己的设置写在 config 中。 可运行的策略示例展示工具前 observe/block 和工具后 observe。先执行 cargo build --locked -p aw-provider --example policy,再从 src/aw 运行, 因为示例命令使用相对路径。其中的阻断工具名仅供演示;测试阻断时,替换成 Agent 实际使用的工具名。样例 Provider 不是 sec-core。

timeout_ms 限制单次命令,default_event_budget_ms 限制整个事件,输出上限 约束返回字节数。Qoder 启动器接受 1 到 55,000 毫秒的事件预算。on_error 处理 执行故障,与 Provider 成功返回的策略阻断分开。 对原生命令,正常获得的非零退出仍是原生结果,不算 AW 传输故障。Qoder 在支持 阻断的点位将退出码 2 解释为阻断,其他非零退出是非阻断错误。observe 结果不授予 新权限,也不覆盖 Qoder 自身的工具权限。

保留已有 Hook 与调度​

Qoder 继续加载原有 user、project 和 local 配置。AW 为本次会话生成回调条目, 不修改这些文件。如果原来通过 Qoder 的 --settings 传入额外 JSON 文件,改用:

target/debug/aw run --config ./aw.yaml --agent qoder --native-settings ./qoder.settings.json

AW 保留该文件的其他字段和 Hook 条目,加入自己的回调,再将合并配置传给 Qoder。 每个 AW 步骤成为独立的同步原生 Hook,串行或并行执行由 Qoder 决定,包括与 其他匹配 Hook 的共同调度。

设置 spec.agents.qoder.qoder.sequential: true,可将生成的组标记为顺序执行。 任一匹配的同步 Qoder 组要求 sequential 时,全部匹配的同步 Hook 都按顺序执行。 省略该字段或设为 false,不会覆盖已有组的 true。属于同一原生事件的步骤共享 AW 预算,后续回调不会重新计时。

当前支持 AW 步骤之间输入保持不变的脚本,不支持顺序输入重写链。若命令返回 updatedInput,后续回调输入变化会被拒绝,并按该步骤的 on_error 处理。 转交原生字节不代表已支持全部原生效果组合或审批流程。

启动器会拒绝禁用或替换接线的设置和参数,不会覆盖用户关闭 Hook 的选择,包括 直接传入的 --settings、--setting-sources、--headless-fast-hooks 和冲突的 原生配置。自定义配置根目录、其他 Qoder 配置目录模式、恢复会话、远程会话和 worktree 启动 尚不在当前 Adapter 范围内。短选项须分别传入,不能合并;请从所需工作目录启动。已有原生 Hook 的行为与审计 仍由它们自身负责。

服务生命周期与记录​

spec.daemon.startup: on_demand 在选定端点没有服务时启动一个;external 要求服务已由外部启动。已有服务的协议和完整配置版本匹配时才会复用。 endpoint: auto、state_dir: auto 会在 XDG_RUNTIME_DIR 下选择按配置区分的 私有目录;该变量未设置时使用 /tmp/aw-UID 下的目录。显式路径必须是绝对路径, 并且指向同一个 aw.sock 位置。

服务保留启动配置快照,编辑 aw.yaml 不会自动热更新它。支持更新的普通 resident 和显式启用受限桥接的实例可使用 空闲策略更新,更换实例 Host,服务身份不变。停用某份配置前,用原文件或 socket 停止相应服务;修改配置后的 auto 路径可能指向另一个服务。退出 Agent 不会 停止其他会话或共享 daemon。本地端点是同用户访问边界,不提供 sandbox。

命令用途
aw validate --config FILE检查语法和静态引用,不执行程序
aw run --config FILE --agent TARGET [OPTIONS] -- ARGS启动配置的 Agent 并接通受支持 Hook
aw agent connect --config FILE --agent TARGET [--native-profile PROFILE]向已有 Hermes profile 显式安装原生插件;Qoder、OpenClaw、QwenPaw、Pi、Claude SDK 和 AgentScope SDK 不支持
aw update --config CURRENT --agent TARGET --policy NEXT更新支持该能力且已就绪的空闲实例;busy 拒绝且不排队
aw serve --config FILE --state-dir ABSOLUTE_DIR在前台运行服务
aw status --config FILE 或 aw status --socket ABSOLUTE_PATH查看选定服务,不启动它
aw stop --config FILE 或 aw stop --socket ABSOLUTE_PATH请求正常关闭服务
aw request --socket ABSOLUTE_PATH [--timeout-ms 1..60000]从 stdin 读取一个开发者操作 JSON 对象,默认 5,000 毫秒

--agent TARGET 选择 spec.agents 中的命名对象,其 adapter 字段选择实现。 当前版本实现了 Qoder CLI、OpenClaw 2026.9.6、QwenPaw 2.2.2.post1 / AgentScope 2.0.10 和 Hermes 官方提交 952c941e Adapter,以及显式 Claude SDK 0.2.88、Pi SDK 0.84.2 与 AgentScope SDK 2.0.6 worker。 aw agent connect 校验配置后分派到对应 Adapter;Hermes 支持持久化插件安装, Qoder、OpenClaw、QwenPaw、Pi、Claude SDK 和 AgentScope SDK 拒绝此命令。 该命令不安装 AW 包或 Agent 软件,不启动 Agent,也不配置模型凭据。aw run 不会隐式调用 agent connect。 旧的 aw install --config FILE --agent TARGET [--native-profile PROFILE] 语法 保留相同的原生注册行为。软件安装使用 aw install --prefix ABS_DIR --bundle ABS_DIR; 两组参数不能混用。

Adapter 专用参数命令当前支持情况
--native-settings JSON_FILErunQoder:可选的附加 JSON 配置,与生成的 Hook 合并,原文件保持不变。OpenClaw:必填的现有原生 JSON 配置
--native-profile PROFILErun、agent connectHermes:run 和 agent connect 必填的已有 profile 绝对路径。Qoder 和 OpenClaw 拒绝此参数
--native-state-dir DIRECTORYrunOpenClaw:必填的原生状态目录绝对路径。Qoder 拒绝此参数,它不是 AW 服务的 --state-dir

公共命令解析器识别这些 Adapter 专用参数,不代表框架已经支持它们。Pi、Claude SDK 和 AgentScope SDK 拒绝这些原生覆盖参数。QwenPaw 也拒绝它们,使用 QWENPAW_WORKING_DIR。 受支持的 AW 参数放在 -- 前,之后的参数 按字面量交给 Agent;agent connect 不接受 Agent 参数。用 aw --help 查看命令格式 和当前支持范围。

源码构建时将 aw 替换为 target/debug/aw。aw hook 是启动器生成的内部回调, 无需用户手写。服务记录包含执行元数据,不包含工具输入或结果、Provider 私有配置 和原始 stdout/stderr。服务运行或调用完成不能证明原生策略已采用。原生回调被杀 或禁用时可能缺失检查,本版本不提供 final/protected 执行或 OS 兜底。

容器与持久化数据​

在镜像中准备 AW 二进制、受支持框架版本、策略程序和默认配置。运行时提供原生 profile,并通过 aw run 启动所选 Agent;Dockerfile 无法保留活跃服务或可复用的 会话绑定。Hermes 须在启动前将匹配插件安装到实际运行的 profile。挂载到镜像 目录可能遮住构建镜像时安装的文件,参见 Docker 的 挂载行为。

数据容器中的处理方式
AW 二进制、脚本、固定 aw.yaml放入镜像或只读提供;可编辑配置保存在临时容器层之外
<state_dir>/journal/需要跨容器重建保留执行历史时持久化;本版本审计固定开启且仅保存元数据
Socket、锁、launch-* 和会话绑定属于运行时产物,不能恢复会话;每次服务/Agent 启动建立新的运行状态
原生 profile、凭据、会话与工作区按所选框架的要求保留,不属于 AW 审计数据
sec-core 后端数据由 sec-core 独立管理,见 Preview 后端配置

即使不跨容器保留历史,AW 也需要可写的本地状态目录。需要持久历史时,将 daemon.state_dir 设置为支持 fsync 的本地持久文件系统上的绝对路径,保留 endpoint: auto 即使用该目录的 aw.sock。目录须属于运行 UID,权限为 0700; 直接父目录也须属于该 UID,且其他用户不可写。启动 AW 前,按实际容器 UID 准备 卷的属主。默认 auto 位于 XDG_RUNTIME_DIR 或 /tmp 下,属于临时存储。

长期运行的 Gateway/App 须按本 Preview 的上限安排生命周期:每个 AW 实例最多 保留 1,024 个不同的关联原生事件,同时启用 before 和 after 时,每次完成的工具 调用占用两个条目。耗尽后,打开新的关联事件以 native_event_limit 失败,此时 尚未运行步骤脚本。这是事件打开失败,不是 Provider 结果。AW 回调桥接将故障 转换为所选框架的原生响应;配置 on_error: block 的 before 回调请求拒绝执行。 工具的最终行为遵循该框架的原生 Hook 语义。退出并重新启动 AW 管理的 Agent 才会 建立新实例,另开原生会话不会重置上限。

当前状态目录同时包含 journal 与运行时产物。整体挂载持久卷时,正常停止会删除 所属 socket,强制终止容器则可能留下它。复用前确认旧服务已经退出,只清理该 遗留 aw.sock,不要删除活跃端点或 journal。独立 AW daemon 不共用一个状态目录。 容器关闭流程应先退出 Agent,再停止 AW 并等待所属进程。保留 journal 可以查询 历史,不会恢复或重放中断工具。Docker 卷在容器删除后继续保留,删除卷是单独 操作,见卷生命周期。

常见接入问题​

现象下一步检查
静态校验通过但启动失败检查所选原生版本/入口、程序路径和 Provider 私有配置;静态校验不执行它们
状态/profile 路径不安全检查运行 UID、目录权限与显式原生路径,使用该用户拥有的私有目录
修改配置后行为不变退出旧 Agent,用原配置/socket 停止旧服务,再启动编辑后的文件
Hook 就绪失败阅读原生启动错误,确认 profile/插件及受支持版本后再发请求
模型回答后没有审计确认受支持工具确实到达回调;原生权限或模型拒绝可能阻止调用
强制终止后已有 socket确认旧服务退出,再按上文清理其遗留 socket

运行本地服务演示​

该演示无需 Agent 账号或模型请求。从 src/aw 执行:

cargo build --locked -p aw-provider --example policy
AW_DEMO_ROOT="$(mktemp -d "$PWD/target/aw-demo.XXXXXX")"
printf 'Socket: %s\n' "$AW_DEMO_ROOT/state/aw.sock"
target/debug/aw serve --config crates/aw-service/examples/aw.yaml \
--state-dir "$AW_DEMO_ROOT/state"

在另一个终端进入 src/aw,使用打印的绝对 socket 路径:

AW_DEMO_SOCKET=/absolute/socket/path/printed/above
target/debug/aw status --socket "$AW_DEMO_SOCKET"
cargo run --locked -p aw-service --example local -- "$AW_DEMO_SOCKET"

示例使用合成能力和事件,检查 read_demo、阻断 delete_demo、观察工具后事件, 并输出审计键。没有启动原生 Agent 或工具。将 AUDIT_KEY 替换为返回的准备记录键 或事件 ID,可以查询记录:

printf '%s\n' '{"method":"audit","key":"AUDIT_KEY"}' | \
target/debug/aw request --socket "$AW_DEMO_SOCKET"
target/debug/aw stop --socket "$AW_DEMO_SOCKET"

terminal: false 表示尚无终结记录,可能仍在运行,也可能已中断。调用超时后不得 作为新步骤重新执行。停止响应仅确认收到请求;等前台服务退出后,在原终端删除 本次演示目录:

rm -r -- "$AW_DEMO_ROOT"

正常关闭保留审计历史,删除所属 socket。强制终止后,AW 会报告遗留 socket, 不会自动删除。确认旧服务已停止后,再移除其所属 aw.sock;保留服务目录时, 保留其中的锁和 Journal。重启产生新的服务身份,历史记录仍可查询,但不会恢复 或重放旧事件。

配置参考列出完整字段和事件名。 本地服务合同面向 Adapter 开发者, 说明操作 JSON、截止时间和生命周期。

sec-core 扫描通过独立的 aw-provider-sec-core 接入,见配置与使用。

模型可见的 PostTool 压缩使用可选的 Tokenless Provider。

启动 Pi SDK worker​

高代码 Pi 应用使用 adapter: pi、公开 Coding Agent/Core SDK 0.84.2 与 Node.js >=22.19.0。AW 管理前台 SDK worker,并接通工具前后两个 Hook 点。 按应用现有依赖流程安装这些 SDK 包,保留应用模型与认证配置。原生 Pi CLI 是 独立入口,这个 Adapter 不启动该 CLI。

在绝对路径的 .mjs 应用模块中暴露已有公共工厂与前台任务:

export async function createSession({ sdk }) {
return sdk.createAgentSession({
cwd: process.cwd(),
agentDir: "/absolute/existing-pi-agent-directory",
});
}

export async function run(session, { args }) {
await session.prompt(args.join(" "));
}

复制 Pi 示例, 将 argv 改为 [node, /absolute/application.mjs] 并设置工具前后策略。 附带命令为中性示例。随后执行:

cd src/aw
target/debug/aw validate --config /absolute/aw.pi.yaml
target/debug/aw run --config /absolute/aw.pi.yaml --agent pi -- 'Your task'
target/debug/aw status --config /absolute/aw.pi.yaml
target/debug/aw stop --config /absolute/aw.pi.yaml

--agent 选择配置中的目标名,adapter 保持为 pi。--native-settings、 --native-profile 与 --native-state-dir 不是 Pi SDK 选项。AW 绑定前核验实际 安装的 SDK 版本,等待工厂与 callbacks 安装,随后报告 AW pi native hooks ready。 应用任务必须留在同一个前台 worker。new/resume/fork/import 替换会话使用传给 run 的 createSession,保证每次工厂返回后安装同样的 Hook 组合。已有 before 拒绝/参数修改、after 结果替换继续生效,AW after 观察最终结果。Pi 被拒绝、参数 非法、提前取消的工具没有 after callback。

Tokenless 使用共享优化示例中的 Pi SDK 目标。 安全检查位于 pre_tool 之前,观察器/自定义 Hook 位于最后 post_tool 替换之前。 重试理由进入模型,建议命令只能通过新工具调用执行。PostTool 替换成功结果的唯一 文本块并保留 SDK metadata;report 故障保留原结果。原生 Hook 不能提供替换。 AW 每次生成 invocation UUID 配对,原工具 ID 保留于 native,提前拒绝时关闭事件。 精确 callback、身份、取消、容量与可 复现的 SDK 验收见 Adapter 合同。 修改策略前退出 Agent 并停止原服务;审计状态按同样的本地服务清理流程保留或删除。

启动 Claude SDK worker​

使用 Claude Agent SDK 0.2.88 及其 bundled CLI 2.1.161。Adapter 启动一个前台 Python script 或 -m module,要求 worker 公共工厂显式使用 aw_claude.create_client(options)。模型认证继续由 SDK 配置。AW 为启动的 worker 通过 PYTHONPATH 提供此模块,不会自动向任意 SDK 应用注入 Hooks。

源码示例从 src/aw 运行,先准备选定的 Python 环境。固定 MCP 版本是为了处理已 复现的 MCP 2.x 不兼容问题:

python3 -m venv target/claude-sdk-venv
target/claude-sdk-venv/bin/pip install -r tests/claude-sdk-requirements.txt

复制 crates/aw-service/examples/aw.claude-sdk.yaml 为自己的配置,将 Agent argv 解释器改为 target/claude-sdk-venv/bin/python 的绝对路径。保留前台示例 worker 路径, 或替换为业务 script。在公共工厂完成普通 MCP tools、权限、resume 与既有 Hooks 配置后使用以下模式:

from aw_claude import create_client

async with create_client(options) as client:
await client.query(prompt)
async for message in client.receive_response():
handle_message(message)
target/debug/aw run --config /absolute/aw.claude-sdk.yaml --agent claude -- 'Use echo to return hello.'
target/debug/aw status --config /absolute/aw.claude-sdk.yaml
target/debug/aw stop --config /absolute/aw.claude-sdk.yaml

Claude SDK 事件预算必须为 1..55,000 ms。每个 tool.before 或 tool.after 路由 优先使用 events.<name>.budget_ms,未设置时使用 execution.default_event_budget_ms。 aw run 在静态配置校验后检查此 Adapter 专有限制。

worker options cwd 必须等于启动 cwd。真实 SDK initialization 握手接受 callbacks 后才发布 readiness。AW 在 PreToolUse 观察或拒绝,PostToolUse 与 PostToolUseFailure 均供 after 观察。被拒绝工具不补造 after。既有 Hook veto 和 原生权限继续有效。既有 pre-hook updatedInput 或 permission updated_input 发生修改时明确拒绝,因为并发 callbacks 无法保证 AW 检查最终参数。启用 tool.before 时,非空 PermissionRequest matchers 在初始化前被拒绝;请改用 受支持的 PreToolUse 或 can_use_tool callbacks。启用 tool.before 时也拒绝调用方 指定 permission_prompt_tool_name;受保护 can_use_tool 的 SDK 内部 stdio 权限 通道继续支持。调用方 cli_path 覆盖、缺失 bundled binary 均被拒绝。worker 不得 detach,也不得在一个 launcher binding 中运行多个 SDK clients/任务;Gunicorn 和业务部署需要自己的任务 生命周期接线。

CLI 2.1.161 对 SDK MCP isError: true 响应仍发 PostToolUse,callback 数据不含 该 flag,因此 after 观察不能分类所有业务失败。原生 Bash 执行失败使用 PostToolUseFailure。身份、取消与验证限制见 Adapter 合同。

无模型的原生采纳验证使用真实 SDK/bundled CLI,连接本地确定 HTTP fixture。 先构建 AW,再运行测试;测试创建独立 profile,私有 UDS 目录也位于 output 下, 停止 owned services 后删除。socket 路径超过 107 bytes 时明确报错:

target/claude-sdk-venv/bin/python tests/test_claude_sdk_native.py --aw target/debug/aw --output target/claude-sdk-native

不再需要证据与环境时,仅删除新建的 target/claude-sdk-native 和 target/claude-sdk-venv 目录。AW 策略是示例,业务部署验收与这些本地原生检查分开。

工厂要求 setting_sources=[]、无 settings 覆盖、无 CLI plugins。extra_args 仅允许 strict-mcp-config: None;SDK 原生 strict_mcp_config 也保留。模型和认证 配置不变。通过 settings sources 发现项目 skills 的应用,需要先明确接入设计才能 使用该首版受限 Bridge。直接任务 worker 模式每进程只允许一个 client;多个任务客户端使用下文显式常驻入口。

当前 adapter: claude-sdk 支持上述受限前台 worker 工厂;aw agent connect 对该 Adapter 不提供持久安装命令,所有 --native-* overrides 均不支持。

启用 Bash PreTool 与 PostTool 优化​

使用 Tokenless 共享配置, 选择 claude target,替换 executable、worker 与状态目录的绝对路径。源码示例 claude-worker.py 除 echo 工具外显式开放并允许原生 Bash;组合业务工厂时保留应用 自己的权限策略。Provider 安装、RTK 要求与统计设置见 Tokenless 指南。

PreTool 阻断原始 Bash 尝试,将重试参数返回模型;新调用重新经过所有策略及原生权限。 PostTool 只替换完成、非图片且未中断的 Bash stdout。完成观察器和自定义步骤放在唯一 最终 replace_result 前,看到原始结果;stderr 与其余原生字段保留。失败/report 保留原始结果。该原生回调路径的 MCP tools 仍可观察,缺少可靠业务错误状态;使用下文受管 MCP 工厂获得结果压缩接点。

构建 AW、其 Tokenless Provider 与当前 Tokenless Protocol v2 CLI 后,扩展原生验收 (PATH 中需要 RTK):

cargo build --locked --manifest-path ../../providers/tokenless/Cargo.toml
target/claude-sdk-venv/bin/python tests/test_claude_sdk_native.py \
--aw target/debug/aw --output target/claude-sdk-native \
--tokenless ../tokenless/target/debug/tokenless \
--tokenless-provider ../../providers/tokenless/target/debug/aw-provider-tokenless

为常驻 SDK 复用一份安全策略​

统一 SDK 安全示例 通过 --agent 选择 Qoder SDK 或 QwenPaw。替换全部绝对路径,按对应章节初始化 原生运行时,并在启动前按配置的 socket 启动 sec-core:

aw validate --config /absolute/path/aw.sdk-security.yaml
aw run --config /absolute/path/aw.sdk-security.yaml --agent qoder-sdk -- "your prompt"
QWENPAW_WORKING_DIR=/absolute/qwenpaw-home aw run \
--config /absolute/path/aw.sdk-security.yaml --agent qwenpaw

sec-core 步骤只匹配 native:qoder-sdk:Bash 和 native:qwenpaw:execute_shell_command。AW 在能力准入和 Provider 准备前投影所选 目标的步骤。其他工具仍执行自定义前后检查,不会隐式增加 sec-core 扫描。扩展扫描 范围时,显式增加 selector 及对应的 Provider 工具映射。

自定义脚本使用布尔 Hook 合同:从 stdin 读取一个规范化事件,输出 JSON 布尔值并以 零退出。本例 Before 的 true 请求 block,After 的 true 记录 observe; After 的 false 不产生效果,检查仍视为成功。结果检查失败须非零退出,随后 on_error: withhold_result 阻止交付及后续派发。保留原生权限和调用方负责的 daemon/App 生命周期。使用普通 aw run,在 Query 关闭或 reply 完成后显式空闲更新。私有凭据需在应用代码 接入显式执行工厂, 此 YAML 安装安全策略。

启动 Qoder SDK Worker​

使用 adapter: qoder-sdk、@qoder-ai/qoder-agent-sdk@1.0.56、随包提供的 Worker 1.1.78(国际版)和 Node.js 22 或更新版本。将 SDK 安装到 Worker 的应用目录, 在现有 AW 配置中设置目标:

agents:
sdk:
adapter: qoder-sdk
argv: [node, /absolute/application/worker.mjs]

Worker 显式选择 AW 的 daemon 和 Query 工厂;同一个 Worker 也可以通过 Node 和原生 SDK 工厂独立启动:

import { startDaemon, query, accessTokenFromEnv } from "@qoder-ai/qoder-agent-sdk";
import { pathToFileURL } from "node:url";

const prompt = process.argv[2];
if (!prompt) throw new Error("A prompt is required");
const bridge = process.env.AW_QODER_SDK_BRIDGE
? await import(pathToFileURL(process.env.AW_QODER_SDK_BRIDGE)) : undefined;
const makeQuery = bridge ? bridge.createQuery : async (request) => query(request);
const makeDaemon = bridge ? bridge.startDaemon : startDaemon;
const daemon = await makeDaemon({ auth: accessTokenFromEnv() });
let current;
try {
current = await makeQuery({ prompt, options: {
daemon, cwd: process.cwd(), settingSources: [],
} });
for await (const message of current) console.log(JSON.stringify(message));
} finally {
await current?.return();
await daemon.stop();
}

执行 aw run --config aw.yaml --agent sdk -- "你的请求",或执行 node /absolute/application/worker.mjs "你的请求" 走不启用 AW 的原生启动方式。 沿用 SDK 认证方式,不把凭据写入配置文件。调用方启动和停止 daemon,并关闭每个 Query。 通过 AW 启动时,使用 Bridge 的两个工厂:startDaemon() 在启动固定版本 daemon 前 校验运行时选择和禁用 Hook 的环境变量;createQuery() 拒绝原生 SDK 直接创建的 daemon,因为无法核验它的启动配置。仅启动 daemon 不会报告 Query 就绪。 AW 沿用前台 Worker 生命周期,在 Worker 退出时释放自己的绑定。

AW 在 Query 初始化前注册回调,SDK 握手成功后报告就绪。 tool.before 支持观察和拒绝;tool.after 观察原生工具成功和失败的结果。 普通 resident Query 准入 on_error: withhold_result:Post 失败或超时会在回复回调前 关闭原生 Query,扣留未核验结果并停止后续派发。Post 之前已发生的工具副作用继续生效。 on_error: report 报告故障并允许正常结果处理。 准入仅允许 tool.before 使用 on_error: block。原生权限拒绝保留优先级,结果替换仍 不支持。现有 SDK Hook 保留;参数改写和权限 Hook 覆盖不受支持,防止实际执行参数 与检查参数不同。

使用 settingSources: [],不要传入 settings、插件、额外 CLI 参数或运行时 transport 覆盖。进程环境和启动环境中的 Hook 禁用标志按 bundled Worker 的去除首尾空白 语义解析并拒绝。普通 createQuery() 为每个 Query 建立已确认的常驻 scope, 使用其规范工作目录和环境快照。直接创建的 Query 可以使用不同环境;共享 daemon 拥有固定环境及当前凭据,其 Query 拒绝 env 和 auth 覆盖。 运行期可通过原生 daemon.auth(payload) 更换 daemon 凭据。daemon.stop() 等待 所有已安装 payload 的活动凭据回调,包括凭据更换后仍在运行的旧回调。需要不同原生凭据时, 使用独立 daemon 或直接创建 Query。受管 Query 共用配置策略;通过原生 SDK 绕过 Bridge 创建的 Query 不受 AW 保护。

普通 Query 要求 evidence mode: off:子 scope 无法继承 AgentSight 观测根 binding。 启动准入在发布就绪前明确拒绝启用的 evidence。

Bridge 返回冻结的公共 Query 接口,隐藏原生解析器、transport、回调映射和 Hook 路由 修改方法。内部启用 Worker partial 输出,使模型工具身份先于分派到达;调用方未设置 includePartialMessages: true 时隐藏 stream_event。回调数据无法自行登记工具身份。 工具完成后,等待原生命令队列屏障及原始回调 finally 结束,再退休其关联记录。 提前 return、取消和 transport 故障均等待原生 close,以及原始 Hook、权限、凭据、 模型和 MCP 回调完成后释放 scope。记忆生成/消费、技能演进的 gate/result 回调, 以及执行中的 sendHostAction()(包括原生 fallback 清理)也纳入等待。 关闭开始后拒绝新 Host action。派发故障在原生工作排空、凭据撤销确认后可退休 scope; 原生清理失败会保留所有权;租约清理失败或超时还会在进程范围内封锁新工作,直到 Worker 重启。 原生认证回调保留自己的生命周期。普通 Query 可通过 options.awExecutionFactory 为每次受管 MCP handler 调用获取版本化私有租约。Bridge 在调用 SDK 前移除此选项, 并导出 PRIVATE_EXECUTION_VERSION、executionEnvironment() 与 hookEnvironment()。handler 显式消费私有环境,结果在 Post 与交付前脱敏。 固定版本 SDK 的内建 Bash 没有对应环境注入接点。公共工厂合同与清理顺序见 私有执行租约。

进程内 MCP 使用 await bridge.createSdkMcpServer(options),每个 Query 提供新的受管 server。保留原生 schema、annotations、权限设置和结构化结果 envelope。 若 schema 通过默认值、transform 或移除未知字段改变已批准参数,则在应用 handler 执行前拒绝。严格 Pre 拒绝阻止 handler 进入。 普通 resident MCP 调用与原生工具共用已准入的 Post withhold_result 屏障。 MCP 子调用绑定原生 control request、精确的 server/tool/arguments 和所属 Query。 parentIdentity: "query" 为默认值:固定版本 Worker 的 MCP 请求未提供来源模型 工具 ID;parentIdentity: "required" 在创建原生 server 前拒绝。元数据与完整结果 封装处理见结构化 MCP 派发。 结果替换仍不支持。

严格 Post 和私有执行租约要求普通 resident 模式。所有 Query 关闭并完成清理后, 显式空闲更新作用于下一 Query。未关闭 Query 即使在轮次之间也保持 busy,并使用原策略。 受管 startDaemon() 在首个 Query 前确认更新就绪并写入启动回执,daemon 可直接预热, 无需创建虚假 Query。启动策略持续生效,直到更新成功;新 Query 在任务预留后取得活动版本快照。 准备 Hook 文件和更新策略时暂停任务派发,成功后再提交工作。

独立的受限 --reloadable 模式拒绝严格 Post 和私有执行租约。兼容该模式的策略若需 在不重启 daemon 的情况下更新已有 Query,使用 aw run --config aw.yaml --agent sdk --reloadable 显式启用。沿用同一个 createQuery 工厂和调用方管理的 startDaemon();异步输入迭代器可让 Query 在请求之间保持可用。使用 aw update --config aw.yaml --agent sdk --policy desired.yaml 通过公共 CLI 和 UpdatePolicy 事务显式激活完整候选策略。

该受限模式要求实例内所有受管 Query 空闲。已提交或排队的消息、模型等待、原生回调、Query 关闭 清理期间,实例都保持 busy。结果消息本身不是空闲确认:可检查 aw service status --config aw.yaml,在 requests 回到零后重新显式更新。 提交前失败保留原活动策略;提交后终态审计失败会阻止派发并停止服务,须重启后复用。即使初始策略没有 Hook,也会注册稳定回调;新增和移除 会作用于已有 Query 的下一次请求,原生权限保持优先。

受限 --reloadable Query 要求显式 daemon 和 msg_lifecycle_v1 能力。桥接等待原生命令队列 完成后释放请求准入;提前 return 或出错时,等待原生 close() 和仍在执行的回调结束。 普通 Bash 命令超时后可能自动转入后台。子进程退出且原生完成通知回合清理结束之前, 对应请求持续保持 busy。提前关闭 Query 时,先通过原生 stopTask() 停止这些任务, 再释放请求准入。 通过 prompt 输入或 streamInput 提交工作。此模式拒绝 goal 选项、setGoal、 resumeGoal、host-action 调度、backgroundTasks、CreateGoal、ScheduleWakeup、 CronCreate 和 run_in_background 工具,因为这些入口可以在准入边界之外调度工作。定时器触发的回合绕过输入迭代器, 因此不支持创建定时唤醒或 cron 任务;CronList 和 CronDelete 仍可使用。 Worker 1.1.78 的 UpdateGoal 只能完成或 阻塞已有 goal,不能激活 goal,因此仍可使用。 创建 Query 时还会拒绝自定义 agents 中的 background: true 或 isolation: "worktree"。 Agent 工具传入 isolation: "worktree" 也会在执行前被拒绝,因为 worktree 执行不属于 支持的绑定边界。前台定义和默认隔离的 Agent 调用仍可使用。普通 aw run 使用常驻 scope 路径并保留原生 goal API。此接入不提供外部 PID attach/detach、按 session 独立选择 AW 策略或 steer。

普通模式下,Worker 1.1.78 的 worktree 子代理回调仍携带父 Query 的 cwd 和子代理 agent_id,而工具实际在 worktree 中执行。AW 能观察到这些回调,但不会重建实际执行 工作目录。依赖该目录的策略不支持 worktree 执行;普通模式不会在创建 Query 时拒绝它。 受限 --reloadable 模式会按上述规则在执行前拒绝 worktree。

受限 --reloadable 桥接会持续读取原生输出,以便在应用暂停读取时仍能观察清理完成。 输出缓冲区没有固定上限:提交工作期间应持续消费 Query 输出,收到 result 后也应继续读取。 若应用停止消费,应停止提交新工作,并等待 close() 或 return();这两个操作会 丢弃缓冲输出并等待原生清理。此模式不为无限期暂停的消费者提供背压。

受限 --reloadable Qoder SDK 路径保留现有容量限制:每实例最多保留 1024 条 Hook 关联记录, request/tool 两类 claim 集合各最多 64 个活动 claim。请求结束后释放 claim;Hook 关联 记录保留到实例释放。这些数值不是可支持的累计 turn 数。调用方需控制实例生命周期和 并发提交量;策略更新不会清空关联历史。

Pi 和 Claude SDK 常驻宿主​

镜像安装相互匹配的 AW、Provider 和固定版本 SDK。使用 共用配置示例, 替换部署路径后选择目标:

aw run --config /etc/aw/aw.yaml --agent claude
aw run --config /etc/aw/aw.yaml --agent pi

Claude target argv 使用应用的 Python 解释器,后接 -m aw_claude -- -m application。 前台 Gunicorn 可使用 -m aw_claude -- -m gunicorn -c conf/gunicorn.py main:app,客户端 在 fork 后的 worker 内创建。公共工厂接入方式:

from aw_claude import create_client

client = create_client(options)
try:
await client.connect()
await client.query(prompt)
async for message in client.receive_response():
yield message
finally:
await client.disconnect()

每轮响应和回调排空后可在同一客户端继续 query,保留会话;resume/session-store 继续可用。 并发工作使用独立客户端,分别使用自己的 cwd/env。每次 query 接受字符串或单消息的有限 AsyncIterable,多消息输入在发送前被拒绝;连续轮次逐次 query。 receive_response() 和 receive_messages() 都在回调排空后交付 ResultMessage; 缺少该消息的 EOF 会报错。保留 finally 中的 disconnect(),确保未完成的 query 执行 interrupt。

进程内 MCP 同时从 aw_claude 导入 create_sdk_mcp_server,每客户端创建新 server, 保留 SDK tool 定义和业务闭包。受管 MCP 合同 说明成功单文本替换、可靠错误状态及明确关联。

常驻 Pi 和 Claude host 会在发布 ready 前拒绝启用 AgentSight evidence 的配置。 常驻 host 可设置 evidence mode: off;旧的任务模式继续支持 evidence。

Pi 保留已有 SDK session 工厂,增加常驻入口:

export async function createSession({ sdk, cwd }) {
return sdk.createAgentSession({ cwd /* application model/tools/options */ });
}
export async function runWorker({ withSession }) {
await serveRequests(async (request) => {
return withSession({ cwd: request.workspace, environment: request.environment },
async (session) => session.prompt(request.prompt));
});
}

serveRequests 为业务服务,在工厂返回前配置业务回调。任务完成即关闭 session,同一 session 并发 prompt 会被拒绝;其他路径也必须经过公共工厂。

示例组合自定义 Hook、sec-core Bash 扫描及 Tokenless PreTool/PostTool。需要单独启动 sec-core daemon,并提供真实自定义 Hook。不透明 MCP 工具还需要明确的安全语义。常驻模式 在回调错误时停止任务,包括 on_error: report;正常策略拒绝沿用原生语义。Claude 中断无法 确认时会终止 AW 的自有前台进程组,部署需配置监督器重启。发送退出信号前先排空请求, 并设置目标的 shutdown_grace_ms 为应用剩余清理留出时间。外层 launcher 从首次转发 退出信号到开始强制清理,默认给予两秒宽限期。 作用范围和限制见退出宽限期。 Schema/BeforeModel、Retrieve 的请求/效果准入和授权依赖见 常驻合同。