Enhance cc-switch-dev-workflow bootstrap
这个提交包含在:
@@ -47,15 +47,17 @@ python3 cn86-sms-keyword-verification/scripts/lubansms_keyword_cli.py demo --key
|
|||||||
|
|
||||||
- 用 `CC Switch` 管理 `GPT-5.4 Pro xhigh`、`Claude Opus 4.6` 和 fallback 模型的内部开发流程
|
- 用 `CC Switch` 管理 `GPT-5.4 Pro xhigh`、`Claude Opus 4.6` 和 fallback 模型的内部开发流程
|
||||||
- 从 `新项目脚手架 / 老项目补 Spec / Spec-Code Gap Closure` 三条主路径里选一条执行
|
- 从 `新项目脚手架 / 老项目补 Spec / Spec-Code Gap Closure` 三条主路径里选一条执行
|
||||||
- 需要把 `CLAUDE.md`、`ANALYSIS.md`、`TODO.yaml`、`SPECS/`、handoff、acceptance checklist 一次性种到目标项目
|
- 需要把 `CLAUDE.md`、`AGENTS.md`、`ANALYSIS.md`、`TODO.yaml`、`SPECS/`、handoff、acceptance checklist 一次性种到目标项目
|
||||||
|
|
||||||
运行示例:
|
运行示例:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 cc-switch-dev-workflow/scripts/inspect_cc_switch_runtime.py --format markdown
|
python3 cc-switch-dev-workflow/scripts/inspect_cc_switch_runtime.py --format markdown
|
||||||
python3 cc-switch-dev-workflow/scripts/bootstrap_workflow_workspace.py \
|
python3 cc-switch-dev-workflow/scripts/init_workflow_repo.py \
|
||||||
--target-dir /absolute/path/to/project \
|
--target-dir /absolute/path/to/project \
|
||||||
--playbook new-project-from-scaffold
|
--playbook new-project-from-scaffold \
|
||||||
|
--project-name "Project Name" \
|
||||||
|
--goal "One-sentence project goal"
|
||||||
```
|
```
|
||||||
|
|
||||||
## 维护建议
|
## 维护建议
|
||||||
|
|||||||
@@ -31,7 +31,17 @@ tags: [cc-switch, workflow, spec-driven, multi-agent, hono, nextjs, typescript]
|
|||||||
python3 scripts/inspect_cc_switch_runtime.py --format markdown
|
python3 scripts/inspect_cc_switch_runtime.py --format markdown
|
||||||
```
|
```
|
||||||
|
|
||||||
3. 如果用户明确要初始化项目目录,用:
|
3. 如果用户明确要一键初始化目标 repo,并直接生成首轮 `CLAUDE.md / AGENTS.md / ANALYSIS.md / TODO.yaml / SPECS/`,优先用:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/init_workflow_repo.py \
|
||||||
|
--target-dir /absolute/path/to/project \
|
||||||
|
--playbook new-project-from-scaffold \
|
||||||
|
--project-name "Project Name" \
|
||||||
|
--goal "One-sentence goal"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. 如果只需要轻量骨架和模板拷贝,再用:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 scripts/bootstrap_workflow_workspace.py \
|
python3 scripts/bootstrap_workflow_workspace.py \
|
||||||
@@ -39,7 +49,7 @@ python3 scripts/bootstrap_workflow_workspace.py \
|
|||||||
--playbook new-project-from-scaffold
|
--playbook new-project-from-scaffold
|
||||||
```
|
```
|
||||||
|
|
||||||
4. 只把高密度产物传给下一阶段,禁止把整段原始聊天直接 handoff 给下一个 agent。
|
5. 只把高密度产物传给下一阶段,禁止把整段原始聊天直接 handoff 给下一个 agent。
|
||||||
|
|
||||||
## Default Operating Rules
|
## Default Operating Rules
|
||||||
|
|
||||||
@@ -82,6 +92,7 @@ python3 scripts/bootstrap_workflow_workspace.py \
|
|||||||
在大多数项目里,至少会出现这些产物:
|
在大多数项目里,至少会出现这些产物:
|
||||||
|
|
||||||
- `CLAUDE.md`
|
- `CLAUDE.md`
|
||||||
|
- `AGENTS.md`
|
||||||
- `ANALYSIS.md`
|
- `ANALYSIS.md`
|
||||||
- `TODO.yaml`
|
- `TODO.yaml`
|
||||||
- `SPECS/*.md`
|
- `SPECS/*.md`
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
interface:
|
interface:
|
||||||
display_name: "CC Switch Dev Workflow"
|
display_name: "CC Switch Dev Workflow"
|
||||||
short_description: "Run the internal spec-driven multi-agent delivery workflow"
|
short_description: "Run the internal spec-driven multi-agent delivery workflow"
|
||||||
default_prompt: "Use $cc-switch-dev-workflow to choose the right playbook, align against my local CC Switch config, and run the 7-stage software delivery workflow."
|
default_prompt: "Use $cc-switch-dev-workflow to choose the right playbook, align against my local CC Switch config, and initialize my repo with CLAUDE.md, AGENTS.md, ANALYSIS.md, TODO.yaml, and first-round specs."
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
1. 从 [`sources/README.md`](./sources/README.md) 确认规则来源和冲突取舍。
|
1. 从 [`sources/README.md`](./sources/README.md) 确认规则来源和冲突取舍。
|
||||||
2. 从 [`playbooks/`](./playbooks/) 选择最贴近当前项目的执行路径。
|
2. 从 [`playbooks/`](./playbooks/) 选择最贴近当前项目的执行路径。
|
||||||
3. 按 [`workflows/README.md`](./workflows/README.md) 所列阶段运行,每阶段只保留高密度产物进入下一阶段。
|
3. 按 [`workflows/README.md`](./workflows/README.md) 所列阶段运行,每阶段只保留高密度产物进入下一阶段。
|
||||||
4. 统一使用 [`templates/README.md`](./templates/README.md) 中的模板生成 `CLAUDE.md`、`ANALYSIS.md`、`TODO.yaml`、Spec 和 handoff 文档。
|
4. 统一使用 [`templates/README.md`](./templates/README.md) 中的模板生成 `CLAUDE.md`、`AGENTS.md`、`ANALYSIS.md`、`TODO.yaml`、Spec 和 handoff 文档。
|
||||||
5. 发生技术栈偏离、模型切换、来源冲突时,先写入 [`decisions/README.md`](./decisions/README.md) 中的 ADR,再继续执行。
|
5. 发生技术栈偏离、模型切换、来源冲突时,先写入 [`decisions/README.md`](./decisions/README.md) 中的 ADR,再继续执行。
|
||||||
|
|
||||||
## Exit Criteria
|
## Exit Criteria
|
||||||
@@ -58,6 +58,7 @@
|
|||||||
|
|
||||||
## Related Templates
|
## Related Templates
|
||||||
- [`templates/claude-md-template.md`](./templates/claude-md-template.md)
|
- [`templates/claude-md-template.md`](./templates/claude-md-template.md)
|
||||||
|
- [`templates/agents-md-template.md`](./templates/agents-md-template.md)
|
||||||
- [`templates/analysis-template.md`](./templates/analysis-template.md)
|
- [`templates/analysis-template.md`](./templates/analysis-template.md)
|
||||||
- [`templates/todo-yaml-template.md`](./templates/todo-yaml-template.md)
|
- [`templates/todo-yaml-template.md`](./templates/todo-yaml-template.md)
|
||||||
- [`templates/agent-handoff-template.md`](./templates/agent-handoff-template.md)
|
- [`templates/agent-handoff-template.md`](./templates/agent-handoff-template.md)
|
||||||
@@ -80,7 +81,7 @@
|
|||||||
|
|
||||||
| 阶段 | 目标 | 核心产物 | 默认主模型 | 默认辅模型 |
|
| 阶段 | 目标 | 核心产物 | 默认主模型 | 默认辅模型 |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| 0 Setup | 项目初始化与规则对齐 | `.meetings/`, `.ralphy/config.yaml`, `CLAUDE.md` | `GPT-5.4 Pro xhigh` | `Claude Opus 4.6` |
|
| 0 Setup | 项目初始化与规则对齐 | `.meetings/`, `.ralphy/config.yaml`, `CLAUDE.md`, `AGENTS.md` | `GPT-5.4 Pro xhigh` | `Claude Opus 4.6` |
|
||||||
| 1 Research | 形成调研结论 | `ANALYSIS.md`, `TODO.yaml`, `.research/*.md` | `GPT-5.4 Pro xhigh` | `Claude Opus 4.6` |
|
| 1 Research | 形成调研结论 | `ANALYSIS.md`, `TODO.yaml`, `.research/*.md` | `GPT-5.4 Pro xhigh` | `Claude Opus 4.6` |
|
||||||
| 2 Spec | 形成可实施规范 | `SPECS/*.md` | `GPT-5.4 Pro xhigh` | `Claude Opus 4.6` |
|
| 2 Spec | 形成可实施规范 | `SPECS/*.md` | `GPT-5.4 Pro xhigh` | `Claude Opus 4.6` |
|
||||||
| 3 Code | 按 Spec 实施代码 | `.plans/*.md`, 代码与测试 | `GPT-5.4 Pro xhigh` | `Claude Opus 4.6` |
|
| 3 Code | 按 Spec 实施代码 | `.plans/*.md`, 代码与测试 | `GPT-5.4 Pro xhigh` | `Claude Opus 4.6` |
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
## Outputs
|
## Outputs
|
||||||
- 补齐后的 `CLAUDE.md`
|
- 补齐后的 `CLAUDE.md`
|
||||||
|
- 补齐后的 `AGENTS.md`
|
||||||
- `.research/*.md`
|
- `.research/*.md`
|
||||||
- `SPECS/*.md`
|
- `SPECS/*.md`
|
||||||
- 重构和补齐计划
|
- 重构和补齐计划
|
||||||
@@ -74,7 +75,7 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Stage Deliverables
|
## Stage Deliverables
|
||||||
- Setup:补写 `CLAUDE.md`、确认轨道与边界
|
- Setup:补写 `CLAUDE.md` 与 `AGENTS.md`、确认轨道与边界
|
||||||
- Research:反向整理 `.research/*.md`
|
- Research:反向整理 `.research/*.md`
|
||||||
- Spec:形成 `SPECS/*.md` 并完成人工审核
|
- Spec:形成 `SPECS/*.md` 并完成人工审核
|
||||||
- Alignment:对齐现有实现与 Spec
|
- Alignment:对齐现有实现与 Spec
|
||||||
@@ -82,6 +83,7 @@
|
|||||||
|
|
||||||
## Acceptance Checklist
|
## Acceptance Checklist
|
||||||
- 老项目已有清晰的 `CLAUDE.md`
|
- 老项目已有清晰的 `CLAUDE.md`
|
||||||
|
- 老项目已有清晰的 `AGENTS.md`
|
||||||
- `SPECS/*.md` 不是代码镜像,而是系统契约
|
- `SPECS/*.md` 不是代码镜像,而是系统契约
|
||||||
- Alignment 后没有高优先级缺口残留
|
- Alignment 后没有高优先级缺口残留
|
||||||
- Refinement 后的结构与命名更清晰,不是更复杂
|
- Refinement 后的结构与命名更清晰,不是更复杂
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
## Outputs
|
## Outputs
|
||||||
- `CLAUDE.md`
|
- `CLAUDE.md`
|
||||||
|
- `AGENTS.md`
|
||||||
- `.ralphy/config.yaml`
|
- `.ralphy/config.yaml`
|
||||||
- `.research/*.md`
|
- `.research/*.md`
|
||||||
- `SPECS/*.md`
|
- `SPECS/*.md`
|
||||||
@@ -77,7 +78,7 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Stage Deliverables
|
## Stage Deliverables
|
||||||
- Setup:`.meetings/`, `.ralphy/config.yaml`, `CLAUDE.md`
|
- Setup:`.meetings/`, `.ralphy/config.yaml`, `CLAUDE.md`, `AGENTS.md`
|
||||||
- Research:`ANALYSIS.md`, `TODO.yaml`, `.research/*.md`
|
- Research:`ANALYSIS.md`, `TODO.yaml`, `.research/*.md`
|
||||||
- Spec:`SPECS/*.md`, 审查结论, 人工审核结论
|
- Spec:`SPECS/*.md`, 审查结论, 人工审核结论
|
||||||
- Code:`.plans/*.md`, 代码与测试
|
- Code:`.plans/*.md`, 代码与测试
|
||||||
@@ -86,5 +87,6 @@
|
|||||||
## Acceptance Checklist
|
## Acceptance Checklist
|
||||||
- 技术轨道只有一个主路线
|
- 技术轨道只有一个主路线
|
||||||
- `CLAUDE.md` 已固定规则与禁用项
|
- `CLAUDE.md` 已固定规则与禁用项
|
||||||
|
- `AGENTS.md` 已为 Codex 固定读文件顺序、边界和升级点
|
||||||
- `SPECS/*.md` 已通过人工审核
|
- `SPECS/*.md` 已通过人工审核
|
||||||
- 第一轮代码实施与 Alignment 已经形成闭环
|
- 第一轮代码实施与 Alignment 已经形成闭环
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
提供知识库中的标准模板集合,统一输入输出格式,降低 agent 自由发挥空间。
|
提供知识库中的标准模板集合,统一输入输出格式,降低 agent 自由发挥空间。
|
||||||
|
|
||||||
## When to Use
|
## When to Use
|
||||||
|
- 新建 `AGENTS.md`
|
||||||
- 新建 `CLAUDE.md`
|
- 新建 `CLAUDE.md`
|
||||||
- 新建 `ANALYSIS.md`
|
- 新建 `ANALYSIS.md`
|
||||||
- 新建 `TODO.yaml`
|
- 新建 `TODO.yaml`
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
|
|
||||||
| 模板 | 用途 |
|
| 模板 | 用途 |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
| [`agents-md-template.md`](./agents-md-template.md) | Codex 项目执行说明 |
|
||||||
| [`claude-md-template.md`](./claude-md-template.md) | 项目执行说明 |
|
| [`claude-md-template.md`](./claude-md-template.md) | 项目执行说明 |
|
||||||
| [`analysis-template.md`](./analysis-template.md) | 阶段分析报告 |
|
| [`analysis-template.md`](./analysis-template.md) | 阶段分析报告 |
|
||||||
| [`todo-yaml-template.md`](./todo-yaml-template.md) | 任务清单 |
|
| [`todo-yaml-template.md`](./todo-yaml-template.md) | 任务清单 |
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# Template: AGENTS.md
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
为 Codex 提供项目级执行约束,让实现、审查和交接都遵守同一套边界。
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
- Setup 阶段
|
||||||
|
- 项目需要同时支持 `Claude Code` 和 `Codex` 时
|
||||||
|
- 需要给 Codex 一个稳定的项目执行入口时
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
- 清洗后的会议纪要
|
||||||
|
- 技术轨道决策
|
||||||
|
- 项目目标与边界
|
||||||
|
- 已确认的 workflow / playbook
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
- `AGENTS.md`
|
||||||
|
|
||||||
|
## Primary Agent/Model
|
||||||
|
`GPT-5.4 Pro xhigh`
|
||||||
|
|
||||||
|
## Secondary Agent/Model
|
||||||
|
`Claude Opus 4.6`
|
||||||
|
|
||||||
|
## Required Skills
|
||||||
|
- `agent-md-writing`
|
||||||
|
- 若未安装,按 `claude-md-template.md` 的约束等价改写
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
1. 用下方模板生成草案。
|
||||||
|
2. 把 `CLAUDE.md` 中的稳定规则压缩为 Codex 可直接执行的指令。
|
||||||
|
3. 明确 Read First 文件、禁止项、审批点和 handoff 方式。
|
||||||
|
|
||||||
|
## Exit Criteria
|
||||||
|
- Codex 在只读 `AGENTS.md` 的情况下,也能知道项目目标、技术边界、流程门禁和升级点
|
||||||
|
|
||||||
|
## Failure Recovery
|
||||||
|
- 若 `AGENTS.md` 只是重复愿景、不写边界与门禁,回到模板重写
|
||||||
|
|
||||||
|
## Related Templates
|
||||||
|
- [`claude-md-template.md`](./claude-md-template.md)
|
||||||
|
- [`agent-handoff-template.md`](./agent-handoff-template.md)
|
||||||
|
|
||||||
|
## Template
|
||||||
|
```markdown
|
||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
## Mission
|
||||||
|
- Project:
|
||||||
|
- Goal:
|
||||||
|
- Audience:
|
||||||
|
- In Scope:
|
||||||
|
- Out of Scope:
|
||||||
|
|
||||||
|
## Read First
|
||||||
|
- `CLAUDE.md`
|
||||||
|
- `ANALYSIS.md`
|
||||||
|
- `TODO.yaml`
|
||||||
|
- Selected playbook:
|
||||||
|
- Key specs:
|
||||||
|
|
||||||
|
## Workflow Contract
|
||||||
|
- Follow stages:
|
||||||
|
- Current playbook:
|
||||||
|
- Reset points:
|
||||||
|
- Human approval gates:
|
||||||
|
|
||||||
|
## Stack Guardrails
|
||||||
|
- Track:
|
||||||
|
- Language:
|
||||||
|
- UI:
|
||||||
|
- Styling:
|
||||||
|
- Auth:
|
||||||
|
- Data Fetching:
|
||||||
|
- Router:
|
||||||
|
- Service Layer:
|
||||||
|
- ORM:
|
||||||
|
- Database:
|
||||||
|
|
||||||
|
## Model Routing
|
||||||
|
- Primary planning and implementation:
|
||||||
|
- Secondary review:
|
||||||
|
- Fallback:
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
- Do not introduce:
|
||||||
|
- Do not modify:
|
||||||
|
- Do not bypass:
|
||||||
|
- Ask before:
|
||||||
|
|
||||||
|
## Execution Defaults
|
||||||
|
- Preferred testing posture:
|
||||||
|
- Refactor rhythm:
|
||||||
|
- Handoff format:
|
||||||
|
- Done means:
|
||||||
|
```
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
- 清洗后的 `.meetings/`
|
- 清洗后的 `.meetings/`
|
||||||
- `.ralphy/config.yaml`
|
- `.ralphy/config.yaml`
|
||||||
- `CLAUDE.md`
|
- `CLAUDE.md`
|
||||||
|
- `AGENTS.md`
|
||||||
- 已确认的技术轨道
|
- 已确认的技术轨道
|
||||||
|
|
||||||
## Primary Agent/Model
|
## Primary Agent/Model
|
||||||
@@ -34,11 +35,11 @@
|
|||||||
1. 清洗会议纪要,只保留项目相关决策。
|
1. 清洗会议纪要,只保留项目相关决策。
|
||||||
2. 选择 `Next.js 全栈` 或 `Hono + React SSR/TanStack` 轨道。
|
2. 选择 `Next.js 全栈` 或 `Hono + React SSR/TanStack` 轨道。
|
||||||
3. 初始化 `.ralphy/config.yaml`。
|
3. 初始化 `.ralphy/config.yaml`。
|
||||||
4. 生成 `CLAUDE.md`,写明哲学、白名单、边界、测试与技能要求。
|
4. 生成 `CLAUDE.md` 和 `AGENTS.md`,写明哲学、白名单、边界、测试与技能要求。
|
||||||
5. 产出 Setup handoff,供 Research 或 Spec 阶段读取。
|
5. 产出 Setup handoff,供 Research 或 Spec 阶段读取。
|
||||||
|
|
||||||
## Exit Criteria
|
## Exit Criteria
|
||||||
- `CLAUDE.md` 存在且可直接约束 agent
|
- `CLAUDE.md` 和 `AGENTS.md` 存在且可直接约束 agent
|
||||||
- 技术轨道已固定
|
- 技术轨道已固定
|
||||||
- 原始会议纪要不再被直接拿去执行
|
- 原始会议纪要不再被直接拿去执行
|
||||||
|
|
||||||
@@ -48,6 +49,7 @@
|
|||||||
|
|
||||||
## Related Templates
|
## Related Templates
|
||||||
- [`../templates/claude-md-template.md`](../templates/claude-md-template.md)
|
- [`../templates/claude-md-template.md`](../templates/claude-md-template.md)
|
||||||
|
- [`../templates/agents-md-template.md`](../templates/agents-md-template.md)
|
||||||
- [`../templates/agent-handoff-template.md`](../templates/agent-handoff-template.md)
|
- [`../templates/agent-handoff-template.md`](../templates/agent-handoff-template.md)
|
||||||
|
|
||||||
## Stable Knowledge Vs Runtime Context
|
## Stable Knowledge Vs Runtime Context
|
||||||
|
|||||||
@@ -25,19 +25,45 @@ def copy_file(source: Path, target: Path, force: bool) -> str:
|
|||||||
return f"write {target}"
|
return f"write {target}"
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def write_text(target: Path, content: str, force: bool) -> str:
|
||||||
parser = argparse.ArgumentParser(description="Bootstrap a repo with the CC Switch workflow files.")
|
if target.exists() and not force:
|
||||||
parser.add_argument("--target-dir", required=True, help="Absolute or relative project directory to seed.")
|
return f"skip {target}"
|
||||||
parser.add_argument("--playbook", required=True, choices=sorted(PLAYBOOK_FILES))
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
parser.add_argument("--force", action="store_true", help="Overwrite existing files.")
|
target.write_text(content.rstrip() + "\n", encoding="utf-8")
|
||||||
args = parser.parse_args()
|
return f"write {target}"
|
||||||
|
|
||||||
|
|
||||||
|
def build_minimal_ralphy_config(playbook: str) -> str:
|
||||||
|
return f"""project:
|
||||||
|
workflow: cc-switch-dev-workflow
|
||||||
|
playbook: {playbook}
|
||||||
|
|
||||||
|
commands:
|
||||||
|
test: pnpm test
|
||||||
|
lint: pnpm lint
|
||||||
|
build: pnpm build
|
||||||
|
typecheck: pnpm exec tsc --noEmit
|
||||||
|
|
||||||
|
rules:
|
||||||
|
- Read CLAUDE.md, AGENTS.md, ANALYSIS.md, TODO.yaml, and .workflow/selected-playbook.md before implementation.
|
||||||
|
- Keep one primary stack track; do not introduce a second router, auth, ORM, or styling system.
|
||||||
|
- Keep task titles self-contained with path and reference.
|
||||||
|
- Use handoff summaries instead of forwarding raw chat history.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def seed_workspace(
|
||||||
|
target_dir: Path,
|
||||||
|
playbook: str,
|
||||||
|
force: bool,
|
||||||
|
include_core_docs: bool = True,
|
||||||
|
include_ralphy_config: bool = True,
|
||||||
|
) -> list[str]:
|
||||||
skill_root = Path(__file__).resolve().parent.parent
|
skill_root = Path(__file__).resolve().parent.parent
|
||||||
knowledge_base = skill_root / "references" / "knowledge-base"
|
knowledge_base = skill_root / "references" / "knowledge-base"
|
||||||
templates_root = knowledge_base / "templates"
|
templates_root = knowledge_base / "templates"
|
||||||
playbooks_root = knowledge_base / "playbooks"
|
playbooks_root = knowledge_base / "playbooks"
|
||||||
workflows_root = knowledge_base / "workflows"
|
workflows_root = knowledge_base / "workflows"
|
||||||
target_dir = Path(args.target_dir).expanduser().resolve()
|
|
||||||
|
|
||||||
required_dirs = [
|
required_dirs = [
|
||||||
target_dir / ".meetings",
|
target_dir / ".meetings",
|
||||||
@@ -47,27 +73,50 @@ def main() -> int:
|
|||||||
target_dir / ".acceptance",
|
target_dir / ".acceptance",
|
||||||
target_dir / ".workflow",
|
target_dir / ".workflow",
|
||||||
target_dir / ".decisions",
|
target_dir / ".decisions",
|
||||||
|
target_dir / ".ralphy",
|
||||||
target_dir / "SPECS",
|
target_dir / "SPECS",
|
||||||
]
|
]
|
||||||
for directory in required_dirs:
|
for directory in required_dirs:
|
||||||
directory.mkdir(parents=True, exist_ok=True)
|
directory.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
writes = []
|
writes: list[str] = []
|
||||||
template_map = {
|
template_map = {
|
||||||
templates_root / "claude-md-template.md": target_dir / "CLAUDE.md",
|
|
||||||
templates_root / "analysis-template.md": target_dir / "ANALYSIS.md",
|
|
||||||
templates_root / "todo-yaml-template.md": target_dir / "TODO.yaml",
|
|
||||||
templates_root / "spec-template.md": target_dir / "SPECS" / "_template.md",
|
templates_root / "spec-template.md": target_dir / "SPECS" / "_template.md",
|
||||||
templates_root / "tdd-plan-template.md": target_dir / ".plans" / "_tdd-plan-template.md",
|
templates_root / "tdd-plan-template.md": target_dir / ".plans" / "_tdd-plan-template.md",
|
||||||
templates_root / "agent-handoff-template.md": target_dir / ".handoff" / "_agent-handoff-template.md",
|
templates_root / "agent-handoff-template.md": target_dir / ".handoff" / "_agent-handoff-template.md",
|
||||||
templates_root / "acceptance-checklist-template.md": target_dir / ".acceptance" / "_acceptance-checklist.md",
|
templates_root / "acceptance-checklist-template.md": target_dir / ".acceptance" / "_acceptance-checklist.md",
|
||||||
playbooks_root / PLAYBOOK_FILES[args.playbook]: target_dir / ".workflow" / "selected-playbook.md",
|
playbooks_root / PLAYBOOK_FILES[playbook]: target_dir / ".workflow" / "selected-playbook.md",
|
||||||
workflows_root / "README.md": target_dir / ".workflow" / "stage-index.md",
|
workflows_root / "README.md": target_dir / ".workflow" / "stage-index.md",
|
||||||
knowledge_base / "README.md": target_dir / ".workflow" / "knowledge-base-overview.md",
|
knowledge_base / "README.md": target_dir / ".workflow" / "knowledge-base-overview.md",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if include_core_docs:
|
||||||
|
template_map.update(
|
||||||
|
{
|
||||||
|
templates_root / "claude-md-template.md": target_dir / "CLAUDE.md",
|
||||||
|
templates_root / "agents-md-template.md": target_dir / "AGENTS.md",
|
||||||
|
templates_root / "analysis-template.md": target_dir / "ANALYSIS.md",
|
||||||
|
templates_root / "todo-yaml-template.md": target_dir / "TODO.yaml",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
for source, target in template_map.items():
|
for source, target in template_map.items():
|
||||||
writes.append(copy_file(source, target, args.force))
|
writes.append(copy_file(source, target, force))
|
||||||
|
|
||||||
|
if include_ralphy_config:
|
||||||
|
writes.append(write_text(target_dir / ".ralphy" / "config.yaml", build_minimal_ralphy_config(playbook), force))
|
||||||
|
return writes
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description="Bootstrap a repo with the CC Switch workflow files.")
|
||||||
|
parser.add_argument("--target-dir", required=True, help="Absolute or relative project directory to seed.")
|
||||||
|
parser.add_argument("--playbook", required=True, choices=sorted(PLAYBOOK_FILES))
|
||||||
|
parser.add_argument("--force", action="store_true", help="Overwrite existing files.")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
target_dir = Path(args.target_dir).expanduser().resolve()
|
||||||
|
writes = seed_workspace(target_dir, args.playbook, args.force)
|
||||||
|
|
||||||
manifest = {
|
manifest = {
|
||||||
"skill": "cc-switch-dev-workflow",
|
"skill": "cc-switch-dev-workflow",
|
||||||
|
|||||||
@@ -0,0 +1,692 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Initialize a target repo with first-round workflow artifacts for Claude and Codex."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from bootstrap_workflow_workspace import PLAYBOOK_FILES, seed_workspace
|
||||||
|
|
||||||
|
try:
|
||||||
|
from inspect_cc_switch_runtime import collect_summary
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
collect_summary = None
|
||||||
|
|
||||||
|
|
||||||
|
TRACKS: dict[str, dict[str, str]] = {
|
||||||
|
"hono-react-ssr-tanstack": {
|
||||||
|
"label": "Hono + React SSR/TanStack",
|
||||||
|
"language": "TypeScript",
|
||||||
|
"ui": "React",
|
||||||
|
"styling": "Tailwind CSS + shadcn/ui",
|
||||||
|
"auth": "Better Auth",
|
||||||
|
"data_fetching": "TanStack Query",
|
||||||
|
"router": "TanStack Router",
|
||||||
|
"service_layer": "Hono",
|
||||||
|
"orm": "Drizzle",
|
||||||
|
"database": "PostgreSQL",
|
||||||
|
"reason": "default tie-break track for clear boundaries and better agent task slicing",
|
||||||
|
},
|
||||||
|
"nextjs-fullstack": {
|
||||||
|
"label": "Next.js Full Stack",
|
||||||
|
"language": "TypeScript",
|
||||||
|
"ui": "React",
|
||||||
|
"styling": "Tailwind CSS + shadcn/ui",
|
||||||
|
"auth": "Better Auth",
|
||||||
|
"data_fetching": "TanStack Query where needed",
|
||||||
|
"router": "Next.js App Router",
|
||||||
|
"service_layer": "Next.js route handlers / server actions",
|
||||||
|
"orm": "Drizzle",
|
||||||
|
"database": "PostgreSQL",
|
||||||
|
"reason": "single-framework delivery track when page and service logic should stay tightly integrated",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
PLAYBOOK_CONTEXT: dict[str, dict[str, Any]] = {
|
||||||
|
"new-project-from-scaffold": {
|
||||||
|
"label": "New Project From Scaffold",
|
||||||
|
"spec_file": "000-foundation-and-bootstrap-constraints.md",
|
||||||
|
"goal_hint": "Bootstrap a new repo with one approved stack track, one workflow contract, and first-round planning artifacts.",
|
||||||
|
"default_in_scope": [
|
||||||
|
"Fix the project on one approved stack track",
|
||||||
|
"Generate first-round workflow documents and handoff",
|
||||||
|
"Prepare the repo for Research -> Spec -> Code",
|
||||||
|
],
|
||||||
|
"default_out_of_scope": [
|
||||||
|
"Feature-complete product implementation",
|
||||||
|
"Adding a second framework track",
|
||||||
|
"Ad-hoc exceptions without ADR approval",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"existing-project-spec-backfill-and-refactor": {
|
||||||
|
"label": "Existing Project Spec Backfill And Refactor",
|
||||||
|
"spec_file": "000-foundation-and-backfill-contract.md",
|
||||||
|
"goal_hint": "Stabilize an existing codebase by backfilling rules, workflow contract, and the first spec/refactor queue.",
|
||||||
|
"default_in_scope": [
|
||||||
|
"Baseline the current repo and write first-round workflow docs",
|
||||||
|
"Backfill initial spec contract and alignment backlog",
|
||||||
|
"Prepare refactor work under an explicit rule layer",
|
||||||
|
],
|
||||||
|
"default_out_of_scope": [
|
||||||
|
"Large implementation rewrites before baseline review",
|
||||||
|
"Unbounded refactors without spec backing",
|
||||||
|
"Running two primary stack tracks in parallel",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"spec-code-alignment-gap-closure": {
|
||||||
|
"label": "Spec-Code Alignment Gap Closure",
|
||||||
|
"spec_file": "000-gap-closure-working-contract.md",
|
||||||
|
"goal_hint": "Re-establish spec/code consistency with a first-round gap-analysis contract and execution queue.",
|
||||||
|
"default_in_scope": [
|
||||||
|
"Classify current spec/code gaps",
|
||||||
|
"Generate first-round alignment docs and tasks",
|
||||||
|
"Prepare implementation and review gates for closure work",
|
||||||
|
],
|
||||||
|
"default_out_of_scope": [
|
||||||
|
"Rewriting the product without gap evidence",
|
||||||
|
"Changing accepted specs without review",
|
||||||
|
"Treating elegance as a substitute for compliance",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def parse_list(values: list[str] | None) -> list[str]:
|
||||||
|
if not values:
|
||||||
|
return []
|
||||||
|
result: list[str] = []
|
||||||
|
for raw in values:
|
||||||
|
parts = [part.strip() for part in raw.split(",")]
|
||||||
|
result.extend(part for part in parts if part)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def slugify(text: str) -> str:
|
||||||
|
lowered = text.strip().lower()
|
||||||
|
slug = re.sub(r"[^a-z0-9]+", "-", lowered)
|
||||||
|
return slug.strip("-") or "project"
|
||||||
|
|
||||||
|
|
||||||
|
def load_package_json(target_dir: Path) -> dict[str, Any]:
|
||||||
|
package_json = target_dir / "package.json"
|
||||||
|
if not package_json.exists():
|
||||||
|
return {}
|
||||||
|
try:
|
||||||
|
data = json.loads(package_json.read_text(encoding="utf-8"))
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return {}
|
||||||
|
return data if isinstance(data, dict) else {}
|
||||||
|
|
||||||
|
|
||||||
|
def detect_track(target_dir: Path, playbook: str) -> tuple[str, str]:
|
||||||
|
package_data = load_package_json(target_dir)
|
||||||
|
dependencies = set()
|
||||||
|
for key in ("dependencies", "devDependencies"):
|
||||||
|
block = package_data.get(key, {})
|
||||||
|
if isinstance(block, dict):
|
||||||
|
dependencies.update(block.keys())
|
||||||
|
|
||||||
|
if "hono" in dependencies or "@tanstack/react-router" in dependencies:
|
||||||
|
return "hono-react-ssr-tanstack", "detected from package.json dependencies"
|
||||||
|
|
||||||
|
if "next" in dependencies or any((target_dir / name).exists() for name in ("next.config.js", "next.config.mjs", "next.config.ts")):
|
||||||
|
return "nextjs-fullstack", "detected from package.json or next.config.*"
|
||||||
|
|
||||||
|
if playbook == "new-project-from-scaffold":
|
||||||
|
return "hono-react-ssr-tanstack", "default tie-break from framework decision matrix"
|
||||||
|
|
||||||
|
return "hono-react-ssr-tanstack", "default target track pending setup confirmation"
|
||||||
|
|
||||||
|
|
||||||
|
def pick_track(target_dir: Path, playbook: str, requested_track: str) -> tuple[str, str]:
|
||||||
|
if requested_track != "auto":
|
||||||
|
return requested_track, "explicitly requested"
|
||||||
|
return detect_track(target_dir, playbook)
|
||||||
|
|
||||||
|
|
||||||
|
def write_text(target: Path, content: str, force: bool) -> str:
|
||||||
|
if target.exists() and not force:
|
||||||
|
return f"skip {target}"
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
target.write_text(content.rstrip() + "\n", encoding="utf-8")
|
||||||
|
return f"write {target}"
|
||||||
|
|
||||||
|
|
||||||
|
def bullets(items: list[str], fallback: str) -> str:
|
||||||
|
rows = items or [fallback]
|
||||||
|
return "\n".join(f"- {item}" for item in rows)
|
||||||
|
|
||||||
|
|
||||||
|
def runtime_model_line(runtime: dict[str, Any]) -> tuple[str, str, str]:
|
||||||
|
current_providers = runtime.get("current_providers", {})
|
||||||
|
codex = current_providers.get("codex") or {}
|
||||||
|
claude = current_providers.get("claude") or {}
|
||||||
|
primary = (
|
||||||
|
f"GPT-5.4 Pro xhigh via Codex provider {codex.get('name', 'n/a')} "
|
||||||
|
f"({codex.get('endpoint_host', 'n/a')})"
|
||||||
|
)
|
||||||
|
secondary = (
|
||||||
|
f"Claude Opus 4.6 via Claude provider {claude.get('name', 'n/a')} "
|
||||||
|
f"({claude.get('endpoint_host', 'n/a')})"
|
||||||
|
)
|
||||||
|
fallback = "GLM / Kimi / Minimax only when primary models are blocked, then return through a compact handoff."
|
||||||
|
return primary, secondary, fallback
|
||||||
|
|
||||||
|
|
||||||
|
def render_claude(context: dict[str, Any]) -> str:
|
||||||
|
track = context["track_profile"]
|
||||||
|
return f"""# CLAUDE.md
|
||||||
|
|
||||||
|
## Project
|
||||||
|
- Name: {context['project_name']}
|
||||||
|
- Goal: {context['goal']}
|
||||||
|
- Audience: {context['audience']}
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
### In Scope
|
||||||
|
{bullets(context['in_scope'], 'Confirm scope during Setup.')}
|
||||||
|
|
||||||
|
### Out of Scope
|
||||||
|
{bullets(context['out_of_scope'], 'Confirm out-of-scope boundaries during Setup.')}
|
||||||
|
|
||||||
|
## Design Philosophy
|
||||||
|
- KISS: Prefer the smallest design that can satisfy the current spec.
|
||||||
|
- DRY: Reuse validated patterns; do not fork architectural styles without approval.
|
||||||
|
- YAGNI: Do not build optional abstraction layers before the spec requires them.
|
||||||
|
- Type Safety First: Keep the application main path in TypeScript with strict checks.
|
||||||
|
- Preferred Architectural Shape: {track['label']} with one primary route, one auth path, one ORM path.
|
||||||
|
|
||||||
|
## Default Stack
|
||||||
|
- Track: {track['label']} ({context['track_reason']})
|
||||||
|
- Language: {track['language']}
|
||||||
|
- UI: {track['ui']}
|
||||||
|
- Styling: {track['styling']}
|
||||||
|
- Auth: {track['auth']}
|
||||||
|
- Data Fetching: {track['data_fetching']}
|
||||||
|
- Router: {track['router']}
|
||||||
|
- Service Layer: {track['service_layer']}
|
||||||
|
- ORM: {track['orm']}
|
||||||
|
- Database: {track['database']}
|
||||||
|
|
||||||
|
## Model Routing
|
||||||
|
- Primary planning and implementation: {context['primary_model']}
|
||||||
|
- Secondary review: {context['secondary_model']}
|
||||||
|
- Fallback: {context['fallback_model']}
|
||||||
|
|
||||||
|
## Hard Boundaries
|
||||||
|
- Do not introduce: Python/PHP on the product application main path, JavaScript-only defaults, or a second primary framework track.
|
||||||
|
- Do not modify: Approved specs, workflow gate definitions, or acceptance criteria without updating related docs and ADRs.
|
||||||
|
- Do not bypass: Spec review, gap analysis, handoff structure, or acceptance checks.
|
||||||
|
- Exceptions require: ADR in `.decisions/`, plus project owner and technical lead approval.
|
||||||
|
|
||||||
|
## Process Requirements
|
||||||
|
- Follow stages: Setup -> Research -> Spec -> Code -> Alignment -> Refinement -> Acceptance.
|
||||||
|
- Source of truth: `CLAUDE.md`, `AGENTS.md`, `ANALYSIS.md`, `TODO.yaml`, `SPECS/`, `.workflow/selected-playbook.md`.
|
||||||
|
- Required review gates: Setup boundary confirmation, Spec review before Code, Acceptance review before release.
|
||||||
|
- Required testing posture: Run typecheck, lint, build, and targeted tests for changed behavior.
|
||||||
|
- Required refactor rhythm: Simplify after each implementation step and refactor after each batch.
|
||||||
|
|
||||||
|
## Skills And Templates
|
||||||
|
- Preferred skills: `cc-switch-dev-workflow`, stage-specific planning/review/implementation skills, and the approved gap/refactor skills when applicable.
|
||||||
|
- Required templates: `templates/claude-md-template.md`, `templates/agents-md-template.md`, `templates/analysis-template.md`, `templates/todo-yaml-template.md`, `templates/spec-template.md`, `templates/agent-handoff-template.md`.
|
||||||
|
|
||||||
|
## Definition Of Done
|
||||||
|
- Spec approved: The current spec is reviewable, testable, and accepted by the responsible human reviewer.
|
||||||
|
- Tests pass: Required checks pass or remaining failures are explicitly documented with owner approval.
|
||||||
|
- Alignment complete: No high-priority spec/code gaps remain hidden.
|
||||||
|
- Acceptance signed off: Final acceptance checklist is reviewed by a human owner.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def render_agents(context: dict[str, Any]) -> str:
|
||||||
|
track = context["track_profile"]
|
||||||
|
return f"""# AGENTS.md
|
||||||
|
|
||||||
|
## Mission
|
||||||
|
- Project: {context['project_name']}
|
||||||
|
- Goal: {context['goal']}
|
||||||
|
- Audience: {context['audience']}
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
### In Scope
|
||||||
|
{bullets(context['in_scope'], 'Confirm scope during Setup.')}
|
||||||
|
|
||||||
|
### Out of Scope
|
||||||
|
{bullets(context['out_of_scope'], 'Confirm out-of-scope boundaries during Setup.')}
|
||||||
|
|
||||||
|
## Read First
|
||||||
|
- `CLAUDE.md`
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `ANALYSIS.md`
|
||||||
|
- `TODO.yaml`
|
||||||
|
- `.workflow/selected-playbook.md`
|
||||||
|
- `SPECS/{context['spec_file']}`
|
||||||
|
|
||||||
|
## Workflow Contract
|
||||||
|
- Follow stages: Setup -> Research -> Spec -> Code -> Alignment -> Refinement -> Acceptance.
|
||||||
|
- Current playbook: {context['playbook_label']}
|
||||||
|
- Reset points: after Research -> Spec, after Spec review -> Code, and after any fallback detour.
|
||||||
|
- Human approval gates: stack exceptions, spec approval, and final acceptance.
|
||||||
|
|
||||||
|
## Stack Guardrails
|
||||||
|
- Track: {track['label']} ({context['track_reason']})
|
||||||
|
- Language: {track['language']}
|
||||||
|
- UI: {track['ui']}
|
||||||
|
- Styling: {track['styling']}
|
||||||
|
- Auth: {track['auth']}
|
||||||
|
- Data Fetching: {track['data_fetching']}
|
||||||
|
- Router: {track['router']}
|
||||||
|
- Service Layer: {track['service_layer']}
|
||||||
|
- ORM: {track['orm']}
|
||||||
|
- Database: {track['database']}
|
||||||
|
|
||||||
|
## Model Routing
|
||||||
|
- Primary planning and implementation: {context['primary_model']}
|
||||||
|
- Secondary review: {context['secondary_model']}
|
||||||
|
- Fallback: {context['fallback_model']}
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
- Do not introduce: a second primary framework route, Python/PHP application code, or speculative abstractions.
|
||||||
|
- Do not modify: accepted specs or workflow gate docs without updating references and ADRs.
|
||||||
|
- Do not bypass: required testing, simplification/refactor checkpoints, or the handoff contract.
|
||||||
|
- Ask before: changing stack track, introducing exceptions, deleting validated files, or contradicting accepted specs.
|
||||||
|
|
||||||
|
## Execution Defaults
|
||||||
|
- Preferred testing posture: typecheck + lint + build + changed-scope tests.
|
||||||
|
- Refactor rhythm: every implementation batch must be followed by simplify/refactor review.
|
||||||
|
- Handoff format: Goal / Scope / Non-Goals / Source of Truth / Constraints / Deliverable / Validation / Escalation.
|
||||||
|
- Done means: approved spec, documented plan, validated changes, and explicit acceptance state.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def render_analysis(context: dict[str, Any]) -> str:
|
||||||
|
return f"""# ANALYSIS
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
- {context['goal']}
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
### Included
|
||||||
|
{bullets(context['in_scope'], 'Confirm scope during Setup.')}
|
||||||
|
|
||||||
|
### Excluded
|
||||||
|
{bullets(context['out_of_scope'], 'Confirm out-of-scope boundaries during Setup.')}
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
- Selected playbook: `.workflow/selected-playbook.md`
|
||||||
|
- Workflow overview: `.workflow/knowledge-base-overview.md`
|
||||||
|
- Stage index: `.workflow/stage-index.md`
|
||||||
|
- Runtime alignment source: `{context['runtime_source']}`
|
||||||
|
|
||||||
|
## Findings
|
||||||
|
- Current track decision: {context['track_profile']['label']} ({context['track_reason']}).
|
||||||
|
- Current primary model path: {context['primary_model']}.
|
||||||
|
- Current secondary review path: {context['secondary_model']}.
|
||||||
|
- First-round repo artifacts should stabilize Setup and unlock Research/Spec without revisiting raw notes.
|
||||||
|
|
||||||
|
## Priority
|
||||||
|
1. Confirm the single stack track and hard boundaries in `CLAUDE.md` and `AGENTS.md`.
|
||||||
|
2. Review and tighten `SPECS/{context['spec_file']}` so it becomes a real source of truth.
|
||||||
|
3. Expand `TODO.yaml` into executable plan/impl tasks before implementation starts.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
- Workflow Foundation: stage contract, handoff contract, human gates.
|
||||||
|
- Stack And Model Policy: approved track, model routing, exception interface.
|
||||||
|
- Execution Queue: Research, Spec expansion, implementation planning, simplification/refactor checkpoints.
|
||||||
|
|
||||||
|
## Risks
|
||||||
|
- The selected track may still need human confirmation if the repo baseline contradicts the default.
|
||||||
|
- Existing code or undocumented requirements may widen scope after initial Research.
|
||||||
|
- Fallback models must not become the default execution path.
|
||||||
|
|
||||||
|
## Decisions Needed
|
||||||
|
- Confirm project goal wording and success boundary.
|
||||||
|
- Confirm stack track if the repo baseline differs from the default detection.
|
||||||
|
- Confirm the first product-domain spec that should follow the bootstrap spec.
|
||||||
|
|
||||||
|
## Exit Criteria
|
||||||
|
- `CLAUDE.md`, `AGENTS.md`, `ANALYSIS.md`, `TODO.yaml`, `.ralphy/config.yaml`, and `SPECS/{context['spec_file']}` are present and internally consistent.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def build_tasks(context: dict[str, Any]) -> list[tuple[str, str]]:
|
||||||
|
date_stamp = context["date_stamp"]
|
||||||
|
spec_path = f"SPECS/{context['spec_file']}"
|
||||||
|
if context["playbook"] == "new-project-from-scaffold":
|
||||||
|
return [
|
||||||
|
(
|
||||||
|
f"Plan repository foundation in .plans/{date_stamp}-foundation-bootstrap.md using .workflow/selected-playbook.md, CLAUDE.md, AGENTS.md, and {spec_path}",
|
||||||
|
"Scope: repo root. Validation: track choice, bootstrap spec sections, and first implementation boundary are explicit.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"Implement repository scaffold in repo root, covering {spec_path}, and use tdd-implementing to follow .plans/{date_stamp}-foundation-bootstrap.md",
|
||||||
|
"Validation: create the approved stack skeleton, baseline commands, and initial checks without introducing a second track.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"Review repo root for simplification opportunities after foundation scaffold and use code-simplifying skill",
|
||||||
|
"Keep behavior unchanged and remove setup noise before the next feature spec.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"Review repo root for refactoring opportunities and use code-refactoring skill to generate .plans/{date_stamp}-foundation-refactor.md",
|
||||||
|
"Focus: DRY, KISS, and stable module boundaries for future specs.",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
if context["playbook"] == "existing-project-spec-backfill-and-refactor":
|
||||||
|
return [
|
||||||
|
(
|
||||||
|
f"Plan baseline audit in .plans/{date_stamp}-baseline-audit.md using .workflow/selected-playbook.md, CLAUDE.md, AGENTS.md, and {spec_path}",
|
||||||
|
"Scope: current repo modules, boundaries, tests, and debt hotspots. Validation: produce a stable baseline for Spec backfill.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"Write or tighten {spec_path} and update ANALYSIS.md with current-repo findings before deeper refactor work",
|
||||||
|
"Validation: the spec reflects real boundaries, approved constraints, and the current alignment target.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"Generate alignment and refactor queue in TODO.yaml covering current repo modules and use spec-tasking plus code-refactoring references",
|
||||||
|
"Impact: create executable tasks that reference concrete paths, specs, and future plan files.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"Review current repo modules for simplification opportunities after baseline audit and use code-simplifying skill",
|
||||||
|
"Keep behavior unchanged and remove obvious complexity before larger refactor batches.",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
return [
|
||||||
|
(
|
||||||
|
f"Plan spec-code gap analysis in .plans/{date_stamp}-gap-analysis.md using .workflow/selected-playbook.md, CLAUDE.md, AGENTS.md, and {spec_path}",
|
||||||
|
"Scope: accepted specs, current code, failing or missing tests. Validation: classify Missing, Partial, Divergent, Untested, and Integration gaps.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"Generate alignment queue in TODO.yaml for current repo modules, referencing {spec_path} and .plans/{date_stamp}-gap-analysis.md",
|
||||||
|
"Validation: every task title names the target path and evidence source; insert simplify/refactor checkpoints by batch.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"Implement highest-priority gap closure in repo root, covering accepted specs, and use tdd-implementing to follow .plans/{date_stamp}-gap-analysis.md",
|
||||||
|
"Validation: close the highest-risk gaps first and record residual risks explicitly.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"Review gap-closure changes for simplification opportunities and use code-simplifying skill",
|
||||||
|
"Keep behavior aligned to spec and remove incidental complexity after each closure batch.",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def render_todo(context: dict[str, Any]) -> str:
|
||||||
|
tasks = build_tasks(context)
|
||||||
|
lines = ["tasks:"]
|
||||||
|
for title, description in tasks:
|
||||||
|
lines.append(f' - title: "{title}"')
|
||||||
|
lines.append(f' description: "{description}"')
|
||||||
|
lines.append(" completed: false")
|
||||||
|
lines.append("")
|
||||||
|
return "\n".join(lines).rstrip() + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def render_spec(context: dict[str, Any]) -> str:
|
||||||
|
track = context["track_profile"]
|
||||||
|
return f"""# Workflow Bootstrap And Project Constraints
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
- Defines: the first-round workflow contract, stack track, model routing, and document set for {context['project_name']}.
|
||||||
|
- Not Covered: feature-level product details beyond the initial bootstrap boundary.
|
||||||
|
- Related SPECS: add feature/domain specs after this file is accepted.
|
||||||
|
|
||||||
|
## Terminology
|
||||||
|
- Workflow Bootstrap: the initial rule layer that makes later Research, Spec, and Code work deterministic.
|
||||||
|
- Approved Track: the single allowed stack path for the application main path.
|
||||||
|
- Handoff: the compact context package that moves work between agents or threads.
|
||||||
|
|
||||||
|
## Domain Sections
|
||||||
|
### Delivery Workflow
|
||||||
|
- Rule: All work follows `{context['playbook_label']}` under the 7-stage contract: Setup -> Research -> Spec -> Code -> Alignment -> Refinement -> Acceptance.
|
||||||
|
- Acceptance: `CLAUDE.md`, `AGENTS.md`, `ANALYSIS.md`, `TODO.yaml`, `.ralphy/config.yaml`, and `.workflow/selected-playbook.md` exist and do not contradict each other.
|
||||||
|
> **Why**: The workflow must be stable before feature implementation starts.
|
||||||
|
> **Rejected**: Free-form prompting without a fixed stage contract.
|
||||||
|
|
||||||
|
### Stack Track
|
||||||
|
- Rule: The application main path uses `{track['label']}` with `{track['language']}`, `{track['ui']}`, `{track['styling']}`, `{track['auth']}`, `{track['data_fetching']}`, `{track['router']}`, `{track['service_layer']}`, `{track['orm']}`, and `{track['database']}`.
|
||||||
|
- Acceptance: No second primary router, auth path, ORM, or styling system is introduced without ADR approval.
|
||||||
|
> **Why**: Agent output quality drops when multiple primary tracks coexist.
|
||||||
|
> **Rejected**: Dual-track implementations or untyped main-path languages.
|
||||||
|
|
||||||
|
### Model Routing And Review
|
||||||
|
- Rule: Planning and implementation default to `{context['primary_model']}`; long-document digestion and second-view review default to `{context['secondary_model']}`.
|
||||||
|
- Acceptance: Any fallback usage is summarized back into the standard handoff contract before the main thread continues.
|
||||||
|
> **Why**: Multi-model workflows only stay reliable when routing is explicit.
|
||||||
|
> **Rejected**: Letting fallback models become the default path.
|
||||||
|
|
||||||
|
### First-Round Deliverables
|
||||||
|
- Rule: The first-round working set must include a bootstrap spec, project execution files, a task queue, and an explicit handoff for the next stage.
|
||||||
|
- Acceptance: `SPECS/{context['spec_file']}`, `.handoff/setup-handoff.md`, and `.workflow/first-round-prompts.md` are present and point to the same source of truth.
|
||||||
|
> **Why**: The next agent should not need the raw setup conversation to continue.
|
||||||
|
> **Rejected**: Starting implementation from memory or scattered notes.
|
||||||
|
|
||||||
|
## Forbidden
|
||||||
|
- Do not: introduce Python or PHP on the application main path, add a second primary stack track, or bypass spec review.
|
||||||
|
- Use instead: TypeScript + React on the approved track, standard handoff, and explicit ADRs for exceptions.
|
||||||
|
- Reason: reliability, testability, and agent consistency depend on fixed constraints.
|
||||||
|
|
||||||
|
## References
|
||||||
|
- Internal:
|
||||||
|
- `CLAUDE.md`
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `ANALYSIS.md`
|
||||||
|
- `TODO.yaml`
|
||||||
|
- `.workflow/selected-playbook.md`
|
||||||
|
- `.workflow/knowledge-base-overview.md`
|
||||||
|
- External:
|
||||||
|
- `references/knowledge-base/platform/framework-decision-matrix.md`
|
||||||
|
- `references/knowledge-base/platform/model-routing-policy.md`
|
||||||
|
- `references/knowledge-base/platform/stack-policy.md`
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def render_ralphy(context: dict[str, Any]) -> str:
|
||||||
|
return f"""project:
|
||||||
|
name: {context['project_slug']}
|
||||||
|
workflow: cc-switch-dev-workflow
|
||||||
|
playbook: {context['playbook']}
|
||||||
|
track: {context['track_profile']['label']}
|
||||||
|
|
||||||
|
commands:
|
||||||
|
test: pnpm test
|
||||||
|
lint: pnpm lint
|
||||||
|
build: pnpm build
|
||||||
|
typecheck: pnpm exec tsc --noEmit
|
||||||
|
|
||||||
|
rules:
|
||||||
|
- Read CLAUDE.md, AGENTS.md, ANALYSIS.md, TODO.yaml, and .workflow/selected-playbook.md before implementation.
|
||||||
|
- Keep one approved stack track and one approved model-routing policy.
|
||||||
|
- Every task title must be self-contained with path and reference.
|
||||||
|
- Run simplify and refactor checkpoints after each implementation batch.
|
||||||
|
|
||||||
|
references:
|
||||||
|
- CLAUDE.md
|
||||||
|
- AGENTS.md
|
||||||
|
- ANALYSIS.md
|
||||||
|
- TODO.yaml
|
||||||
|
- SPECS/{context['spec_file']}
|
||||||
|
- .workflow/selected-playbook.md
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def render_prompts(context: dict[str, Any]) -> str:
|
||||||
|
return f"""# First-Round Prompts
|
||||||
|
|
||||||
|
## Prompt 1: Setup Confirmation
|
||||||
|
基于当前仓库和以下初始化产物,确认项目边界和单一技术轨道:`CLAUDE.md`、`AGENTS.md`、`ANALYSIS.md`、`TODO.yaml`、`SPECS/{context['spec_file']}`、`.workflow/selected-playbook.md`。如果发现现有代码与默认轨道冲突,只输出差异、风险和建议,不直接改代码。
|
||||||
|
|
||||||
|
## Prompt 2: Research And Spec Expansion
|
||||||
|
基于 `ANALYSIS.md`、`.workflow/selected-playbook.md` 和 `SPECS/{context['spec_file']}`,扩展第一轮 `.research/*.md` 和后续产品/模块 Spec。只保留与目标 `{context['goal']}` 相关的结论、模块边界和拒绝理由。
|
||||||
|
|
||||||
|
## Prompt 3: Tasking And Implementation Plan
|
||||||
|
基于 `TODO.yaml`、`CLAUDE.md`、`AGENTS.md` 和 `SPECS/{context['spec_file']}`,生成下一轮 `.plans/*.md`,把每个真实任务拆成可执行的 Plan/Impl 对,并在批次后插入 simplify/refactor 检查点。
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def render_handoff(context: dict[str, Any]) -> str:
|
||||||
|
return f"""# Handoff
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
- Start the first real workflow round for {context['project_name']} under the {context['playbook_label']} playbook.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
- Confirm boundaries in `CLAUDE.md` and `AGENTS.md`.
|
||||||
|
- Tighten `SPECS/{context['spec_file']}`.
|
||||||
|
- Expand `TODO.yaml` into the next actionable plan files.
|
||||||
|
|
||||||
|
## Non-Goals
|
||||||
|
- Do not implement broad product features yet.
|
||||||
|
- Do not change the approved stack track without review.
|
||||||
|
- Do not bypass spec or acceptance gates.
|
||||||
|
|
||||||
|
## Source of Truth
|
||||||
|
- `CLAUDE.md`
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `ANALYSIS.md`
|
||||||
|
- `TODO.yaml`
|
||||||
|
- `SPECS/{context['spec_file']}`
|
||||||
|
- `.workflow/selected-playbook.md`
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
- Keep one primary stack track.
|
||||||
|
- Keep the main path in TypeScript + React.
|
||||||
|
- Use explicit handoff and reset rules when switching agents or models.
|
||||||
|
|
||||||
|
## Deliverable
|
||||||
|
- Updated analysis, tightened spec, next `.plans/*.md`, and an implementation-ready task queue.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
- The next agent can proceed without raw setup chat.
|
||||||
|
- The stack track, model routing, and task queue remain internally consistent.
|
||||||
|
- Human decisions required by the setup round are clearly listed.
|
||||||
|
|
||||||
|
## Escalation
|
||||||
|
- Stop and ask when: the repo baseline contradicts the chosen track, the spec needs a structural exception, or the first implementation batch would violate accepted boundaries.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def render_meetings_readme(context: dict[str, Any]) -> str:
|
||||||
|
lines = [
|
||||||
|
"# Meetings",
|
||||||
|
"",
|
||||||
|
"Place raw notes, screenshots, or imported meeting summaries for this repo here.",
|
||||||
|
"",
|
||||||
|
"Current bootstrap context:",
|
||||||
|
f"- Project: {context['project_name']}",
|
||||||
|
f"- Playbook: {context['playbook_label']}",
|
||||||
|
f"- Goal: {context['goal']}",
|
||||||
|
]
|
||||||
|
if context["source_notes"]:
|
||||||
|
lines.extend(["", "Suggested source notes:"])
|
||||||
|
lines.extend(f"- {note}" for note in context["source_notes"])
|
||||||
|
return "\n".join(lines) + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def build_context(args: argparse.Namespace, target_dir: Path) -> dict[str, Any]:
|
||||||
|
project_name = args.project_name or target_dir.name
|
||||||
|
project_slug = slugify(project_name)
|
||||||
|
playbook_profile = PLAYBOOK_CONTEXT[args.playbook]
|
||||||
|
track_key, track_reason = pick_track(target_dir, args.playbook, args.track)
|
||||||
|
runtime = collect_summary(Path.home() / ".cc-switch") if collect_summary else {}
|
||||||
|
primary_model, secondary_model, fallback_model = runtime_model_line(runtime) if runtime else (
|
||||||
|
"GPT-5.4 Pro xhigh",
|
||||||
|
"Claude Opus 4.6",
|
||||||
|
"GLM / Kimi / Minimax only when blocked",
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"project_name": project_name,
|
||||||
|
"project_slug": project_slug,
|
||||||
|
"goal": args.goal or playbook_profile["goal_hint"],
|
||||||
|
"audience": args.audience or "Internal team and future implementing agents",
|
||||||
|
"playbook": args.playbook,
|
||||||
|
"playbook_label": playbook_profile["label"],
|
||||||
|
"spec_file": args.spec_file or playbook_profile["spec_file"],
|
||||||
|
"in_scope": parse_list(args.in_scope) or playbook_profile["default_in_scope"],
|
||||||
|
"out_of_scope": parse_list(args.out_of_scope) or playbook_profile["default_out_of_scope"],
|
||||||
|
"track_profile": TRACKS[track_key],
|
||||||
|
"track_reason": track_reason,
|
||||||
|
"primary_model": primary_model,
|
||||||
|
"secondary_model": secondary_model,
|
||||||
|
"fallback_model": fallback_model,
|
||||||
|
"runtime_source": str(Path.home() / ".cc-switch") if runtime else "knowledge-base default policy",
|
||||||
|
"date_stamp": datetime.now().strftime("%Y-%m-%d"),
|
||||||
|
"source_notes": parse_list(args.source_note),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(description="Generate first-round workflow artifacts for a target repo.")
|
||||||
|
parser.add_argument("--target-dir", required=True, help="Absolute or relative repo directory to initialize.")
|
||||||
|
parser.add_argument("--playbook", required=True, choices=sorted(PLAYBOOK_FILES))
|
||||||
|
parser.add_argument("--project-name", help="Human-readable project name. Defaults to target directory name.")
|
||||||
|
parser.add_argument("--goal", help="Primary project goal for the bootstrap set.")
|
||||||
|
parser.add_argument("--audience", help="Primary audience for the product or repo.")
|
||||||
|
parser.add_argument("--in-scope", action="append", help="Comma-separated in-scope items. Can be passed multiple times.")
|
||||||
|
parser.add_argument("--out-of-scope", action="append", help="Comma-separated out-of-scope items. Can be passed multiple times.")
|
||||||
|
parser.add_argument("--source-note", action="append", help="Comma-separated raw note or source doc names to remember.")
|
||||||
|
parser.add_argument(
|
||||||
|
"--track",
|
||||||
|
choices=("auto", "hono-react-ssr-tanstack", "nextjs-fullstack"),
|
||||||
|
default="auto",
|
||||||
|
help="Preferred application track. Defaults to auto detection + workflow tie-break.",
|
||||||
|
)
|
||||||
|
parser.add_argument("--spec-file", help="Custom bootstrap spec filename under SPECS/.")
|
||||||
|
parser.add_argument("--force", action="store_true", help="Overwrite existing generated files.")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
args = parse_args()
|
||||||
|
target_dir = Path(args.target_dir).expanduser().resolve()
|
||||||
|
target_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
writes = seed_workspace(
|
||||||
|
target_dir,
|
||||||
|
args.playbook,
|
||||||
|
args.force,
|
||||||
|
include_core_docs=False,
|
||||||
|
include_ralphy_config=False,
|
||||||
|
)
|
||||||
|
context = build_context(args, target_dir)
|
||||||
|
|
||||||
|
generated_files = {
|
||||||
|
target_dir / "CLAUDE.md": render_claude(context),
|
||||||
|
target_dir / "AGENTS.md": render_agents(context),
|
||||||
|
target_dir / "ANALYSIS.md": render_analysis(context),
|
||||||
|
target_dir / "TODO.yaml": render_todo(context),
|
||||||
|
target_dir / "SPECS" / context["spec_file"]: render_spec(context),
|
||||||
|
target_dir / ".ralphy" / "config.yaml": render_ralphy(context),
|
||||||
|
target_dir / ".workflow" / "first-round-prompts.md": render_prompts(context),
|
||||||
|
target_dir / ".handoff" / "setup-handoff.md": render_handoff(context),
|
||||||
|
target_dir / ".meetings" / "README.md": render_meetings_readme(context),
|
||||||
|
}
|
||||||
|
|
||||||
|
for target, content in generated_files.items():
|
||||||
|
writes.append(write_text(target, content, True))
|
||||||
|
|
||||||
|
manifest_path = target_dir / ".workflow" / "bootstrap-manifest.json"
|
||||||
|
manifest = {
|
||||||
|
"skill": "cc-switch-dev-workflow",
|
||||||
|
"mode": "full-init",
|
||||||
|
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||||
|
"project_name": context["project_name"],
|
||||||
|
"playbook": args.playbook,
|
||||||
|
"track": context["track_profile"]["label"],
|
||||||
|
"track_reason": context["track_reason"],
|
||||||
|
"spec_file": context["spec_file"],
|
||||||
|
}
|
||||||
|
writes.append(write_text(manifest_path, json.dumps(manifest, indent=2, ensure_ascii=False), True))
|
||||||
|
|
||||||
|
print("\n".join(writes))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
在新工单中引用
屏蔽一个用户