夜雨聆风学习资料网

ARTICLE · 1305663

【AX 实战 08】文档说 AX 会把 MCP 和技能包装好,我读完源码发现它只建了个目录

【AX 实战 08】文档说 AX 会把 MCP 和技能包装好,我读完源码发现它只建了个目录

副标题:git、files、MCP、Skills 四类内容的真实边界,与 F11 那个不说就踩的例外

金句:「只准备一次」的真正含义是——成功才打卡,失败下次再来。

上期回顾:第 7 章我们摸清了 Manifest 的两道闸:10 种坏 YAML 当场打回,2 种骗过 apply 再变 Failed。那些反例都围绕 Task 身上的字段。这一章换主角——Workspace,AX 里负责「开工前把家当备齐」的那个 kind。git 仓库、规则文件、MCP 工具、Skills 技能,四类内容全靠它带进沙箱。

本篇要点:

  1. 四类内容各解决什么:spec.git / spec.files / spec.mcp / spec.skills 的真实职责边界
  2. spec.git
     五个字段全解:clone 到哪个子目录,name / dir / depth 的隐藏规则
  3. 文档口径核对
    :README 和 concepts.md 说 AX 会「pre-wire」MCP 与技能包——源码只建目录(三处文档说法逐一核实)
  4. F11 例外
    :「只准备一次」的 marker 机制;git clone 失败不写 marker,下次启动重试(5 次 × 2s)
  5. 多仓库为什么必须合并进一个 Workspace

和多数 AX 文章不同:本章三处「文档与代码不一致」的说法,每一条都当场回源码核实(原文引用 + 文件行号),不含「据说」;F11 的例外从注释、常量到 e2e 测试缺口(M5)一路钉到源码行。

目录锚点:一、四类内容总图|二、spec.git|三、spec.files|四、MCP 与 Skills 的真实边界|五、F11:只准备一次的例外|六、多仓库与单绑定|七、完整案例|八、失败复盘|九、反例/正例|十、自测

前置与难度:第 5~7 章读完即可。难度 ★3(机制不深,但文档误导性最强的一章)。预计 15 分钟。


一、四类内容总图:家当分四类,各走各的门

一个 Workspace 的 spec 只有四个字段(ax.proto:137-141):

spec:  git:     []   # 代码从哪来  files:   []   # 规则写在哪  mcp:     {}   # 工具怎么接  skills:  {}   # 技能从哪加载

四类内容在 maiden run(首次准备) 里的落点和真实行为:

内容
AX 实际做的事
出处
git
clone 到 workspace 子目录
setup.go:114-135
files
原样写文件
setup.go:300-316
skills.path只建目录setup.go:243-251
mcp
 + skills.registries
声明式透传,AX 不拉取
见第四节核实

顺序有讲究:writeFiles 先于 cloneRepos(setup.go:96-98)。checkout -f 只会覆盖仓库里已跟踪的路径——如果你把文件写进某个仓库将要检出的同名路径(比如根目录的 config.yaml 正好是仓库文件),会被检出内容盖掉;untracked 的新路径不会被删(e2e 的 overlay/config.yaml 就是这么活下来的,见 e2e_test.go:387-388)。稳妥做法:overlay 文件写到仓库外的目录。


二、spec.git:代码从哪来

2.1 五个字段,不止三个

GitRepo 有五个字段(ax.proto:144-150):

字段
作用
默认
repo
仓库 URL,必填
—
branch
分支或 tag
main
name
 / dir
落点目录(见下)
从 URL 派生
depth
>0 时浅 fetch
0(全量)

大纲只列了 name / repo / branch 三个——dir 和 depth 是源码里真实存在的另外两个,别漏。

2.2 落点决策:name 可能根本不生效

clone 目标目录的规则(setup.go:154-173):

  1. dir 优先
    :"." → workspace 根;绝对路径 → 原样用;其他 → 相对 workspace
  2. dir
     空 → 用 name;但 name 为空、"repo"、"origin" 时当占位名丢弃,改从 URL 派生
  3. URL 派生规则:去 .git 后缀取最后一段(setup.go:268-276)
# 例:docs/manifests.md 官方示例name: originrepo: https://github.com/chalk/chalk.git# name=origin 是占位名 → 被丢弃# 目录从 URL 派生 → /workspace/chalk# (不是 /workspace/origin!)

这个坑后面「文档核对」再回来算账。

2.3 clone 的实现:init + fetch,不是 git clone

