#!/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())