diff --git a/scripts/playbook.py b/scripts/playbook.py index 8eb29507..bb359bfe 100644 --- a/scripts/playbook.py +++ b/scripts/playbook.py @@ -626,10 +626,13 @@ def replace_placeholders( project_name: str | None, date_value: str, playbook_scripts: str | None, + playbook_root: str | None, ) -> str: result = text.replace("{{DATE}}", date_value) if project_name: result = result.replace("{{PROJECT_NAME}}", project_name) + if playbook_root: + result = result.replace("{{PLAYBOOK_ROOT}}", playbook_root) if playbook_scripts: result = result.replace("{{PLAYBOOK_SCRIPTS}}", playbook_scripts) return result @@ -649,11 +652,14 @@ def replace_placeholders_in_file( project_name: str | None, date_value: str, playbook_scripts: str | None, + playbook_root: str | None, ) -> None: if file_path.suffix != ".md": return text = file_path.read_text(encoding="utf-8") - updated = replace_placeholders(text, project_name, date_value, playbook_scripts) + updated = replace_placeholders( + text, project_name, date_value, playbook_scripts, playbook_root + ) if updated != text: file_path.write_text(updated, encoding="utf-8", newline="\n") @@ -673,6 +679,7 @@ def sync_directory( project_name: str | None, date_value: str, playbook_scripts: str | None, + playbook_root: str | None, force: bool, no_backup: bool, ) -> None: @@ -693,6 +700,7 @@ def sync_directory( project_name, date_value, playbook_scripts, + playbook_root, ) @@ -720,10 +728,11 @@ def update_agents_section( project_name: str | None, date_value: str, playbook_scripts: str | None, + playbook_root: str | None, ) -> None: template_text = template_path.read_text(encoding="utf-8") template_text = replace_placeholders( - template_text, project_name, date_value, playbook_scripts + template_text, project_name, date_value, playbook_scripts, playbook_root ) block = extract_block_lines(template_text, start_marker, end_marker) if not block: @@ -802,6 +811,7 @@ def sync_agents_template(context: dict) -> int: project_name = resolve_project_name(context) playbook_scripts = resolve_playbook_scripts(context) + playbook_root = resolve_playbook_root(context) date_value = resolve_template_date(context) agents_dst = project_root / "AGENTS.md" @@ -828,6 +838,7 @@ def sync_agents_template(context: dict) -> int: project_name, date_value, playbook_scripts, + playbook_root, ) sync_claude_md(project_root, context.get("config", {})) return 0 @@ -944,12 +955,15 @@ def sync_rules_action(config: dict, context: dict) -> int: project_name = resolve_project_name(context) playbook_scripts = resolve_playbook_scripts(context) + playbook_root = resolve_playbook_root(context) date_value = config.get("date") or datetime.now().strftime("%Y-%m-%d") no_backup = bool(config.get("no_backup", False)) backup_path(rules_dst, no_backup) text = rules_src.read_text(encoding="utf-8") - text = replace_placeholders(text, project_name, date_value, playbook_scripts) + text = replace_placeholders( + text, project_name, date_value, playbook_scripts, playbook_root + ) rules_dst.write_text(text.rstrip("\n") + "\n", encoding="utf-8", newline="\n") log("Synced: AGENT_RULES.md") @@ -987,6 +1001,7 @@ def sync_memory_bank_action(config: dict, context: dict) -> int: project_name = config.get("project_name") playbook_scripts = resolve_playbook_scripts(context) + playbook_root = resolve_playbook_root(context) date_value = config.get("date") or datetime.now().strftime("%Y-%m-%d") force = bool(config.get("force", False)) no_backup = bool(config.get("no_backup", False)) @@ -999,6 +1014,7 @@ def sync_memory_bank_action(config: dict, context: dict) -> int: project_name, date_value, playbook_scripts, + playbook_root, force, no_backup, ) @@ -1020,6 +1036,7 @@ def sync_prompts_action(config: dict, context: dict) -> int: project_name = resolve_project_name(context) playbook_scripts = resolve_playbook_scripts(context) + playbook_root = resolve_playbook_root(context) date_value = config.get("date") or datetime.now().strftime("%Y-%m-%d") force = bool(config.get("force", False)) no_backup = bool(config.get("no_backup", False)) @@ -1033,6 +1050,7 @@ def sync_prompts_action(config: dict, context: dict) -> int: project_name, date_value, playbook_scripts, + playbook_root, force, no_backup, ) diff --git a/templates/AGENT_RULES.template.md b/templates/AGENT_RULES.template.md index c7d1a1a8..bf23b091 100644 --- a/templates/AGENT_RULES.template.md +++ b/templates/AGENT_RULES.template.md @@ -41,6 +41,23 @@ - 只做当前任务需要的改动,不顺手加功能、不顺手重构 - 不为一次性操作增加抽象,不为假设的未来需求设计 +## 项目边界 + +### Playbook 目录 + +- `{{PLAYBOOK_ROOT}}/` 是 Playbook 模板/供应商目录,不是业务项目源码、 + 业务文档或当前项目私有规则 +- 除非用户明确要求维护、升级或调试 Playbook 本身,不得修改 + `{{PLAYBOOK_ROOT}}/` 下内容 +- 当前项目已生效的规则入口是项目根目录的 `AGENT_RULES.md`、 + `AGENT_RULES.local.md`、`AGENTS.md` 与 `.agents/` +- `{{PLAYBOOK_ROOT}}/templates/` 与 `{{PLAYBOOK_ROOT}}/rulesets/` + 是模板源;不要把它们当作当前项目已生效规则 +- 可按 `.agents/` 指向读取 `{{PLAYBOOK_ROOT}}/docs/` 作为标准文档; + 读取不代表该目录属于业务改动范围 +- 搜索、批量修改、代码审查、归档/提交时,默认排除 `{{PLAYBOOK_ROOT}}/`; + 只有任务目标明确涉及 Playbook 时才纳入 + ## 会话启动 每次新会话开始时,按顺序加载以下上下文: diff --git a/templates/README.md b/templates/README.md index beceb536..f5fb65d9 100644 --- a/templates/README.md +++ b/templates/README.md @@ -141,7 +141,7 @@ python scripts/playbook.py -config playbook.toml - **force**:默认 false,已存在则跳过;设为 true 时覆盖框架文件(会先备份) - **no_backup**:默认 false;设为 true 时跳过备份直接覆盖 - **不删除项目文件**:只更新框架提供的文件,项目新增的文件不会被删除 -- **占位符替换**:自动替换 `{{DATE}}`、`{{PROJECT_NAME}}`、`{{PLAYBOOK_SCRIPTS}}` +- **占位符替换**:自动替换 `{{DATE}}`、`{{PROJECT_NAME}}`、`{{PLAYBOOK_ROOT}}`、`{{PLAYBOOK_SCRIPTS}}` ### 典型场景 @@ -229,11 +229,15 @@ project/ | `{{PROJECT_NAME}}` | 项目名称 | ✅ 可选 | | `{{PROJECT_GOAL}}` | 项目目标 | ❌ 手动 | | `{{PROJECT_DESCRIPTION}}` | 项目描述 | ❌ 手动 | +| `{{PLAYBOOK_ROOT}}` | Playbook 根 | ✅ 是 | | `{{PLAYBOOK_SCRIPTS}}` | 脚本路径 | ✅ 是 | | 其他 `{{...}}` | 项目特定内容 | ❌ 手动 | `{{PROJECT_NAME}}` 可通过 `sync_memory_bank.project_name` 自动替换; 未配置时保持原样。 +`{{PLAYBOOK_ROOT}}` 自动替换为项目内 Playbook 根目录 +(默认 `docs/standards/playbook`, +也可按项目配置改成 `custom/playbook` 等)。 `{{PLAYBOOK_SCRIPTS}}` 自动替换为 Playbook 脚本路径 (默认 `docs/standards/playbook/scripts`, 也可按项目配置改成 `custom/playbook/scripts` 等)。