fetchRepo(setup.go:183-215)走的是 git init → remote add(已存在则 set-url)→ fetch origin <branch> → checkout -f FETCH_HEAD。所以:

  • 幂等
    :失败后重试落在半初始化目录上也能跑(:197 注释)
  • 钉的是分支/tag
    ,不是 commit——branch: "my-fix" 就 fetch my-fix
  • depth > 0
     时 fetch 带 --depth=N(:206-208)
  • 参数直接传 exec.Command,不经 shell(:192)

重试:每个仓库失败重试 5 次 × 2s(setup.go:43-44、:132)。重试期间 git-error.log / 成功后的 git-success.log 落在 /ax 下(:39-40)。


三、spec.files:规则写在哪

File 就两个字段:path + content(ax.proto:152-155)。把 AGENTS.md 当「环境里的系统提示」写进来,是官方示例的典型用法(docs/manifests.md:79-84):

files:  - path: "AGENTS.md"    content: |      # Project Guidelines      - Run `go test ./...` before submitting changes.      - Keep dependencies minimal.

三条规则(setup.go:300-316):

  1. path必填
    ——ValidateWorkspace 当场拒绝空 path(types.go:378-384,报错 spec.files[i]: path is required)
  2. 相对路径 → 落在 workspace 下;绝对路径原样用(可以写到 workspace 外,自己负责)
  3. 只在 maiden run 写
    ——marker 在,writeFiles 根本不会执行(setup.go:85-89 直接 return)

为什么把 AGENTS.md 当「环境里的系统提示」?因为 agent 一睁眼就能在工作目录里看到它,不需要任何人「注入」——规则跟着环境走,而不是跟着某次会话走。换一个 Task、换一个 agent 框架,只要绑同一个 Workspace,规矩就一样。这就是「环境即代码」在 files 这一项上的含义。

第 3 条规则和 F11 直接挂钩:改了 files 内容再 apply,老 Task 里看不到新文件。要么 delete 重建,要么删 marker 再重启(rm /ax/initialized-*)。这是「只准备一次」最容易被忽视的副作用——它省下的不只是 clone 时间,也锁住了你的规则更新。


四、MCP 与 Skills 的真实边界:三处文档说法逐条核实

这一节是本章的「文档核对」环节。README 与 concepts.md 对 MCP/Skills 的描述比代码做的事多。以下三处说法逐一回源码核实,结论只写代码能证明的。

核实 1|README 说「Pre-wire Git repos, MCP servers, and skill packages」

原文:「Pre-wire Git repos, MCP servers, and skill packages so every agent starts warm」(README.md:59)

代码现实(setup.go:62-108):maiden run 只做三件事——写文件、clone 仓库、给 skills.path建目录(setup.go:243-251 就一个 MkdirAll)。MCP servers 没有任何连接动作,skill packages 没有任何下载动作。

消费方在哪:mcp 与 skills.registries 原样存进 AX,经 AX_WORKSPACE_YAML 送到任务容器(reconciler.go:195),任务进程可从 metadata 端点 /metadata/v1alpha1/ax/workspace 拿到 YAML(metadata/server.go:122-123)。全仓库检索 Registries 的消费点只有 describe 打印(main.go:637-663)——按 query 发现、拉取技能包的是 agent 自己,不是 AX。

结论:⚠️ 措辞过强。AX 的「pre-wire」对 git/files 成立;对 MCP/Skills 只到「声明 + 建目录 + 透传」为止。

核实 2|concepts.md 说 runner 会 materialize MCP 与 skill registries

原文:「the runner materializes it inside each sandbox before the command starts」,清单含「MCP servers and registries」「Skill registries and the path where skills are materialized」(docs/concepts.md:26-30)

代码现实:runner 调 SetupWorkspace(runner/runner.go:126),行为同核实 1——skills 只建 path 目录,registries 零动作。「materialized」对 git/files/目录成立,对 MCP/registries 不成立。

结论:⚠️ 与核实 1 同源的措辞问题。「the path where skills are materialized」一句最准确的读法是:AX 保证目录存在,技能包由消费方放进去。

核实 3|manifests.md 示例的 name: origin 是占位名

原文示例:git: [{name: origin, repo: "https://github.com/chalk/chalk.git", branch: "main"}](docs/manifests.md:75-78)

代码现实:"origin" 和 "repo" 一样是被丢弃的占位名(setup.go:167),目录从 URL 派生为 chalk,不是origin。

结论:⚠️ 示例可跑,但读者若按 name 找目录会扑空。自己写 manifest 时,name 要么不写、要么起个有意义的目录名,别用 origin;最确定的写法是直接给 dir(见 §九 正例)。


