第 2 课
AGENTS.md 规则、技能与 agy -p 无头自动化
按官方 Rules、Skills、Headless mode 与 Permissions 文档:写 AGENTS.md 与 glob 规则并验证加载、写 /run-tests 技能、Gemini CLI 迁移要点;agy -p 的 JSON 信封、JSON Schema 结构化输出、stream-json 事件、软拒绝与 permissions.allow、--continue / --model / --print-timeout,以及可放进 CI 的脚本。
学习位置仅保存在当前浏览器,有效期 180 天。
图文讲义
来源:Google Antigravity 官方文档 · Rules、Agent skills、Headless mode、Permissions、Migration from Gemini CLI。核对日期 2026-10-08(CLI 1.3.1)。 本课沿用上一课的
~/kun-agy-demo项目:先用AGENTS.md与.agents/rules/把项目规矩固定下来,再写一个技能(skill),最后用agy -p无头模式接入脚本与 CI。
你将得到什么
- 项目根目录的
AGENTS.md,以及一条按文件类型自动生效的.agents/rules/规则 - 一个能用
/run-tests调用的项目技能 - 会用
agy -p输出纯文本、JSON、NDJSON 流和按 JSON Schema 约束的结构化结果 - 会用
permissions.allow给无头模式精确放权,而不是一律--dangerously-skip-permissions - 一个可直接放进 CI 的 bash 脚本,失败时让流水线报错
开始前准备
- 已完成课时 1:
agy可运行、已登录(或已配置 Gemini API Key),~/kun-agy-demo测试全绿 - 安装
jq(macOS:brew install jq;Debian / Ubuntu:sudo apt install jq),用jq --version确认 - 无头模式使用已缓存的登录信息:用账号登录的话,先在交互模式下登录一次
一、规则文件放在哪里
Antigravity 会自动发现规则并注入 Agent 上下文。各层规则是累加的,冲突时越具体的目录规则优先。
| 范围 | 位置 | 说明 |
|---|---|---|
| 目录 / 项目 | AGENTS.md 或 GEMINI.md(项目根或任意子目录) | 无需 frontmatter,始终生效 |
| 目录 / 项目 | <目录>/.agents/AGENTS.md、<目录>/.agents/GEMINI.md | 同上 |
| 目录 / 项目 | <目录>/.agents/rules/*.md | 必须有 YAML frontmatter,按 trigger 激活 |
| 全局 | ~/.gemini/AGENTS.md、~/.gemini/GEMINI.md | 对本机所有项目生效 |
| 全局(CLI) | ~/.gemini/config/rules/*.md、~/.gemini/antigravity-cli/rules/*.md | 模块化全局规则,需 frontmatter |
Agent 读写某个文件时,会从该文件所在目录一路向上找到工作区根,沿途的规则都会加载。
从 Gemini CLI 迁移过来的项目,原有的
GEMINI.md无需改动,继续有效。
步骤 1:写项目根的 AGENTS.md
cd ~/kun-agy-demo
cat > AGENTS.md <<'MD'
# kun-agy-demo 项目规则
- 只用 Python 标准库,不引入第三方依赖。
- 每次改动代码后运行 `python3 -m unittest -v`,全部通过才算完成。
- 新增或修改函数时,同步在 test_stats.py 中补充测试。
- 函数遇到非法输入时抛出 ValueError,错误信息用英文。
- 回答用中文,提交信息用英文并遵循 Conventional Commits(如 fix:、feat:)。
MD
步骤 2:加一条按文件类型生效的规则
.agents/rules/ 下的每个 .md 文件都必须以 frontmatter 开头,并声明合法的 trigger,否则会被静默丢弃。可选值只有 always_on、model_decision、glob、manual 四种(注意是下划线写法,alwaysOn 这类驼峰写法无效)。
mkdir -p .agents/rules
cat > .agents/rules/python-style.md <<'MD'
---
trigger: glob
globs: "*.py"
description: "Python 代码风格:类型注解与文档字符串。"
---
# Python 风格
1. 公开函数必须写类型注解,例如 `def mean(values: list[float]) -> float:`。
2. 公开函数必须有一行英文 docstring。
MD
四种 trigger 的区别:
| trigger | 何时加载 | 适合 |
|---|---|---|
always_on | 每一轮都完整注入 | 少量硬约束(更推荐直接写进 AGENTS.md) |
model_decision | 只先注入 description,任务相关时 Agent 再读全文 | 较长的领域指南,必须写 description |
glob | Agent 接触到匹配 globs 的文件时 | 按语言或目录区分的约定,必须写 globs |
manual | 只有你在对话里用 @ 提到它时 | 发布检查单、审计清单 |
globs以*开头时要加引号,否则 YAML 会把*当成别名符号。.agents/rules/只扫描第一层.md文件,子目录里的规则需要在.agents/rules.json中登记。
步骤 3:验证规则已被加载
用无头模式提一个只读问题:
agy -p "不要修改任何文件。逐条列出你在这个项目里必须遵守的规则,\
并注明每条来自哪个文件。"
对照结果:回答应列出 AGENTS.md 中的五条规则;如果它读过 .py 文件,还会提到 .agents/rules/python-style.md 中的类型注解与 docstring 要求。措辞每次会不同。
再让它真正按规则改代码(这一步会写文件,交互模式更直观):
agy
按项目规则给 stats.py 的两个函数补上类型注解和 docstring,然后运行测试。
对照结果:diff 中应出现 def mean(values: list[float]) -> float: 这类注解和英文 docstring,测试仍是 OK。按 y 接受,/exit 退出。
两个上限
- 单个规则文件最多 24,000 字节(展开
@[标签](路径)引用之后计算),超出部分被截断。 - 所有全局与
always_on规则共享 20,000 token 预算;超出时最大的文件会被降级为「路径 + 描述」的指针,由 Agent 按需读取。
步骤 4:写一个项目技能(skill)
规则管「约束」,技能管「多步骤流程」。技能是一个包含 SKILL.md 的文件夹,CLI 会把它自动变成同名斜杠命令。
mkdir -p .agents/skills/run-tests
cat > .agents/skills/run-tests/SKILL.md <<'MD'
---
name: run-tests
description: Runs this project's unit tests and summarizes failures.
---
# Run tests
1. Run `python3 -m unittest -v` in the project root.
2. If all tests pass, reply with the number of tests and "OK".
3. If any test fails, list each failing test, its error line,
and the most likely cause.
MD
重新启动 agy,在输入框键入 /run 应能看到 /run-tests 补全;执行后 Agent 会按 SKILL.md 的步骤跑测试并汇报。全局技能放在 ~/.gemini/antigravity-cli/skills/<技能名>/。
Gemini CLI 用户注意:工作区技能目录由
.gemini/skills/改为.agents/skills/,需要手动移动;旧扩展可以用agy plugin import gemini转成插件,MCP 服务器配置改放~/.gemini/config/mcp_config.json(全局)或.agents/mcp_config.json(工作区),远程服务器的url/httpUrl键要改为serverUrl。
把规则和技能提交进仓库,团队成员拉代码后即可共享:
git add AGENTS.md .agents stats.py
git commit -m "chore: add agent rules and run-tests skill"
二、用 agy -p 跑无头模式
-p(同 --print、--prompt)发送一个提示词、输出结果后退出。回答写到 stdout,错误、认证提示、进度与权限通知写到 stderr,所以可以放心地把回答赋值给变量。
步骤 5:纯文本与 JSON 输出
answer=$(agy -p "用一句话说明 stats.py 里 median() 的作用。")
echo "$answer"
改用 JSON 信封,并用 jq 取字段:
agy -p "用一句话说明 stats.py 里 median() 的作用。" \
--output-format json | jq '{status, response, usage}'
对照结果(数值会不同):
{
"status": "SUCCESS",
"response": "median() 返回列表排序后的中位数……\n",
"usage": {
"input_tokens": 10415,
"output_tokens": 657,
"thinking_tokens": 616,
"cache_read_tokens": 8113,
"total_tokens": 11072
}
}
JSON 信封的字段:
| 字段 | 含义 |
|---|---|
conversation_id | 会话 ID,可用于继续对话 |
status | 结束状态:SUCCESS、ERROR、CANCELED、INTERRUPTED、INVALID、WAITING、RUNNING |
response | Agent 的文本回答 |
error | 错误信息,仅失败时出现 |
duration_seconds / num_turns | 耗时(秒)与轮数 |
usage | token 用量:输入、输出、思考、缓存命中、合计 |
structured_output | 仅在使用 --json-schema 时出现 |
步骤 6:用 JSON Schema 拿到结构化结果
--json-schema 接受 Schema 字符串或文件路径。把 Schema 存成文件更好维护:
cat > schema.json <<'JSON'
{
"type": "object",
"properties": {
"functions": { "type": "array", "items": { "type": "string" } },
"has_tests": { "type": "boolean" }
},
"required": ["functions", "has_tests"]
}
JSON
agy -p "列出 stats.py 中定义的所有函数名,并判断项目里是否有对应的单元测试。" \
--output-format json --json-schema schema.json \
| jq '.structured_output'
对照结果(应类似):
{
"functions": ["mean", "median"],
"has_tests": true
}
步骤 7:流式事件(stream-json)
stream-json 每行一个 JSON 事件:先 1 个 init,再若干 step_update,最后 1 个 result(结构同 JSON 信封)。
边生成边打印文字(jq -j 让片段首尾相接、不插换行):
agy -p "用两句话解释什么是中位数。" --output-format stream-json \
| jq -j 'select(.event=="step_update") | .step_update.text_delta // empty'
只看最终的用量:
agy -p "用两句话解释什么是中位数。" --output-format stream-json \
| jq 'select(.event=="result") | .result.usage'
工具调用会出现在 step_type 为 tool 的事件里,tool_info 包含工具名、参数和输出,适合做运行日志。
步骤 8:无头模式下的权限
无头模式没有人来按 y。默认规则是:
- 读写工作区内的文件自动允许;
- 运行 shell 命令等默认是 Ask,在无头模式下会被软拒绝:任务继续、退出码仍是
0,stderr 会打印一条通知,说明哪个工具被拦下、该怎么放行。
先观察软拒绝:
agy -p "运行 python3 -m unittest -v,并报告通过了几个测试。"; echo "exit=$?"
对照结果:exit=0,但 stderr 里有权限通知,回答会说明它没能运行命令。
再精确放行。编辑 ~/.gemini/antigravity-cli/settings.json,加入 permissions.allow(如果文件里已有 "modelProvider": "gemini" 等键,要合并进同一个 JSON 对象,不要覆盖):
{
"permissions": {
"allow": [
"command(python3 -m unittest)",
"command(git status)",
"command(git diff)"
]
}
}
重跑同一条命令,这次应能看到 Ran 4 tests 与 OK 的总结。
规则写法要点:
- 格式是
action(target);常用 action 有command、read_file、write_file、read_url、mcp。 command(前缀)按词逐个前缀匹配:command(git)会放行git status && git log,但不会放行git log $(whoami)这类含命令替换的写法。- 需要正则时加
regex:,例如command(regex:npm run (build|lint|test))。 - 冲突时优先级是 Deny > Ask > Allow。
--dangerously-skip-permissions会批准所有工具调用(含写文件和任意命令),只在一次性的隔离环境里使用。
步骤 9:继续对话、固定模型与超时
无头运行默认无状态。继续最近一次对话用 -c,指定会话用 --conversation:
agy -p "把你上一个回答压缩成一句话。" --continue
agy -p "总结我们讨论过的内容。" --conversation 你的-conversation_id
固定模型(标识来自 agy models)与推理强度:
agy -p "把字符串 antigravity 反转。" --model gemini-3.8-flash-medium
agy -p "为 stats.py 设计一个 mode() 函数的实现方案。" --effort high
--model 写错时不会悄悄回退,而是直接失败。编辑部实测:
agy -p "hi" --model does-not-exist-model --output-format json \
| jq -r '.status'; echo "exit=${PIPESTATUS[0]}"
ERROR
exit=1
此时 error 字段以 invalid model selection 开头,后面附上当前可用模型清单(如 Gemini 3.8 Flash (High)),方便你在流水线日志里直接看到该填什么。
关于超时:官方 Headless 文档写的是默认等待 5 分钟,而 1.3.1 的 agy --help 显示 --print-timeout 默认 0s(等到本轮结束)。两者不一致时,在脚本里显式写上 --print-timeout 10m,行为就不受版本影响。
步骤 10:放进 CI 的脚本
CI 里没有浏览器,用 Gemini API Key 最省事:在流水线的密钥管理里保存 GEMINI_API_KEY,运行前写好设置文件。在项目根新建 ci-agent.sh:
cat > ci-agent.sh <<'SH'
#!/usr/bin/env bash
set -euo pipefail
mkdir -p ~/.gemini/antigravity-cli
cat > ~/.gemini/antigravity-cli/settings.json <<'JSON'
{
"modelProvider": "gemini",
"permissions": {
"allow": ["command(python3 -m unittest)", "command(git diff)"]
}
}
JSON
prompt="运行 python3 -m unittest -v。全部通过回复 PASS,否则列出失败测试和原因。"
result=$(agy -p "$prompt" \
--output-format json \
--print-timeout 10m)
status=$(echo "$result" | jq -r '.status')
if [[ "$status" != "SUCCESS" ]]; then
echo "Agent run failed: $(echo "$result" | jq -r '.error')" >&2
exit 1
fi
echo "$result" | jq -r '.response' | tee agent-report.txt
SH
chmod +x ci-agent.sh
本地先试一遍。脚本会覆盖你的全局 settings.json,所以先备份(文件不存在时第一条会报错,可忽略):
cp ~/.gemini/antigravity-cli/settings.json /tmp/agy-settings.bak
export GEMINI_API_KEY="你的-api-key"
./ci-agent.sh; echo "exit=$?"
对照结果:终端打印 PASS(或失败清单),目录下生成 agent-report.txt,exit=0。Key 无效时,编辑部实测 status 为 ERROR、error 中包含 API key not valid,脚本以 exit=1 结束。试完恢复设置:
cp /tmp/agy-settings.bak ~/.gemini/antigravity-cli/settings.json
不要把
GEMINI_API_KEY写进仓库或脚本,始终通过 CI 的加密变量注入。
收尾检查清单
-
AGENTS.md已提交,agy -p能复述其中的规则 -
.agents/rules/python-style.md有合法 frontmatter(trigger: glob+globs) -
/run-tests能在交互模式中补全并执行 - 会用
--output-format json+jq判断status - 无头模式用
permissions.allow精确放权,没有默认带--dangerously-skip-permissions - CI 脚本显式设置了
--print-timeout,Key 走加密变量
本课来源
- https://antigravity.google/docs/rules
- https://antigravity.google/docs/skills
- https://antigravity.google/docs/cli/headless
- https://antigravity.google/docs/permissions?tab=cli
- https://antigravity.google/docs/cli/gcli-migration
- https://antigravity.google/docs/cli/install
- https://antigravity.google/docs/cli/reference

