一个技能就是一个带 SKILL.md 的目录:frontmatter 加上一段针对某类工作的指令。技能是 Cetas 获得领域能力的方式 —— 不用把所有内容都塞进提示里,其中也包括“Cetas 自己怎么配、怎么用”。
/skills列出本次会话里发现的技能。
三层披露
启动时全部加载既浪费又吵,所以技能是分阶段打开的:
- 目录 —— 发现阶段校验每个
SKILL.md,只保留元数据。指令正文根本不进上下文。 - 激活 —— 任务需要时,agent 按名字激活恰好一个技能。Cetas 重新读取并校验那个文件,返回它的指令,同时列出它带的资源(但不读内容)。
- 读资源 —— agent 按需打开该技能目录下的某一个具名资源。
最后这道边界是强制的:资源路径会经过规范化真实路径解析,必须留在这个技能目录里。
技能从哪来
| 作用域 | 路径 |
|---|---|
| 用户 | <CETAS_HOME>/.agents/skills/<skill>/SKILL.md |
| 仓库 | .agents/skills/<skill>/SKILL.md,从当前目录逐级向上找到仓库根 |
仓库里的技能来自一次 checkout,按定义就是不可信输入 —— 你对仓库里任何脚本的戒心,同样适用于这里。宿主可以选择完全排除仓库技能;Cetas 不会替你做信任判断。
技能目录可以是软链接,但解析后的包必须留在仓库边界内,除非宿主明确允许外部包。
怎么写一个
---
name: repo-map
description: 这个仓库该怎么逛
---
## 目录结构
...frontmatter 在发现阶段就会被校验:校验不过的技能会被跳过,而不是加载一半;同名冲突会按确定规则解决,而不是取决于目录遍历顺序。
因为正文只在激活时读取,一个很长的技能在你用不到它的时候不花任何代价。写 frontmatter 时想着发现阶段 —— 描述才是决定 agent 会不会打开这个文件的东西。