五、F11:「只准备一次」的例外

5.1 marker 机制

maiden run 成功后,AX 在 /ax 写一个 marker 文件:initialized-<path>(setup.go:32-35、:256-264)。路径里的 / 换成 -——workspace 挂在 /workspace/primary,marker 就叫 initialized-workspace-primary(e2e 实测断言 MARKERS_OK,e2e_test.go:431)。

下次启动,SetupWorkspace 开头查 marker:存在 → 直接返回,什么都不做(setup.go:85-89)。git 不重新 clone,files 不重写,skills 目录不重建。

5.2 F11 的例外:git 失败不打卡

源码注释写得明明白白(setup.go:66-67):

Git failures are logged and recorded under AXDirbut do not abort setup. The marker is withheld inthat case so the next start retries the clone.

行为逐条对齐:

事实
出处
git 失败不中止 setup,继续下一个仓库
setup.go:129-135
失败信息写 /ax/git-error.log
setup.go:133-134
不写 marker
,返回前打日志
setup.go:102-103
、:106
单仓重试 5 次 × 2s 后才判失败
setup.go:43-44
、:132

这意味着:clone 失败的 Task 照样起来(SetupWorkspace 对 git 失败返回 nil,setup.go:102-103,于是 runner 侧走 SetWorkspaceReady(true),runner/runner.go:126-131——这是「失败不中止」的直接后果,而非缺陷),但沙箱里缺仓库。下一次 runner 冷启动(新 Task、或重新创建的容器)会重新走 maiden run,再 clone 一次。

写作与使用口径(FACTS F11):讲「只准备一次」必须带这个例外——否则读者会以为失败也被标记、永远不再 clone,从而误判「改好 URL 后什么都不用做」。实际上:改好 URL 后要触发一次新的冷启动。suspend → resume 是否属于「新的冷启动」取决于 resume 走快照恢复还是重建容器(M4/M5 待实测,别打包票)。

M5 缺口(诚实声明):e2e 只测成功路径(TestE2E_WorkspaceSetup_FilesAndGit,e2e_test.go:408-438),失败重试无实测用例(FACTS M5,静态先证 ✅ / 实跑 ⬜)。源码承诺「会重试」,眼见为实要等 M5。


六、多仓库与单绑定:为什么必须合并进一个 Workspace

Task 绑定 workspace 的字段 WorkspaceRef 只有 name + path 两个字段,没有列表(ax.proto:106-109)——一个 Task 至多绑一个 Workspace(docs/manifests.md:40-42)。

要两个仓库?声明在一个 Workspace 的 spec.git 里:

spec:  git:    - name: backend      repo: https://example.com/org/backend.git    - name: frontend      repo: https://example.com/org/frontend.git

落点就是两个子目录:/workspace/backend、/workspace/frontend(name 不是占位名时直接当目录名,setup.go:165-166)。

为什么这么设计:workspace 的挂载路径就是命令的工作目录(第 6 章讲过的一 cwd 原则)。两套环境 = 两个 Task,各自绑各自的 Workspace——这正好接上第 6 章的扇出模型。


七、完整案例:把团队环境固化成一个 Workspace

以下 manifest 改写自 e2e 测试的 workspaceSetupManifest(e2e_test.go:375-401,字段与落点全部实测过):

apiVersion: ax.io/v1alpha1kind: Workspacemetadata:  name: team-envspec:  git:    - name: primary      dir: "."      repo: https://example.com/org/mono.git      branch: v1.0.0      depth: 1  files:    - path: overlay/config.yaml      content: "mode: git-plus-overlay"    - path: AGENTS.md      content: |        - Run tests before submitting.  mcp:    registries:      - provider: google        query: "mcp.tags:build"    servers:      - name: git-tools        endpoint: "http://git-mcp.default:8080"  skills:    registries:      - provider: google        query: "skills.tags:nodejs"    path: /workspace/primary/.agents/skills---apiVersion: ax.io/v1alpha1kind: Taskmetadata:  name: dev-taskspec:  debug: true  workspace:    name: team-env    path: /workspace/primary

这份 manifest 不是拍脑袋写的——四类字段各就各位,落点全部对应 e2e 断言:

  1. 仓库 clone 到 /workspace/primary(dir: "."),tag v1.0.0,浅 fetch
  2. overlay/config.yaml
     写在仓库外,不被 checkout -f 覆盖
  3. skills 目录 /workspace/primary/.agents/skills 被创建(断言 SKILLS_DIR_OK)
  4. marker 是 /ax/initialized-workspace-primary(断言 MARKERS_OK)
  5. mcp
     与 skills.registries 原样进 metadata 端点,等 agent 自己消费

