🔧 feat(skills): install to agents home
This commit is contained in:
parent
8b75747587
commit
872c1afc24
14
SKILLS.md
14
SKILLS.md
|
|
@ -4,8 +4,8 @@
|
|||
并给出与本 Playbook(`docs/` + `rulesets/`)配套的技能编写建议与内置技能清单。
|
||||
|
||||
> 提示:Codex skills 是“按用户安装”的(默认在
|
||||
> `~/.codex/skills`)。本仓库将 skills 以可分发的形式放在
|
||||
> `codex/skills/`,并提供脚本一键安装到你的 `CODEX_HOME`。
|
||||
> `~/.agents/skills`)。本仓库将 skills 以可分发的形式放在
|
||||
> `codex/skills/`,并提供脚本一键安装到你的 `~/.agents`。
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -38,14 +38,14 @@ codex/skills/
|
|||
最终安装到本机后,对应路径为:
|
||||
|
||||
```txt
|
||||
$CODEX_HOME/skills/<skill-name>/SKILL.md
|
||||
~/.agents/skills/<skill-name>/SKILL.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 安装到本机(推荐)
|
||||
|
||||
使用统一入口 `playbook.py` 安装 skills(会把 `codex/skills/*` 复制到 `$CODEX_HOME/skills/`):
|
||||
使用统一入口 `playbook.py` 安装 skills(会把 `codex/skills/*` 复制到 `~/.agents/skills/`):
|
||||
|
||||
```toml
|
||||
# playbook.toml
|
||||
|
|
@ -54,7 +54,7 @@ project_root = "."
|
|||
|
||||
[install_skills]
|
||||
mode = "all" # list|all
|
||||
codex_home = "~/.codex"
|
||||
agents_home = "~/.agents"
|
||||
```
|
||||
|
||||
```bash
|
||||
|
|
@ -74,10 +74,10 @@ skills = ["style-cleanup", "commit-message"]
|
|||
```toml
|
||||
[install_skills]
|
||||
mode = "all"
|
||||
codex_home = "./.codex"
|
||||
agents_home = "./.agents"
|
||||
```
|
||||
|
||||
> 注意:Codex 只会从 `CODEX_HOME` 加载 skills;使用本地安装时,启动 Codex 需设置同样的 `CODEX_HOME`。
|
||||
> 注意:Codex 默认从 `~/.agents/skills` 加载 skills;使用本地安装时,需要确保 Codex 能发现该路径。
|
||||
|
||||
如果你的项目通过 `git subtree` vendoring 本 Playbook(推荐前缀
|
||||
`docs/standards/playbook`),则在目标项目里执行:
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ description: Use when creating new skills, editing existing skills, or verifying
|
|||
|
||||
**Writing skills IS Test-Driven Development applied to process documentation.**
|
||||
|
||||
**Personal skills live in agent-specific directories (`~/.claude/skills` for Claude Code, `~/.codex/skills` for Codex)**
|
||||
**Personal skills live in agent-specific directories (`~/.claude/skills` for Claude Code, `~/.agents/skills` for Codex)**
|
||||
|
||||
You write test cases (pressure scenarios with subagents), watch them fail (baseline behavior), write the skill (documentation), watch tests pass (agents comply), and refactor (close loopholes).
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
[sync_rules]
|
||||
# 同步 AGENT_RULES.md(配置节存在即启用)
|
||||
# force = false # 可选:覆盖已有文件
|
||||
# no_backup = false # 可选:跳过备份
|
||||
|
||||
[sync_memory_bank]
|
||||
# 同步 memory-bank/(配置节存在即启用)
|
||||
|
|
@ -32,11 +33,12 @@
|
|||
[sync_standards]
|
||||
# langs = ["tsl", "cpp"] # 必填:要同步的语言
|
||||
# gitattr_mode = "append" # append(补全缺失)|overwrite(覆盖)|block(插入块)|skip(跳过)
|
||||
# no_backup = false # 可选:跳过备份(.agents/.gitattributes)
|
||||
|
||||
[install_skills]
|
||||
# mode = "list" # list|all
|
||||
# skills = ["brainstorming"] # mode=list 时必填
|
||||
# codex_home = "~/.codex" # 可选:默认 ~/.codex
|
||||
# agents_home = "~/.agents" # 可选:默认 ~/.agents
|
||||
|
||||
[format_md]
|
||||
# tool = "prettier" # 仅支持 prettier
|
||||
|
|
|
|||
|
|
@ -1056,16 +1056,19 @@ def normalize_globs(raw: object) -> list[str]:
|
|||
|
||||
def install_skills_action(config: dict, context: dict) -> int:
|
||||
mode = str(config.get("mode", "list")).lower()
|
||||
codex_home = Path(config.get("codex_home", "~/.codex")).expanduser()
|
||||
if not codex_home.is_absolute():
|
||||
codex_home = (context["project_root"] / codex_home).resolve()
|
||||
if "codex_home" in config:
|
||||
print("ERROR: codex_home is no longer supported; use agents_home", file=sys.stderr)
|
||||
return 2
|
||||
agents_home = Path(config.get("agents_home", "~/.agents")).expanduser()
|
||||
if not agents_home.is_absolute():
|
||||
agents_home = (context["project_root"] / agents_home).resolve()
|
||||
|
||||
skills_src_root = PLAYBOOK_ROOT / "codex/skills"
|
||||
if not skills_src_root.is_dir():
|
||||
print(f"ERROR: skills source not found: {skills_src_root}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
skills_dst_root = codex_home / "skills"
|
||||
skills_dst_root = agents_home / "skills"
|
||||
ensure_dir(skills_dst_root)
|
||||
|
||||
if mode == "all":
|
||||
|
|
|
|||
|
|
@ -126,6 +126,27 @@ langs = ["tsl"]
|
|||
self.assertEqual(block[bullet_idx - 1], "")
|
||||
|
||||
def test_install_skills(self):
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
target = Path(tmp_dir) / "agents"
|
||||
config_body = f"""
|
||||
[playbook]
|
||||
project_root = "{tmp_dir}"
|
||||
|
||||
[install_skills]
|
||||
agents_home = "{target}"
|
||||
mode = "list"
|
||||
skills = ["brainstorming"]
|
||||
"""
|
||||
config_path = Path(tmp_dir) / "playbook.toml"
|
||||
config_path.write_text(config_body, encoding="utf-8")
|
||||
|
||||
result = run_cli("-config", str(config_path))
|
||||
|
||||
skill_file = target / "skills/brainstorming/SKILL.md"
|
||||
self.assertEqual(result.returncode, 0)
|
||||
self.assertTrue(skill_file.is_file())
|
||||
|
||||
def test_install_skills_rejects_codex_home(self):
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
target = Path(tmp_dir) / "codex"
|
||||
config_body = f"""
|
||||
|
|
@ -142,9 +163,8 @@ skills = ["brainstorming"]
|
|||
|
||||
result = run_cli("-config", str(config_path))
|
||||
|
||||
skill_file = target / "skills/brainstorming/SKILL.md"
|
||||
self.assertEqual(result.returncode, 0)
|
||||
self.assertTrue(skill_file.is_file())
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertIn("codex_home", result.stdout + result.stderr)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Reference in New Issue