# pb-spec (Plan-Build Spec) pb-spec is a Python CLI tool that installs AI coding assistant skills into your project, providing a structured workflow for transforming natural-language requirements into implemented, tested code. It supports three major AI coding platforms: Claude Code, VS Code Copilot, and OpenCode, managing skill files across their different configuration directories and formats. The tool provides four core agent skills that chain together in a workflow: `pb-init` (project initialization), `pb-plan` (design and task planning), `pb-refine` (iterative refinement), and `pb-build` (subagent-driven TDD implementation). Built with Python 3.12+ and Click, pb-spec uses a template-based generation system where skill files are rendered into platform-specific formats with appropriate frontmatter and directory structures. ## CLI Installation Install pb-spec globally using uv or pipx to make it available system-wide. ```bash # Recommended installation using uv uv tool install pb-spec # Alternative installation using pipx pipx install pb-spec # Verify installation pb-spec version # Output: pb-spec 0.2.1 ``` ## Initialize Skills for a Platform The `init` command installs pb-spec skill files into your project's AI tool configuration directory. ```bash # Initialize skills for Claude Code cd my-project pb-spec init --ai claude # Output: # Installing for claude... # + .claude/skills/pb-init/SKILL.md # + .claude/skills/pb-plan/SKILL.md # + .claude/skills/pb-plan/references/design_template.md # + .claude/skills/pb-plan/references/tasks_template.md # + .claude/skills/pb-refine/SKILL.md # + .claude/skills/pb-build/SKILL.md # + .claude/skills/pb-build/references/implementer_prompt.md # pb-spec skills installed successfully! # Initialize for VS Code Copilot pb-spec init --ai copilot # Output: # Installing for copilot... # + .github/prompts/pb-init.prompt.md # + .github/prompts/pb-plan.prompt.md # + .github/prompts/pb-refine.prompt.md # + .github/prompts/pb-build.prompt.md # pb-spec skills installed successfully! # Initialize for OpenCode pb-spec init --ai opencode # Output: # Installing for opencode... # + .opencode/skills/pb-init/SKILL.md # + .opencode/skills/pb-plan/SKILL.md # + .opencode/skills/pb-build/SKILL.md # pb-spec skills installed successfully! # Initialize for all platforms at once pb-spec init --ai all ``` ## Force Overwrite Existing Skills Use the `--force` flag to overwrite existing skill files when updating to a newer version. ```bash # Overwrite existing skill files pb-spec init --ai claude --force # Output: # Installing for claude... # + .claude/skills/pb-init/SKILL.md # + .claude/skills/pb-plan/SKILL.md # + .claude/skills/pb-plan/references/design_template.md # + .claude/skills/pb-plan/references/tasks_template.md # + .claude/skills/pb-refine/SKILL.md # + .claude/skills/pb-build/SKILL.md # + .claude/skills/pb-build/references/implementer_prompt.md # pb-spec skills installed successfully! # Without --force, existing files are skipped pb-spec init --ai claude # Output: # Installing for claude... # Skipping .claude/skills/pb-init/SKILL.md (exists, use --force) # Skipping .claude/skills/pb-plan/SKILL.md (exists, use --force) # ... ``` ## Update pb-spec to Latest Version The `update` command upgrades pb-spec to the latest version using uv. ```bash # Update pb-spec to latest version pb-spec update # Output: pb-spec updated successfully. # If uv is not installed pb-spec update # Output: Error: uv is not installed. Install it first: https://docs.astral.sh/uv/ ``` ## /pb-init Skill - Project Initialization After installing skills, use `/pb-init` in your AI coding assistant to analyze your project and generate an `AGENTS.md` context file. ```markdown # In Claude Code, VS Code Copilot, or OpenCode: /pb-init # The agent will: # 1. Detect language, framework, and build tool from config files # 2. Generate directory tree (depth 3, excluding node_modules, .git, etc.) # 3. Identify key files (entry point, config, tests, CI) # 4. Check for active specs in specs/ directory # 5. Write AGENTS.md at project root # Generated AGENTS.md example: # # AGENTS.md # > Auto-generated by pb-init. Last updated: 2025-02-11 # # ## Project Overview # - **Language**: Python # - **Framework**: Click # - **Build Tool**: uv # - **Test Command**: `pytest` # # ## Project Structure # ``` # src/ # pb_spec/ # cli.py # commands/ # platforms/ # templates/ # tests/ # docs/ # ``` # # ## Key Files # - Entry point: src/pb_spec/cli.py # - Config: pyproject.toml # - Tests: tests/ ``` ## /pb-plan Skill - Design and Task Planning Use `/pb-plan` to generate a complete design proposal and task breakdown from a requirement description. ```markdown # In your AI coding assistant: /pb-plan Add WebSocket authentication support # The agent will: # 1. Parse requirements and generate feature-name: "add-websocket-auth" # 2. Read AGENTS.md and scan related source code # 3. Create specs/add-websocket-auth/ directory # 4. Output design.md with full architecture # 5. Output tasks.md with ordered implementation tasks # Generated directory structure: # specs/ # add-websocket-auth/ # design.md # Architecture, API contracts, data models # tasks.md # Ordered tasks with checkboxes # design.md includes: # - Executive Summary # - Requirements & Goals (functional, non-functional, out of scope) # - Architecture Overview with Mermaid diagrams # - Detailed Design (interfaces, data structures, logic flows) # - Verification & Testing Strategy # tasks.md includes: # - Phase grouping (Foundation -> Core -> Integration -> Polish) # - Task IDs (Task 1.1, Task 1.2, Task 2.1, etc.) # - Context, Steps (checkboxes), Verification per task # - Summary & Timeline table ``` ## /pb-refine Skill - Design Iteration Use `/pb-refine` to update existing specs based on user feedback or Design Change Requests. ```markdown # In your AI coding assistant: /pb-refine add-websocket-auth # Then provide feedback: "The WebSocket connection should use token-based auth instead of session cookies. Also, we need to add a reconnection strategy." # The agent will: # 1. Load specs/add-websocket-auth/design.md and tasks.md # 2. Parse and categorize your feedback # 3. Update design.md with precise edits # 4. Cascade changes to tasks.md # 5. Add Revision History entry # Output summary: # Changes to design.md: # - Section 4.2: Changed auth mechanism from session to token-based # - Section 4.5: Added reconnection strategy with exponential backoff # # Changes to tasks.md: # - Added: Task 2.4 - Implement reconnection logic # - Modified: Task 2.1 - Updated auth implementation approach ``` ## /pb-build Skill - Subagent-Driven Implementation Use `/pb-build` to implement tasks sequentially using TDD with fresh subagents per task. ```markdown # In your AI coding assistant: /pb-build add-websocket-auth # The agent will: # 1. Read specs/add-websocket-auth/tasks.md # 2. Parse unfinished tasks (- [ ]) # 3. For each task, spawn a fresh subagent that: # a. Writes a failing test (RED) # b. Runs tests to confirm failure # c. Implements minimum code (GREEN) # d. Runs tests to confirm pass # e. Refactors if needed # f. Self-reviews before submitting # 4. Mark completed tasks with - [x] # 5. Output progress after each task # Progress display: # [1/8] Implementing Task 1.1: Define WebSocket connection interface... # [1/8] RED: Test written - test_websocket_connects_with_token # [1/8] GREEN: Implementation complete - 2 tests pass # [1/8] Done Task 1.1: Define WebSocket connection interface - 2 tests, 3 files # # [2/8] Implementing Task 1.2: Implement token validation... # Final summary: # Tasks: 8/8 completed | 0 skipped | 0 failed # Files changed: # - src/websocket/client.py # - src/auth/token.py # - tests/test_websocket.py ``` ## Platform Adapter System The Platform base class provides a unified interface for installing skills across different AI tools. ```python from abc import ABC, abstractmethod from pathlib import Path class Platform(ABC): """AI Platform Adapter Base Class.""" @property @abstractmethod def name(self) -> str: ... @property def skill_names(self) -> list[str]: """Return list of skill names to install.""" return ["pb-init", "pb-plan", "pb-refine", "pb-build"] @abstractmethod def get_skill_path(self, cwd: Path, skill_name: str) -> Path: """Return path for skill file in target project.""" ... @abstractmethod def render_skill(self, skill_name: str, template_content: str) -> str: """Render template content into platform-specific format.""" ... def install(self, cwd: Path, force: bool = False) -> list[str]: """Install all skills to target directory.""" installed = [] for skill_name in self.skill_names: target = self.get_skill_path(cwd, skill_name) if target.exists() and not force: print(f" Skipping {target} (exists, use --force)") continue content = self._load_and_render(skill_name) target.parent.mkdir(parents=True, exist_ok=True) target.write_text(content) installed.append(str(target.relative_to(cwd))) return installed # Platform implementations: # - ClaudePlatform: .claude/skills//SKILL.md with YAML frontmatter # - CopilotPlatform: .github/prompts/.prompt.md (no frontmatter) # - OpenCodePlatform: .opencode/skills//SKILL.md with YAML frontmatter ``` ## Template Loading System Templates are loaded from the package using importlib.resources for reliable access after installation. ```python import importlib.resources def load_template(skill_name: str, filename: str) -> str: """Load a template file from the skills directory. Args: skill_name: e.g. "pb-init", "pb-plan", "pb-build" filename: e.g. "SKILL.md" Returns: File content as string """ ref = importlib.resources.files("pb_spec.templates") / "skills" / skill_name / filename return ref.read_text(encoding="utf-8") def load_skill_content(skill_name: str) -> str: """Load the main SKILL.md content for a skill.""" return load_template(skill_name, "SKILL.md") def load_references(skill_name: str) -> dict[str, str]: """Load all reference files for a skill. Returns: Dict mapping filename to content. Empty dict if no references/ directory. """ refs_dir = importlib.resources.files("pb_spec.templates") / "skills" / skill_name / "references" result = {} for item in refs_dir.iterdir(): if item.is_file(): result[item.name] = item.read_text(encoding="utf-8") return result def load_prompt(skill_name: str) -> str: """Load a Copilot prompt template (self-contained, no references).""" ref = importlib.resources.files("pb_spec.templates") / "prompts" / f"{skill_name}.prompt.md" return ref.read_text(encoding="utf-8") ``` ## Platform Resolution and Factory Get platform instances by name and resolve the `--ai` argument to platform targets. ```python from pb_spec.platforms import get_platform, resolve_targets # Resolve --ai argument to list of platform names targets = resolve_targets("all") # Returns: ["claude", "copilot", "opencode"] targets = resolve_targets("claude") # Returns: ["claude"] # Get platform instance by name platform = get_platform("claude") # Returns: ClaudePlatform instance # Get skill path for a platform path = platform.get_skill_path(Path("/my-project"), "pb-init") # Returns: Path("/my-project/.claude/skills/pb-init/SKILL.md") # Render skill with platform-specific format content = platform.render_skill("pb-init", template_content) # Claude adds YAML frontmatter: # --- # name: pb-init # description: "Project State Initialization" # --- # ``` ## Running Tests The project uses pytest for testing with comprehensive coverage of CLI commands and platform installations. ```bash # Install dev dependencies uv sync --group dev # Run all tests uv run pytest -v # Output: # tests/test_cli.py::test_help_contains_subcommands PASSED # tests/test_cli.py::test_version_shows_version_number PASSED # tests/test_cli.py::test_version_option PASSED # tests/test_cli.py::test_update_calls_uv PASSED # tests/test_init.py::test_init_claude PASSED # tests/test_init.py::test_init_copilot PASSED # tests/test_init.py::test_init_opencode PASSED # tests/test_init.py::test_init_all PASSED # tests/test_init.py::test_init_force_overwrites PASSED # tests/test_init.py::test_init_skips_existing PASSED # tests/test_init.py::test_init_claude_has_frontmatter PASSED # tests/test_init.py::test_init_copilot_no_frontmatter PASSED # Run specific test file uv run pytest tests/test_init.py -v # Run with coverage uv run pytest --cov=pb_spec ``` ## Development Setup Clone the repository and set up a local development environment. ```bash # Clone the repository git clone https://github.com/longcipher/pb-spec.git cd pb-spec # Install dependencies including dev tools uv sync --group dev # Install locally for testing uv pip install -e . # Run linting uv run ruff check src/ # Format code uv run ruff format src/ # Build distribution uv build # Creates: dist/pb_spec-0.2.1-py3-none-any.whl # Verify wheel contains templates unzip -l dist/pb_spec-*.whl | grep templates # Output: # pb_spec/templates/__init__.py # pb_spec/templates/skills/pb-init/SKILL.md # pb_spec/templates/skills/pb-plan/SKILL.md # pb_spec/templates/prompts/pb-init.prompt.md # ... ``` pb-spec is designed for developers using AI coding assistants who want a structured, repeatable workflow for feature development. The init-plan-build pipeline enforces design-first thinking, where requirements are fully analyzed and broken into tasks before implementation begins. This approach reduces context loss in multi-turn AI conversations and ensures consistent implementation through fresh subagent contexts. The tool integrates seamlessly with existing projects by detecting tech stacks automatically and respecting project conventions. Its platform abstraction allows the same workflow across Claude Code, VS Code Copilot, and OpenCode, with each platform receiving appropriately formatted skill files. The TDD-driven implementation phase ensures code quality through the Red-Green-Refactor cycle, while the self-review step catches over-engineering before it reaches the codebase.