验收序列:apply → resume → ax ssh dev-task -- ls /workspace/primary 看仓库在不在 → cat /ax/initialized-workspace-primary 看打卡记录。一次跑通之后,这份 Workspace 就是团队的环境基线——新成员、新 Task、新框架,绑上即用。


八、失败复盘:三个真会踩的坑

坑 1:clone 失败,Task 看起来一切正常

SetupWorkspace 对 git 失败返回 nil,WorkspaceReady 照样 True。你 ssh 进去才发现仓库目录是空的。排查路径:ls /ax/git-error.log → 里面有 error 和 git 输出 → 修 URL/网络 → 触发一次冷启动(delete+apply 最稳)→ 下次 maiden run 重试。别盯着 marker 等它自己好——它没写 marker,等的是重启。

坑 2:改了 files,老 Task 看不到

marker 在,writeFiles 不执行。改规则文件的正确姿势:delete 旧 Task → apply 新的。如果连 Workspace 的 spec 也改了,注意 marker 是按挂载路径打点的(setup.go:256-264)——同一路径的 marker 还在,新 spec 同样不生效,要么换新路径,要么 rm /ax/initialized-* 清掉再启动。

坑 3:按 name: origin 找目录

官方示例的 name: origin 是占位名,目录实际叫 chalk(核实 3)。找不到仓库先 ls /workspace,再对照 setup.go:154-173 的决策树。


九、反例 / 正例

反例(照抄官方示例然后猜目录):

git:  - name: origin    repo: https://github.com/chalk/chalk.git# 猜目录:/workspace/origin → 不存在# 实际:  /workspace/chalk

正例(要可控就用 dir):

git:  - dir: chalk    repo: https://github.com/chalk/chalk.git# dir 优先,落点确定:/workspace/chalk

十、自测 3 题

  1. git clone 失败后,marker 写了吗?下次会发生什么?
        答:没写(setup.go:102-103)。本次启动照常跑(可 ssh,缺仓库);下一次启动重走 maiden run,单仓再试 5 次 × 2s。
  2. mcp.registries 里的 query 是谁消费的?
        答:agent 自己。AX 只存声明、透传 YAML(metadata 端点),不做发现和连接。
  3. 改了 spec.files 的内容,已运行的 Task 会更新吗?
        答:不会。maiden run 一次定终身;要 delete 重建或清 marker 重启。

十一、一页速查

问题
答案
spec 四字段?
git / files / mcp / skills
clone 落点谁说了算?
dir
 > name > URL 派生
name: origin
?
占位名,丢弃
clone 失败打卡吗?
不打,下次启动重试
重试几次?
5 次 × 2s
files 会重写吗?
只在 maiden run
MCP 谁来连?
agent,AX 只透传
多仓库怎么办?
合并进一个 Workspace

一句话小结

Workspace 把「开工前的家当」变成声明:git 真 clone、files 真写入、目录真创建;MCP 与 registries 只透传——而「只准备一次」的打卡,只记成功。


十二、下期预告

第 9 章|Model 与凭证:为什么密钥不该出现在 Task 里。provider / model / parameters 三件套,F14 的参数键名陷阱(proto 说 maxOutputTokens,文档示例写 maxTokens),以及 secretKey 两步创建——把 token 从 config 里救出来。


互动

你是怎么发现 clone 失败的?投票:A. ssh 进去看到空目录 B. 先撞上 /ax/git-error.log C. 根本没发现,agent 自己瞎编了答案。评论区报个字母,选 C 的多就单独开一篇「F11 失败现场」。


事实锚点:AX 4b7bf6f / Substrate v0.6.0适用边界:基于上述锚点撰写;AX 为 pre-1.0,行为可能漂移,以你实际部署的版本为准。


附:标题候选库(留档,供 §6.4 多平台改编复用)

★ 公众号推荐标题(系列统一定稿):【AX 实战 8】文档说 AX 会把 MCP 和技能包装好,我读完源码发现它只建了个目录 副标题(技术定位):git、files、MCP、Skills 的真实边界

类型
标题
钩子型
文档说 AX 会把 MCP 和技能包装好,我读完源码发现它只建了个目录
数字型
4 类家当 3 个真相:git 真 clone、目录真建、MCP 只透传
身份代入型
如果你按官方示例找过 origin 目录,这篇能救你十分钟
反差型
「只准备一次」是骗你的——失败的那一次 AX 根本不记

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料