promptdriven/pdd

Prompt Driven Development (PDD): The Last Programming Language™. Prompt files are source; code is generated output.

863

stars

3,165

commits

Python

primary language

Aug 24, 2026

updated

promptdriven.ai
ai
cli
code
developer-tools
development
methodology
prompt
prompt-engineering
prompts
prompts-template
prompt-toolkit
Browse cluster: LLM Prompt Injection Security

README

PDD: The Last Programming Language™

PyPI version Discord

Introduction

PDD (Prompt-Driven Development) is a prompt-native programming system. .prompt files are the human-authored source language; Python, TypeScript, Go, and other traditional languages are generated artifacts.

PDD is the last programming language in this specific sense: developers author durable intent, constraints, examples, and tests, then compile that source into whatever implementation language the project needs. Code remains real and reviewable, but it is no longer the primary source of truth.

Getting started is simple:

# Install and run
uv tool install pdd-cli
pdd setup
pdd connect

This launches a web interface at localhost:9876 where you can:

  • Implement GitHub issues automatically
  • Generate and test code from prompts
  • Manage your PDD projects visually

PDD Handpaint Demo

For CLI users, PDD also offers powerful agentic commands that implement GitHub issues automatically:

  • pdd change <issue-url> - Implement feature requests (13-step workflow)
  • pdd bug <issue-url> - Create failing tests for bugs
  • pdd fix <issue-url> - Fix the failing tests
  • pdd split <target-file> - Diagnose and split large dev units (15-step workflow with intent classification, diagnosis, phase extraction, per-child verify gate, and repair)
  • pdd generate <issue-url> - Generate architecture.json from a PRD issue (11-step workflow)
  • pdd test <issue-url> - Generate UI tests from issue descriptions (18-step workflow with exploratory testing, contract validation, accessibility audits)

Choose pdd bug before pdd change when an issue reports a current runtime symptom, even if it says the prompt or spec should be updated. Stack traces, failing commands, wrong CLI/API/UI output, regressions, crashes, and incorrect generated behavior should run through pdd bug <issue-url> followed by pdd fix <issue-url> (bug → fix) so the failure is reproduced and covered by a behavioral test. Use pdd change for explicit source-truth/spec/product changes with no current runtime failure to reproduce (change → sync after the source-truth change lands).

For prompt-based workflows, the sync command automates the complete development cycle with intelligent decision-making, real-time visual feedback, and sophisticated state management.

Whitepaper

For the positioning essay behind this shift, read The Last Programming Language.

For a detailed explanation of the concepts, architecture, and benefits of Prompt-Driven Development, please refer to our full whitepaper. This document provides an in-depth look at the PDD philosophy, its advantages over traditional development, and includes benchmarks and case studies.

Read the Full Whitepaper with Benchmarks

For a case study on specification drift in AI-assisted coding workflows, read Why AI Code Falls Apart.

Also see the Prompt‑Driven Development Doctrine for core principles and practices: docs/prompt-driven-development-doctrine.md

For a step-by-step methodology on turning a GitHub issue into a durable, human-verified user story, see docs/generating_user_stories.md.

For pre-merge prompt and user-story quality (vague terms, vocabulary, optional LLM review), see docs/prompt_lint.md.

For deterministic contract-section lint (<contract_rules>, <coverage>, waivers, story ## Covers), see docs/contract_check.md.

For a rule-to-story/test coverage matrix (pdd checkup coverage), including the @pytest.mark.story regression marker and the per-story has_regression_test dimension, see docs/coverage_contracts.md and docs/generating_user_stories.md.

For non-interactive bounded prompt repair after a failed prompt source-set checkup, see docs/prompt_repair.md.

For the deterministic prompt source-set quality gate and its pdd.prompt_source_set_report.v1 JSON schema (including the per-finding requires_clarification / clarification_reason clarification signal), see docs/checkup_prompt_quality_gate.md.

For the agentic CLI routing policy (task-class-keyed static config table and bounded escalation ladder for run_agentic_task), see docs/routing_policy.md.

Installation

Prerequisites for macOS

On macOS, you'll need to install some prerequisites before installing PDD:

  1. Install Xcode Command Line Tools (required for Python compilation):

    xcode-select --install
    
  2. Install Homebrew (recommended package manager for macOS):

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    

    After installation, add Homebrew to your PATH:

    echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile && eval "$(/opt/homebrew/bin/brew shellenv)"
    
  3. Install Python (if not already installed):

    # Check if Python is installed
    python3 --version
    
    # If Python is not found, install it via Homebrew
    brew install python
    

    Note: Recent versions of macOS no longer ship with Python pre-installed. PDD requires Python 3.12 or higher. The brew install python command installs the latest Python 3 version.

We recommend installing PDD using the uv package manager for better dependency management and automatic environment configuration:

# Install uv if you haven't already 
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install PDD using uv tool install
uv tool install pdd-cli

This installation method ensures:

  • Faster installations with optimized dependency resolution
  • Automatic environment setup without manual configuration
  • Proper handling of the PDD_PATH environment variable
  • Better isolation from other Python packages

The PDD CLI will be available immediately after installation without requiring any additional environment configuration.

Verify installation:

pdd --version

With the CLI on your PATH, continue with:

pdd setup

The command detects agentic CLI tools, scans for API keys, configures models, and seeds local configuration files. If you postpone this step, the CLI detects the missing setup artifacts the first time you run another command and shows a reminder banner so you can complete it later (the banner is suppressed once ~/.pdd/api-env exists or when your project already provides credentials via .env or .pdd/).

Alternative: pip Installation

If you prefer using pip, you can install PDD with:

pip install pdd-cli

Advanced Installation Options

Virtual Environment Installation

# Create virtual environment
python -m venv pdd-env

# Activate environment
# On Windows:
pdd-env\Scripts\activate
# On Unix/MacOS:
source pdd-env/bin/activate

# Install PDD
pip install pdd-cli

Getting Started

The easiest way to use PDD is through the web interface:

# 1. Install PDD
curl -LsSf https://astral.sh/uv/install.sh | sh
uv tool install pdd-cli

# 2. Run setup (API keys, shell completion)
pdd setup

# 3. Launch the web interface
pdd connect

This opens a browser-based interface where you can:

  • Run Commands: Execute pdd change, pdd bug, pdd fix, pdd sync etc. visually
  • Browse Files: View and edit prompts, code, and tests in your project
  • Remote Access: Access your session from any browser via PDD Cloud (use --local-only to disable)

Option 2: Issue-Driven CLI

For CLI enthusiasts, implement GitHub issues directly:

Prerequisites:

  1. GitHub CLI - Required for issue access:

    brew install gh && gh auth login
    
  2. One Agentic CLI - Required to run the workflows (install at least one):

    • Claude Code: npm install -g @anthropic-ai/claude-code (uses your stored Claude Max/Pro OAuth login if you've run claude auth login, otherwise falls back to ANTHROPIC_API_KEY; pdd auto-prefers OAuth — set PDD_KEEP_ANTHROPIC_API_KEY=1 to force API-key billing)
    • Antigravity CLI (agy, preferred): install via curl -fsSL https://antigravity.google/cli/install.sh | bash (uses Antigravity OAuth or keyring-backed Google subscription sign-in if present, otherwise ANTIGRAVITY_API_KEY/GOOGLE_API_KEY, Vertex AI env auth, or PDD's compatibility bridge from GEMINI_API_KEY). Set PDD_AGENTIC_PROVIDER=antigravity to pin the Antigravity binary, or PDD_GOOGLE_CLI=agy|gemini|auto to control binary selection (auto prefers agy when credentialed, but keeps legacy gemini for legacy-OAuth-only setups).
    • Gemini CLI (legacy, rollback): npm install -g @google/gemini-cli (uses ~/.gemini OAuth credentials if present, otherwise GOOGLE_API_KEY or GEMINI_API_KEY). Google announced consumer-tier Gemini CLI cutoff on 2026-06-18; set PDD_GOOGLE_CLI=gemini only when you intentionally need the old binary.
    • Codex CLI: npm install -g @openai/codex@latest (GPT-5.6 requires Codex CLI 0.144.0 or newer; uses ~/.codex/auth.json ChatGPT login if present, otherwise OPENAI_API_KEY)
    • OpenCode CLI: npm install -g opencode-ai (uses OpenCode provider auth from opencode auth login, ~/.config/opencode/opencode.json, project opencode.json, or provider env vars; set OPENCODE_MODEL=provider/model)

Usage:

# Implement a feature request
pdd change https://github.com/owner/repo/issues/123

# Or fix a bug
pdd bug https://github.com/owner/repo/issues/456
pdd fix https://github.com/owner/repo/issues/456

Option 3: Manual Prompt Workflow

For learning PDD fundamentals or working with existing prompt files:

cd your-project
pdd sync module_name  # Full automated workflow

See the Hello Example below for a step-by-step introduction.


🚀 Quickstart (Hello Example)

If you want to understand PDD fundamentals, follow this manual example to see it in action.

  1. Install prerequisites (macOS/Linux):

    xcode-select --install      # macOS only
    curl -LsSf https://astral.sh/uv/install.sh | sh
    uv tool install pdd-cli
    pdd --version
    
  2. Clone repo

      # Clone the repository (if not already done)
     git clone https://github.com/promptdriven/pdd.git
     cd pdd/examples/hello
    
  3. Set one API key (choose your provider):

    export GEMINI_API_KEY="your-gemini-key"
    # OR
    export OPENAI_API_KEY="your-openai-key"
    

Post-Installation Setup (Required first step after installation)

Run the comprehensive setup wizard:

pdd setup

The setup wizard runs these steps:

  1. Detects agentic CLI tools (Claude, Gemini/Antigravity, Codex, OpenCode) and offers installation and credential configuration if needed. Credentials can be environment-variable API keys, stored OAuth/subscription/config credentials such as Claude Max/Pro, Google Gemini/Antigravity login, Vertex AI env auth, Codex ChatGPT login, or OpenCode provider auth/config.
  2. Scans for API keys across .env, ~/.pdd/api-env.*, and the shell environment. If no API key is found but a selected CLI already has a stored OAuth/subscription/config credential, setup skips the API-key prompt for the agentic workflow and explains which direct prompt/LiteLLM commands still need API keys.
  3. Configures models from a reference CSV data/llm_model.csv of top ranked models across all LiteLLM-supported providers based on your available API keys
  4. If you have credentials for more than one provider, asks which provider(s) pdd --local should use, then removes the unselected providers' PDD-managed rows from ~/.pdd/llm_model.csv (rows you hand-edited or added yourself are preserved — see below)
  5. Optionally creates a .pddrc project config
  6. Tests a model from your selected provider with a real LLM call
  7. Prints a structured summary (CLIs, keys, models, test result)

The wizard can be re-run at any time to update keys, add providers, or reconfigure settings.

Choosing your local provider

pdd --local selects a model from ~/.pdd/llm_model.csv by cost/ranking, so if the file lists several providers it can route to one you didn't intend — for example a free GitHub Copilot login outranking a GEMINI_API_KEY you set on purpose. To prevent that, when setup ends up with more than one usable provider — which includes always-available device-login providers like GitHub Copilot, so the prompt can appear even if you only set a single API key — it asks you to pick which provider(s) to keep, then removes the unselected providers' PDD-managed rows (rows you hand-edited or added yourself are preserved):

  • Default selection excludes device-login providers (e.g. GitHub Copilot, which needs no API key) so a free login never silently outranks a key you configured. Select them explicitly to keep them.
  • Local models (Ollama, LM Studio) and any hand-edited/custom rows for providers you don't configure are never offered for removal and are left untouched.
  • Before removing any rows, setup lists exactly what will be removed and asks you to confirm, and snapshots the previous file to ~/.pdd/llm_model.csv.backup.<timestamp> so the change is always reversible.
  • Your choice is saved to ~/.pdd/setup_preferences.json. Re-running setup re-uses it without re-asking and without re-adding the providers you dropped (so a later run stays quiet — no repeated prompt, no Copilot churn). It only adds new models for the providers you already chose.

To use a different provider later, delete ~/.pdd/setup_preferences.json and re-run pdd setup to pick a new selection (or edit ~/.pdd/llm_model.csv directly). Adding a provider through the setup options menu also updates your saved selection.

Important: After setup completes, source the API environment file so your keys take effect in the current terminal session:

source ~/.pdd/api-env.zsh   # or api-env.bash, depending on your shell

New terminal windows will load keys automatically.

If you skip this step, the first regular pdd command you run will detect the missing setup files and print a reminder banner so you can finish onboarding later.

  1. Run Hello:

    cd ../hello
    pdd --force generate hello_python.prompt
    python3 hello.py
    

    ✅ Expected output:

    hello
    

Cloud vs Local Execution

PDD commands can be run either in the cloud or locally. By default, all commands run in the cloud mode, which provides several advantages:

  • No need to manage API keys locally
  • Access to more powerful models
  • Shared examples and improvements across the PDD community
  • Automatic updates and improvements
  • Better cost optimization

Cloud Authentication

When running in cloud mode (default), PDD uses GitHub Single Sign-On (SSO) for authentication. On first use, you'll be prompted to authenticate:

  1. PDD will open your default browser to the GitHub login page
  2. Log in with your GitHub account
  3. Authorize PDD Cloud to access your GitHub profile
  4. Once authenticated, you can return to your terminal to continue using PDD

The authentication token is securely stored locally and automatically refreshed as needed.

Local Mode Requirements

When running in local mode with the --local flag, you'll need to set up API keys for the language models:

# For OpenAI
export OPENAI_API_KEY=your_api_key_here

# For Anthropic
export ANTHROPIC_API_KEY=your_api_key_here

# For other supported providers (LiteLLM supports multiple LLM providers)
export PROVIDER_API_KEY=your_api_key_here

Some local-mode providers do not use API keys. GitHub Copilot models authenticate through LiteLLM's OAuth device flow; run pdd setup, then choose Add a provider from the options menu and pick GitHub Copilot to complete that device login. (The provider-selection prompt described above only decides which already-configured providers pdd --local uses — it does not perform the OAuth login.)

Add these to your .bashrc, .zshrc, or equivalent for persistence.

PDD's local mode uses the packaged LiteLLM dependency (>=1.84.0,<1.85 in this release) for interacting with language models, providing:

  • Support for multiple model providers (OpenAI, Anthropic, Google/Vertex AI, and more)
  • Automatic model selection based on strength settings
  • Response caching for improved performance
  • Smart token usage tracking and cost estimation
  • Interactive API key acquisition when keys are missing

When keys are missing, PDD will prompt for them interactively and securely store them in your local .env file.

Local Model Configuration

PDD uses a CSV file to configure model selection and capabilities. This configuration is loaded from:

  1. User-specific configuration: ~/.pdd/llm_model.csv (takes precedence if it exists)
  2. Project-specific configuration: <PROJECT_ROOT>/.pdd/llm_model.csv
  3. Package default: Bundled with PDD installation (fallback when no local configurations exist)

The CSV includes columns for:

  • provider: The LLM provider (e.g., "openai", "anthropic", "google")
  • model: The LiteLLM model identifier (e.g., "gpt-4", "claude-3-opus-20240229")
  • input/output: Costs per million tokens
  • coding_arena_elo: Raw Arena/static ELO metadata
  • model_rank_score: Primary selection rank. DeepSWE rows use a high solve-rate band; Arena/static rows fall back to raw ELO.
  • model_rank_source: Source of model_rank_score (for example deepswe-solve-rate, arena-elo-fallback, or static)
  • api_key: The environment variable name for required authentication, or blank for local and device-flow providers such as Ollama, LM Studio, and GitHub Copilot
  • structured_output: Whether the model supports structured JSON output
  • reasoning_type: Support for reasoning capabilities ("none", "budget", "effort", or "adaptive")

For a concrete, up-to-date reference of supported models and example rows, see the bundled CSV in this repository: pdd/data/llm_model.csv.

For proper model identifiers to use in your custom configuration, refer to the LiteLLM Model List documentation. LiteLLM typically uses model identifiers in the format provider/model_name (e.g., "openai/gpt-4", "anthropic/claude-3-opus-20240229").

Z.AI (GLM Models)

PDD supports two Z.AI API endpoints:

  • General API (https://api.z.ai/api/paas/v4) — standard prepaid/resource billing, suitable for general use.
  • GLM Coding Plan (https://api.z.ai/api/coding/paas/v4) — quota-backed subscription plan designed for coding workflows. Diagnostics show it as quota-backed rather than a per-token dollar estimate.

Both endpoints use the same API key. To use the bundled GLM Coding Plan rows:

export ZAI_API_KEY=your_zai_api_key_here
export PDD_MODEL_DEFAULT=glm-5.2

Or in your .pddrc:

defaults:
  model: glm-5.2

The bundled catalog includes rows for Z.AI (general API) and Z.AI Coding Plan providers. PDD stores these rows as OpenAI-compatible openai/glm-5.2 model strings with explicit base_url values, and resolves a bare user default such as glm-5.2 to the quota-backed Coding Plan row instead of falling through to an unrelated provider.

To target the per-token General API endpoint (https://api.z.ai/api/paas/v4) instead of the Coding Plan endpoint, select the explicit OpenAI-compatible row:

export ZAI_API_KEY=your_zai_api_key_here
export PDD_MODEL_DEFAULT=openai/glm-5.2

Structured-output forcing is disabled for Z.AI rows until Z.AI schema support is verified; reasoning_effort is enabled through PDD's normal low/medium/high effort mapping.

Run pdd setup with ZAI_API_KEY set to have PDD detect Z.AI and include it in the provider configuration.

Troubleshooting Common Installation Issues

  1. Command not found

    # Add to PATH if needed
    export PATH="$HOME/.local/bin:$PATH"
    
  2. Permission errors

    # Install with user permissions
    pip install --user pdd-cli
    
  3. macOS-specific issues

    • Xcode Command Line Tools not found: Run xcode-select --install to install the required development tools
    • Homebrew not found: Install Homebrew using the command in the prerequisites section above
    • Python not found or wrong version: Install Python 3 via Homebrew: brew install python
    • Permission denied during compilation: Ensure Xcode Command Line Tools are properly installed and you have write permissions to the installation directory
    • uv installation fails: Try installing uv through Homebrew: brew install uv
    • Python version conflicts: If you have multiple Python versions, ensure python3 points to Python 3.12+: which python3 && python3 --version

Version

To check your installed version, run:

pdd --version

PDD includes an auto-update feature to ensure you always have access to the latest features and security patches. You can control this behavior using an environment variable (see "Auto-Update Control" section below).

Supported Programming Languages

PDD supports a wide range of programming languages, including but not limited to:

  • Python
  • JavaScript
  • TypeScript
  • Java
  • C++
  • Ruby
  • Go

The specific language is often determined by the prompt file's naming convention or specified in the command options.

Prompt File Naming Convention

Prompt files in PDD commonly follow one of these formats:

<basename>_<language>.prompt

or, for architecture-driven projects with nested output paths:

<path/to/output_stem>_<Language>.prompt

Where:

  • <basename> is the base name of the file or project in legacy flat layouts
  • <path/to/output_stem> mirrors the output filepath without its extension in architecture-driven layouts
  • <language> / <Language> is the programming language or prompt context suffix used by the project

Examples:

  • factorial_calculator_python.prompt (basename: factorial_calculator, language: python)
  • responsive_layout_css.prompt (basename: responsive_layout, language: css)
  • data_processing_pipeline_python.prompt (basename: data_processing_pipeline, language: python)
  • src/models/user_Python.prompt → generates src/models/user.py
  • app/api/orders/route_TypeScript.prompt → generates app/api/orders/route.ts

PDD supports both conventions. Legacy hand-written prompts are often flat, while prompts generated from architecture.json typically mirror the target filepath directory structure.

Prompt-Driven Development Philosophy

Core Concepts

Prompt-Driven Development (PDD) inverts traditional software development by treating prompts as the primary artifact - not code. This paradigm shift has profound implications:

  1. Prompts as Source of Truth: In traditional development, source code is the ground truth that defines system behavior. In PDD, the prompts are authoritative, with code being a generated artifact.

  2. Natural Language Over Code: Prompts are written primarily in natural language, making them more accessible to non-programmers and clearer in expressing intent.

  3. Regenerative Development: When changes are needed, you modify the prompt and regenerate code, rather than directly editing the code. This maintains the conceptual integrity between requirements and implementation.

  4. Intent Preservation: Prompts capture the "why" behind code in addition to the "what" - preserving design rationale in a way that comments often fail to do.

Mental Model

To work effectively with PDD, adopt these mental shifts:

  1. Prompt-First Thinking: Always start by defining what you want in a prompt before generating any code.

  2. Bidirectional Flow:

    • Prompt → Code: The primary direction (generation)
    • Code → Prompt: Secondary but crucial (keeping prompts in sync with code changes)
  3. Modular Prompts: Just as you modularize code, you should modularize prompts into self-contained units that can be composed.

  4. Integration via Examples: Modules integrate through their examples, which serve as interfaces, allowing for token-efficient references.

PDD Workflows: Conceptual Understanding

Each workflow in PDD addresses a fundamental development need:

  1. Initial Development Workflow

    • Purpose: Creating functionality from scratch
    • Conceptual Flow: Define dependencies → Generate implementation → Create interfaces → Ensure runtime functionality → Verify correctness

    This workflow embodies the prompt-to-code pipeline, moving from concept to tested implementation.

  2. Code-to-Prompt Update Workflow

    • Purpose: Maintaining prompt as source of truth when code changes
    • Conceptual Flow: Sync code changes to prompt → Identify impacts → Propagate changes

    This workflow ensures the information flow from code back to prompts, preserving prompts as the source of truth.

  3. Debugging Workflows

    • Purpose: Resolving different types of issues
    • Conceptual Types:
      • Context Issues: Addressing misunderstandings in prompt interpretation
      • Runtime Issues: Fixing execution failures
      • Logical Issues: Correcting incorrect behavior
      • Traceability Issues: Connecting code problems back to prompt sections

    These workflows recognize that different errors require different resolution approaches.

  4. Refactoring Workflow

    • Purpose: Improving prompt organization and reusability
    • Conceptual Flow: Extract functionality → Ensure dependencies → Create interfaces

    This workflow parallels code refactoring but operates at the prompt level.

  5. Multi-Prompt Architecture Workflow

    • Purpose: Coordinating systems with multiple prompts
    • Conceptual Flow: Detect conflicts → Resolve incompatibilities → Regenerate code → Update interfaces → Verify system

    This workflow addresses the complexity of managing multiple interdependent prompts.

  6. Enhancement Phase: Use Feature Enhancement when adding capabilities to existing modules.

Workflow Selection Principles

The choice of workflow should be guided by your current development phase:

  1. Creation Phase: Use Initial Development when building new functionality.

  2. Maintenance Phase: Use Code-to-Prompt Update when existing code changes.

  3. Problem-Solving Phase: Choose the appropriate Debugging workflow based on the issue type:

    • Preprocess → Generate for prompt interpretation issues
    • Crash for runtime errors
    • Bug → Fix for logical errors
    • Trace for locating problematic prompt sections
  4. Restructuring Phase: Use Refactoring when prompts grow too large or complex.

  5. System Design Phase: Use Multi-Prompt Architecture when coordinating multiple components.

  6. Enhancement Phase: Use Feature Enhancement when adding capabilities to existing modules.

PDD Design Patterns

Effective PDD employs these recurring patterns:

  1. Dependency Injection via Auto-deps: Automatically including relevant dependencies in prompts.

  2. Interface Extraction via Example: Creating minimal reference implementations for reuse.

  3. Bidirectional Traceability: Maintaining connections between prompt sections and generated code.

  4. Test-Driven Prompt Fixing: Using tests to guide prompt improvements when fixing issues.

  5. Hierarchical Prompt Organization: Structuring prompts from high-level architecture to detailed implementations.

Basic Usage

pdd [GLOBAL OPTIONS] COMMAND [OPTIONS] [ARGS]...

Command Overview

Here is a brief overview of the main commands provided by PDD. Click the command name to jump to its detailed section:

Command Relationships

The following diagram shows how PDD commands interact:

graph TB
    subgraph Entry Points
        connect["pdd connect (Web UI - Recommended)"]
        cli["Direct CLI"]
        ghapp["GitHub App"]
    end

    gen_url["pdd generate &lt;url&gt;"]

    subgraph sync workflow
        sync["pdd sync"]
        s_deps["auto-deps"]
        s_gen["generate"]
        s_example["example"]
        s_crash["crash"]
        s_verify["verify"]
        s_test["test"]
        s_fix["fix"]
        s_update["update"]
    end

    checkup["pdd checkup &lt;url&gt;"]
    test_url["pdd test &lt;url&gt;"]
    bug_url["pdd bug &lt;url&gt;"]
    fix_url["pdd fix &lt;url&gt;"]
    change["pdd change &lt;url&gt;"]
    sync_url["pdd sync &lt;url&gt;"]

    connect --> gen_url
    cli --> gen_url
    ghapp --> gen_url
    gen_url --> sync
    sync --> s_deps
    s_deps --> s_gen
    s_gen --> s_example
    s_example --> s_crash
    s_crash --> s_verify
    s_verify --> s_test
    s_test --> s_fix
    s_fix --> s_update
    sync --> checkup
    checkup --> test_url
    checkup --> bug_url
    checkup --> change
    test_url --> fix_url
    bug_url --> fix_url
    change --> sync_url
    sync_url -.-> sync

Key concepts:

  • Entry points: pdd connect (web UI), direct CLI, or the GitHub App
  • Start: pdd generate <url> scaffolds architecture, prompts, and .pddrc from a PRD GitHub issue
  • Core loop: pdd sync runs the full auto-deps → generate → example → crash → verify → test → fix → update cycle for each module
  • Health check: pdd checkup <url> identifies what needs attention next; pdd checkup --pr ... reviews an existing PR on its own merits (add --issue ... to also verify it resolves a specific issue)
  • Defect path: test <url> or bug <url> surfaces failing tests → fix <url> resolves them
  • Feature path: change <url> implements the feature → sync <url> re-runs sync across affected modules. Auth caveat: sync <url> still runs a LiteLLM-backed generate phase, so OAuth-only CLI setup is not enough; configure an API key first.

Getting Started

  • connect: [RECOMMENDED] Launch web interface for visual PDD interaction
  • setup: Configure API keys and shell completion

Agentic Commands (Issue-Driven)

  • change: Implement feature requests from GitHub issues (13-step workflow)
  • bug: Analyze bugs and create failing tests from GitHub issues
  • checkup: Run automated project health checks from GitHub issues, or review/verify existing PRs (optionally against a source issue)
  • fix: Fix failing tests (supports issue-driven and manual modes)
  • sync: Multi-module parallel sync from a GitHub issue (when passed a URL instead of basename). This mode still requires API-key-backed LiteLLM for its generate phase; stored CLI OAuth alone is not sufficient.
  • test: Generate UI tests from GitHub issues (18-step workflow in agentic mode)

Core Commands (Prompt-Based)

  • sync: [PRIMARY FOR PROMPT WORKFLOWS] Automated prompt-to-code cycle
  • generate: Creates runnable code from a prompt file; supports parameterized prompts via -e/--env
  • example: Generates a compact example showing how to use functionality defined in a prompt
  • test: Generates or enhances unit tests for a code file and its prompt
  • update: Updates the original prompt file based on modified code
  • verify: Verifies functional correctness by running a program and judging output against intent
  • crash: Fixes errors in a code module and its calling program that caused a crash

Prompt Management

  • preprocess: Preprocesses prompt files, handling includes, comments, and other directives
  • replay: Reconstructs and audits expanded prompt context from a snapshot-enabled run artifact
  • context: Shows context-window usage by source for a hydrated prompt, Claude-Code /context-style
  • split: Splits large prompt files into smaller, more manageable ones
  • extracts prune: Garbage-collect orphaned extracts cache entries
  • auto-deps: Analyzes and inserts needed dependencies into a prompt file
  • sync-architecture: Updates architecture.json from prompt metadata tags
  • detect: Analyzes prompts to determine which ones need changes based on a description
  • conflicts: Finds and suggests resolutions for conflicts between two prompt files
  • trace: Finds the corresponding line number in a prompt file for a given code line

Utility Commands

  • auth: Manages authentication with PDD Cloud
  • sessions: Manage remote sessions for connect
  • report-core: Create a GitHub issue from a debug snapshot
  • contracts check: Run deterministic contract section checks; see docs/contract_check.md
  • templates: List, inspect, and copy packaged prompt templates
  • which: Print resolved configuration values and search paths
  • install_completion: Refresh shell completion scripts

User Story Prompt Tests

PDD can validate prompt changes against user stories stored as Markdown files. This uses detect under the hood: a story passes when detect returns no required prompt changes.

Defaults:

  • Stories live in user_stories/ and match story__*.md.
  • Prompts are loaded from prompts/ (excluding *_llm.prompt by default).

Overrides:

  • PDD_USER_STORIES_DIR sets the stories directory.
  • PDD_PROMPTS_DIR sets the prompts directory.

Commands:

  • pdd story add <issue-source> --devunit <name> [--devunit <name>] creates a story file from a GitHub issue URL, issue number, or local Markdown file, linked to one or more dev units. Use --text "..." to supply the story source as inline text instead of a URL or file path. Supports --prompt <path> for explicit prompt selection, --from-changed-files to link currently changed .prompt files, --dry-run for a no-write preview, --update to merge prompt links into an existing story, and --generate-regression to print the follow-up pdd test --from-story command.
  • pdd story list [--with-regression-status] lists all stories in user_stories/ with their slug, file path, linked prompts, and (when the traceability API is available) missing / has-test / stale regression status. This is a presence/freshness signal only: has-test means a fresh, marker-linked regression test exists (or a legacy hashless traceability link), not that it passed — pass/fail is verified separately by the story lane (pytest -m story).
  • pdd story link <story-file> --prompt <path> adds a prompt link to an existing story file without regenerating the story body. Validates that the story file is inside user_stories/.
  • pdd test --from-story user_stories/story__*.md --output tests/story_regression/test_story_*.py generates deterministic pytest regression tests from the story contract. When the contract declares a machine-readable ## Entry Point, the generated test is behavioral (preferred): it imports and calls the entry point and asserts the ## Oracle / ## Negative Cases bullets as Python expressions over result. Without an ## Entry Point, it falls back to a text-pin test that pins the story/contract hash and clauses. Either way, generated tests are tagged with @pytest.mark.story(...). See docs/generating_user_stories.md Step 8.
  • pdd detect --stories runs the validation suite.
  • pdd change runs story validation after prompt modifications and fails if any story fails.
  • pdd fix user_stories/story__*.md applies a single story to prompts and re-validates it.
  • pdd test --issue <url|number|issue.md> <prompt_1.prompt> [prompt_2.prompt ...] generates a story__*.md file from the issue text and links those prompts.
  • pdd test user_stories/story__*.md updates prompt links for an existing story file.
  • Story validation prints PASS/FAIL/UNKNOWN and exits non-zero if any story does not pass. pdd detect --stories does not support CSV --output. Automation should use --json or atomic --json-output FILE; these modes imply read-only, non-interactive execution and emit schema pdd.detect.stories.v1. Exit 0 means every scoped story explicitly passed, 1 is a completed semantic story failure, 2 is a scope/configuration error, and 3 is an authentication/provider/timeout or incomplete-evaluation failure. The canonical scoped form is pdd detect --stories --stories-dir user_stories --prompts-dir prompts --no-fail-fast --json. Do not pass a story directory positionally.

Failure output:

  • When a completed semantic evaluation fails, pdd detect --stories prints the evaluated prompt paths, per-prompt descriptions of the missing or stale behavior, and a pdd fix user_stories/story__<slug>.md next-step command.
  • If prompt metadata is only partially or not at all resolvable, the story is UNKNOWN: PDD lists evaluated prompts and unresolved references, recommends repairing pdd-story-prompts metadata, and does not describe the problem as missing/stale behavior or recommend pdd fix.

Story prompt linkage:

  • Stories may include optional metadata to scope validation to a subset of prompts: <!-- pdd-story-prompts: prompts/a_python.prompt, prompts/b_python.prompt -->
  • If metadata is missing, pdd detect --stories validates against the full prompt set.
  • pdd test --issue ... <*.prompt> links the prompt files passed on the command line directly in story metadata; it does not run detect_change during story authoring.
  • In --stories mode, existing story metadata scopes validation; when metadata is missing, validation falls back to the full prompt set.
  • Cross-dev-unit stories: When ≥2 prompt files are passed to pdd test --issue, a second metadata comment is also written alongside pdd-story-prompts: <!-- pdd-story-dev-units: basename1.prompt, basename2.prompt --> This marks the story as spanning multiple dev units (cross-unit). Single-prompt stories do not receive a pdd-story-dev-units comment. Cross-unit traceability is exposed via get_cross_unit_stories_for_prompt (forward lookup: which cross-unit stories include a given prompt) and story_is_cross_unit (returns True when the deduplicated union of the pdd-story-prompts and pdd-story-dev-units entries has ≥2 names — so one prompt link plus one distinct dev-unit link already counts as cross-unit). pdd checkup coverage reports cross-unit stories separately and counts each story once globally to prevent double-counting.

Template:

  • See user_stories/story__template.md for a starter format.

Contract coverage:

  • User stories are example-level coverage for named contract rules in prompts. Document rule IDs under each story's ## Covers section (for example R1 or prompts/module_python.prompt#R2). See docs/coverage_contracts.md and docs/contract_check.md.

Executable regression suite:

  • Beyond drift validation, a story can carry a generated executable regression test marked @pytest.mark.story. Run the suite with make regression-stories (i.e. pytest -m story) in the public-safe, no-secrets lane.
  • Generate a test for a story with pdd test --from-story user_stories/story__<slug>.md.
  • Seed coverage ships for the top flows (generate, sync, fix, change, update) plus a batch of previously-fixed-bug regressions. See docs/generating_user_stories.md.

Global Options

These options can be used with any command:

  • --force: Skip all interactive prompts (file overwrites, API key requests). Useful for CI/automation.
  • --strength FLOAT: Set the strength of the AI model (0.0 to 1.0, default is 1.0 unless .pddrc or PDD_STRENGTH_DEFAULT overrides it).
    • 0.0: Cheapest available model
    • 0.5: Mid-ranked model
    • 1.0: Most powerful model (highest DeepSWE-first rank score)
  • --time FLOAT: Controls the reasoning allocation for LLM models supporting reasoning capabilities (0.0 to 1.0, default is 0.25).
    • For models with specific reasoning token limits (e.g., 64k), a value of 1.0 utilizes the maximum available tokens.
    • For models with discrete effort levels, 1.0 corresponds to the highest effort level.
    • Values between 0.0 and 1.0 scale the allocation proportionally.
  • --temperature FLOAT: Set the temperature of the AI model (default is 0.0).
  • --verbose: Increase output verbosity for more detailed information. Includes token count and context window usage for each LLM call.
  • --quiet: Decrease output verbosity for minimal information.
  • --color / --no-color: Force or disable colored output across all commands. Default is auto: color is on when writing to a TTY and off when piped or when NO_COLOR is set. --no-color disables color everywhere; --color forces it on even through a pipe (e.g. pdd --color sync | less -R). The flag sets NO_COLOR/FORCE_COLOR for the run, so every console PDD builds inherits the choice. For pdd context, which has its own --color/--no-color, precedence is: the command's own flag wins, otherwise the global flag, otherwise auto-detect.
  • --output-cost PATH_TO_CSV_FILE: Enable cost tracking and output a CSV file with usage details.
  • --estimate, --dry-run-cost: Preview the LLM token and rough cost estimate for pdd generate without calling a provider, writing command outputs, or appending cost CSV rows.
  • --estimate-json: Emit the estimate result as machine-readable JSON instead of the human-readable table.
  • --review-examples: Review and optionally exclude few-shot examples before command execution.
  • --local: Run commands locally instead of in the cloud.
  • --core-dump / --no-core-dump: Write a debug snapshot for this run into .pdd/core_dumps (default: on). Use --no-core-dump to disable it.
  • --keep-core-dumps N: Keep the most recent N debug snapshots (default: 10; use 0 to clean them immediately after writing).
  • --context CONTEXT_NAME: Override automatic context detection and use the specified context from .pddrc.
  • --list-contexts: List all available contexts defined in .pddrc and exit.
  • --compress-examples: Automatically apply mode="interface" to example includes (legacy; prefer --context-compression examples).
  • --compress-test-context: Rank and select tests under a configurable token budget (PDD_TEST_TOKEN_BUDGET, default 2 000 tokens) using import-graph distance, symbol overlap, failure recency, and file recency. Failing tests (from PDD_FAILING_TESTS or .pytest_cache) are always included first. A TestPackingManifest explaining selected and omitted tests is emitted in the run telemetry (legacy: prefer --context-compression test).
  • --context-compression {off,test,examples,contracts,all}: Set context compression for this CLI invocation (default: off). Must appear before the subcommand (e.g. pdd --context-compression test generate ...). sync and fix also accept the same flags after their subcommand.
  • --compression-fallback {full,error}: When compression or slicing fails, use full content (full, default) or abort (error). Global placement is the same as --context-compression.

Core Dump Debug Bundles

PDD writes JSON debug snapshots to .pdd/core_dumps by default and keeps the 10 most recent files. These snapshots capture enough run context to replay and analyze failures. Disable them with --no-core-dump, or change retention with --keep-core-dumps.

pdd sync factorial_calculator
pdd --no-core-dump sync factorial_calculator
pdd --keep-core-dumps 20 crash prompts/calc_python.prompt src/calc.py examples/run_calc.py crash_errors.log

When debug snapshots are enabled, PDD:

  • Captures the full CLI command and arguments
  • Records relevant logs and internal trace information for that run
  • Bundles the prompt(s), generated code, and key metadata needed to replay the issue

At the end of the run, PDD prints the path to the debug snapshot.
Attach that bundle when you open a GitHub issue or send a bug report so maintainers can quickly reproduce and diagnose your problem.

report-core Command

The report-core command helps you report a bug by creating a GitHub issue with the core dump file. It simplifies the reporting process by automatically collecting relevant files and information.

Usage:

pdd report-core [OPTIONS] [CORE_FILE]

Arguments:

  • CORE_FILE: The path to the core dump file (e.g., .pdd/core_dumps/pdd-core-....json). If omitted, the most recent core dump is used.

Options:

  • --api: Create the issue directly via the GitHub API instead of opening a browser. This enables automatic Gist creation for attached files.
  • --repo OWNER/REPO: Target GitHub repository. Required unless PDD_GITHUB_REPO is set.
  • --description, -d TEXT: A short description of what went wrong.

Authentication:

To use the --api flag, you need to be authenticated with GitHub. PDD checks for credentials in the following order:

  1. GitHub CLI: gh auth token (recommended)
  2. Environment Variables: GITHUB_TOKEN or GH_TOKEN
  3. Legacy: PDD_GITHUB_TOKEN

File Tracking & Gists:

When using --api, PDD will:

  1. Collect all relevant files (prompts, code, tests, configs, meta files).
  2. Create a private GitHub Gist containing these files.
  3. Link the Gist in the created issue.

This ensures that all necessary context is available for debugging while keeping the issue body clean. If you don't use --api, files will be truncated to fit within the URL length limits of the browser-based submission.


Context Selection Flags

  • --list-contexts reads the nearest .pddrc (searching upward from the current directory), prints the available contexts one per line, and exits immediately with status 0. No auto‑update checks or subcommands run when this flag is present.
  • --context CONTEXT_NAME is validated early against the same .pddrc source of truth. If the name is unknown, the CLI raises a UsageError and exits with code 2 before running auto‑update or subcommands.
  • Precedence for configuration is: CLI options > .pddrc context > environment variables > defaults. See Configuration for details.

Auto-Update Control

PDD automatically updates itself to ensure you have the latest features and security patches. However, you can control this behavior using the PDD_AUTO_UPDATE environment variable:

# Disable auto-updates
export PDD_AUTO_UPDATE=false

# Enable auto-updates (default behavior)
export PDD_AUTO_UPDATE=true

For persistent settings, add this environment variable to your shell's configuration file (e.g., .bashrc or .zshrc).

This is particularly useful in:

  • Production environments where version stability is crucial
  • CI/CD pipelines where consistent behavior is required
  • Version-sensitive projects that require specific PDD versions

AI Model Information

PDD uses a large language model to generate and manipulate code. The --strength and --temperature options allow you to control the model's output:

  • Strength: Determines how powerful/expensive a model should be used. Higher values (closer to 1.0) result in high performance models with better capabilities (selected by model_rank_score, where DeepSWE is primary and Arena/static ELO is fallback), while lower values (closer to 0.0) select more cost-effective models.
  • Temperature: Controls the randomness of the output. Higher values increase diversity but may lead to less coherent results, while lower values produce more focused and deterministic outputs.
  • Time: (Optional, controlled by --time FLOAT) For models supporting reasoning, this scales the allocated reasoning resources (e.g., tokens or effort level) between minimum (0.0) and maximum (1.0), with a default of 0.25.

When running in local mode, PDD uses LiteLLM to select and interact with language models based on a configuration file that includes:

  • Input and output costs per million tokens
  • Primary model_rank_score values for selection and raw Arena/static coding_arena_elo metadata
  • Required API key environment variables
  • Structured output capability flags
  • Reasoning capabilities (budget-based, effort-based, or adaptive)

Output Cost Tracking

PDD includes a feature for tracking and reporting the cost of operations. When enabled, it generates a CSV file with usage details for each command execution.

Usage

To enable cost tracking, use the --output-cost option with any command:

pdd --output-cost PATH_TO_CSV_FILE [COMMAND] [OPTIONS] [ARGS]...

The PATH_TO_CSV_FILE should be the desired location and filename for the CSV output.

Dry-Run Cost Estimates

Use the global --estimate flag, or its alias --dry-run-cost, to preview the LLM cost for pdd generate before running it.

pdd --estimate generate prompts/example_python.prompt
pdd --estimate-json generate prompts/example_python.prompt

Estimate mode assembles the generate messages that would be sent to the provider, counts input tokens, predicts output tokens with a generate-specific heuristic, and prints the selected model, input tokens, predicted output tokens, uncertainty range, known input/output rates, rough estimated cost or unknown, and context-window usage percentage. It exits before provider invocation and before command output files are written.

This first version supports generate only. Other commands, including sync, agentic sync, example, test, update, conflicts, crash, and fix, fail closed with a clear unsupported-command message rather than showing a partial first-call or lower-bound estimate.

--estimate-json prints the same estimate fields as JSON for scripts. Estimate mode does not append rows to --output-cost CSV files; use --output-cost for actual-run accounting. Cost CSV rows are written only for real command executions, because no billable LLM call occurs in estimate mode.

Cost Calculation and Presentation

PDD calculates costs based on the AI model usage for each operation. Costs are presented in USD (United States Dollars) and are calculated using the following factors:

  1. Model strength: Higher strength settings generally result in higher costs.
  2. Input size: Larger inputs (e.g., longer prompts or code files) typically incur higher costs.
  3. Operation complexity: Some operations (like fix and crash with multiple iterations) may be more costly than simpler operations.

The exact cost per operation is determined by the LiteLLM integration using the provider's current pricing model. PDD uses an internal pricing table that is regularly updated to reflect the most current rates.

CSV Output

The generated CSV file includes the following columns:

  • timestamp: The date and time of the command execution
  • model: The AI model used for the operation
  • command: The PDD command that was executed
  • cost: The estimated cost of the operation in USD (e.g., 0.05 for 5 cents). This will be zero for local models or operations that do not use a LLM.
  • input_files: A list of input files involved in the operation
  • output_files: A list of output files generated or modified by the operation
  • attempted_models: Semicolon-delimited audit log of every model PDD attempted for the command, across all LLM calls the command made (e.g. generate runs code-generation followed by postprocess code extraction — both contribute). When PDD's default model fails and the run falls back to another provider (for example Vertex AI → DeepSeek), each attempted model appears here so users can see the full fallback history rather than only the final successful model. The model column above names the model that actually produced the command's output; attempted_models is the complete record of what was tried. For commands that catch a substep failure and recover with a different model, the list may contain entries that came AFTER the model named in model — those represent attempts that were tried but didn't produce the final output. For a single-attempt successful command this column contains just the successful model. Semicolons inside model names are sanitized to preserve the delimiter. Ordering: sequential (single-thread) command paths produce a list in wall-clock attempt order; concurrent paths (e.g. auto-deps --concurrency > 1, which fans summarization across worker threads) sort their per-file contributions by file-submission index — a deterministic alternative to wall-clock ordering, which would otherwise depend on thread-scheduler timing.
  • requested_model: The model name that was explicitly requested for this command (e.g. the value of PDD_MODEL_DEFAULT or the model argument), before provider resolution or fallback.
  • resolved_model: The actual model identity as observed after resolution, where observable. For agentic CLIs that do not expose their selected model, this field is empty.
  • model_selection_outcome: How the final model was determined. One of direct (the requested model was used without fallback), fallback (a fallback model was substituted), fixed_by_config (model is fixed by user config and cannot be controlled by PDD), or unconfirmed (model identity could not be observed).
  • strength_used: The strength value (0.0–1.0) passed to the LLM invocation for this command.
  • cli_version: The installed PDD version at the time the command ran (from importlib.metadata).
  • deepswe_manifest_date: The retrieved_at date of the DeepSWE manifest used for model ranking during this command. Empty if no manifest was loaded.

This comprehensive output allows for detailed tracking of not only the cost and type of operations but also the specific files involved in each PDD command execution.

Environment Variable

You can set a default location for the cost output CSV file using the environment variable:

  • PDD_OUTPUT_COST_PATH: Default path for the cost tracking CSV file.

If this environment variable is set, the CSV file will be saved to the specified path by default, unless overridden by the --output-cost option. For example, if PDD_OUTPUT_COST_PATH=/path/to/cost/reports/, the CSV file will be saved in that directory with a default filename.

Cost Budgeting

For commands that support it (like the fix command), you can set a maximum budget using the --budget option. This helps prevent unexpected high costs, especially for operations that might involve multiple AI model calls.

Example:

pdd [GLOBAL OPTIONS] fix --budget 5.0 [OTHER OPTIONS] [ARGS]...

This sets a maximum budget of $5.00 for the fix operation.

Commands

Here are the main commands provided by PDD:

1. sync

[PRIMARY COMMAND] Automatically execute the complete PDD workflow loop. With a basename, it syncs one module. With no argument, it runs Tier 1 project-wide sync by scanning architecture.json for modules whose prompt fingerprints changed or whose code outputs are missing, then runs those modules in dependency order. With a GitHub issue URL, it runs multi-module issue sync, but the generate phase still calls LiteLLM and requires an API key; stored Claude/Gemini/Antigravity/Codex OAuth or OpenCode provider auth alone is not sufficient for this mode.

# Project-wide architecture sync (no argument)
pdd [GLOBAL OPTIONS] sync [OPTIONS]

# Single-module sync
pdd [GLOBAL OPTIONS] sync [OPTIONS] BASENAME

# Multi-module sync from a GitHub issue (requires API-key-backed LiteLLM)
pdd [GLOBAL OPTIONS] sync [OPTIONS] GITHUB_ISSUE_URL

Important: Sync frequently overwrites generated files to keep outputs up to date. In most real runs, include the global --force flag to allow overwrites without interactive confirmation:

pdd --force sync BASENAME
# Single-module sync with replayable context snapshots
pdd --force sync --snapshot-context factorial_calculator

Snapshot-enabled runs write the canonical run manifest to .pdd/evidence/runs/<run_id>.json and replayable context artifacts to the sibling directory .pdd/evidence/runs/<run_id>/. Snapshot redaction runs before hashing and storage for known token, key, authorization header, URL credential, and secret-assignment patterns; raw environment dumps and bearer/API tokens must not be persisted. Commit only policy-approved snapshot files.

Arguments:

  • No argument: Scan architecture.json and sync all modules that need deterministic Tier 1 prompt-to-code updates.
  • architecture.json as a positional value is not a global-sync alias in v1; use no-argument pdd sync for project-wide Tier 1 sync.
  • BASENAME: The base name for the prompt file (e.g., "factorial_calculator" for "factorial_calculator_python.prompt")
  • GITHUB_ISSUE_URL: A GitHub issue URL for issue-driven multi-module sync. This path is not OAuth-only friendly because its generate phase uses LiteLLM; configure an API key even if your agentic CLI has a stored OAuth login.

Options:

  • --max-attempts INT: Maximum number of fix attempts in any iterative loop (default is 3)
  • --model NAME: Override the base model for this sync run (sets PDD_MODEL_DEFAULT for the invocation, e.g. chatgpt/gpt-5.3-codex, claude-fable-5, or claude-opus-5). Opus 5 and Fable 5 are distinct Anthropic models and each identifier executes its matching model; neither selection changes PDD's ordinary default model. The override is restored after the run. It affects the local llm_invoke route; for a chatgpt/* subscription model on a cloud-enabled install, also pass --local.
  • --budget FLOAT: Maximum total cost allowed for the entire sync process (default is $20.0)
  • --skip-verify: Skip the functional verification step
  • --skip-tests: Skip unit test generation and fixing
  • --target-coverage FLOAT: Desired code coverage percentage (default is 90.0)
  • --compress: Use AST-based compression for Python few-shot examples (strips docstrings and logic-external comments). Helps fit more context into limited LLM windows without losing executable logic.
  • --fresh: Disable the default surgical/edit-shaped regeneration of a mature module. By default, when a module already has non-empty code and its prompt changed, pdd sync edits the existing code in place (feeding the current code plus the prompt delta to the generator) so declared public symbols are preserved rather than dropped by a from-scratch rewrite. With --fresh, sync uses standard generation, which regenerates the module from scratch when the prompt change is large — use it when you intend a large rewrite rather than an in-place edit. New/empty modules are always generated fresh, and the public-surface / declared-interface gate still guards either path. --fresh acts on the standard multi-step single-module sync; in one-session/agentic sync the code is regenerated by the agent session, so --fresh only affects from-scratch (re)generation there. Single-module sync only: passing --fresh to project-wide (no-argument) or GitHub-issue agentic sync raises a UsageError.
  • --dry-run: Display real-time sync analysis instead of running sync operations. For no-argument project-wide sync, this prints the dependency-ordered module list and estimated cost without executing any module syncs, plus a single compact roll-up of modules outside the Tier 1 (generate / auto-deps) scope — bucketed by reason (e.g. Out of Tier 1 scope: 42 example, 31 test, 18 verify, 12 update, 74 no-prompt fixture) instead of one warning line per skipped entry. When zero modules are stale, the 0 stale module(s) fragment is rendered in green so the success signal is visually unambiguous. Actionable architecture-graph warnings (ambiguous or unresolved cross-arch dependencies) are still printed individually in yellow. For single-module sync, it performs the same state analysis as a normal sync run but without acquiring exclusive locks or executing operations. Passing the top-level pdd --verbose flag (see above) restores the legacy per-module enumeration after the compact roll-up — one yellow warning line per module outside the Tier 1 scope — for debugging.
  • --snapshot-context: Capture the fully expanded prompt context used for generation, including nondeterministic <shell>, <web>, and <include ... query="..."> outputs. The run manifest is .pdd/evidence/runs/<run_id>.json; snapshot artifacts are in .pdd/evidence/runs/<run_id>/. Replay can later reconstruct the same prompt/context from the recorded run artifact.
  • --compressed-context / --no-compressed-context: Enable or disable compressed sync context for generation and repair phases. This option is tri-state internally: omitting it lets .pddrc defaults.compressed_context apply, --compressed-context forces it on, and --no-compressed-context forces it off. When enabled, sync builds bounded phase packages from the prompt, existing tests, examples when present, contract sections, and recent repair evidence, then passes those packages to generate, verify, test, and fix attempts. The sync result records whether compression was used and whether any agentic fallback was needed.
  • --one-session / --no-one-session: Run sync in a single agentic session instead of separate sessions for each step. Cannot be combined with --skip-tests or --skip-verify.
  • --no-steer: Disable interactive steering of sync operations.
  • --steer-timeout FLOAT: Timeout in seconds for steering prompts (default: 8.0).
  • --compress-examples: Automatically apply mode="interface" to example files in the <include> graph for this sync operation.
  • --compress-test-context: Rank and select test files under PDD_TEST_TOKEN_BUDGET (default 2 000 tokens) for this sync operation. Failing tests are packed first; remaining candidates are ranked by import distance, symbol overlap, and recency. Emits a TestPackingManifest in telemetry.
  • --context-compression {off,test,examples,contracts,all}: Set a global compression mode for this sync operation (default: off). test and examples mirror the legacy flags; contracts extracts contract rules and metadata from prompts and documentation; all enables all compression modes.
  • --compression-fallback {full,error}: Strategy for when a file cannot be compressed (default: full).
  • --durable: Issue-sync only. Run each module in an isolated git worktree under .pdd/worktrees/sync-issue-<N>-<module>/ and checkpoint successful module output to a dedicated durable branch worktree under .pdd/worktrees/durable-issue-<N>/. Default issue-sync behavior (shared parallel worktree) is unchanged unless this flag is passed.
  • --durable-branch TEXT: Durable mode only. Override the durable checkpoint branch name. Default is sync/issue-<N> derived from the GitHub issue. Refused if it resolves to main, master, or the repository default branch.
  • --no-resume: Durable mode only. Ignore existing PDD-Sync-Checkpoint-V1 commit trailers on the durable branch and re-run every selected module. By default, durable sync reads checkpoint trailers (PDD-Sync-Checkpoint-V1: issue=<N> module=<basename>) and skips modules already checkpointed for the same issue, which is what makes a cloud rerun safely resume completed work after a partial failure.
  • --durable-max-parallel INT: Durable mode only. Cap how many module worktrees run concurrently. Defaults to the standard runner concurrency. A total budget still forces sequential execution.

Estimate-mode note: global --estimate currently supports pdd generate only. pdd sync and agentic sync do not expose cost estimates in this first version because downstream prompts depend on generated artifacts that do not exist during a side-effect-free preview.

Durable Issue Sync (--durable):

Standard issue sync runs all modules in one shared worktree. If the worker exits before every module completes (timeout, crash, ephemeral cloud checkout deletion), the work that already succeeded is lost and a rerun starts over from the original branch state. Durable mode is the opt-in fix: each module runs in its own git worktree, and on success its diff is applied to a separate durable branch worktree as a checkpoint commit carrying a PDD-Sync-Checkpoint-V1: issue=<N> module=<basename> trailer. Independent modules still run in parallel (capped by --durable-max-parallel); the serialization guarantee is narrower — a module is only marked successful, and its dependents only become eligible to schedule, after its checkpoint commit has been pushed. Any rerun then reads the trailers and skips modules already checkpointed for the same issue. Failed module worktrees are left in place for inspection; successful ones are cleaned up after their checkpoint pushes. Durable sync requires a git repository with an origin remote and refuses to operate on main, master, or the repository default branch. Module-scoped .pdd/meta/<module>_*.json is included in checkpoints; secrets, lock files, cost CSVs, .pdd/worktrees/, and .pdd/agentic_sync_state.json are not.

# Cloud-friendly issue sync: resumable across reruns
pdd --force sync --durable https://github.com/myorg/myrepo/issues/1328

# Rerun every module fresh on the same durable branch (ignores existing trailers)
pdd --force sync --durable --no-resume \
  https://github.com/myorg/myrepo/issues/1328

The dedicated durable-branch worktree path is keyed on the issue number (.pdd/worktrees/durable-issue-<N>/), not the branch name. A given issue's first durable run claims that path for whichever branch it picked (default sync/issue-<N> or an explicit --durable-branch). To switch a later run for the same issue to a different durable branch, remove the existing worktree first (git worktree remove .pdd/worktrees/durable-issue-<N>) before re-invoking with the new --durable-branch. Different issue numbers do not collide.

Real-time Progress Animation: The sync command provides live visual feedback modeled on the real execution pipeline — Entry → Inspect → Plan → Execute → Output — rendered at a fixed height so the display never jumps as it advances:

  • An execute-step strip that spells out the full command names being run (auto-deps, generate, example, verify, test, fix, update), marking each step as it completes. The strip adapts to the terminal width: full names at wide widths, tighter separators as it narrows, and a rotating marquee at very narrow widths.
  • File status indicators with color coding:
    • Green: File exists and up-to-date
    • Yellow: File being processed
    • Red: File has errors or missing
    • Blue: File analysis in progress
  • Running cost totals and time elapsed
  • Progress through the pipeline stages

Color in the animation (and all other CLI output) follows the global --color / --no-color preference and NO_COLOR; see Global Options.

Language Detection: The sync command automatically detects the programming language by scanning for existing development prompt files for the requested basename. In classic layouts this is typically {basename}_{language}.prompt; in architecture-driven layouts it can also resolve nested prompt paths whose filenames mirror the target output path. For example:

  • factorial_calculator_python.prompt → generates factorial_calculator.py
  • factorial_calculator_typescript.prompt → generates factorial_calculator.ts
  • factorial_calculator_javascript.prompt → generates factorial_calculator.js
  • src/models/user_Python.prompt → generates src/models/user.py

If multiple development language prompt files exist for the same basename, sync will process all of them.

Language Filtering: The sync command only processes development languages (python, javascript, typescript, java, cpp, etc.) and excludes runtime languages (LLM). Files ending in _llm.prompt are used for internal processing only and cannot form valid development units since they lack associated code, examples, and tests required for the sync workflow.

Advanced Configuration Integration:

  • Automatic Context Detection: Detects project structure and applies appropriate settings from .pddrc
  • Configuration Hierarchy: CLI options > .pddrc context > environment variables > defaults
  • Multi-language Support: Automatically processes all language variants of a basename
  • Intelligent Path Resolution: Uses sophisticated directory management for complex project structures
  • Architecture-Aware Outputs: When architecture.json provides an explicit filepath for a prompt entry, sync honors it according to whether that filepath includes a directory component:
    • If filepath includes a directory (e.g. backend/api/widget.py), that explicit directory structure wins and is preserved as-is — .pddrc output paths are not applied to it.
    • If filepath is a bare filename at the project root (e.g. widget.py), the filename is preserved but its parent directory is taken from .pddrc generate_output_path. This makes the code path resolve consistently with example_output_path and test_output_path, which are always sourced from .pddrc defaults (Issue #1201). When no generate_output_path is configured, the bare filename resolves at the project root as before.
  • Runner-aware test paths (Issue #1903): When PDD would otherwise write a module's test to its derived default location and a single existing co-located test already exists (a jest/vitest/Next.js __test__/{name}.test.tsx-style sibling, or a Python test_{name}.py sibling), pdd test/change/sync adopt that existing test as the canonical path instead of maintaining a separate runner-blind tests/ shadow — so PDD updates and verifies the test your runner actually collects. Adoption never overrides an explicit pin (CLI --output, PDD_TEST_OUTPUT_PATH, or .pddrc test_output_path/outputs.test.path), and never fires when more than one co-located test exists. Greenfield (Issue #1903 §A): when no co-located test exists yet but the project configures a jest/vitest runner, PDD writes the FIRST test to the location the runner will actually collect instead of a runner-blind tests/ shadow. The write path honors JSON-readable config — testMatch/testRegex pick the .test/.spec + __test__/__tests__ convention, and roots/rootDir/testPathIgnorePatterns are enforced so a custom layout never yields an uncollected test. For a centralized layout (tests only under a configured roots/testMatch directory) PDD derives a collected path under that directory, mirroring the module's relative sub-path so two same-stem modules never collapse onto one file (never fork/overwrite), rather than falling back to a runner-blind shadow. Jest testMatch is evaluated with ordered include/exclude semantics (a leading-! negation removes matches). Both the jest and vitest dialects are covered. A JS-only config (jest.config.js/vitest.config.ts, unparseable in Python) is handled by whole-word text-inspection: it uses the default convention ONLY when the config is a plain literal that customizes nothing discovery-related; if it customizes discovery, or composes/delegates it in a way a static scan can't follow (require/import/spread/preset/extends/function config), or a parseable config uses projects/include/exclude we can't fully resolve, PDD conservatively refuses to write (sets the test path to None and emits a needs-review signal) rather than guess or fall back to the derived path. It also only co-locates for an extension the default discovery collects — .mjs/.cjs are version-aware (vitest and jest 30+ collect them; jest ≤29 / unknown versions do not, so they're refused) — and evaluates testMatch with jest's ordered include/exclude semantics (a negated character class [!x] means "not x"; an explicit-empty or both-testMatch-and-testRegex config matches nothing → refuse). Repo-controlled runner patterns are matched under a strict per-match timeout plus an aggregate pattern-count cap (ReDoS/DoS-safe, fail-closed). Python keeps its pytest-idiomatic tests/ default.
  • Opaque runner safety: When Jest/Vitest configuration is detected but PDD cannot prove a runner-collected output, PDD does not fall back to a derived path. It sets the test path to None, emits a needs-review signal, and performs no test write until the configuration is made resolvable.
  • Context-specific settings include output paths, default language, model parameters, coverage targets, and budgets

Workflow Logic:

The sync command automatically detects what files exist and executes the appropriate workflow:

  1. auto-deps: Find and inject relevant dependencies into the prompt — both code examples and documentation files (schema docs, API docs, etc.). Removes redundant inline content that duplicates included documents.
  2. generate: Create or update the code module from the prompt. When compressed context is enabled, this phase receives a generated phase package containing compressed prompt/test/example/contract context instead of the raw boolean option value or repeatedly expanded full context. After generation an architecture conformance gate validates the output against both architecture.json and the prompt's <pdd-interface> block:
    • Each declared symbol must exist in the generated code (architecture.json symbol-existence check).
    • Python naming convention: Python exports should be snake_case, so a camelCase export (e.g. processData) fails the gate — UNLESS its exact name is a declared interface symbol (declared in architecture.json module.functions or the prompt's own <pdd-interface>), in which case it is treated as intentional public API (e.g. Firebase Cloud Function exports like generateCode) and allowed. Honoring the prompt — the source of truth — means a name you declare there is accepted even before architecture.json is regenerated to match. Only undeclared/accidental camelCase is rejected.
    • For interface entries that declare a paren-list signature (module, cli, and command types), each declared parameter name must appear in the matching function/method signature (dotted names like ContentSelector.select are resolved through the class body; variadic *args/**kwargs do not satisfy a declared named parameter).
    • Signature drift is checked per parameter: annotation drift fires only when both sides specify and differ (conservative — gradually-typed code does not churn), while default drift fires whenever the prompt declares a default and the generated code drops or changes it (strict — a missing default is a runtime contract break for callers omitting the optional kwarg).
    • Public-surface regression gate: when a module already has a generated code file in the working tree (i.e., not a first-time generation), the gate ALSO snapshots the pre-generation public surface and rejects a generation that removes, renames, or changes the callable signature of any public symbol. For Python the snapshot covers top-level functions, classes, class.method symbols (including nested classes), module-level constants (PUBLIC_FLAG = ..., including bound AnnAssign like PUBLIC_FLAG: bool = True), and re-exported imports (import git exposes git; from .helpers import load exposes load). from __future__ import … directives and bare type-only annotations are not part of the surface. Intentional removals/signature changes must be scoped, e.g. BREAKING-CHANGE: remove calculate_sha256 or BREAKING-CHANGE: change signature calculate; listing a top-level class (BREAKING-CHANGE: remove Service) implicitly authorizes removing every Service.method / Service.Inner.method descendant captured in the snapshot. A bare BREAKING-CHANGE: does not disable the gate. Prompt-declared interface as the contract (#1900): when the prompt's <pdd-interface> declares a type: module interface, each declared top-level function is validated against its DECLARED signature — a stable contract — instead of against the previous generation, so an intended interface change is authorized simply by editing the declaration (reviewable in the prompt diff) and the standard pdd change → pdd sync flow no longer needs a BREAKING-CHANGE: prose permit for declared symbols. Undeclared symbols keep the previous-generation baseline above (and its BREAKING-CHANGE: opt-out), so protection for helpers/re-exports is unchanged. Any declared symbol with a parseable paren signature — a top-level function, a dotted method (Class.method), or a constructor (Class.__init__), including declared _-prefixed helpers — is validated against its DECLARED signature (methods/constructors are receiver-stripped to match the snapshot: a leading self/cls is dropped, and Class.__init__ compares against the class's constructor ABI), so editing the declaration authorizes an intended function/method/constructor change too. Binding-kind/async — which the declaration cannot express — stay anchored to the previous generation, so a @staticmethod→instance flip or an async↔sync change is still caught, with BREAKING-CHANGE: change signature relaxing only those un-declarable facets (never the declared parameters). A declared symbol WITHOUT a parseable paren signature (a description-only entry, or a class declared as class Service) is presence-only and falls back to the previous-generation baseline (an existing symbol's ABI drift is still caught there). On a declared-surface violation the failure lists the full declared-expected-vs-actual signature. First-time generation (no prior code file) is exempt. Set PDD_SKIP_PUBLIC_SURFACE_GATE=1 to disable only this gate, or PDD_SKIP_CONFORMANCE=1 to skip all conformance gates.
    • Test-churn gate: if pdd sync is about to overwrite an existing test file through the code-generation writer, cmd_test_main, or one-session agentic sync, and the unified-diff churn ratio between the pre-sync and proposed test file exceeds PDD_TEST_CHURN_THRESHOLD (default 0.40, i.e., 40%), the gate fails fast with TestChurnError so a small prompt change cannot land a thousand-line test rewrite that drops broad existing coverage. Pure additive test growth is allowed, first-time test generation is exempt, and intentional rewrites require an explicit marker such as BREAKING-CHANGE: rewrite tests. Set PDD_SKIP_TEST_CHURN_GATE=1 to disable only this gate. One-session auto-recovery: when the one-session sync retry loop exhausts on test churn, instead of hard-failing it accepts the rewrite IFF it is coverage-preserving — every pre-existing test file keeps at least as many test cases AND assertions (with at least one real assertion), deletes nothing, and is in a measurable language (Python via AST, TS/JS via a comment/string/regex-aware scanner); otherwise the strict gate still hard-fails. This lets a legitimate large rewrite driven by a real prompt change complete instead of forcing manual intervention, while still blocking silent coverage loss. An accepted rewrite prints a PDD_TEST_CHURN_ACCEPTED marker; set PDD_DISABLE_TEST_CHURN_AUTOACCEPT=1 to force the strict gate. Issue-driven never-block (issue #1903 §B.4): when the coverage-preserving auto-accept refuses (a genuinely coverage-losing rewrite) inside the agentic issue-driven sync (a GitHub issue URL, which opens a PR) AND the churned test is an adopted co-located human test (a jest/vitest .test./.spec. file, a file under __test__/__tests__, or a Python sibling test_<stem>.py / <stem>_test.py outside the top-level tests/ shadow — classified by _is_adopted_collocated_test_path), the workflow does NOT hand work back to the user by failing the command. The human-authored test is kept unchanged, a PDD_TEST_CHURN_NEEDS_REVIEW marker is emitted, the module is reported as synced, and the PR is opened with that test flagged needs review in the progress comment / PR body (ModuleState.needs_review, persisted across durable resumes). THREE independent guards keep this from ever masking coverage loss, and ALL must hold: (1) the runner is issue-driven — self.issue_url is set only for a GitHub issue → PR sync; a project-wide pdd sync builds the runner with issue_url=None, opens no PR, and keeps the strict hard-fail (there is no PR to flag against); (2) structured adoption provenance — the child sync stamps adopted: true on the churn block only when the test was adopted from an existing human co-located test, unpinned, decided at path resolution before generation (a pinned path, a greenfield test PDD created, or an older child with no marker reads false); and (3) the churned path is an in-repo co-located shape — not a PDD-owned tests/ shadow, traversal, or out-of-root path. Standalone pdd test / pdd sync <module> never run through the issue-driven runner at all, so they always keep the strict hard-fail above.
    • Prose/empty-output classification gate: when the extractor returns empty or whitespace-only content for a code generation request — for example, because the provider returned a planning sentence or reasoning trace instead of a code block — pdd sync raises ProseOutputError before reaching the architecture conformance gate. This prevents an empty extraction from being misdiagnosed as a missing-symbol architecture failure. The repair directive on retry instructs the model to "return the complete source file only, inside a single code block; do not include planning text, prose explanation, or partial snippets outside the code block." Prose retries are limited to 1 additional attempt; a repeated prose response triggers a structured === generation output extraction failure === hard-failure block naming the provider/model, prompt, output path, extractor result, raw-output excerpt, and directing the user to check provider configuration. The target file is never overwritten. Set PDD_ALLOW_EMPTY_GENERATION=1 to bypass. Providers that tend to return planning-style responses (e.g., local lm_studio/*, ollama/*, or ChatGPT/Codex interactive providers flagged interactive_only in llm_model.csv) are most likely to trigger this path.
    • Empty-generation guard: when the LLM provider returns an empty (or whitespace-only) body and the output path already has non-empty existing content, the writer refuses to truncate the file. Python public modules / test files trip PublicSurfaceRegressionError / TestChurnError through the normal gates; non-Python artifacts (JSON, YAML, prompts, etc.) raise a click.UsageError("Refusing to overwrite ...") instead. Set PDD_ALLOW_EMPTY_GENERATION=1 for the rare case where empty output is intentional.
    • On failure, sync retries the generation step up to MAX_CONFORMANCE_ATTEMPTS with a PDD_REPAIR_DIRECTIVE that names the function to fix and the parameters/annotations/defaults to add or restore. Prose/empty-output failures (ProseOutputError) use a separate output-shape retry limited to 1 additional attempt. Public-surface and test-churn failures use the same repair loop only on the generate and one-session paths; surface regressions detected after a crash/fix/verify write are hard failures (no retry) because each of those operations already runs its own internal fix loop and a second outer retry would compound retries (N × M) without converging. .pddrc context/strength are pinned across the entire retry sequence so a retry never silently switches model or context. The retry stops early when the missing-symbol/signature set repeats across attempts, and the final failure is surfaced as a structured === generation output extraction failure ===, === architecture conformance failure ===, === public surface regression ===, or === test churn threshold exceeded === block listing the offending symbols / churn ratio / provider context plus a Reproduce locally: pdd sync <basename> line.
  3. example: Generate usage example if it doesn't exist or is outdated
  4. crash: Fix any runtime errors to make code executable
  5. verify: Run functional verification against prompt intent (unless --skip-verify). When compressed context is enabled, verification receives its own phase-aware compressed context package built from the same bounded prompt/test/example/contract evidence.
  6. test: Generate comprehensive unit tests if they don't exist (unless --skip-tests). Auth modules get auth-specific test patterns (mock OAuth servers, JWT fixtures, token lifecycle testing)
  7. fix: Resolve any bugs found by unit tests (unless --skip-tests). Because --skip-tests skips both unit test generation (step 6) and fixing, the fix step is skipped along with the test step. When the requested operation is an isolated code repair or generation replay, sync consumes existing examples if present but must not detour into unrelated example generation just to construct repair context.
  8. update: Back-propagate any learnings to the prompt file

One-Session Mode (--one-session):

By default, sync runs each step (example, crash-fix, verify, test, fix) as a separate LLM session. One-session mode runs all these steps in a single agentic session. This results in faster and cheaper sync runs.

One-session mode is enabled by default for agentic sync (GitHub issue URLs) and disabled by default for single-module sync. Use --one-session or --no-one-session to override.

# Project-wide sync dry run
pdd sync --dry-run

# Single-module sync with one-session mode
pdd sync --one-session factorial_calculator

# Agentic sync (one-session is the default)
pdd sync https://github.com/myorg/myrepo/issues/100
pdd sync calculator --model chatgpt/gpt-5.3-codex  # force a model on the local route; for chatgpt/* on a cloud-enabled install add --local
pdd sync calculator --local --model chatgpt/gpt-5.3-codex  # local route: required for a chatgpt/* subscription model when PDD Cloud is configured

# Disable one-session for agentic sync
pdd sync --no-one-session https://github.com/myorg/myrepo/issues/100

Advanced Decision Making:

  • Fingerprint-based Change Detection: Uses content hashes and timestamps to precisely detect what changed
  • LLM-powered Conflict Resolution: For complex scenarios with multiple file changes, uses AI to determine the best approach
  • Persistent State Tracking: Maintains sync history and learns from previous operations
  • Smart Lock Management: Prevents concurrent sync operations with automatic stale lock cleanup
  • Detects which files already exist and are up-to-date
  • Skips unnecessary steps (e.g., won't regenerate code if prompt hasn't changed)
  • Uses git integration to detect changes; regenerates mature modules surgically (edit-shaped) by default so declared symbols are preserved, falling back to full regeneration for new modules or when --fresh is passed
  • Accumulates tests over time rather than replacing them (in a single test file per target)
  • Automatically handles dependencies between steps
  • Compressed Context Telemetry: Sync results and logs record whether compressed context was requested, the effective value after CLI and .pddrc resolution, whether it was actually applied for each phase, the source inputs used to build it, and whether the run fell back to agentic repair. This makes replay and benchmark comparisons distinguish normal sync from compressed-context sync.

Robust State Management:

  • Fingerprint Files: Maintains .pdd/meta/{basename}_{language}.json with operation history. All fingerprint writes across every mutating command (sync, generate, example, update, fix, auto-deps, ci-heal) route through a single FingerprintTransaction context manager; writes are atomic (temp-file + os.replace) and enforced — a finalization failure is a command failure, not a silent warning.
  • Run Reports: Tracks test results, coverage, and execution status
  • Lock Management: Prevents race conditions with file-descriptor based locking
  • Git Integration: Leverages version control for change detection and rollback safety

The .pdd Directory: PDD uses a .pdd directory in your project root to store various metadata and configuration files:

  • .pdd/meta/ - Contains fingerprint files, run reports, and sync logs
  • .pdd/locks/ - Stores lock files to prevent concurrent operations
  • .pdd/llm_model.csv - Project-specific LLM model configuration (optional)
  • .pdd/worktrees/ - Transient git worktrees used by pdd sync --durable (per-module execution sandboxes and the dedicated durable-branch worktree). Local scratch state, not project state.

This directory should typically be added to version control (except for .pdd/locks/ and .pdd/worktrees/), as it contains important project state information.

Environment Variables: All existing PDD output path environment variables are respected, allowing the sync command to save files in the appropriate locations for your project structure.

Sync State Analysis: The sync command maintains detailed decision-making logs which you can view using the --dry-run option:

# View current sync state analysis (non-blocking)
pdd sync --dry-run calculator

# View detailed LLM reasoning for complex scenarios
pdd --verbose sync --dry-run calculator

Analysis Contents Include:

  • Current file state and fingerprint comparisons
  • Real-time decision reasoning (heuristic-based vs LLM-powered analysis)
  • Operation recommendations with confidence levels
  • Estimated costs for recommended operations
  • Lock status and potential conflicts
  • State management details

The --dry-run option performs live analysis of the current project state, making it safe to run even when another sync operation is in progress. This differs from viewing historical logs - it shows what sync would decide to do right now based on current file states.

Use --verbose with --dry-run to see detailed LLM reasoning for complex multi-file change scenarios and advanced state analysis.

When to use: This is the recommended starting point for most PDD workflows. Use sync when you want to ensure all artifacts (code, examples, tests) are up-to-date and synchronized with your prompt files. The command embodies the PDD philosophy by treating the workflow as a batch process that developers can launch and return to later, freeing them from constant supervision.

Examples:

# Complete workflow with progress animation and intelligent decision-making
pdd --force sync factorial_calculator

# Advanced sync with higher budget, custom coverage, and full visual feedback
pdd --force sync --budget 15.0 --target-coverage 95.0 data_processor

# Quick sync with animation showing real-time status updates
pdd --force sync --skip-verify --budget 5.0 web_scraper

# Multi-language sync with fingerprint-based change detection
pdd --force sync multi_language_module

# View comprehensive sync analysis with decision analysis
pdd sync --dry-run factorial_calculator

# View detailed sync analysis with LLM reasoning for complex conflict resolution
pdd --verbose sync --dry-run factorial_calculator

# Monitor what sync would do without executing (with state analysis)
pdd sync --dry-run calculator

# Context-aware examples with automatic configuration detection
cd backend && pdd --force sync calculator     # Uses backend context settings with animation
cd frontend && pdd --force sync dashboard     # Uses frontend context with real-time feedback
pdd --context backend --force sync calculator # Explicit context override with visual progress

Agentic Multi-Module Sync (GitHub Issue Mode):

When a GitHub issue URL is passed instead of a basename, sync enters agentic mode:

  1. Module Identification: Fetches the issue content and identifies which modules need syncing using a four-strategy hierarchy: (a) branch-diff detection (deterministic, free), (b) runtime-template-only short-circuit (no-op when all diff files are *_LLM.prompt templates), (c) PDD_CHANGED_MODULES env-var bypass (deterministic, free — skips LLM when branch-diff returned empty), (d) LLM fallback
  2. Dependency Validation: Validates architecture.json dependencies and applies corrections if needed
  3. Parallel Execution: Dispatches parallel sync via AsyncSyncRunner with dependency-aware scheduling (up to 4 concurrent workers by default; set PDD_SYNC_MAX_WORKERS to cap concurrency lower — e.g. 1 on memory-constrained runners)
  4. Live Progress: Posts and updates a GitHub comment with real-time module sync status
# Sync modules identified from a GitHub issue (parallel, dependency-aware)
pdd sync https://github.com/myorg/myrepo/issues/100

# Extend the per-module timeout for a very large module
pdd sync --timeout-adder 600 https://github.com/myorg/myrepo/issues/100

Options (agentic mode):

  • --timeout-adder FLOAT: Add seconds to the per-module timeout (default: 0.0).
  • --no-github-state: Disable GitHub state persistence, use local-only

Cross-Machine Resume: Workflow state is stored in a hidden GitHub comment, enabling resume from any machine. Use --no-github-state to disable.

1a. sync-architecture

Sync architecture.json from prompt metadata tags (<pdd-reason>, <pdd-interface>, and <pdd-dependency>). This is useful after editing prompt metadata directly, or after backfilling prompt tags, so the architecture graph and command metadata stay aligned with the prompts.

# Preview architecture updates for all prompts
pdd sync-architecture --dry-run

# Update architecture.json from all prompt metadata tags
pdd sync-architecture

# Update architecture.json from specific prompt entries
pdd sync-architecture commands/maintenance_python.prompt

Arguments:

  • No argument: Scan all prompt files known to the current project.
  • FILENAMES: Optional prompt filenames as they appear in architecture.json or under the configured prompts directory.

Options:

  • --dry-run: Report which architecture entries would change without writing architecture.json.

The command prints updated prompt entries and validation errors or warnings. It exits non-zero when validation fails, even if it was able to write requested metadata updates before validation.

Note: Validation is repo-wide and runs even when you target a single prompt. If your architecture.json already has unrelated missing-dependency errors elsewhere, the exit code stays non-zero on --dry-run even for an otherwise-clean target prompt. Fix the repo-wide errors (or scope your check) before relying on the exit code in scripts.

2. generate

Create runnable code from a prompt file. This command produces the full implementation code that fulfills all requirements in the prompt. When changes are detected between the current prompt and its last committed version, it can automatically perform incremental updates rather than full regeneration.

# Basic usage
pdd [GLOBAL OPTIONS] generate [OPTIONS] PROMPT_FILE

Arguments:

  • PROMPT_FILE: The filename of the prompt file used to generate the code.

Options:

  • --output LOCATION: Specify where to save the generated code. Supports ${VAR}/$VAR expansion from -e/--env. The default file name is <basename>.<language_file_extension>. If an environment variable PDD_GENERATE_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --original-prompt FILENAME: The original prompt file used to generate the existing code. If not specified, the command automatically uses the last committed version of the prompt file from git.
  • --incremental: For prompt-to-code generation, force incremental patching when an output location is specified and the file exists. To run the experimental PRD-to-architecture workflow, combine it with --experimental-prd.
  • --experimental-prd: Explicitly opt in to experimental Incremental PRD Mode for PRD-like files (.md, .markdown, .txt, .rst, .adoc) or GitHub issue URLs. Requires --incremental.
  • --unit-test FILENAME: Path to a unit test file. If provided, automatic test discovery is disabled and only the content of this file is included in the prompt, instructing the model to generate code that passes the specified tests.
  • --exclude-tests: Do not automatically include test files found in the default tests directory.
  • Context compression: use global --context-compression / --compression-fallback before generate (see Global Options); generate does not accept these flags after the subcommand.
  • --snapshot-context: Capture the expanded prompt and dynamic context outputs used for this generation. The run manifest is .pdd/evidence/runs/<run_id>.json; snapshot artifacts are in .pdd/evidence/runs/<run_id>/. This is recommended when a prompt uses <shell>, <web>, or <include ... query="..."> for contract-relevant context.

Parameter Variables (-e/--env): Pass key=value pairs to parameterize a prompt so one prompt can generate multiple variants (e.g., multiple files) by invoking generate repeatedly with different values.

  • Syntax: -e KEY=VALUE or --env KEY=VALUE (repeatable).
  • Docker-style env fallback: -e KEY reads VALUE from the current process environment variable KEY.
  • Scope: Applies to generate.
  • Precedence: Values passed with -e/--env override same‑named OS environment variables during template expansion for this command.

Templating: Prompt files and --output values may reference variables using $VAR or ${VAR}. Only variables explicitly provided via -e/--env (or via env fallback with -e KEY) are substituted; all other dollar-prefixed text is left unchanged. No escaping is required for ordinary $ usage.

  • In prompt content: $VAR and ${VAR} are replaced only when VAR was provided.
  • In output path: When using --output, PDD also expands $VAR/${VAR} using the same variable set.
  • Unknowns: Placeholders without a provided value are left unchanged. If you pass -e KEY (no value) and KEY exists in the OS environment, that environment value is used.

Examples:

# Basic parameterized generation (Python module)
pdd generate -e MODULE=orders --output 'src/${MODULE}.py' prompts/module_python.prompt

# Generate multiple files from the same prompt
pdd generate -e MODULE=orders   --output 'src/${MODULE}.py' prompts/module_python.prompt
pdd generate -e MODULE=payments --output 'src/${MODULE}.py' prompts/module_python.prompt
pdd generate -e MODULE=customers --output 'src/${MODULE}.py' prompts/module_python.prompt

# Multiple variables
pdd generate -e MODULE=orders -e PACKAGE=core --output 'src/${PACKAGE}/${MODULE}.py' prompts/module_python.prompt

# Docker-style env fallback (reads MODULE from your shell env)
export MODULE=orders
pdd generate -e MODULE --output 'src/${MODULE}.py' prompts/module_python.prompt
pdd generate prompts/refund_python.prompt --output src/refund.py --snapshot-context

Shell quoting options:

  • Quote KEY=VALUE if the value contains spaces or shell-special characters: -e "DISPLAY_NAME=Order Processor".
  • PDD-side expansion (portable): prevent shell expansion and let PDD expand using -e/--env — e.g., --output 'src/${MODULE}.py'.
  • Shell-side expansion (familiar): set an env var and let the shell expand --output, while still passing -e KEY so prompts get the same value — e.g.,
    • export MODULE=orders && pdd generate -e MODULE --output "src/$MODULE.py" prompts/module_python.prompt
    • Or inline for POSIX shells: MODULE=orders pdd generate -e MODULE --output "src/$MODULE.py" prompts/module_python.prompt
    • Note: PowerShell/Windows shells differ; PDD-side expansion is more portable across shells.

Git Integration:

  • When the command detects changes between the current prompt and its last committed version, it automatically considers incremental generation if the output file exists.
  • If incremental generation is performed, both the current prompt and code files are staged with git add (if not already committed/added) to ensure you can roll back if needed.
  • Full regeneration always happens for new files (when there's no existing output file to update) or when the existing output file is deleted.

When to use: Choose this command when implementing new functionality from scratch or updating existing code based on prompt changes. The command will automatically detect changes and determine whether to use incremental patching or full regeneration based on the significance of the changes.

Examples:

# Basic generation with automatic git-based change detection
# (incremental if output file exists, full generation if it doesn't)
pdd [GLOBAL OPTIONS] generate --output src/calculator.py calculator_python.prompt 

# Force incremental patching (requires output file to exist)
pdd [GLOBAL OPTIONS] generate --incremental --output src/calculator.py calculator_python.prompt

# Force full regeneration (just delete the output file first)
rm src/calculator.py  # Delete the file
pdd [GLOBAL OPTIONS] generate --output src/calculator.py calculator_python.prompt

# Specify a different original prompt (bypassing git detection)
pdd [GLOBAL OPTIONS] generate --output src/calculator.py  --original-prompt old_calculator_python.prompt calculator_python.prompt

Agentic Architecture Mode:

When the positional argument is a GitHub issue URL instead of a prompt file, generate enters agentic architecture mode. The issue body serves as the PRD (Product Requirements Document), and an 11-step agentic workflow generates architecture.json, .pddrc, and prompt files automatically.

pdd generate https://github.com/owner/repo/issues/42

The 11-step workflow:

Analysis & Generation (Steps 1-8):

  1. Analyze PRD: Extract features, tech stack, and requirements from the issue content
  2. Deep Analysis: Feature decomposition, module boundaries, shared concerns
  3. Research: Web search for tech stack documentation and best practices
  4. Design: Module breakdown with dependency graph and priority ordering (auth modules are separated into dedicated concerns with low priority numbers)
  5. Research Dependencies: Find relevant API docs and code examples per module
  6. Generate: Produce complete architecture.json and scaffolding files
  7. Generate .pddrc: Create project configuration with context-specific paths
  8. Generate Prompts: Create prompt files for each module in architecture.json

Validation (Steps 9-11): 9. Completeness Validation: Verify all modules have prompts and dependencies 10. Sync Validation: Run pdd sync --dry-run on each module to catch prompt-discovery and output path issues, including architecture-driven nested paths 11. Dependency Validation: Preprocess prompts to verify <include> tags resolve under the same rules used at runtime, and reject fabricated example-file include paths

Each validation step retries up to 3 times with automatic fixes before proceeding.

Options:

  • --skip-prompts: Skip prompt file generation (steps 8-11), only generate architecture.json and .pddrc
  • --project-root <path>: Explicit project-root override. Use the given path as the resolved project root instead of walking up from cwd. Useful when the cwd is a self-contained pdd project nested inside an unrelated outer git repo.

Project Root Detection:

pdd generate <issue-url> (and pdd generate --incremental --experimental-prd) resolves the project root by walking up from cwd. Tier A, Tier B, and Tier C are all project boundaries — the nearest boundary found while walking upward wins. This lets a nested PDD marker beat an enclosing outer .git, but prevents an enclosing outer PDD marker from overriding a nearer inner git repository:

  1. Tier A (PDD-explicit): a directory containing .pddrc or a .pdd/ directory.
  2. Tier B (PDD-conventional): a directory containing sources/ plus PRD/spec markdown (prd*.md, spec*.md, or *_prd.md/*_spec.md).
  3. Tier C (git): a directory containing .git.

Path.home() (the user's $HOME) is skipped for the PDD-marker check — ~/.pdd and ~/.pddrc are user-global config (created by pdd setup), not project markers. So a normal repo under $HOME without its own marker still falls through to its enclosing .git rather than resolving to $HOME.

A self-contained pdd project nested inside an unrelated outer git repo is correctly identified as its own project root. A separate git repository nested inside an outer PDD project is also correctly identified as its own root. When the resolved project root is a strict descendant of the enclosing git toplevel, the remote-vs-issue mismatch warning is suppressed (it would be a false positive). Pass --project-root <path> to bypass marker-based discovery entirely; this is most useful for CI scripts and unusual layouts where automatic detection cannot infer the right root, since marker-based detection already handles the nested-project case.

Prerequisites:

  • gh CLI must be installed and authenticated
  • The issue must contain a PRD describing the project scope

Workflow Resumption: Re-running pdd generate <issue-url> resumes from the last completed step. State is persisted to GitHub issue comments for cross-machine resume.

Hard Stops: The workflow stops if the PRD content is insufficient, the tech stack is ambiguous, or clarification is needed. Address the issue and re-run.

Example:

pdd generate https://github.com/myorg/myrepo/issues/42
# Generates: architecture.json, architecture_diagram.html, .pddrc, prompts/*.prompt

# Skip prompt generation (faster, just architecture)
pdd generate --skip-prompts https://github.com/myorg/myrepo/issues/42
# Generates: architecture.json, architecture_diagram.html, .pddrc

Experimental Incremental PRD Mode (--incremental --experimental-prd with a PRD file or issue URL):

After the initial architecture has been generated, pdd generate --incremental --experimental-prd <prd_file_or_issue_url> produces a targeted, validated patch instead of regenerating from scratch. The flow diffs the PRD against a hash/provenance record in .pdd/meta/prd_hashes.json plus an ignored local raw-baseline cache in .pdd/cache/prd_snapshots/, asks the LLM for a structured ArchitecturePatch (add/remove/modify modules + dependency updates), validates it deterministically (rejecting unknown modules, dangling dependencies, removals that leave dependents, unsupported fields, path traversal, and dependency cycles), and on success applies it atomically with .bak backups, propagates Requirements changes into affected prompts via detect_change + change, and generates new prompt files for added modules. Tracked metadata never stores raw PRD text, GitHub issue bodies, or issue comments; the command also writes .pdd/cache/.gitignore so raw baselines stay local even in projects without a root ignore rule.

# Diff PRD vs last fingerprint, patch architecture.json + prompts
pdd generate --incremental --experimental-prd docs/prd.md

# Same, sourced from a GitHub issue
pdd generate --incremental --experimental-prd https://github.com/owner/repo/issues/42

# Preview without writing — dry-run is safe (no files modified)
pdd generate --incremental --experimental-prd --dry-run docs/prd.md

# Suppress GitHub issue status comments during agentic runs
pdd generate --incremental --experimental-prd --no-github-state docs/prd.md

# Patch a subproject architecture/prompts directory
pdd generate --incremental --experimental-prd --output-dir service docs/prd.md

This mode is never selected by suffix alone: --experimental-prd is required. --incremental with a .prompt file remains the legacy code-patching mode (see "Force incremental patching" example above), and .md/.markdown/.txt/.rst/.adoc inputs also stay in legacy code generation when options such as --output, --original-prompt, --template, or --unit-test are present. Re-running with no PRD changes is a free no-op ("No PRD changes detected"). On invalid LLM patches the orchestrator retries up to 3 times with concrete validation feedback before failing without writes.

Current limitations (this experimental mode is intentionally narrower than pdd generate <issue-url>):

  • Starter prompts for new modules. When the LLM patch adds a new module, this command generates a lightweight starter prompt (PDD metadata tags, architecture-target-relative <include> per dependency, Role / Requirements / Interface Specification / Dependencies skeleton) — not the richer artifacts produced by the full agentic Step 9 prompt-generation flow. If you used --output-dir service or an issue-derived target directory, run follow-up sync from that target directory (cd service && pdd sync) because generated includes resolve there. Run pdd sync from the repo root only for root-level architectures.
  • Hidden/config file targets are blocked. Incremental mode refuses LLM-proposed filepath values with hidden path components or secret-like names such as .env, .github/..., private keys, credentials, and secrets files. Use full agentic generation or a manual architecture edit for legitimate hidden/config-file modules.
  • No shared-context-doc merge. Step 8.5's merge across data_dictionary.yaml / api_contracts.yaml / integration_points.yaml is not invoked. Update those files manually if the PRD change affects them.
  • No pdd sync --dry-run validation. New or modified modules are not validated against the wider sync pipeline before this command writes; run pdd sync after the experimental PRD update to catch any downstream issues.

These are tracked as follow-ups under #859. The architecture-side propagation (patch validation, transactional commit with rollback, concurrent-modification guard, <pdd-*> tag preservation, Requirements updates via detect_change + change) is fully implemented and live-verified.

Prompt Templates

Templates are reusable prompt files that generate a specific artifact (code, JSON, tests, etc.). Templates carry human/CLI metadata in YAML front matter (parsed by the CLI and not sent to the LLM), while the body stays concise and model‑focused.

  • Front matter (human/CLI):
    • name, description, version, tags, language, output
    • variables: schema for -e/--env (required/optional, type, examples)
    • usage: copyable pdd generate commands
    • discover (optional): CLI‑executed file discovery (root, patterns, exclude, caps)
    • output_schema (optional): JSON shape used by the CLI for validation and by pdd templates show
  • Prompt body (LLM):
    • Includes to hydrate context: <include>${VAR}</include>, <include-many>${LIST}</include-many>
    • Crisp instructions and an explicit output contract; no human usage notes or discovery logic

Quick examples (templates)

# Minimal (PRD required)
pdd generate -e PRD_FILE=docs/specs.md --output architecture.json \
  pdd/templates/architecture/architecture_json.prompt

# With extra context
pdd generate -e PRD_FILE=docs/specs.md -e TECH_STACK_FILE=docs/tech_stack.md \
  -e DOC_FILES='docs/ux.md,docs/components.md' \
  -e INCLUDE_FILES='src/app.py,src/api.py,frontend/app/layout.tsx' \
  --output architecture.json pdd/templates/architecture/architecture_json.prompt

# Multiple variants
pdd generate -e PRD_FILE=docs/specs.md -e APP_NAME=Shop   --output apps/shop/architecture.json   pdd/templates/architecture/architecture_json.prompt
pdd generate -e PRD_FILE=docs/specs.md -e APP_NAME=Admin  --output apps/admin/architecture.json  pdd/templates/architecture/architecture_json.prompt
pdd generate -e PRD_FILE=docs/specs.md -e APP_NAME=Public --output apps/public/architecture.json pdd/templates/architecture/architecture_json.prompt

# 4) Use variables in the output path
# 5) Use shell env fallback for convenience
export APP=shop
pdd generate -e APP -e PRD_FILE=docs/specs.md --output 'apps/${APP}/architecture.json' pdd/templates/architecture/architecture_json.prompt

Tips for authoring templates

  • Put human guidance in YAML front matter (variables with examples, usage, notes); keep the prompt body model‑focused.
  • Use <include>/<include-many> for curated context; prefer specs/configs over large code dumps.
  • Parameterized includes: pass file paths via -e, e.g. <include>${PRD_FILE}</include>; the engine resolves includes after variable expansion.
  • If your template outputs a specific filename, show example commands with --output.

Behavior notes

  • Variable expansion only applies to variables explicitly passed via -e/--env (or via the env fallback with -e KEY). Other $NAME occurrences remain unchanged.
  • --output also accepts $VAR/${VAR} from the same set of variables.
  • If you omit --output, PDD derives the filename from the prompt basename and detected language extension; set PDD_GENERATE_OUTPUT_PATH to direct outputs to a common directory.

Templates: Commands

  • Front matter is parsed (not sent to the LLM) and powers:
    • Variables schema and validation
    • Usage examples (rendered by pdd templates show)
    • Optional discover settings (executed by the CLI with caps)
    • Optional output_schema for validation
  • Commands:
    • pdd templates list [--json] [--filter tag=...]
    • pdd templates show <name>
    • pdd templates copy <name> --to prompts/
    • pdd generate --template <name> [-e KEY=VALUE...] [--output PATH]

Built-In Templates

PDD can distribute a curated set of popular templates as part of the package to help you get started quickly (e.g., frontend/Next.js, backend/Flask, data/ETL).

Where built-ins live (packaged)

  • Under the installed package at pdd/templates/<category>/**/*.prompt (plus optional README/index files). When installed from PyPI, these are included as package data.

Included starter templates

  • architecture/architecture_json.prompt: Universal architecture generator (requires -e PRD_FILE=...; supports optional TECH_STACK_FILE, DOC_FILES, INCLUDE_FILES).

LLM Toggle Functionality:

All templates support the llm parameter to control whether LLM generation runs:

  • llm=true (default): Full generation with LLM + post-processing
  • llm=false: Skip LLM generation, run only post-processing

Architecture JSON Template Features:

The architecture/architecture_json template includes automatic Mermaid diagram generation:

  • Post-processing: Automatically converts the generated JSON into an interactive HTML Mermaid diagram
  • Visualization: Creates architecture_diagram.html with color-coded modules (frontend/backend/shared)
  • Interactive: Hover tooltips show module details, dependencies, and descriptions
  • Self-contained: HTML file works offline with embedded Mermaid library

Example Commands:

# Full generation (LLM + post-processing + Mermaid HTML)
pdd generate --template architecture/architecture_json \
  -e PRD_FILE=docs/specs.md \
  -e APP_NAME="MyApp" \
  --output architecture.json
# Results in: architecture.json + architecture_diagram.html

# Post-processing only (skip LLM, generate HTML from existing JSON)
pdd generate --template architecture/architecture_json \
  -e APP_NAME="MyApp" \
  -e llm=false \
  --output architecture.json
# Results in: architecture_diagram.html (from existing architecture.json)

Context URLs (optional field):

Architecture entries support an optional context_urls array that associates web documentation references with each module. When prompts are generated from the architecture (via generate_prompt), these URLs are emitted as <web> tags in the Dependencies section, enabling the LLM to fetch relevant API documentation during code generation.

{
  "filename": "orders_api_Python.prompt",
  "dependencies": ["models_Python.prompt"],
  "context_urls": [
    {"url": "https://fastapi.tiangolo.com/tutorial/first-steps/", "purpose": "FastAPI routing patterns"},
    {"url": "https://docs.pydantic.dev/latest/concepts/models/", "purpose": "Pydantic model validation"}
  ],
  ...
}

The context_urls field is populated automatically by the agentic architecture workflow (step 5: research dependencies) but can also be added manually to any architecture entry.

Front Matter (YAML) metadata

  • Templates include YAML front matter with human-readable metadata:
    • name, description, version, tags: docs and discovery
    • language, output: defaults for generate
    • variables: parameter schema for -e/--env (type, required, default)

Example (architecture template):

---
name: architecture/architecture_json
description: Unified architecture template for multiple stacks
version: 1.0.0
tags: [architecture, template, json]
language: json
output: architecture.json
variables:
  TECH_STACK:
    required: false
    type: string
    description: Target tech stack for interface shaping and conventions.
    examples: [nextjs, python, fastapi, flask, django, node, go]
  API_STYLE:
    required: false
    type: string
    description: API style for backends.
    examples: [rest, graphql]
  APP_NAME:
    required: false
    type: string
    description: Optional app name for context.
    example: Shop
  PRD_FILE:
    required: true
    type: path
    description: Primary product requirements document (PRD) describing scope and goals.
    example_paths: [PRD.md, docs/specs.md, docs/product/prd.md]
    example_content: |
      Title: Order Management MVP
      Goals: Enable customers to create and track orders end-to-end.
      Key Features:
        - Create Order: id, user_id, items[], total, status
        - View Order: details page with status timeline
        - List Orders: filter by status, date, user
      Non-Functional Requirements:
        - P95 latency < 300ms for read endpoints
        - Error rate < 0.1%
  TECH_STACK_FILE:
    required: false
    type: path
    description: Tech stack overview (languages, frameworks, infrastructure, and tools).
    example_paths: [docs/tech_stack.md, docs/architecture/stack.md]
    example_content: |
      Backend: Python (FastAPI), Postgres (SQLAlchemy), PyTest
      Frontend: Next.js (TypeScript), shadcn/ui, Tailwind CSS
      API: REST
      Auth: Firebase Auth (GitHub Device Flow), JWT for API
      Infra: Vercel (frontend), Cloud Run (backend), Cloud SQL (Postgres)
      Observability: OpenTelemetry traces, Cloud Logging
  DOC_FILES:
    required: false
    type: list
    description: Additional documentation files (comma/newline-separated).
    example_paths: [docs/ux.md, docs/components.md]
    example_content: |
      Design overview, patterns and constraints
  INCLUDE_FILES:
    required: false
    type: list
    description: Specific source files to include (comma/newline-separated).
    example_paths: [src/app.py, src/api.py, frontend/app/layout.tsx, frontend/app/page.tsx]
  usage:
    generate:
      - name: Minimal (PRD only)
        command: pdd generate -e PRD_FILE=docs/specs.md --output architecture.json pdd/templates/architecture/architecture_json.prompt
      - name: With tech stack overview
        command: pdd generate -e PRD_FILE=docs/specs.md -e TECH_STACK_FILE=docs/tech_stack.md --output architecture.json pdd/templates/architecture/architecture_json.prompt
  discover:
    enabled: false
    max_per_pattern: 5
    max_total: 10
---

Notes

  • YAML front matter is parsed and not sent to the LLM. Use pdd templates show to view variables, usage, discover, and output schema. Pass variables via -e at the CLI.

Template Variables (reference)

  • Architecture (architecture/architecture_json.prompt)
    • PRD_FILE (path, required): Primary spec/PRD file path
    • TECH_STACK_FILE (path, optional): Tech stack overview file (includes API style; e.g., docs/tech_stack.md)
    • APP_NAME (string, optional): App name for context
    • DOC_FILES (list, optional): Comma/newline-separated list of additional doc paths
    • INCLUDE_FILES (list, optional): Comma/newline-separated list of source files to include
    • SCAN_PATTERNS (list, optional): Discovery patterns defined in front matter discover and executed by the CLI
    • SCAN_ROOT (path, optional): Discovery root defined in front matter discover

Notes

  • These variables are declared in YAML front matter at the top of each template for clarity and future CLI discovery. Until the CLI parses front matter, pass values via -e as shown in examples.

Copy-and-generate

  • Copy the desired template(s) into your project’s prompts/ folder, then use pdd generate as usual. This keeps prompts versioned with your repo so you can edit and evolve them.
  • Quick copy (Python one‑liner; run from your project root):
python - <<'PY'
from importlib.resources import files
import shutil, os

dst_dir = 'prompts/architecture'
src_dir = files('pdd').joinpath('templates/architecture')
os.makedirs(dst_dir, exist_ok=True)

for p in src_dir.rglob('*.prompt'):
    shutil.copy(p, dst_dir)
print(f'Copied built-in templates from {src_dir} -> {dst_dir}')
PY

# Then generate from the copied prompt(s)
pdd generate --output architecture.json prompts/architecture/architecture_json.prompt

Unified template examples

# Frontend (Next.js) — interface.page.route and component props
pdd generate \
  -e APP_NAME=Shop \
  # (routes are inferred from PRD/tech stack/files)
  -e PRD_FILE=docs/specs.md \
  -e DOC_FILES='docs/ux.md,docs/components.md' \
  -e TECH_STACK_FILE=docs/tech_stack.md \
  # discovery, if needed, is configured in template YAML and executed by the CLI
  --output architecture.json \
  pdd/templates/architecture/architecture_json.prompt

# Backend (Python) — interface.module.functions or interface.api.endpoints
pdd generate \
  -e PRD_FILE=docs/backend-spec.md \
  -e TECH_STACK_FILE=docs/tech_stack.md \
  -e INCLUDE_FILES='src/app.py,src/api.py,pyproject.toml' \
  --output architecture.json \
  pdd/templates/architecture/architecture_json.prompt

Interface Schema

  • Core keys (every item):
    • reason, description, dependencies, priority, filename, optional tags.
  • Interface object (typed, include only what applies):
    • type: component | page | module | api | graphql | cli | job | message | config | entrypoint
    • component: props[], optional emits[], context[]
    • page: route, optional params[], layout, and dataSources[] where each entry is an object with required kind (e.g., api, query) and source (URL or identifier), plus optional method, description, auth, inputs[], outputs[], refreshInterval, notes
    • module: functions[] with name, signature, optional returns, errors, sideEffects
    • api: endpoints[] with method, path, optional auth, requestSchema, responseSchema, errors
    • graphql: optional sdl, or operations with queries[], mutations[], subscriptions[]
    • cli: commands[] with name, optional args[], flags[], exitCodes[]; optional io (stdin, stdout)
    • job: trigger (cron/event), optional inputs[], outputs[], retryPolicy
    • message: topics[] with name, direction (publish|subscribe), optional schema, qos
    • config: keys[] with name, type, optional default, required, source (env|file|secret)
    • entrypoint: empty object {} for framework/runtime-discovered entry files that expose no named exports (e.g. main.py, app/layout.tsx)
    • Optional: version, stability (experimental|stable)

Examples:

{
  "reason": "Top-level products page",
  "description": "...",
  "dependencies": ["layout_tsx.prompt"],
  "priority": 1,
  "filename": "page_tsx.prompt",
  "tags": ["frontend","nextjs"],
  "interface": {
    "type": "page",
    "page": {"route": "/products", "params": [{"name":"id","type":"string"}]},
    "component": {"props": [{"name":"initialProducts","type":"Product[]","required":true}]}
  }
}
{
  "reason": "Order service module",
  "description": "...",
  "dependencies": ["db_python.prompt"],
  "priority": 1,
  "filename": "orders_python.prompt",
  "tags": ["backend","python"],
  "interface": {
    "type": "module",
    "module": {
      "functions": [
        {"name": "load_orders", "signature": "def load_orders(user_id: str) -> list[Order]"},
        {"name": "create_order", "signature": "def create_order(dto: OrderIn) -> Order"}
      ]
    }
  }
}
{
  "reason": "Orders HTTP API",
  "description": "...",
  "dependencies": ["orders_python.prompt"],
  "priority": 2,
  "filename": "api_python.prompt",
  "tags": ["backend","api"],
  "interface": {
    "type": "api",
    "api": {
      "endpoints": [
        {
          "method": "GET",
          "path": "/orders/{id}",
          "auth": "bearer",
          "responseSchema": {"type":"object","properties":{"id":{"type":"string"}}},
          "errors": ["404 Not Found","401 Unauthorized"]
        }
      ]
    }
  }
}

Notes and recommendations

  • Treat copied templates as a starting point; edit them to match your stack and conventions.
  • Keep templates under version control along with your code to preserve the prompt‑as‑source‑of‑truth model.
  • If you maintain your own template set, store them under prompts/<org_or_team>/... and compose with <include> to maximize reuse.

Templates: additional UX

  • Goals:

    • Discover, inspect, and vendor templates without manual file paths.
    • Validate required variables and surface defaults from template metadata.
    • Support a search order so project templates can override packaged ones.
  • Commands:

    • pdd templates list [--json] [--filter tag=frontend] to discover templates
    • pdd templates show <name> [--raw] to view metadata and variables
    • pdd templates copy <name> --to prompts/ to vendor into your repo
    • pdd generate --template <name> [-e KEY=VALUE...] [--output PATH]
  • Example usage:

# Discover and inspect
pdd templates list --filter tag=frontend
pdd templates show frontend/nextjs_architecture_json

# Vendor and customize
pdd templates copy frontend/nextjs_architecture_json --to prompts/frontend/

# Generate without specifying a file path
pdd generate --template frontend/nextjs_architecture_json \
  -e APP_NAME=Shop \
  # routes are inferred from PRD/tech stack/files
  --output architecture.json
  • Search order:

    • Project: ./prompts/** (allows team overrides)
    • .pddrc paths: any configured templates.paths
    • Packaged: pdd/templates/** (built‑ins)
    • Optional: $PDD_PATH/prompts/** (org‑level packs)
  • Template front matter:

    • YAML metadata at the top of .prompt files to declare name, description, tags, version, language, default output, and variables (with required, default, type such as string or json).
    • Variable precedence: values from -e/--env override front‑matter defaults; unknowns are validated and surfaced to the user.
    • Output path precedence: --output (CLI) > output: (front matter) > generate_output_path (.pddrc). If front‑matter output: cannot be resolved, the CLI emits a yellow warning and falls back to the default path instead of failing silently.
    • Example:
      ---
      name: frontend/nextjs_architecture_json
      description: Generate a Next.js architecture.json file from app metadata
      tags: [frontend, nextjs, json]
      version: 1.0.0
      language: json
      output: architecture.json
      variables:
        APP_NAME: { required: true }
        ROUTES:   { type: json, default: [] }
      ---
      ...prompt body...
      

3. example

Create a compact example demonstrating how to use functionality defined in a prompt. Similar to a header file or API documentation, this produces minimal, token-efficient code that shows the interface without implementation details.

pdd [GLOBAL OPTIONS] example [OPTIONS] PROMPT_FILE CODE_FILE

Arguments:

  • PROMPT_FILE: The filename of the prompt file that generated the code.
  • CODE_FILE: The filename of the existing code file.

Options:

  • --output LOCATION: Specify where to save the generated example code. The default file name is <basename>_example.<language_file_extension>. If an environment variable PDD_EXAMPLE_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --format FORMAT: Output format for the generated example (default: code). Valid values:
    • code: Uses the language-specific file extension (e.g., .py for Python, .js for JavaScript) when no suffix is supplied on --output. If --output includes a suffix (.yml, .m, .txt, …), that suffix is honored verbatim — pass --format md to force a .md extension.
    • md: Generates markdown content; the resolved output path will always end in lowercase .md, replacing any other suffix (including upper-case variants like .MD) on --output. When --format md overrides an explicit non-.md output suffix, the wrapper prints a warning naming both the requested and resolved paths unless --quiet is set. If any wrapper-rewritten output path already exists (--format md suffix override, or a bare name under --format code), you will also be prompted to confirm the overwrite unless --force is set.

Where used:

  • Dependency references: Examples serve as lightweight (token efficient) interface references for other prompts and can be included as dependencies of a generate target.
  • Sanity checks: The example program is typically used as the runnable program for crash and verify, providing a quick end-to-end sanity check that the generated code runs and behaves as intended.
  • Auto-deps integration: The auto-deps command can scan example files (e.g., examples/**/*.py) and insert relevant references into prompts. Based on each example’s content (imports, API usage, filenames), it identifies useful development units to include as dependencies.
  • Metadata finalization: A successful pdd example updates the affected module's fingerprint and clears its stale .pdd/meta/<basename>_<language>_run.json runtime-verification report, so a regenerated example never leaves runtime state describing the pre-mutation output. The fingerprint write is atomic (temp-file + rename via FingerprintTransaction); a finalization failure exits non-zero rather than being surfaced as a warning.

When to use: Choose this command when creating reusable references that other prompts can efficiently import. This produces token-efficient examples that are easier to reuse across multiple prompts compared to including full implementations.

Example:

pdd [GLOBAL OPTIONS] example --output examples/factorial_calculator_example.py factorial_calculator_python.prompt src/factorial_calculator.py

4. test

Generate or enhance unit tests for a given code file and its corresponding prompt file. Also supports agentic mode for generating UI tests from GitHub issues.

Agentic Mode (UI Test Generation)

Generate UI tests from a GitHub issue. The issue describes what needs to be tested (a webpage, CLI, or desktop app), and an agentic workflow analyzes the target, creates a test plan, and generates comprehensive UI tests.

pdd [GLOBAL OPTIONS] test <github-issue-url>

How it works (18-step workflow with GitHub comments):

  1. Duplicate check - Search for existing issues describing the same test requirements. If found, merge content and close the duplicate.

  2. Documentation check - Review repo documentation and codebase to understand what needs to be tested. Identifies OpenAPI/Swagger specs if present.

  3. Analyze & clarify - Determine if enough information exists in the issue to create tests. Posts comment requesting clarification if needed.

  4. Detect frontend - Identify the test type: web UI, CLI, desktop app, or API. Determines the appropriate testing framework.

  5. Create test plan - Design a comprehensive test plan and verify it's achievable.

5b. Enhance test plan - Add contract validation test cases (from OpenAPI/Swagger specs) and accessibility test cases (for web apps using @axe-core/playwright at WCAG 2.1 AA level).

  1. Assess coverage (web only, requires playwright-cli) - Compare requirements against the enhanced test plan to identify gaps needing manual testing.

  2. Create manual testing checklist (web only) - Generate a checklist using three strategies: page-by-page exhaustive testing, user-story walkthroughs, and accessibility spot-checks.

  3. Manual testing execution (web only) - Execute checklist items via playwright-cli commands. Runs serially in CLI mode or in parallel via Cloud Batch when PDD_CLOUD_RUN=true.

  4. Create regression tests (web only) - Generate automated tests that reproduce bugs found in Step 8.

  5. Validate regression tests (web only) - Confirm regression tests fail against current code (proving bugs exist).

  6. Loop check (web only) - Check checklist completion. Loops back to Step 8 if items remain (max 3 iterations).

  7. Generate tests - Create tests in a worktree from the enhanced plan, including behavioral, contract, and accessibility tests.

  8. Run tests - Execute all generated tests against the target.

  9. Fix & iterate - Fix any failing tests and re-run until they pass.

  10. Validate tests against plan - Cross-reference the enhanced plan against generated tests. Generate missing tests for any unimplemented cases.

  11. Run newly generated tests - Run and fix tests created in Step 15 (if any).

  12. Submit PR - Create a draft PR with enhanced description including test plan coverage ratio, contract test summary, accessibility audit summary, and manual testing summary.

Execution Modes:

ModeSteps 6-11 behavior
CLI (pdd test <url>)Serial: Runs each checklist chunk one at a time
GitHub App (PDD_CLOUD_RUN=true)Parallel: Fans out to Cloud Batch spot VMs

Prerequisites:

  • Steps 6-11 (manual/exploratory testing) require playwright-cli in PATH. If not found, these steps are skipped with a warning.
  • Steps 6-11 only run for web test types (TEST_TYPE: web).

Agentic Options:

  • --timeout-adder FLOAT: Add additional seconds to each step's timeout (default: 0.0)
  • --no-github-state: Disable GitHub issue comment-based state persistence, use local-only
  • --clean-restart: Discard saved agentic test state and start the 18-step workflow fresh
  • --manual: Use legacy prompt-based mode instead of agentic mode

Environment Variables:

  • PDD_CLOUD_RUN=true: Enable parallel execution mode for manual testing (Steps 6-11)
  • PDD_NO_GITHUB_STATE=1: Disable GitHub state persistence

Cross-Machine Resume: By default, workflow state is stored in a hidden comment on the GitHub issue, enabling resume from any machine. Use --no-github-state to disable this feature, or --clean-restart to discard saved state and rerun from the beginning.

Example (Agentic Mode):

# Generate UI tests from a GitHub issue
pdd test https://github.com/myorg/myrepo/issues/789

# Resume after answering clarifying questions
pdd test https://github.com/myorg/myrepo/issues/789

# Start fresh and ignore saved workflow state
pdd test --clean-restart https://github.com/myorg/myrepo/issues/789

Next Step - Fixing Test Issues:

If the generated tests reveal issues that need code fixes, use pdd fix with the same issue URL:

pdd fix https://github.com/myorg/myrepo/issues/789

Manual Mode (Prompt-Based)

Generate or enhance unit tests for a given code file and its corresponding prompt file.

Test organization:

  • For each target <basename>, PDD maintains a single test file (by default named test_<basename>.<language_extension> and typically placed under a tests directory).
  • New tests accumulate in that same file over time rather than being regenerated from scratch. When augmenting tests, PDD can merge additions into the existing file (see --merge).
pdd [GLOBAL OPTIONS] test [OPTIONS] PROMPT_FILE CODE_OR_EXAMPLE_FILE
pdd [GLOBAL OPTIONS] test --manual [OPTIONS] PROMPT_FILE CODE_OR_EXAMPLE_FILE

Arguments:

  • PROMPT_FILE: The filename of the prompt file that generated the code.
  • CODE_OR_EXAMPLE_FILE: The filename of the code implementation or example file. Files ending with _example are treated as example files for TDD-style test generation.

Options:

  • --output LOCATION: Specify where to save the generated test file. The default file name is test_<basename>.<language_file_extension>. If an output file with the specified name already exists, a new file with a numbered suffix (e.g., test_calculator_1.py) will be created instead of overwriting.
  • --language: Specify the programming language. Defaults to the language specified by the prompt file name.
  • --coverage-report PATH: Path to the coverage report file for existing tests. When provided, generates additional tests to improve coverage.
  • --existing-tests PATH [PATH...]: Path(s) to the existing unit test file(s). Required when using --coverage-report. Multiple paths can be provided.
  • --target-coverage FLOAT: Desired code coverage percentage to achieve (default is 90.0).
  • --merge: When used with --existing-tests, merges new tests with existing test file instead of creating a separate file.

When the prompt contains a contract_rules section, unit test generation uses those rule IDs for planning: MUST rules should receive behavioral tests, MUST NOT rules should receive negative tests when fixtures allow, and generated test names or comments should reference the relevant rule ID where practical. If a rule cannot be exercised with the available fixtures, the generated test file should include a TODO or skipped-test reason instead of silently omitting the rule.

Story Mode

Generate issue-derived user stories or update story prompt metadata.

pdd [GLOBAL OPTIONS] test --issue https://github.com/myorg/myrepo/issues/789 prompts/upload_python.prompt prompts/notify_python.prompt
pdd [GLOBAL OPTIONS] test --issue ./issues/upload.md prompts/upload_python.prompt
pdd [GLOBAL OPTIONS] test user_stories/story__my_flow.md

Behavior:

  • If input is one or more .prompt files, --issue is required. The issue source can be a GitHub issue/PR URL, an issue number resolvable from the current repo, or a local issue markdown file.
  • PDD resolves the issue first and authors user_stories/story__<name>.md from that issue text. Prompt file content is withheld from the story author so the story can catch prompt drift from the issue intent.
  • The prompt files passed on the command line are linked directly in pdd-story-prompts metadata. Story generation does not run detect_change or auto-detect touched prompts.
  • Missing/unresolvable issue sources or invalid LLM story output fail the command instead of writing a prompt-derived fallback story.
  • pdd test user_stories/story__*.md updates metadata for an existing story file. If metadata is missing or stale, PDD runs prompt detection and writes: <!-- pdd-story-prompts: prompt_a_python.prompt, prompt_b_python.prompt -->
  • This enables deterministic prompt-subset validation in pdd detect --stories.

Providing Command-Specific Context

While prompts are the primary source of instructions, some PDD commands (like test and example) can be further guided by project-specific context files. These commands may automatically look for conventional files (e.g., context/test.prompt, context/example.prompt) in the current working directory during their internal prompt preprocessing phase.

If found, the content of these context files is included (using the <include> mechanism described in the preprocess section) into the internal prompt used by the command. This allows you to provide specific instructions tailored to your project, such as:

  • Specifying required import statements.
  • Suggesting preferred testing frameworks or libraries.
  • Providing project-specific coding conventions or patterns.

Example: Creating a file named context/test.prompt with the content:

Please ensure all tests use the 'unittest' framework and import the main module as 'from my_module import *'.

could influence the output of the pdd test command when run in the same directory.

Note: This feature relies on the internal implementation of specific PDD commands incorporating the necessary <include> tags for these conventional context files. It is primarily used by test and example but may be adopted by other commands in the future. Check the specific command documentation or experiment to confirm if a command utilizes this pattern.

Basic Examples:

  1. Generate initial unit tests:
pdd [GLOBAL OPTIONS] test --output tests/test_factorial_calculator.py factorial_calculator_python.prompt src/factorial_calculator.py
  1. Generate tests from an example file (TDD-style):
pdd [GLOBAL OPTIONS] test --output tests/test_calculator.py calculator_python.prompt examples/calculator_example.py
  1. Generate additional tests to improve coverage (with multiple existing test files):
pdd [GLOBAL OPTIONS] test --coverage-report coverage.xml --existing-tests tests/test_calculator.py --existing-tests tests/test_calculator_edge_cases.py --output tests/test_calculator_enhanced.py calculator_python.prompt src/calculator.py
  1. Improve coverage and merge with existing tests:
pdd [GLOBAL OPTIONS] test --coverage-report coverage.xml --existing-tests tests/test_calculator.py --merge --target-coverage 95.0 calculator_python.prompt src/calculator.py

Coverage Analysis Strategy

When coverage options are provided, the test command will:

  1. Analyze the coverage report to identify:

    • Uncovered lines and branches
    • Partially tested conditions
    • Missing edge cases
  2. Generate additional test cases prioritizing:

    • Complex uncovered code paths
    • Error conditions
    • Boundary values
    • Integration points
  3. Maintain consistency with:

    • Existing test style and patterns
    • Project's testing conventions
    • Original prompt's intentions

5. preprocess

Preprocess prompt files and save the results.

pdd [GLOBAL OPTIONS] preprocess [OPTIONS] PROMPT_FILE

Arguments:

  • PROMPT_FILE: The filename of the prompt file to preprocess.

Options:

  • --output LOCATION: Specify where to save the preprocessed prompt file. The default file name is <basename>_<language>_preprocessed.prompt.
  • --xml: Automatically insert XML delimiters for long and complex prompt files to structure the content better. With this option prompts are only preprocessed to insert in XML delimiters, but not preprocessed otherwise.
  • --recursive: Recursively preprocess all prompt files in the prompt file.
  • --double: Curly brackets will be doubled.
  • --exclude: List of keys to exclude from curly bracket doubling.
  • Context compression: use global --context-compression / --compression-fallback before preprocess (see Global Options); preprocess does not accept these flags after the subcommand.
  • --snapshot: Write the expanded prompt plus a snapshot manifest for any dynamic context resolved during preprocessing. The manifest records hashes and artifact paths for captured <shell>, <web>, and semantic query= include outputs so a later replay can reconstruct the same prompt context.
pdd preprocess prompts/refund_python.prompt --snapshot

Use snapshots when dynamic tags are needed for durable behavior. Static prompts with only deterministic includes report that no nondeterministic context was captured. Do not pass --recursive with --snapshot when the prompt uses <shell>, <web>, or query= includes (recursive mode defers those tags). Enforce captured snapshots in CI with pdd checkup snapshot prompts/refund_python.prompt (see docs/ci.md).

XML-like Tags

PDD supports the following XML-like tags in prompt files. Note: XML-like tags (<include>, <include-many>, <shell>, <web>) are left untouched inside fenced code blocks (``` or ~~~) or inline single backticks so documentation examples remain literal.

  1. include: Includes file content into the prompt. The file path is always the tag body. Optional attributes extract specific parts instead of the full file:

    <include>./path/to/file.txt</include>
    <include select="def:foo,class:Bar">src/utils.py</include>
    <include select="pytest:test_my_feature">tests/test_existing.py</include>
    <include select="class:Handler" mode="interface">src/api.py</include>
    <include query="authentication flow">docs/api_reference.md</include>
    
    • select= — deterministic structural extraction (functions, classes, pytest tests, API contract slices (contract:symbol), line ranges, headings, regex, JSON/YAML paths). Composable via comma-separation; values like pytest:test_a,test_b stay grouped.
    • mode="interface" — Python-only. Extracts signatures and docstrings with bodies replaced by ....
    • query= — LLM-powered semantic extraction, cached in .pdd/extracts/.
    • optional — when present on an <include ...> tag, a missing file resolves to an empty string ("") during non-recursive preprocessing (while still logging a warning).
    • When both select= and query= are present, select= wins (no LLM cost).

    This mechanism is also used internally by some commands (like test and example) to automatically incorporate project-specific context files if they exist in conventional locations (e.g., context/test.prompt). See 'Providing Command-Specific Context' for details. For the full selector reference, see the Prompting Guide.

  2. pdd: Indicates a comment that will be removed from the preprocessed prompt, including the tags themselves.

    <pdd>This is a comment that won't appear in the preprocessed output</pdd>
    
  3. shell: Executes shell commands and includes their output in the prompt, removing the shell tags.

    <shell>ls -la</shell>
    
  4. web: Scrapes a web page and includes its markdown content in the prompt, removing the web tags.

    <web>https://example.com</web>
    

Triple Backtick Includes

PDD supports two ways of including external content:

  1. Triple backtick includes: Replaces angle brackets in triple backticks with the content of the specified file.
    ```
    <./path/to/file.txt>
    ```
    This will be recursively processed until there are no more angle brackets in triple backticks.
    
    
  2. XML include tags: As described above.

Curly Bracket Handling

When using the --double option:

  • Single curly brackets are doubled if they're not already doubled
  • Already doubled brackets are preserved
  • Nested curly brackets are properly handled
  • Special handling is applied for code blocks (JSON, JavaScript, TypeScript, Python)
  • Multiline variables with curly brackets receive special handling

Use the --exclude option to specify keys that should be excluded from curly bracket doubling. This option only applies if the entire string inside a pair of single curly braces exactly matches one of the excluded keys.

For example, with --exclude model:

  • {model} remains {model} (excluded due to exact match).
  • {model_name} is doubled, as 'model_name' is not an exact match for 'model'.
  • {api_model} is doubled, not an exact match.
  • Braces containing other content, even if related to the key (e.g., var={key}_value), will generally still follow doubling rules unless the inner {key} itself is excluded.

Example command usage:

pdd [GLOBAL OPTIONS] preprocess --output preprocessed/factorial_calculator_python_preprocessed.prompt --recursive --double --exclude model,temperature factorial_calculator_python.prompt

5a. replay

Reconstruct and audit the expanded prompt context recorded by a snapshot-enabled run.

pdd replay .pdd/evidence/runs/<run_id>.json

Replay verifies that the expanded prompt hash can be reconstructed from the run artifact and its captured context snapshots. It does not promise identical generated code, because model execution may remain nondeterministic; the replay contract is identical prompt/context reconstruction.

5b. context

Show context-window usage broken down by source for a preprocessed prompt, rendered like Claude Code's /context display.

pdd context <prompt_path> [--model MODEL] [--json] [--table] [--threshold N]

Preprocesses the prompt the same way generation does and counts tokens per source segment without making an LLM call.

Arguments

  • prompt_path: Path to the prompt file to audit.

Options

  • --model MODEL: Model name used for context-limit lookup. Defaults to PDD_MODEL_DEFAULT env var, or gpt-4o if unset.
  • --json: Emit machine-readable JSON output to stdout instead of the usage box.
  • --table: Show the raw per-source token-attribution table instead of the usage box.
  • --threshold N: Integer percentage (0–100, default 80) above which the command exits with code 2 to signal context budget exceeded. Set to 0 to disable.

Output

By default it prints a Claude-Code /context-style usage box:

  • A grid of cells showing used context-window space split by category against free space ().
  • The model name and total/limit tokens (percent%) summary.
  • An Estimated usage by category breakdown — one line per source (prompt body, each <include> file, tests, examples, grounding) — followed by a Free space line.

--table instead prints a table with a header (total tokens, model, context-limit size, percentage used) and rows sorted by token count descending (largest consumer first).

Attribution follows the real hydration path, so a targeted include (lines=, select=, mode=, or a literal <include-many> list) is counted by the content it actually contributes — not the whole source file. Nested includes roll up into their top-level parent, while independent top-level includes each keep their own row even when their text overlaps.

Unresolved/missing includes are surfaced as a warning and a 0-token row instead of being silently folded into the prompt body, but only when preprocess would treat the syntax as a real directive. Include examples inside code fences are not expanded or reported, and optional missing includes are skipped silently.

In both modes, warnings are printed for any dynamic tags (<shell>, <web>, semantic query= includes) — in the prompt or inside an included file — that were detected but not expanded (nondeterministic, deferred); their markup is excluded from the token total.

JSON output (--json) emits a single object with keys: total_tokens, context_limit, percent_used, model, rows, warnings, and threshold_exceeded.

The context command suppresses global PDD command footers for all modes. In --json mode stdout is only the JSON object, so CI and dashboards can parse it directly.

Exit codes

  • 0: audit completed within threshold.
  • 2: total tokens exceed --threshold percent of the model's context limit (useful for CI and dashboards).

Examples

# Claude-Code /context-style usage box with default 80% threshold
pdd context prompts/my_module_python.prompt

# Raw per-source attribution table
pdd context prompts/my_module_python.prompt --table

# Audit against a specific model
pdd context prompts/my_module_python.prompt --model claude-sonnet-4-6

# JSON output for CI dashboards
pdd context prompts/my_module_python.prompt --json

# Fail CI when prompt uses more than 60% of context
pdd context prompts/my_module_python.prompt --threshold 60

6. fix

Fix errors in code and unit tests. Supports two modes: Agentic E2E Fix (default when given a GitHub URL) for multi-dev-unit test fixing, and Manual mode for single dev-unit fixing with explicit file arguments.

Agentic E2E Fix Mode (GitHub URL):

pdd [GLOBAL OPTIONS] fix [OPTIONS] <GITHUB_ISSUE_URL>

Manual Mode (file arguments):

pdd [GLOBAL OPTIONS] fix --manual [OPTIONS] PROMPT_FILE CODE_FILE UNIT_TEST_FILE ERROR_FILE

Manual Mode Arguments

  • PROMPT_FILE: The filename of the prompt file that generated the code under test.
  • CODE_FILE: The filename of the code file to be fixed.
  • UNIT_TEST_FILES: The filename(s) of the unit test file(s). Multiple files can be provided, and each will be processed individually.
  • ERROR_FILE: The filename containing the unit test runtime error messages. Optional and does not need to exist when used with the --loop command.

Common Options

  • --manual: Use manual mode with explicit file arguments (required for legacy/single dev-unit fixing).
  • --verbose: Show detailed output during processing.
  • --quiet: Suppress all output except errors.
  • --protect-tests/--no-protect-tests: When enabled, prevents the LLM from modifying test files. The LLM will treat tests as read-only specifications and only fix the code. This is especially useful when tests created by pdd bug are known to be correct. Default: --no-protect-tests.

Passing tests are also checked against repository-backed data contracts. When a fix introduces a literal query field or a generated mock fabricates a field for an existing query, pdd fix compares that shape with the exact resource section in schema Markdown/JSON and independent production readers/writers. A real contradiction (for example, querying user_waitlist.userId when the user_waitlist schema has no userId field while the test mocks one) is a hard non-zero failure before manual outputs are written or agentic changes are committed. If no exact contract exists, the result is surfaced as inconclusive instead of guessing from the field name.

Agentic E2E Fix Options

  • --timeout-adder FLOAT: Additional seconds to add to each step's timeout (default: 0.0).
  • --max-cycles INT: Maximum number of outer loop cycles before giving up (default: 5).
  • --resume/--no-resume: Resume from saved state if available (default: --resume).
  • --clean-restart: Discard saved agentic E2E fix state and ignore sibling pdd bug analysis state before starting fresh. Implies --no-resume.
  • --context-compression {off,test,examples,contracts,all}: Command-local on pdd fix (and also available globally before the subcommand). Unlike generate and preprocess, fix accepts these flags after fix in the argv list.
  • --compression-fallback {full,error}: Same placement as --context-compression on fix (command-local or global before fix).
  • --force: Override the branch mismatch safety check. By default, the command aborts if the current git branch doesn't match the expected branch from the issue (to prevent accidentally modifying the wrong codebase).

Manual Mode Options

  • --output-test LOCATION: Specify where to save the fixed unit test file. The default file name is test_<basename>_fixed.<language_file_extension>. Warning: If multiple UNIT_TEST_FILES are provided along with this option, only the fixed content of the last processed test file will be saved to this location, overwriting previous results. For individual fixed files, omit this option.
  • --output-code LOCATION: Specify where to save the fixed code file. The default file name is <basename>_fixed.<language_file_extension>. If an environment variable PDD_FIX_CODE_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --output-results LOCATION: Specify where to save the results of the error fixing process. The default file name is <basename>_fix_results.log. If an environment variable PDD_FIX_RESULTS_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --loop: Enable iterative fixing process.
    • --verification-program PATH: Specify the path to a Python program that verifies if the code still runs correctly.
    • --max-attempts INT: Set the maximum number of fix attempts before giving up (default is 3).
    • --budget FLOAT: Set the maximum cost allowed for the fixing process (default is $5.0).
  • --auto-submit: Automatically submit the example if all unit tests pass during the fix loop.
  • --context-compression / --compression-fallback: Same command-local fix options as in Agentic E2E Fix Options above (not accepted after generate or preprocess).

When the --loop option is used, the fix command will attempt to fix errors through multiple iterations. It will use the specified verification program to check if the code runs correctly after each fix attempt. The process will continue until either the errors are fixed, the maximum number of attempts is reached, or the budget is exhausted.

Outputs:

  • Fixed unit test file(s).
  • Fixed code file.
  • Results file containing the LLM model's output with unit test results.
  • Print out of results when using '--loop' containing:
    • Success status (boolean)
    • Total number of fix attempts made
    • Total cost of all fix attempts
  • This will also create intermediate versions of the unit test and code files for the different iterations with timestamp-based naming (e.g., basename_1_0_3_0_20250402_124442.py, standalone_test_1_0_3_0_20250402_124442.py).

Example:

pdd [GLOBAL OPTIONS] fix --output-code src/factorial_calculator_fixed.py --output-results results/factorial_fix_results.log factorial_calculator_python.prompt src/factorial_calculator.py tests/test_factorial_calculator.py tests/test_factorial_calculator_edge_cases.py errors.log

In this example, pdd fix will be run for each test file, and the fixed test files will be saved as tests/test_factorial_calculator_fixed.py and tests/test_factorial_calculator_edge_cases_fixed.py.

Focused Repair for Large Dev Units

For dev units where the code file exceeds 500 lines or the test file exceeds 1000 lines, pdd fix automatically switches to a two-phase focused-repair strategy instead of sending the entire file to the LLM in one shot.

How it Works:

  1. Fast-path: If the pytest traceback directly names 1–3 functions, those function slices plus their failing tests are sent to the LLM immediately — no diagnosis step needed.
  2. Phase 1 — Diagnose: For all other large dev units, a code skeleton (function signatures only, no bodies) is sent along with the error log so the LLM can identify which functions are likely broken.
  3. Phase 2 — Fix: Only the identified function slices plus their failing tests are sent for the actual fix. The repaired bodies are spliced back into the original file at their original line offsets.
  4. Automatic fallback: If the focused-repair path encounters a parse error or returns an empty result, pdd fix silently falls back to the standard full-file behavior.

This strategy is fully automatic and requires no flags. The threshold check and focused-repair path are internal to pdd fix; its public interface and all existing flags remain unchanged.

Agentic Fallback Mode

(This feature is also available for the crash and verify command.)

For particularly difficult bugs that the standard iterative fix process cannot resolve, pdd fix offers a powerful agentic fallback mode. When activated, it invokes a project-aware CLI agent to attempt a fix with a much broader context.

How it Works: If the standard fix loop completes all its attempts and fails to make the tests pass, the agentic fallback will take over. It constructs a detailed set of instructions and delegates the fixing task to a dedicated CLI agent like Google's Gemini, Anthropic's Claude, OpenAI's Codex, or OpenCode.

How to Use:

This feature only takes effect when --loop is set.

When the --loop flag is set, agentic fallback is enabled by default:

pdd [GLOBAL OPTIONS] fix --manual --loop [OTHER OPTIONS] PROMPT_FILE CODE_FILE UNIT_TEST_FILE

Or you may want to enable it explicitly

pdd [GLOBAL OPTIONS] fix --manual --loop --agentic-fallback [OTHER OPTIONS] PROMPT_FILE CODE_FILE UNIT_TEST_FILE

To disable this feature while using --loop, add --no-agentic-fallback to turn it off.

pdd [GLOBAL OPTIONS] fix --manual --loop --no-agentic-fallback [OTHER OPTIONS] PROMPT_FILE CODE_FILE UNIT_TEST_FILE

Prerequisites: For the agentic fallback to function, you need to have at least one of the supported agent CLIs installed with valid credentials. Each CLI has its own credential store and falls back to environment-variable API keys if you don't have a stored login. The agents are tried in the following order of preference:

  1. Anthropic Claude:
    • Requires the claude CLI to be installed and in your PATH.
    • Authenticates with your stored Claude Max/Pro OAuth login if you've run claude auth login (recommended), otherwise with ANTHROPIC_API_KEY from your environment.
    • Issue #813: under CI=1 (which pdd always sets) the claude CLI normally prefers ANTHROPIC_API_KEY over OAuth — pdd auto-detects this and drops a stale env key when an OAuth login is present so your subscription is used. Set PDD_KEEP_ANTHROPIC_API_KEY=1 to force API-key billing instead.
  2. Google (Antigravity agy / legacy gemini):
    • Requires either the agy CLI (preferred, install via curl -fsSL https://antigravity.google/cli/install.sh | bash) or the legacy gemini CLI (npm install -g @google/gemini-cli) to be on your PATH. When both are installed, auto mode picks agy when an Antigravity-compatible key/OAuth/Vertex credential is configured; if the only Google auth signal is legacy ~/.gemini/oauth_creds.json, it uses gemini so rollback OAuth keeps working. PDD_GOOGLE_CLI=gemini is the explicit rollback to the old binary. PDD_AGENTIC_PROVIDER=antigravity pins agy and overrides any prior PDD_GOOGLE_CLI.
    • Authenticates with Antigravity OAuth or keyring-backed Google subscription sign-in (~/.gemini/antigravity-cli/ state), API keys (ANTIGRAVITY_API_KEY/GOOGLE_API_KEY, plus PDD maps GEMINI_API_KEY to GOOGLE_API_KEY for the agy subprocess), or Vertex AI env auth. Legacy gemini uses its own OAuth file (~/.gemini/oauth_creds.json) plus GEMINI_API_KEY/GOOGLE_API_KEY. Google announced consumer-tier Gemini CLI cutoff on 2026-06-18.
  3. OpenAI Codex/GPT:
    • Requires the codex CLI to be installed and in your PATH.
    • Authenticates with ~/.codex/auth.json ChatGPT login (run codex login once) or OPENAI_API_KEY from your environment.
  4. OpenCode (provider-agnostic):
    • Requires the opencode CLI to be installed and in your PATH (npm install -g opencode-ai).
    • Authenticates with OpenCode provider credentials from opencode auth login (stored in ~/.local/share/opencode/auth.json), OpenCode JSON config (~/.config/opencode/opencode.json or project opencode.json), or underlying provider env vars such as ANTHROPIC_API_KEY, OPENAI_API_KEY, OPENROUTER_API_KEY, GITHUB_TOKEN, etc.
    • Recommended: set OPENCODE_MODEL=provider/model (for example, anthropic/claude-sonnet-4-5) to avoid relying on default model resolution.
    • Optional: set OPENCODE_AGENT and OPENCODE_VARIANT for OpenCode agent/variant selection.

You can configure environment-variable keys using pdd setup or by setting them in your shell. For OAuth/subscription auth, run each CLI's login command once interactively.

Provider-limit marker for automation:

When an agentic provider or credential hits a real rate, usage, session, or credential limit, PDD emits a single secret-safe marker line on plain stdout that automation can parse without scraping raw provider stderr. Quiet mode may suppress the explanatory diagnostic, but it does not suppress this scheduling marker.

PDD_PROVIDER_LIMIT provider=<anthropic|openai|google|antigravity|opencode> status=<429|credential_limit> reason=<rate_limit|usage_limit|session_limit|credential_limit> reset_at=<UTC ISO-8601 timestamp or empty> reset_source=<provider|parsed_text|estimated|none>

reset_at is normalized to UTC (YYYY-MM-DDTHH:MM:SSZ) when PDD can read or infer a reset time, for example from Claude Code limit text — reset_source=parsed_text for an explicit date/timestamp, estimated when only a time-of-day was given and the date was inferred. Generic provider 429s without reset metadata still emit the marker with an empty reset_at and reset_source=none. The marker fires once per provider after its retry budget is spent (a 429 that recovers on retry emits nothing). It is a per-provider detection signal, not a job-failure signal: in a multi-provider run PDD can emit a marker for a limited provider and still succeed via the next provider, so consumers should combine the marker with the command's exit status before rescheduling. It is additive: existing credential-limit classification text remains for backward compatibility. The marker never includes raw provider stderr, tokens, API keys, user prompt content, or other untrusted provider text. (Antigravity runs under the google provider slot; PDD reports provider=antigravity only when the selected Google CLI is agy. An unmappable provider is reported as the literal unknown rather than any raw text.)

Agentic E2E Fix Mode

For fixing end-to-end tests that span multiple dev units, use the agentic E2E fix mode by passing a GitHub issue URL (typically created by pdd bug). This mode orchestrates an iterative 11-step workflow, fixing both unit tests and e2e tests across your codebase, validating CI, and cleaning up code.

How it Works:

The workflow analyzes the GitHub issue to extract test information, then iteratively fixes failing tests:

  1. Run Unit Tests: Execute unit tests from the issue and run pdd fix on each failing test sequentially
  2. Run E2E Tests: Execute end-to-end tests to identify failures; stop if all pass
  3. Root Cause Analysis: Analyze failures against documentation to determine if issues are in code, tests, or both
  4. Fix E2E Tests: If e2e tests themselves are incorrect, fix them and return to step 2
  5. Identify Dev Units: Determine which dev units are involved in the failures
  6. Create Unit Tests: For code bugs, create or append unit tests for the affected dev units
  7. Verify Tests: Run new unit tests to confirm they detect the bugs and will pass once fixed
  8. Run PDD Fix: Execute pdd fix sequentially on failing unit tests for each dev unit
  9. Verify All: Final verification that all tests pass locally. The orchestrator independently re-runs the discovered test files (not the agent's possibly-targeted selection); if that independent verification rejects an agent-reported pass, PDD posts a trusted ## Step 9/11: rejection comment on the issue with the exact verifier command and bounded output, and the cycle is not recorded as a success. Before terminal success, the shared mock-contract gate checks every workflow-owned Python query/mock change against real repository schema and sibling evidence; a divergence blocks commit/push even when all tests pass
  10. CI Validation: First poll external CI, retrieve logs on failure, and run an LLM fix loop to remediate any CI-specific issues (lint, artifacts, build). Once CI is green, run a real pre-checkup gate (the fix path's first drift-sync step) that blocks on any mechanical failure (build/smoke — compile, import, caller-compat, targeted tests) or unhealable update-drift. (Architecture-sync residuals and example-only drift are advisory in default mode — not hard blocks — because they are frequently spurious on a clean tree; strict mode promotes them.) It first drift-syncs code ↔ prompt ↔ architecture.json.pdd/meta in the worktree (the prompt/code sync is committed to the PR (an example regenerated as a side effect of an update-heal is committed and validated too; example-only drift is advisory — the gate does not auto-heal it, to avoid the #1243 null-hash heal loop); .pdd/meta fingerprint finalization is intentionally left to the post-merge sync — see #1317 — so the PR tree itself may still show fingerprint drift until then), then executes its own deterministic build/smoke checks — compile touched files, import changed modules, probe changed router/app modules for route/router objects (a non-blocking note, not a hard block — best-effort app-wiring smoke that stays with checkup), lint, caller-compatibility sweep, and run targeted unit tests by git-diff (Python tests are executed; a changed JS/TS test is reported, not run). It runs these checks itself rather than relying solely on GitHub required checks (which are often absent or vacuous)
  11. Code Cleanup: Review all changes from the workflow and clean up code quality issues (debug statements, unused imports, duplicated code); revert if tests or the mock-contract gate fail

After Step 11 the workflow clears state and returns. pdd fix does not run pdd checkup (no Layer-1 PR-mode checkup, no Layer-2 review-loop) as a final gate — verification is the workflow's own Step 7/9 plus the deterministic pre-checkup build/smoke gate in Step 10. pdd checkup remains a separate command you run on its own (the semantic ship-verdict is available there via --final-gate). Removing the agentic gate stops a transient checkup verdict (an empty/garbled review output, or a provider rate-limit) from failing an already-committed, correct fix. Note that CI is treated as best-effort: a pending / manually-triggered / ACTION_REQUIRED / timed-out required check the bot cannot run is inconclusive, not fatal — so a successful pdd fix run may mean external CI was inconclusive (still pending or waiting for manual action), not confirmed green. Failed required checks remain fail-closed by default and can still drive the CI-fix loop; repos that intentionally want pure external setup/auth failures such as missing GitHub Actions/Firebase credentials to be treated as inconclusive must opt in with .pddrc ci.external_setup_fail_open: true.

For repos with comment-gated CI, configure the trigger in .pddrc so pdd fix can post each matching trigger once and repoll before falling back to an inconclusive manual-action note:

ci:
  manual_trigger_comment: "/gcbrun"
  manual_triggers:
    "auto-heal-pr": "/gcbrun"

For repos that intentionally want missing-secret external setup failures to be reported as inconclusive instead of repairable CI failures:

ci:
  external_setup_fail_open: true

Resumable Operations:

State is automatically persisted, allowing you to resume interrupted workflows. Use --clean-restart to discard saved workflow state and sibling pdd bug analysis before starting fresh. Use --no-resume only when you want to ignore the E2E fix checkpoint while still allowing reusable bug-analysis context.

Cross-Machine Resume: By default, workflow state is stored in a hidden comment on the GitHub issue, enabling resume from any machine. If you start the workflow on machine A, you can continue from machine B by checking out the branch and running pdd fix again. Use --no-github-state to disable this feature and use local-only state persistence. You can also set PDD_NO_GITHUB_STATE=1 environment variable.

Example:

# Fix tests from a GitHub issue (agentic mode)
pdd fix https://github.com/myorg/myrepo/issues/42

# With custom timeout and max cycles
pdd fix --timeout-adder 30 --max-cycles 10 https://github.com/myorg/myrepo/issues/42

# Configure CI retries and validation
pdd fix --ci-retries 5 https://github.com/myorg/myrepo/issues/42

# Skip post-push CI validation entirely
pdd fix --skip-ci https://github.com/myorg/myrepo/issues/42

# Start fresh (ignore saved state and sibling bug analysis)
pdd fix --clean-restart https://github.com/myorg/myrepo/issues/42

# Disable GitHub state persistence (local-only)
pdd fix --no-github-state https://github.com/myorg/myrepo/issues/42

# Protect tests from modification (only fix code, not tests)
pdd fix --protect-tests https://github.com/myorg/myrepo/issues/42

Prerequisites:

  • The gh CLI must be installed and authenticated
  • At least one supported agent CLI (Claude, Gemini/Antigravity, Codex, or OpenCode) with valid credentials — either a stored OAuth/subscription/config credential (recommended) or an API key in the environment
  • For CI validation, the current branch must have an open PR on GitHub

Relationship with pdd bug:

This feature works seamlessly with issues processed by pdd bug. The typical workflow is:

  1. Use pdd bug <issue_url> to analyze a bug and generate failing unit tests
  2. Use pdd fix <issue_url> to iteratively fix the failing tests across all affected dev units

7. split

Diagnose whether a PDD dev unit has an architectural problem, and if so, split the full dev unit (prompt + code + example + tests) into smaller PDD-native dev units. The 15-step agentic workflow classifies intent, surveys the codebase, diagnoses the problem, proposes options with a responsibility-based rubric, extracts children with phase decomposition (and a per-child verify gate as a sub-step within extraction), runs deterministic verification gates (including test-seam resolution and parent-wiring checks), proves the new prompts can regenerate via pdd sync, derives architecture.json from prompt metadata tags, and checks architecture↔include drift after that derivation.

Agentic Mode (default):

pdd [GLOBAL OPTIONS] split [OPTIONS] TARGET_FILE

Arguments:

  • TARGET_FILE: The source file to diagnose and potentially split (e.g., pdd/large_module.py).

The 15-step workflow (with 6v running as a per-child sub-step inside step 6): 0. Intent: Classify the goal (REDUCE_MONOLITH / ENABLE_PARALLEL_WORK / EXTRACT_REUSABLE_LAYER / REDUCE_TEST_TIME); re-weights step 4's rubric

  1. Survey: Neighborhood survey + target-file scan (architecture, siblings, churn, health signals, co-change)
  2. Diagnose: Classify architectural problem; can return LEAVE_ALONE (stops here)
  3. Investigate: Extend with test-seam data, test ownership classification, "stays put" rules, shared-layer candidates
  4. Propose Options: 2-4 SplitPlan options with responsibility-based scoring; auto-pick winner
  5. Setup Worktree: Create isolated git worktree for extraction 6a. Phase Extract (planning): For each child, judge whether its dominant symbol has multi-phase structure worth extracting as sibling-file helpers
  6. Extract: One child per call, full dev unit (prompt + code + example + tests); applies phase plan from 6a when present 6v. Per-Child Verify Gate: After each child extracts in step 6, run validate_extraction() filtered to that child's files only and route any error-severity failures to a bounded step-8 repair sub-loop (max 2 attempts per child). Status is tracked per child in state["children_extracted_status"] (pending / extracted / verified / failed_extract / failed_verify / failed) so a crash mid-pipeline never silently re-bills already-verified children. 7a. Verify Local: Final cross-cutting deterministic check across all children — tests, lint, parent line reduction, and test-seam resolution. Catches issues only visible at full-package scope (e.g. circular imports between children). 7b. Regen Gate: Deterministic — pdd sync must regenerate each new prompt 7c. Arch Sync: Deterministic — derive architecture.json from <pdd-*> prompt metadata tags 7d. Post-Arch Checkup: Run pdd checkup --validate-arch-includes --project-root <worktree> after 7c so architecture↔include drift is checked against freshly synced metadata.
  7. Assess: LLM qualitative verdict; feeds improvement gate alongside 7a/7d metrics
  8. Repair: Fix cross-cutting verification failures from 7a/7d (max 5 iterations across the whole plan), re-running arch sync before each checkup retry. Per-child gate failures (6v, max 2 attempts per child) are repaired inline within step 6 and DO NOT enter step 8 — once the per-child budget is exhausted the child enters terminal failed status, step 8 is short-circuited entirely (the global loop cannot recover what the per-child gate already gave up on). The improvement gate downgrades AUTO_SHIP to HUMAN_REVIEW_REQUIRED for ANY non-verified child (including failed_extract from exhausted file-existence retries and failed from exhausted per-child repair). Per-child reason strings are persisted in state["terminal_child_failures"] (covering both failed_extract missing-file detail and failed ValidationFailure.message detail) and surfaced in the final message + console output so the user knows which child broke and why.
  9. Refine Check: Ask the agent whether any child is still too monolithic; if yes, run one focused phase-extraction pass

Options:

  • --diagnose: Run steps 0-2 only, return diagnosis report
  • --propose-only: Run steps 0-4 only, show all options with scores (cheap plan preview)
  • --intent [reduce|parallel|reuse|tests]: Skip step 0 and set intent explicitly (reduce = REDUCE_MONOLITH, etc.)
  • --no-phase-extraction: Skip step 6a (only move whole symbols, no refactoring inside functions)
  • --strangler: Use the first proposed plan only to determine N (number of children), then run N independent full orchestrator passes (each pass starts fresh, picks its own plan, and extracts whatever children that pass's plan contains); see issue #1402 for true one-child-per-PR enforcement
  • --delete-dead: Opt-in dead symbol deletion (default: surface candidates for human review)
  • --force-split: Override LEAVE_ALONE diagnosis
  • --no-verify: Skip step 7a test gate (dev only)
  • --skip-regen-gate: Skip step 7b regen gate (dev only, logged loudly)
  • --experimental-language: Opt-in for non-Python languages (Python is the only supported tier in this release)
  • --no-github-state: Disable GitHub state persistence (local-only)
  • --timeout-adder FLOAT: Add seconds to each step timeout (default: 0.0)
  • --max-cost FLOAT: Abort if total cost would cross USD threshold. State is persisted, so re-running without --max-cost (or with a higher cap) resumes from the same step. Useful as a budget guardrail on long strangler runs (default: no cap)

Resume: State is persisted after every per-child status transition (in state["children_extracted_status"], keyed by child name). On resumption, pdd split picks up at the first non-terminal child — terminal statuses are verified (success) and failed (per-child repair budget exhausted), both of which are skipped without re-billing tokens. Children in failed_verify (verify failed but repair budget remaining) are re-extracted on resume; the saved repair_attempts count is carried forward (not reset), so the per-child gate continues from where it left off rather than re-spending the full N=2 budget.

Example (agentic mode — full pipeline):

pdd split pdd/large_module.py

Example (with budget cap):

# Stop cleanly if the run would cross $50; state is saved so you can
# resume later by re-running without --max-cost (or with a higher cap).
pdd split --max-cost 50 pdd/large_module.py

Example (diagnosis only):

pdd split --diagnose pdd/large_module.py

Example (compare options without extracting):

pdd split --propose-only pdd/large_module.py

Example (extract reusable shared layer across sibling workers):

pdd split pdd/big_worker.py --intent=reuse

Legacy Mode:

pdd [GLOBAL OPTIONS] split --legacy [OPTIONS] INPUT_PROMPT INPUT_CODE EXAMPLE_CODE

Arguments:

  • INPUT_PROMPT: The filename of the large prompt file to be split.
  • INPUT_CODE: The filename of the code generated from the input prompt.
  • EXAMPLE_CODE: The filename of the example code that serves as the interface to the sub-module prompt file.

Options:

  • --output-sub LOCATION: Specify where to save the generated sub-prompt file. The default file name is sub_<basename>.prompt. If an environment variable PDD_SPLIT_SUB_PROMPT_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --output-modified LOCATION: Specify where to save the modified prompt file. The default file name is modified_<basename>.prompt. If an environment variable PDD_SPLIT_MODIFIED_PROMPT_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --legacy: Use the legacy 2-LLM-call splitting path. When omitted, split() acts as the prompt-splitting primitive for the agentic split orchestrator. This flag is kept for one release for backward compatibility.

Example (legacy mode):

pdd [GLOBAL OPTIONS] split --legacy --output-sub prompts/sub_data_processing.prompt --output-modified prompts/modified_main_pipeline.prompt data_processing_pipeline_python.prompt src/data_pipeline.py examples/pipeline_interface.py

8. change

Implement a change request from a GitHub issue using a 13-step agentic workflow. The workflow researches the feature, ensures requirements are clear (asking clarifying questions if needed), reviews architecture (asking for decisions if needed), analyzes documentation changes, identifies affected dev units, designs prompt modifications, implements them, runs a review loop to identify and fix issues, and creates a PR.

Do not use pdd change as the first step for a reported runtime defect. If an issue says "the prompt should be updated because the generated CLI crashes" or includes a stack trace, failing command, wrong runtime output, or regression, start with pdd bug <issue-url> and then run pdd fix <issue-url>. pdd change is for source-truth/spec/product changes that do not require reproducing a current failure.

Agentic Mode (default):

pdd [GLOBAL OPTIONS] change GITHUB_ISSUE_URL

Arguments:

  • GITHUB_ISSUE_URL: The URL of the GitHub issue describing the change request.

The 13-step workflow:

  1. Duplicate Check: Search for duplicate issues
  2. Documentation Check: Verify feature isn't already implemented
  3. Research: Web search to clarify specifications and find best practices
  4. Clarification: Ensure requirements are clear; ask questions with options if not (stops workflow until answered)
  5. Documentation Changes: Analyze what documentation updates are needed (including associated documents discovered via the prompt <include> graph)
  6. Identify Dev Units: Find affected prompts, code, examples, and tests
  7. Architecture Review: Identify architectural decisions; ask questions with options if needed (stops workflow until answered)
  8. Analyze Changes: Design prompt modifications
  9. Implement Changes: Modify prompts in an isolated git worktree, atomically apply drafted associated-document edits, and emit MANUAL_REVIEW: lines for conflicts that cannot be auto-resolved
  10. Architecture & Doc Sync: Update architecture.json metadata and synchronize associated documents (verified by the doc-sync contract; see Step 10.5)
  11. Identify Issues: Review changes for problems (part of review loop)
  12. Fix Issues: Fix identified issues (part of review loop, max 5 iterations) 12.5. Pre-PR Build/Smoke Gate (issue #1293): Before creating the PR, run the same shared pre-checkup gate the fix path uses. It first drift-syncs code ↔ prompt ↔ architecture.json.pdd/meta in the worktree (largely a no-op here since Step 8.5/10 already healed prompt + architecture drift; .pdd/meta finalization is completed canonically by the post-merge sync, see #1317), then runs a blocking build/smoke pass over the changed files — compile touched files, import changed modules, probe changed router/app modules for route/router objects (a non-blocking note, not a hard block — best-effort app-wiring smoke that stays with checkup), lint, caller-compatibility sweep, and targeted unit tests by git-diff (Python tests are executed under a hardened, credential-free env; a changed JS/TS test is reported, not run) — so the change/feature PR enters checkup --pr already building and wired. A red gate blocks PR creation in both default and strict mode (issue #1293: "block — don't hand off to checkup until green"); it does not create the PR and surface the findings for later review
  13. Create PR: Create a pull request linking to the issue and surface any unresolved MANUAL_REVIEW: flags in the PR body

Workflow Resumption: Steps 4 and 7 may pause the workflow to ask clarifying or architectural questions. When this happens, answer the questions in the GitHub issue and run pdd change again. The workflow will resume from where it left off, skipping already-completed steps to save tokens.

Cross-Machine Resume: By default, workflow state is stored in a hidden comment on the GitHub issue, enabling resume from any machine. If you start the workflow on machine A, you can continue from machine B by checking out the branch and running pdd change again. Use --no-github-state to disable this feature and use local-only state persistence. You can also set the PDD_NO_GITHUB_STATE=1 environment variable to disable GitHub state globally.

Clean Restart (--clean-restart, issue #1149): For pdd change, discards any persisted solving state for the issue and runs a fresh 13-step pdd-issue flow from the default base branch, ignoring any previously generated change/issue-N branch or PR. Use when recovering from a stopped or wrong-model run (e.g. you cancelled a Gemini-based run and want to rerun cleanly under Opus on the same issue). The orchestrator posts a ## Step 0/13: Workflow Startup comment on the issue naming the mode, model, base branch, and command so reviewers can tell at a glance whether a run is resuming or clean-starting. The same restart intent is also available for pdd bug, pdd test, and pdd fix agentic GitHub issue workflows. If the standard issue branch ({command}/issue-N) is checked out in another local worktree (e.g. a concurrent runner), the clean restart does not fail: it prunes stale worktree registrations and, if the branch is still genuinely locked, creates a fresh unique fallback branch ({command}/issue-N-job-<id>) from the base branch, pushes and opens/updates the PR on that branch, and leaves the locked worktree untouched. Cannot be combined with --manual.

Review Loop: Steps 11-12 form a review loop that identifies and fixes issues iteratively. The loop runs until no issues are found (max 5 iterations).

Worktree Branching Behavior: When running pdd change, pdd bug, or pdd split, a new git worktree is created based on your current HEAD:

  • From main/master: Branch is based on latest main - creates independent PR
  • From feature branch: Branch inherits commits from that branch - useful for stacked/dependent PRs

If you want independent changes, run the command from the main branch. A warning will be displayed when running from a non-main branch.

Example (agentic mode):

pdd change https://github.com/myorg/myrepo/issues/239

After the workflow completes, a PR is automatically created linking to the issue. The PR includes a sync_order.sh script that runs pdd sync commands in dependency order. Review the PR and run ./sync_order.sh after merge to regenerate code.

Manual Mode (legacy):

pdd [GLOBAL OPTIONS] change --manual [OPTIONS] CHANGE_PROMPT_FILE INPUT_CODE INPUT_PROMPT_FILE

Arguments:

  • CHANGE_PROMPT_FILE: The filename containing the instructions on how to modify the input prompt file.
  • INPUT_CODE: The filename of the code that was generated from the input prompt file, or the directory containing the code files when used with the '--csv' option.
  • INPUT_PROMPT_FILE: The filename of the prompt file that will be modified. Required in standard mode; not used when using the '--csv' option.

Options:

  • --budget FLOAT: Set the maximum cost allowed for the change process (default is $5.0).
  • --output LOCATION: Specify where to save the modified prompt file. The default file name is modified_<basename>.prompt. If an environment variable PDD_CHANGE_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --csv: Use a CSV file for the change prompts instead of a single change prompt file. The CSV file should have columns: prompt_name and change_instructions. When this option is used, INPUT_PROMPT_FILE is not needed, and INPUT_CODE should be the directory where the code files are located. The command expects prompt names in the CSV to follow the <basename>_<language>.prompt convention. For each prompt_name, it derives the corresponding code file (for example, <basename>.<language_extension>) under the specified INPUT_CODE directory. If the prompt is in a prompt-root subdirectory such as prompts/pkg/widget_python.prompt or pdd/prompts/pkg/widget_python.prompt, CSV mode first strips the prompt root and looks for INPUT_CODE/pkg/widget.py, then falls back to the preserved-subpath and historical flat lookups. Code lookup is constrained to remain inside the resolved INPUT_CODE directory, including symlink targets. Output files will overwrite existing files unless --output LOCATION is specified. If LOCATION is a directory, the modified prompt files will be saved inside this directory using the default naming convention otherwise, if a csv filename is specified the modified prompts will be saved in that CSV file with columns 'prompt_name' and 'modified_prompt'.

Example (manual single prompt change):

pdd [GLOBAL OPTIONS] change --manual --output modified_factorial_calculator_python.prompt changes_factorial.prompt src/factorial_calculator.py factorial_calculator_python.prompt

Example (manual batch change using CSV):

pdd [GLOBAL OPTIONS] change --manual --csv --output modified_prompts/ changes_batch.csv src/

9. update

Update prompts based on code changes. This command operates in two primary modes:

Agentic Prompt Optimization (Default)

The update command uses an agentic AI (Claude Code, Gemini/Antigravity, Codex, or OpenCode) by default to produce compact, high-quality prompts. The agent has full file access and performs a 4-step optimization:

  1. Assess Differences: Reads the prompt (including all <include> files) and compares against the modified code
  2. Filter Using Guide + Tests: Consults docs/prompting_guide.md and existing tests to determine what belongs in the prompt
  3. Remove Duplication: Eliminates redundant content that duplicates included files
  4. Validate: Ensures the prompt is human-readable and can reliably regenerate the code

This produces prompts that are more concise while remaining clear to developers and reliable for code generation.

Prerequisites: Requires one of these CLI tools installed and configured:

  • claude (Anthropic Claude Code)
  • agy (Google Antigravity CLI, preferred for Google provider) or gemini (legacy Google Gemini CLI, rollback)
  • codex (OpenAI Codex CLI)
  • opencode (OpenCode CLI)

If no agentic CLI is available, the command automatically falls back to the legacy 2-stage LLM update process.

Test-Aware Updates: When tests exist for a module (e.g., test_my_module.py, test_my_module_1.py), the agentic update automatically discovers and considers them. Behaviors verified by tests don't need to be explicitly specified in the prompt, resulting in more compact prompts.

Modes:

  1. Repository-Wide Mode (Default): When run with no file arguments, pdd update scans the entire repository. It finds all code/prompt pairs, creates any missing prompt files, and updates all of them based on the latest Git changes. This is the easiest way to keep your entire project in sync.

  2. Single-File Mode: When you provide file arguments, the command operates on a specific file. There are three distinct use cases for this mode:

    A) Prompt Generation / Regeneration To generate a brand new prompt for a code file from scratch, or to regenerate an existing prompt, simply provide the path to that code file. This will create a new prompt file or overwrite an existing one.

    pdd update <path/to/your_code_file.py>
    

    B) Prompt Update (using Git) To update an existing prompt by comparing the modified code against the version in your last commit. This requires the prompt file and the modified code file.

    pdd update --git <path/to/prompt.prompt> <path/to/modified_code.py>
    

    C) Prompt Update (Manual) To update an existing prompt by manually providing the original code, the modified code, and the prompt. This is for scenarios where Git history is not available or desired.

    pdd update <path/to/prompt.prompt> <path/to/modified_code.py> <path/to/original_code.py>
    
# Repository-Wide Mode (no arguments)
pdd [GLOBAL OPTIONS] update

# Single-File Mode: Examples
# Generate/Regenerate a prompt for a code file
pdd [GLOBAL OPTIONS] update src/my_new_module.py

# Update an existing prompt using Git history
pdd [GLOBAL OPTIONS] update --git factorial_calculator_python.prompt src/modified_factorial_calculator.py

# Update an existing prompt by manually providing original code
pdd [GLOBAL OPTIONS] update factorial_calculator_python.prompt src/modified_factorial_calculator.py src/original_factorial_calculator.py

# Repository-wide update filtered by extension
pdd [GLOBAL OPTIONS] update --extensions py,js

Arguments:

  • MODIFIED_CODE_FILE: The filename of the code that was modified or for which a prompt should be generated/regenerated.
  • INPUT_PROMPT_FILE: (Optional) The filename of the prompt file that generated the original code. Required for true update scenarios (B and C).
  • INPUT_CODE_FILE: (Optional) The filename of the original code. Required for manual update (C), not required when using --git (B), and not applicable for generation (A).

Important: By default, this command overwrites the original prompt file to maintain the core PDD principle of "prompts as source of truth."

Options:

  • --output LOCATION: Specify where to save the updated prompt file. If not specified, the original prompt file is overwritten to maintain it as the authoritative source of truth. If an environment variable PDD_UPDATE_OUTPUT_PATH is set, it will be used only when --output is explicitly omitted and you want a different default location.
  • --git: Use git history to find the original code file, eliminating the need for the INPUT_CODE_FILE argument.
  • --extensions EXTENSIONS: In repository-wide mode, filter the update to only include files with the specified comma-separated extensions (e.g., py,js,ts).
  • --simple: Use the legacy 2-stage LLM update process instead of the default agentic mode. Useful when agentic CLIs are not available or for faster updates.
  • --sync-metadata: After the prompt update, run the shared metadata-sync orchestrator so prompt PDD tags, architecture.json entries, run reports, and fingerprint state are reconciled in one step. Works in single-file, regeneration, and repo modes. Fingerprint note: without this flag, every successful single-file/regeneration update and every successful --repo pair finalizes through the shared FingerprintTransaction path. The command first resolves the complete unit path set, clears the affected stale _run.json, verifies it is gone, and atomically writes the new fingerprint. Identity, cleanup, hashing, or persistence failure is a hard non-zero command failure; the update cannot return a false-green success tuple after mutating an artifact. With --sync-metadata, the orchestrator owns that fingerprint stage, so the default finalizer intentionally skips instead of double-writing. The stale-report warning still surfaces under --quiet because it describes a real consistency failure. Without this flag, the broader prompt-tag/architecture stages are not run and must be reconciled separately. Scope note: the tags stage currently preserves existing PDD tags and only seeds tags from the matching architecture.json entry when a prompt has none — LLM-first refresh of stale-but-present tags is tracked at issue #870 and is not invoked by this orchestrator. When a prompt has zero PDD tags AND no architecture entry, the tags stage reports skipped (never ok) so operators see honest status. On any stage failed, pdd update --sync-metadata exits non-zero so CI auto-heal does not treat a half-finalized update as healed.

Example (Metadata Sync):

# Update a single prompt and reconcile metadata (preserve/seed tags,
# architecture entry, run reports, fingerprint) in one step
pdd update --sync-metadata src/my_module.py

# Repo-wide update with metadata sync — each updated pair is finalized via the shared orchestrator
pdd update --sync-metadata

When --sync-metadata is enabled, the summary table shows a metadata column with one of:

  • synced — every metadata stage wrote successfully.
  • partial:<stage> — orchestration succeeded but one or more stages were skipped (for example, the prompt is not registered in architecture.json); the first skipped stage is named.
  • failed:<stage> — a stage hit a hard failure; the failing stage is named.
  • skipped — the orchestrator did not run for this pair (e.g. the pair was unchanged or the per-pair call returned no result).
  • dry-run — the call was made with dry_run=True; no on-disk state was written.

If any layer is incomplete, the relevant stage is named explicitly so it is obvious whether tags, architecture, run reports, or the fingerprint is the unresolved gap.

Example (overwrite original prompt - default behavior):

pdd [GLOBAL OPTIONS] update factorial_calculator_python.prompt src/modified_factorial_calculator.py src/original_factorial_calculator.py
# This overwrites factorial_calculator_python.prompt in place

Example (agentic vs simple mode):

# Default: Agentic mode (uses claude/agy/gemini/codex/opencode for intelligent optimization)
pdd update --git my_module_python.prompt src/my_module.py

# Legacy: Simple 2-stage LLM update (faster, no agentic CLI required)
pdd update --simple --git my_module_python.prompt src/my_module.py

10. detect

Analyze a list of prompt files and a change description to determine which prompts need t

Truncated — view the full README on GitHub.

Contributors

gltanaka

898 commits

Serhan-Asad

678 commits

DianaTao

528 commits

sohni-tagirisa

380 commits

promptdriven/pdd

Prompt Driven Development (PDD): The Last Programming Language™. Prompt files are source; code is generated output.

863

stars

3,165

commits

Python

primary language

Aug 24, 2026

updated

promptdriven.ai
ai
cli
code
developer-tools
development
methodology
prompt
prompt-engineering
prompts
prompts-template
prompt-toolkit
Browse cluster: LLM Prompt Injection Security

README

PDD: The Last Programming Language™

PyPI version Discord

Introduction

PDD (Prompt-Driven Development) is a prompt-native programming system. .prompt files are the human-authored source language; Python, TypeScript, Go, and other traditional languages are generated artifacts.

PDD is the last programming language in this specific sense: developers author durable intent, constraints, examples, and tests, then compile that source into whatever implementation language the project needs. Code remains real and reviewable, but it is no longer the primary source of truth.

Getting started is simple:

# Install and run
uv tool install pdd-cli
pdd setup
pdd connect

This launches a web interface at localhost:9876 where you can:

  • Implement GitHub issues automatically
  • Generate and test code from prompts
  • Manage your PDD projects visually

PDD Handpaint Demo

For CLI users, PDD also offers powerful agentic commands that implement GitHub issues automatically:

  • pdd change <issue-url> - Implement feature requests (13-step workflow)
  • pdd bug <issue-url> - Create failing tests for bugs
  • pdd fix <issue-url> - Fix the failing tests
  • pdd split <target-file> - Diagnose and split large dev units (15-step workflow with intent classification, diagnosis, phase extraction, per-child verify gate, and repair)
  • pdd generate <issue-url> - Generate architecture.json from a PRD issue (11-step workflow)
  • pdd test <issue-url> - Generate UI tests from issue descriptions (18-step workflow with exploratory testing, contract validation, accessibility audits)

Choose pdd bug before pdd change when an issue reports a current runtime symptom, even if it says the prompt or spec should be updated. Stack traces, failing commands, wrong CLI/API/UI output, regressions, crashes, and incorrect generated behavior should run through pdd bug <issue-url> followed by pdd fix <issue-url> (bug → fix) so the failure is reproduced and covered by a behavioral test. Use pdd change for explicit source-truth/spec/product changes with no current runtime failure to reproduce (change → sync after the source-truth change lands).

For prompt-based workflows, the sync command automates the complete development cycle with intelligent decision-making, real-time visual feedback, and sophisticated state management.

Whitepaper

For the positioning essay behind this shift, read The Last Programming Language.

For a detailed explanation of the concepts, architecture, and benefits of Prompt-Driven Development, please refer to our full whitepaper. This document provides an in-depth look at the PDD philosophy, its advantages over traditional development, and includes benchmarks and case studies.

Read the Full Whitepaper with Benchmarks

For a case study on specification drift in AI-assisted coding workflows, read Why AI Code Falls Apart.

Also see the Prompt‑Driven Development Doctrine for core principles and practices: docs/prompt-driven-development-doctrine.md

For a step-by-step methodology on turning a GitHub issue into a durable, human-verified user story, see docs/generating_user_stories.md.

For pre-merge prompt and user-story quality (vague terms, vocabulary, optional LLM review), see docs/prompt_lint.md.

For deterministic contract-section lint (<contract_rules>, <coverage>, waivers, story ## Covers), see docs/contract_check.md.

For a rule-to-story/test coverage matrix (pdd checkup coverage), including the @pytest.mark.story regression marker and the per-story has_regression_test dimension, see docs/coverage_contracts.md and docs/generating_user_stories.md.

For non-interactive bounded prompt repair after a failed prompt source-set checkup, see docs/prompt_repair.md.

For the deterministic prompt source-set quality gate and its pdd.prompt_source_set_report.v1 JSON schema (including the per-finding requires_clarification / clarification_reason clarification signal), see docs/checkup_prompt_quality_gate.md.

For the agentic CLI routing policy (task-class-keyed static config table and bounded escalation ladder for run_agentic_task), see docs/routing_policy.md.

Installation

Prerequisites for macOS

On macOS, you'll need to install some prerequisites before installing PDD:

  1. Install Xcode Command Line Tools (required for Python compilation):

    xcode-select --install
    
  2. Install Homebrew (recommended package manager for macOS):

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    

    After installation, add Homebrew to your PATH:

    echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile && eval "$(/opt/homebrew/bin/brew shellenv)"
    
  3. Install Python (if not already installed):

    # Check if Python is installed
    python3 --version
    
    # If Python is not found, install it via Homebrew
    brew install python
    

    Note: Recent versions of macOS no longer ship with Python pre-installed. PDD requires Python 3.12 or higher. The brew install python command installs the latest Python 3 version.

We recommend installing PDD using the uv package manager for better dependency management and automatic environment configuration:

# Install uv if you haven't already 
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install PDD using uv tool install
uv tool install pdd-cli

This installation method ensures:

  • Faster installations with optimized dependency resolution
  • Automatic environment setup without manual configuration
  • Proper handling of the PDD_PATH environment variable
  • Better isolation from other Python packages

The PDD CLI will be available immediately after installation without requiring any additional environment configuration.

Verify installation:

pdd --version

With the CLI on your PATH, continue with:

pdd setup

The command detects agentic CLI tools, scans for API keys, configures models, and seeds local configuration files. If you postpone this step, the CLI detects the missing setup artifacts the first time you run another command and shows a reminder banner so you can complete it later (the banner is suppressed once ~/.pdd/api-env exists or when your project already provides credentials via .env or .pdd/).

Alternative: pip Installation

If you prefer using pip, you can install PDD with:

pip install pdd-cli

Advanced Installation Options

Virtual Environment Installation

# Create virtual environment
python -m venv pdd-env

# Activate environment
# On Windows:
pdd-env\Scripts\activate
# On Unix/MacOS:
source pdd-env/bin/activate

# Install PDD
pip install pdd-cli

Getting Started

The easiest way to use PDD is through the web interface:

# 1. Install PDD
curl -LsSf https://astral.sh/uv/install.sh | sh
uv tool install pdd-cli

# 2. Run setup (API keys, shell completion)
pdd setup

# 3. Launch the web interface
pdd connect

This opens a browser-based interface where you can:

  • Run Commands: Execute pdd change, pdd bug, pdd fix, pdd sync etc. visually
  • Browse Files: View and edit prompts, code, and tests in your project
  • Remote Access: Access your session from any browser via PDD Cloud (use --local-only to disable)

Option 2: Issue-Driven CLI

For CLI enthusiasts, implement GitHub issues directly:

Prerequisites:

  1. GitHub CLI - Required for issue access:

    brew install gh && gh auth login
    
  2. One Agentic CLI - Required to run the workflows (install at least one):

    • Claude Code: npm install -g @anthropic-ai/claude-code (uses your stored Claude Max/Pro OAuth login if you've run claude auth login, otherwise falls back to ANTHROPIC_API_KEY; pdd auto-prefers OAuth — set PDD_KEEP_ANTHROPIC_API_KEY=1 to force API-key billing)
    • Antigravity CLI (agy, preferred): install via curl -fsSL https://antigravity.google/cli/install.sh | bash (uses Antigravity OAuth or keyring-backed Google subscription sign-in if present, otherwise ANTIGRAVITY_API_KEY/GOOGLE_API_KEY, Vertex AI env auth, or PDD's compatibility bridge from GEMINI_API_KEY). Set PDD_AGENTIC_PROVIDER=antigravity to pin the Antigravity binary, or PDD_GOOGLE_CLI=agy|gemini|auto to control binary selection (auto prefers agy when credentialed, but keeps legacy gemini for legacy-OAuth-only setups).
    • Gemini CLI (legacy, rollback): npm install -g @google/gemini-cli (uses ~/.gemini OAuth credentials if present, otherwise GOOGLE_API_KEY or GEMINI_API_KEY). Google announced consumer-tier Gemini CLI cutoff on 2026-06-18; set PDD_GOOGLE_CLI=gemini only when you intentionally need the old binary.
    • Codex CLI: npm install -g @openai/codex@latest (GPT-5.6 requires Codex CLI 0.144.0 or newer; uses ~/.codex/auth.json ChatGPT login if present, otherwise OPENAI_API_KEY)
    • OpenCode CLI: npm install -g opencode-ai (uses OpenCode provider auth from opencode auth login, ~/.config/opencode/opencode.json, project opencode.json, or provider env vars; set OPENCODE_MODEL=provider/model)

Usage:

# Implement a feature request
pdd change https://github.com/owner/repo/issues/123

# Or fix a bug
pdd bug https://github.com/owner/repo/issues/456
pdd fix https://github.com/owner/repo/issues/456

Option 3: Manual Prompt Workflow

For learning PDD fundamentals or working with existing prompt files:

cd your-project
pdd sync module_name  # Full automated workflow

See the Hello Example below for a step-by-step introduction.


🚀 Quickstart (Hello Example)

If you want to understand PDD fundamentals, follow this manual example to see it in action.

  1. Install prerequisites (macOS/Linux):

    xcode-select --install      # macOS only
    curl -LsSf https://astral.sh/uv/install.sh | sh
    uv tool install pdd-cli
    pdd --version
    
  2. Clone repo

      # Clone the repository (if not already done)
     git clone https://github.com/promptdriven/pdd.git
     cd pdd/examples/hello
    
  3. Set one API key (choose your provider):

    export GEMINI_API_KEY="your-gemini-key"
    # OR
    export OPENAI_API_KEY="your-openai-key"
    

Post-Installation Setup (Required first step after installation)

Run the comprehensive setup wizard:

pdd setup

The setup wizard runs these steps:

  1. Detects agentic CLI tools (Claude, Gemini/Antigravity, Codex, OpenCode) and offers installation and credential configuration if needed. Credentials can be environment-variable API keys, stored OAuth/subscription/config credentials such as Claude Max/Pro, Google Gemini/Antigravity login, Vertex AI env auth, Codex ChatGPT login, or OpenCode provider auth/config.
  2. Scans for API keys across .env, ~/.pdd/api-env.*, and the shell environment. If no API key is found but a selected CLI already has a stored OAuth/subscription/config credential, setup skips the API-key prompt for the agentic workflow and explains which direct prompt/LiteLLM commands still need API keys.
  3. Configures models from a reference CSV data/llm_model.csv of top ranked models across all LiteLLM-supported providers based on your available API keys
  4. If you have credentials for more than one provider, asks which provider(s) pdd --local should use, then removes the unselected providers' PDD-managed rows from ~/.pdd/llm_model.csv (rows you hand-edited or added yourself are preserved — see below)
  5. Optionally creates a .pddrc project config
  6. Tests a model from your selected provider with a real LLM call
  7. Prints a structured summary (CLIs, keys, models, test result)

The wizard can be re-run at any time to update keys, add providers, or reconfigure settings.

Choosing your local provider

pdd --local selects a model from ~/.pdd/llm_model.csv by cost/ranking, so if the file lists several providers it can route to one you didn't intend — for example a free GitHub Copilot login outranking a GEMINI_API_KEY you set on purpose. To prevent that, when setup ends up with more than one usable provider — which includes always-available device-login providers like GitHub Copilot, so the prompt can appear even if you only set a single API key — it asks you to pick which provider(s) to keep, then removes the unselected providers' PDD-managed rows (rows you hand-edited or added yourself are preserved):

  • Default selection excludes device-login providers (e.g. GitHub Copilot, which needs no API key) so a free login never silently outranks a key you configured. Select them explicitly to keep them.
  • Local models (Ollama, LM Studio) and any hand-edited/custom rows for providers you don't configure are never offered for removal and are left untouched.
  • Before removing any rows, setup lists exactly what will be removed and asks you to confirm, and snapshots the previous file to ~/.pdd/llm_model.csv.backup.<timestamp> so the change is always reversible.
  • Your choice is saved to ~/.pdd/setup_preferences.json. Re-running setup re-uses it without re-asking and without re-adding the providers you dropped (so a later run stays quiet — no repeated prompt, no Copilot churn). It only adds new models for the providers you already chose.

To use a different provider later, delete ~/.pdd/setup_preferences.json and re-run pdd setup to pick a new selection (or edit ~/.pdd/llm_model.csv directly). Adding a provider through the setup options menu also updates your saved selection.

Important: After setup completes, source the API environment file so your keys take effect in the current terminal session:

source ~/.pdd/api-env.zsh   # or api-env.bash, depending on your shell

New terminal windows will load keys automatically.

If you skip this step, the first regular pdd command you run will detect the missing setup files and print a reminder banner so you can finish onboarding later.

  1. Run Hello:

    cd ../hello
    pdd --force generate hello_python.prompt
    python3 hello.py
    

    ✅ Expected output:

    hello
    

Cloud vs Local Execution

PDD commands can be run either in the cloud or locally. By default, all commands run in the cloud mode, which provides several advantages:

  • No need to manage API keys locally
  • Access to more powerful models
  • Shared examples and improvements across the PDD community
  • Automatic updates and improvements
  • Better cost optimization

Cloud Authentication

When running in cloud mode (default), PDD uses GitHub Single Sign-On (SSO) for authentication. On first use, you'll be prompted to authenticate:

  1. PDD will open your default browser to the GitHub login page
  2. Log in with your GitHub account
  3. Authorize PDD Cloud to access your GitHub profile
  4. Once authenticated, you can return to your terminal to continue using PDD

The authentication token is securely stored locally and automatically refreshed as needed.

Local Mode Requirements

When running in local mode with the --local flag, you'll need to set up API keys for the language models:

# For OpenAI
export OPENAI_API_KEY=your_api_key_here

# For Anthropic
export ANTHROPIC_API_KEY=your_api_key_here

# For other supported providers (LiteLLM supports multiple LLM providers)
export PROVIDER_API_KEY=your_api_key_here

Some local-mode providers do not use API keys. GitHub Copilot models authenticate through LiteLLM's OAuth device flow; run pdd setup, then choose Add a provider from the options menu and pick GitHub Copilot to complete that device login. (The provider-selection prompt described above only decides which already-configured providers pdd --local uses — it does not perform the OAuth login.)

Add these to your .bashrc, .zshrc, or equivalent for persistence.

PDD's local mode uses the packaged LiteLLM dependency (>=1.84.0,<1.85 in this release) for interacting with language models, providing:

  • Support for multiple model providers (OpenAI, Anthropic, Google/Vertex AI, and more)
  • Automatic model selection based on strength settings
  • Response caching for improved performance
  • Smart token usage tracking and cost estimation
  • Interactive API key acquisition when keys are missing

When keys are missing, PDD will prompt for them interactively and securely store them in your local .env file.

Local Model Configuration

PDD uses a CSV file to configure model selection and capabilities. This configuration is loaded from:

  1. User-specific configuration: ~/.pdd/llm_model.csv (takes precedence if it exists)
  2. Project-specific configuration: <PROJECT_ROOT>/.pdd/llm_model.csv
  3. Package default: Bundled with PDD installation (fallback when no local configurations exist)

The CSV includes columns for:

  • provider: The LLM provider (e.g., "openai", "anthropic", "google")
  • model: The LiteLLM model identifier (e.g., "gpt-4", "claude-3-opus-20240229")
  • input/output: Costs per million tokens
  • coding_arena_elo: Raw Arena/static ELO metadata
  • model_rank_score: Primary selection rank. DeepSWE rows use a high solve-rate band; Arena/static rows fall back to raw ELO.
  • model_rank_source: Source of model_rank_score (for example deepswe-solve-rate, arena-elo-fallback, or static)
  • api_key: The environment variable name for required authentication, or blank for local and device-flow providers such as Ollama, LM Studio, and GitHub Copilot
  • structured_output: Whether the model supports structured JSON output
  • reasoning_type: Support for reasoning capabilities ("none", "budget", "effort", or "adaptive")

For a concrete, up-to-date reference of supported models and example rows, see the bundled CSV in this repository: pdd/data/llm_model.csv.

For proper model identifiers to use in your custom configuration, refer to the LiteLLM Model List documentation. LiteLLM typically uses model identifiers in the format provider/model_name (e.g., "openai/gpt-4", "anthropic/claude-3-opus-20240229").

Z.AI (GLM Models)

PDD supports two Z.AI API endpoints:

  • General API (https://api.z.ai/api/paas/v4) — standard prepaid/resource billing, suitable for general use.
  • GLM Coding Plan (https://api.z.ai/api/coding/paas/v4) — quota-backed subscription plan designed for coding workflows. Diagnostics show it as quota-backed rather than a per-token dollar estimate.

Both endpoints use the same API key. To use the bundled GLM Coding Plan rows:

export ZAI_API_KEY=your_zai_api_key_here
export PDD_MODEL_DEFAULT=glm-5.2

Or in your .pddrc:

defaults:
  model: glm-5.2

The bundled catalog includes rows for Z.AI (general API) and Z.AI Coding Plan providers. PDD stores these rows as OpenAI-compatible openai/glm-5.2 model strings with explicit base_url values, and resolves a bare user default such as glm-5.2 to the quota-backed Coding Plan row instead of falling through to an unrelated provider.

To target the per-token General API endpoint (https://api.z.ai/api/paas/v4) instead of the Coding Plan endpoint, select the explicit OpenAI-compatible row:

export ZAI_API_KEY=your_zai_api_key_here
export PDD_MODEL_DEFAULT=openai/glm-5.2

Structured-output forcing is disabled for Z.AI rows until Z.AI schema support is verified; reasoning_effort is enabled through PDD's normal low/medium/high effort mapping.

Run pdd setup with ZAI_API_KEY set to have PDD detect Z.AI and include it in the provider configuration.

Troubleshooting Common Installation Issues

  1. Command not found

    # Add to PATH if needed
    export PATH="$HOME/.local/bin:$PATH"
    
  2. Permission errors

    # Install with user permissions
    pip install --user pdd-cli
    
  3. macOS-specific issues

    • Xcode Command Line Tools not found: Run xcode-select --install to install the required development tools
    • Homebrew not found: Install Homebrew using the command in the prerequisites section above
    • Python not found or wrong version: Install Python 3 via Homebrew: brew install python
    • Permission denied during compilation: Ensure Xcode Command Line Tools are properly installed and you have write permissions to the installation directory
    • uv installation fails: Try installing uv through Homebrew: brew install uv
    • Python version conflicts: If you have multiple Python versions, ensure python3 points to Python 3.12+: which python3 && python3 --version

Version

To check your installed version, run:

pdd --version

PDD includes an auto-update feature to ensure you always have access to the latest features and security patches. You can control this behavior using an environment variable (see "Auto-Update Control" section below).

Supported Programming Languages

PDD supports a wide range of programming languages, including but not limited to:

  • Python
  • JavaScript
  • TypeScript
  • Java
  • C++
  • Ruby
  • Go

The specific language is often determined by the prompt file's naming convention or specified in the command options.

Prompt File Naming Convention

Prompt files in PDD commonly follow one of these formats:

<basename>_<language>.prompt

or, for architecture-driven projects with nested output paths:

<path/to/output_stem>_<Language>.prompt

Where:

  • <basename> is the base name of the file or project in legacy flat layouts
  • <path/to/output_stem> mirrors the output filepath without its extension in architecture-driven layouts
  • <language> / <Language> is the programming language or prompt context suffix used by the project

Examples:

  • factorial_calculator_python.prompt (basename: factorial_calculator, language: python)
  • responsive_layout_css.prompt (basename: responsive_layout, language: css)
  • data_processing_pipeline_python.prompt (basename: data_processing_pipeline, language: python)
  • src/models/user_Python.prompt → generates src/models/user.py
  • app/api/orders/route_TypeScript.prompt → generates app/api/orders/route.ts

PDD supports both conventions. Legacy hand-written prompts are often flat, while prompts generated from architecture.json typically mirror the target filepath directory structure.

Prompt-Driven Development Philosophy

Core Concepts

Prompt-Driven Development (PDD) inverts traditional software development by treating prompts as the primary artifact - not code. This paradigm shift has profound implications:

  1. Prompts as Source of Truth: In traditional development, source code is the ground truth that defines system behavior. In PDD, the prompts are authoritative, with code being a generated artifact.

  2. Natural Language Over Code: Prompts are written primarily in natural language, making them more accessible to non-programmers and clearer in expressing intent.

  3. Regenerative Development: When changes are needed, you modify the prompt and regenerate code, rather than directly editing the code. This maintains the conceptual integrity between requirements and implementation.

  4. Intent Preservation: Prompts capture the "why" behind code in addition to the "what" - preserving design rationale in a way that comments often fail to do.

Mental Model

To work effectively with PDD, adopt these mental shifts:

  1. Prompt-First Thinking: Always start by defining what you want in a prompt before generating any code.

  2. Bidirectional Flow:

    • Prompt → Code: The primary direction (generation)
    • Code → Prompt: Secondary but crucial (keeping prompts in sync with code changes)
  3. Modular Prompts: Just as you modularize code, you should modularize prompts into self-contained units that can be composed.

  4. Integration via Examples: Modules integrate through their examples, which serve as interfaces, allowing for token-efficient references.

PDD Workflows: Conceptual Understanding

Each workflow in PDD addresses a fundamental development need:

  1. Initial Development Workflow

    • Purpose: Creating functionality from scratch
    • Conceptual Flow: Define dependencies → Generate implementation → Create interfaces → Ensure runtime functionality → Verify correctness

    This workflow embodies the prompt-to-code pipeline, moving from concept to tested implementation.

  2. Code-to-Prompt Update Workflow

    • Purpose: Maintaining prompt as source of truth when code changes
    • Conceptual Flow: Sync code changes to prompt → Identify impacts → Propagate changes

    This workflow ensures the information flow from code back to prompts, preserving prompts as the source of truth.

  3. Debugging Workflows

    • Purpose: Resolving different types of issues
    • Conceptual Types:
      • Context Issues: Addressing misunderstandings in prompt interpretation
      • Runtime Issues: Fixing execution failures
      • Logical Issues: Correcting incorrect behavior
      • Traceability Issues: Connecting code problems back to prompt sections

    These workflows recognize that different errors require different resolution approaches.

  4. Refactoring Workflow

    • Purpose: Improving prompt organization and reusability
    • Conceptual Flow: Extract functionality → Ensure dependencies → Create interfaces

    This workflow parallels code refactoring but operates at the prompt level.

  5. Multi-Prompt Architecture Workflow

    • Purpose: Coordinating systems with multiple prompts
    • Conceptual Flow: Detect conflicts → Resolve incompatibilities → Regenerate code → Update interfaces → Verify system

    This workflow addresses the complexity of managing multiple interdependent prompts.

  6. Enhancement Phase: Use Feature Enhancement when adding capabilities to existing modules.

Workflow Selection Principles

The choice of workflow should be guided by your current development phase:

  1. Creation Phase: Use Initial Development when building new functionality.

  2. Maintenance Phase: Use Code-to-Prompt Update when existing code changes.

  3. Problem-Solving Phase: Choose the appropriate Debugging workflow based on the issue type:

    • Preprocess → Generate for prompt interpretation issues
    • Crash for runtime errors
    • Bug → Fix for logical errors
    • Trace for locating problematic prompt sections
  4. Restructuring Phase: Use Refactoring when prompts grow too large or complex.

  5. System Design Phase: Use Multi-Prompt Architecture when coordinating multiple components.

  6. Enhancement Phase: Use Feature Enhancement when adding capabilities to existing modules.

PDD Design Patterns

Effective PDD employs these recurring patterns:

  1. Dependency Injection via Auto-deps: Automatically including relevant dependencies in prompts.

  2. Interface Extraction via Example: Creating minimal reference implementations for reuse.

  3. Bidirectional Traceability: Maintaining connections between prompt sections and generated code.

  4. Test-Driven Prompt Fixing: Using tests to guide prompt improvements when fixing issues.

  5. Hierarchical Prompt Organization: Structuring prompts from high-level architecture to detailed implementations.

Basic Usage

pdd [GLOBAL OPTIONS] COMMAND [OPTIONS] [ARGS]...

Command Overview

Here is a brief overview of the main commands provided by PDD. Click the command name to jump to its detailed section:

Command Relationships

The following diagram shows how PDD commands interact:

graph TB
    subgraph Entry Points
        connect["pdd connect (Web UI - Recommended)"]
        cli["Direct CLI"]
        ghapp["GitHub App"]
    end

    gen_url["pdd generate &lt;url&gt;"]

    subgraph sync workflow
        sync["pdd sync"]
        s_deps["auto-deps"]
        s_gen["generate"]
        s_example["example"]
        s_crash["crash"]
        s_verify["verify"]
        s_test["test"]
        s_fix["fix"]
        s_update["update"]
    end

    checkup["pdd checkup &lt;url&gt;"]
    test_url["pdd test &lt;url&gt;"]
    bug_url["pdd bug &lt;url&gt;"]
    fix_url["pdd fix &lt;url&gt;"]
    change["pdd change &lt;url&gt;"]
    sync_url["pdd sync &lt;url&gt;"]

    connect --> gen_url
    cli --> gen_url
    ghapp --> gen_url
    gen_url --> sync
    sync --> s_deps
    s_deps --> s_gen
    s_gen --> s_example
    s_example --> s_crash
    s_crash --> s_verify
    s_verify --> s_test
    s_test --> s_fix
    s_fix --> s_update
    sync --> checkup
    checkup --> test_url
    checkup --> bug_url
    checkup --> change
    test_url --> fix_url
    bug_url --> fix_url
    change --> sync_url
    sync_url -.-> sync

Key concepts:

  • Entry points: pdd connect (web UI), direct CLI, or the GitHub App
  • Start: pdd generate <url> scaffolds architecture, prompts, and .pddrc from a PRD GitHub issue
  • Core loop: pdd sync runs the full auto-deps → generate → example → crash → verify → test → fix → update cycle for each module
  • Health check: pdd checkup <url> identifies what needs attention next; pdd checkup --pr ... reviews an existing PR on its own merits (add --issue ... to also verify it resolves a specific issue)
  • Defect path: test <url> or bug <url> surfaces failing tests → fix <url> resolves them
  • Feature path: change <url> implements the feature → sync <url> re-runs sync across affected modules. Auth caveat: sync <url> still runs a LiteLLM-backed generate phase, so OAuth-only CLI setup is not enough; configure an API key first.

Getting Started

  • connect: [RECOMMENDED] Launch web interface for visual PDD interaction
  • setup: Configure API keys and shell completion

Agentic Commands (Issue-Driven)

  • change: Implement feature requests from GitHub issues (13-step workflow)
  • bug: Analyze bugs and create failing tests from GitHub issues
  • checkup: Run automated project health checks from GitHub issues, or review/verify existing PRs (optionally against a source issue)
  • fix: Fix failing tests (supports issue-driven and manual modes)
  • sync: Multi-module parallel sync from a GitHub issue (when passed a URL instead of basename). This mode still requires API-key-backed LiteLLM for its generate phase; stored CLI OAuth alone is not sufficient.
  • test: Generate UI tests from GitHub issues (18-step workflow in agentic mode)

Core Commands (Prompt-Based)

  • sync: [PRIMARY FOR PROMPT WORKFLOWS] Automated prompt-to-code cycle
  • generate: Creates runnable code from a prompt file; supports parameterized prompts via -e/--env
  • example: Generates a compact example showing how to use functionality defined in a prompt
  • test: Generates or enhances unit tests for a code file and its prompt
  • update: Updates the original prompt file based on modified code
  • verify: Verifies functional correctness by running a program and judging output against intent
  • crash: Fixes errors in a code module and its calling program that caused a crash

Prompt Management

  • preprocess: Preprocesses prompt files, handling includes, comments, and other directives
  • replay: Reconstructs and audits expanded prompt context from a snapshot-enabled run artifact
  • context: Shows context-window usage by source for a hydrated prompt, Claude-Code /context-style
  • split: Splits large prompt files into smaller, more manageable ones
  • extracts prune: Garbage-collect orphaned extracts cache entries
  • auto-deps: Analyzes and inserts needed dependencies into a prompt file
  • sync-architecture: Updates architecture.json from prompt metadata tags
  • detect: Analyzes prompts to determine which ones need changes based on a description
  • conflicts: Finds and suggests resolutions for conflicts between two prompt files
  • trace: Finds the corresponding line number in a prompt file for a given code line

Utility Commands

  • auth: Manages authentication with PDD Cloud
  • sessions: Manage remote sessions for connect
  • report-core: Create a GitHub issue from a debug snapshot
  • contracts check: Run deterministic contract section checks; see docs/contract_check.md
  • templates: List, inspect, and copy packaged prompt templates
  • which: Print resolved configuration values and search paths
  • install_completion: Refresh shell completion scripts

User Story Prompt Tests

PDD can validate prompt changes against user stories stored as Markdown files. This uses detect under the hood: a story passes when detect returns no required prompt changes.

Defaults:

  • Stories live in user_stories/ and match story__*.md.
  • Prompts are loaded from prompts/ (excluding *_llm.prompt by default).

Overrides:

  • PDD_USER_STORIES_DIR sets the stories directory.
  • PDD_PROMPTS_DIR sets the prompts directory.

Commands:

  • pdd story add <issue-source> --devunit <name> [--devunit <name>] creates a story file from a GitHub issue URL, issue number, or local Markdown file, linked to one or more dev units. Use --text "..." to supply the story source as inline text instead of a URL or file path. Supports --prompt <path> for explicit prompt selection, --from-changed-files to link currently changed .prompt files, --dry-run for a no-write preview, --update to merge prompt links into an existing story, and --generate-regression to print the follow-up pdd test --from-story command.
  • pdd story list [--with-regression-status] lists all stories in user_stories/ with their slug, file path, linked prompts, and (when the traceability API is available) missing / has-test / stale regression status. This is a presence/freshness signal only: has-test means a fresh, marker-linked regression test exists (or a legacy hashless traceability link), not that it passed — pass/fail is verified separately by the story lane (pytest -m story).
  • pdd story link <story-file> --prompt <path> adds a prompt link to an existing story file without regenerating the story body. Validates that the story file is inside user_stories/.
  • pdd test --from-story user_stories/story__*.md --output tests/story_regression/test_story_*.py generates deterministic pytest regression tests from the story contract. When the contract declares a machine-readable ## Entry Point, the generated test is behavioral (preferred): it imports and calls the entry point and asserts the ## Oracle / ## Negative Cases bullets as Python expressions over result. Without an ## Entry Point, it falls back to a text-pin test that pins the story/contract hash and clauses. Either way, generated tests are tagged with @pytest.mark.story(...). See docs/generating_user_stories.md Step 8.
  • pdd detect --stories runs the validation suite.
  • pdd change runs story validation after prompt modifications and fails if any story fails.
  • pdd fix user_stories/story__*.md applies a single story to prompts and re-validates it.
  • pdd test --issue <url|number|issue.md> <prompt_1.prompt> [prompt_2.prompt ...] generates a story__*.md file from the issue text and links those prompts.
  • pdd test user_stories/story__*.md updates prompt links for an existing story file.
  • Story validation prints PASS/FAIL/UNKNOWN and exits non-zero if any story does not pass. pdd detect --stories does not support CSV --output. Automation should use --json or atomic --json-output FILE; these modes imply read-only, non-interactive execution and emit schema pdd.detect.stories.v1. Exit 0 means every scoped story explicitly passed, 1 is a completed semantic story failure, 2 is a scope/configuration error, and 3 is an authentication/provider/timeout or incomplete-evaluation failure. The canonical scoped form is pdd detect --stories --stories-dir user_stories --prompts-dir prompts --no-fail-fast --json. Do not pass a story directory positionally.

Failure output:

  • When a completed semantic evaluation fails, pdd detect --stories prints the evaluated prompt paths, per-prompt descriptions of the missing or stale behavior, and a pdd fix user_stories/story__<slug>.md next-step command.
  • If prompt metadata is only partially or not at all resolvable, the story is UNKNOWN: PDD lists evaluated prompts and unresolved references, recommends repairing pdd-story-prompts metadata, and does not describe the problem as missing/stale behavior or recommend pdd fix.

Story prompt linkage:

  • Stories may include optional metadata to scope validation to a subset of prompts: <!-- pdd-story-prompts: prompts/a_python.prompt, prompts/b_python.prompt -->
  • If metadata is missing, pdd detect --stories validates against the full prompt set.
  • pdd test --issue ... <*.prompt> links the prompt files passed on the command line directly in story metadata; it does not run detect_change during story authoring.
  • In --stories mode, existing story metadata scopes validation; when metadata is missing, validation falls back to the full prompt set.
  • Cross-dev-unit stories: When ≥2 prompt files are passed to pdd test --issue, a second metadata comment is also written alongside pdd-story-prompts: <!-- pdd-story-dev-units: basename1.prompt, basename2.prompt --> This marks the story as spanning multiple dev units (cross-unit). Single-prompt stories do not receive a pdd-story-dev-units comment. Cross-unit traceability is exposed via get_cross_unit_stories_for_prompt (forward lookup: which cross-unit stories include a given prompt) and story_is_cross_unit (returns True when the deduplicated union of the pdd-story-prompts and pdd-story-dev-units entries has ≥2 names — so one prompt link plus one distinct dev-unit link already counts as cross-unit). pdd checkup coverage reports cross-unit stories separately and counts each story once globally to prevent double-counting.

Template:

  • See user_stories/story__template.md for a starter format.

Contract coverage:

  • User stories are example-level coverage for named contract rules in prompts. Document rule IDs under each story's ## Covers section (for example R1 or prompts/module_python.prompt#R2). See docs/coverage_contracts.md and docs/contract_check.md.

Executable regression suite:

  • Beyond drift validation, a story can carry a generated executable regression test marked @pytest.mark.story. Run the suite with make regression-stories (i.e. pytest -m story) in the public-safe, no-secrets lane.
  • Generate a test for a story with pdd test --from-story user_stories/story__<slug>.md.
  • Seed coverage ships for the top flows (generate, sync, fix, change, update) plus a batch of previously-fixed-bug regressions. See docs/generating_user_stories.md.

Global Options

These options can be used with any command:

  • --force: Skip all interactive prompts (file overwrites, API key requests). Useful for CI/automation.
  • --strength FLOAT: Set the strength of the AI model (0.0 to 1.0, default is 1.0 unless .pddrc or PDD_STRENGTH_DEFAULT overrides it).
    • 0.0: Cheapest available model
    • 0.5: Mid-ranked model
    • 1.0: Most powerful model (highest DeepSWE-first rank score)
  • --time FLOAT: Controls the reasoning allocation for LLM models supporting reasoning capabilities (0.0 to 1.0, default is 0.25).
    • For models with specific reasoning token limits (e.g., 64k), a value of 1.0 utilizes the maximum available tokens.
    • For models with discrete effort levels, 1.0 corresponds to the highest effort level.
    • Values between 0.0 and 1.0 scale the allocation proportionally.
  • --temperature FLOAT: Set the temperature of the AI model (default is 0.0).
  • --verbose: Increase output verbosity for more detailed information. Includes token count and context window usage for each LLM call.
  • --quiet: Decrease output verbosity for minimal information.
  • --color / --no-color: Force or disable colored output across all commands. Default is auto: color is on when writing to a TTY and off when piped or when NO_COLOR is set. --no-color disables color everywhere; --color forces it on even through a pipe (e.g. pdd --color sync | less -R). The flag sets NO_COLOR/FORCE_COLOR for the run, so every console PDD builds inherits the choice. For pdd context, which has its own --color/--no-color, precedence is: the command's own flag wins, otherwise the global flag, otherwise auto-detect.
  • --output-cost PATH_TO_CSV_FILE: Enable cost tracking and output a CSV file with usage details.
  • --estimate, --dry-run-cost: Preview the LLM token and rough cost estimate for pdd generate without calling a provider, writing command outputs, or appending cost CSV rows.
  • --estimate-json: Emit the estimate result as machine-readable JSON instead of the human-readable table.
  • --review-examples: Review and optionally exclude few-shot examples before command execution.
  • --local: Run commands locally instead of in the cloud.
  • --core-dump / --no-core-dump: Write a debug snapshot for this run into .pdd/core_dumps (default: on). Use --no-core-dump to disable it.
  • --keep-core-dumps N: Keep the most recent N debug snapshots (default: 10; use 0 to clean them immediately after writing).
  • --context CONTEXT_NAME: Override automatic context detection and use the specified context from .pddrc.
  • --list-contexts: List all available contexts defined in .pddrc and exit.
  • --compress-examples: Automatically apply mode="interface" to example includes (legacy; prefer --context-compression examples).
  • --compress-test-context: Rank and select tests under a configurable token budget (PDD_TEST_TOKEN_BUDGET, default 2 000 tokens) using import-graph distance, symbol overlap, failure recency, and file recency. Failing tests (from PDD_FAILING_TESTS or .pytest_cache) are always included first. A TestPackingManifest explaining selected and omitted tests is emitted in the run telemetry (legacy: prefer --context-compression test).
  • --context-compression {off,test,examples,contracts,all}: Set context compression for this CLI invocation (default: off). Must appear before the subcommand (e.g. pdd --context-compression test generate ...). sync and fix also accept the same flags after their subcommand.
  • --compression-fallback {full,error}: When compression or slicing fails, use full content (full, default) or abort (error). Global placement is the same as --context-compression.

Core Dump Debug Bundles

PDD writes JSON debug snapshots to .pdd/core_dumps by default and keeps the 10 most recent files. These snapshots capture enough run context to replay and analyze failures. Disable them with --no-core-dump, or change retention with --keep-core-dumps.

pdd sync factorial_calculator
pdd --no-core-dump sync factorial_calculator
pdd --keep-core-dumps 20 crash prompts/calc_python.prompt src/calc.py examples/run_calc.py crash_errors.log

When debug snapshots are enabled, PDD:

  • Captures the full CLI command and arguments
  • Records relevant logs and internal trace information for that run
  • Bundles the prompt(s), generated code, and key metadata needed to replay the issue

At the end of the run, PDD prints the path to the debug snapshot.
Attach that bundle when you open a GitHub issue or send a bug report so maintainers can quickly reproduce and diagnose your problem.

report-core Command

The report-core command helps you report a bug by creating a GitHub issue with the core dump file. It simplifies the reporting process by automatically collecting relevant files and information.

Usage:

pdd report-core [OPTIONS] [CORE_FILE]

Arguments:

  • CORE_FILE: The path to the core dump file (e.g., .pdd/core_dumps/pdd-core-....json). If omitted, the most recent core dump is used.

Options:

  • --api: Create the issue directly via the GitHub API instead of opening a browser. This enables automatic Gist creation for attached files.
  • --repo OWNER/REPO: Target GitHub repository. Required unless PDD_GITHUB_REPO is set.
  • --description, -d TEXT: A short description of what went wrong.

Authentication:

To use the --api flag, you need to be authenticated with GitHub. PDD checks for credentials in the following order:

  1. GitHub CLI: gh auth token (recommended)
  2. Environment Variables: GITHUB_TOKEN or GH_TOKEN
  3. Legacy: PDD_GITHUB_TOKEN

File Tracking & Gists:

When using --api, PDD will:

  1. Collect all relevant files (prompts, code, tests, configs, meta files).
  2. Create a private GitHub Gist containing these files.
  3. Link the Gist in the created issue.

This ensures that all necessary context is available for debugging while keeping the issue body clean. If you don't use --api, files will be truncated to fit within the URL length limits of the browser-based submission.


Context Selection Flags

  • --list-contexts reads the nearest .pddrc (searching upward from the current directory), prints the available contexts one per line, and exits immediately with status 0. No auto‑update checks or subcommands run when this flag is present.
  • --context CONTEXT_NAME is validated early against the same .pddrc source of truth. If the name is unknown, the CLI raises a UsageError and exits with code 2 before running auto‑update or subcommands.
  • Precedence for configuration is: CLI options > .pddrc context > environment variables > defaults. See Configuration for details.

Auto-Update Control

PDD automatically updates itself to ensure you have the latest features and security patches. However, you can control this behavior using the PDD_AUTO_UPDATE environment variable:

# Disable auto-updates
export PDD_AUTO_UPDATE=false

# Enable auto-updates (default behavior)
export PDD_AUTO_UPDATE=true

For persistent settings, add this environment variable to your shell's configuration file (e.g., .bashrc or .zshrc).

This is particularly useful in:

  • Production environments where version stability is crucial
  • CI/CD pipelines where consistent behavior is required
  • Version-sensitive projects that require specific PDD versions

AI Model Information

PDD uses a large language model to generate and manipulate code. The --strength and --temperature options allow you to control the model's output:

  • Strength: Determines how powerful/expensive a model should be used. Higher values (closer to 1.0) result in high performance models with better capabilities (selected by model_rank_score, where DeepSWE is primary and Arena/static ELO is fallback), while lower values (closer to 0.0) select more cost-effective models.
  • Temperature: Controls the randomness of the output. Higher values increase diversity but may lead to less coherent results, while lower values produce more focused and deterministic outputs.
  • Time: (Optional, controlled by --time FLOAT) For models supporting reasoning, this scales the allocated reasoning resources (e.g., tokens or effort level) between minimum (0.0) and maximum (1.0), with a default of 0.25.

When running in local mode, PDD uses LiteLLM to select and interact with language models based on a configuration file that includes:

  • Input and output costs per million tokens
  • Primary model_rank_score values for selection and raw Arena/static coding_arena_elo metadata
  • Required API key environment variables
  • Structured output capability flags
  • Reasoning capabilities (budget-based, effort-based, or adaptive)

Output Cost Tracking

PDD includes a feature for tracking and reporting the cost of operations. When enabled, it generates a CSV file with usage details for each command execution.

Usage

To enable cost tracking, use the --output-cost option with any command:

pdd --output-cost PATH_TO_CSV_FILE [COMMAND] [OPTIONS] [ARGS]...

The PATH_TO_CSV_FILE should be the desired location and filename for the CSV output.

Dry-Run Cost Estimates

Use the global --estimate flag, or its alias --dry-run-cost, to preview the LLM cost for pdd generate before running it.

pdd --estimate generate prompts/example_python.prompt
pdd --estimate-json generate prompts/example_python.prompt

Estimate mode assembles the generate messages that would be sent to the provider, counts input tokens, predicts output tokens with a generate-specific heuristic, and prints the selected model, input tokens, predicted output tokens, uncertainty range, known input/output rates, rough estimated cost or unknown, and context-window usage percentage. It exits before provider invocation and before command output files are written.

This first version supports generate only. Other commands, including sync, agentic sync, example, test, update, conflicts, crash, and fix, fail closed with a clear unsupported-command message rather than showing a partial first-call or lower-bound estimate.

--estimate-json prints the same estimate fields as JSON for scripts. Estimate mode does not append rows to --output-cost CSV files; use --output-cost for actual-run accounting. Cost CSV rows are written only for real command executions, because no billable LLM call occurs in estimate mode.

Cost Calculation and Presentation

PDD calculates costs based on the AI model usage for each operation. Costs are presented in USD (United States Dollars) and are calculated using the following factors:

  1. Model strength: Higher strength settings generally result in higher costs.
  2. Input size: Larger inputs (e.g., longer prompts or code files) typically incur higher costs.
  3. Operation complexity: Some operations (like fix and crash with multiple iterations) may be more costly than simpler operations.

The exact cost per operation is determined by the LiteLLM integration using the provider's current pricing model. PDD uses an internal pricing table that is regularly updated to reflect the most current rates.

CSV Output

The generated CSV file includes the following columns:

  • timestamp: The date and time of the command execution
  • model: The AI model used for the operation
  • command: The PDD command that was executed
  • cost: The estimated cost of the operation in USD (e.g., 0.05 for 5 cents). This will be zero for local models or operations that do not use a LLM.
  • input_files: A list of input files involved in the operation
  • output_files: A list of output files generated or modified by the operation
  • attempted_models: Semicolon-delimited audit log of every model PDD attempted for the command, across all LLM calls the command made (e.g. generate runs code-generation followed by postprocess code extraction — both contribute). When PDD's default model fails and the run falls back to another provider (for example Vertex AI → DeepSeek), each attempted model appears here so users can see the full fallback history rather than only the final successful model. The model column above names the model that actually produced the command's output; attempted_models is the complete record of what was tried. For commands that catch a substep failure and recover with a different model, the list may contain entries that came AFTER the model named in model — those represent attempts that were tried but didn't produce the final output. For a single-attempt successful command this column contains just the successful model. Semicolons inside model names are sanitized to preserve the delimiter. Ordering: sequential (single-thread) command paths produce a list in wall-clock attempt order; concurrent paths (e.g. auto-deps --concurrency > 1, which fans summarization across worker threads) sort their per-file contributions by file-submission index — a deterministic alternative to wall-clock ordering, which would otherwise depend on thread-scheduler timing.
  • requested_model: The model name that was explicitly requested for this command (e.g. the value of PDD_MODEL_DEFAULT or the model argument), before provider resolution or fallback.
  • resolved_model: The actual model identity as observed after resolution, where observable. For agentic CLIs that do not expose their selected model, this field is empty.
  • model_selection_outcome: How the final model was determined. One of direct (the requested model was used without fallback), fallback (a fallback model was substituted), fixed_by_config (model is fixed by user config and cannot be controlled by PDD), or unconfirmed (model identity could not be observed).
  • strength_used: The strength value (0.0–1.0) passed to the LLM invocation for this command.
  • cli_version: The installed PDD version at the time the command ran (from importlib.metadata).
  • deepswe_manifest_date: The retrieved_at date of the DeepSWE manifest used for model ranking during this command. Empty if no manifest was loaded.

This comprehensive output allows for detailed tracking of not only the cost and type of operations but also the specific files involved in each PDD command execution.

Environment Variable

You can set a default location for the cost output CSV file using the environment variable:

  • PDD_OUTPUT_COST_PATH: Default path for the cost tracking CSV file.

If this environment variable is set, the CSV file will be saved to the specified path by default, unless overridden by the --output-cost option. For example, if PDD_OUTPUT_COST_PATH=/path/to/cost/reports/, the CSV file will be saved in that directory with a default filename.

Cost Budgeting

For commands that support it (like the fix command), you can set a maximum budget using the --budget option. This helps prevent unexpected high costs, especially for operations that might involve multiple AI model calls.

Example:

pdd [GLOBAL OPTIONS] fix --budget 5.0 [OTHER OPTIONS] [ARGS]...

This sets a maximum budget of $5.00 for the fix operation.

Commands

Here are the main commands provided by PDD:

1. sync

[PRIMARY COMMAND] Automatically execute the complete PDD workflow loop. With a basename, it syncs one module. With no argument, it runs Tier 1 project-wide sync by scanning architecture.json for modules whose prompt fingerprints changed or whose code outputs are missing, then runs those modules in dependency order. With a GitHub issue URL, it runs multi-module issue sync, but the generate phase still calls LiteLLM and requires an API key; stored Claude/Gemini/Antigravity/Codex OAuth or OpenCode provider auth alone is not sufficient for this mode.

# Project-wide architecture sync (no argument)
pdd [GLOBAL OPTIONS] sync [OPTIONS]

# Single-module sync
pdd [GLOBAL OPTIONS] sync [OPTIONS] BASENAME

# Multi-module sync from a GitHub issue (requires API-key-backed LiteLLM)
pdd [GLOBAL OPTIONS] sync [OPTIONS] GITHUB_ISSUE_URL

Important: Sync frequently overwrites generated files to keep outputs up to date. In most real runs, include the global --force flag to allow overwrites without interactive confirmation:

pdd --force sync BASENAME
# Single-module sync with replayable context snapshots
pdd --force sync --snapshot-context factorial_calculator

Snapshot-enabled runs write the canonical run manifest to .pdd/evidence/runs/<run_id>.json and replayable context artifacts to the sibling directory .pdd/evidence/runs/<run_id>/. Snapshot redaction runs before hashing and storage for known token, key, authorization header, URL credential, and secret-assignment patterns; raw environment dumps and bearer/API tokens must not be persisted. Commit only policy-approved snapshot files.

Arguments:

  • No argument: Scan architecture.json and sync all modules that need deterministic Tier 1 prompt-to-code updates.
  • architecture.json as a positional value is not a global-sync alias in v1; use no-argument pdd sync for project-wide Tier 1 sync.
  • BASENAME: The base name for the prompt file (e.g., "factorial_calculator" for "factorial_calculator_python.prompt")
  • GITHUB_ISSUE_URL: A GitHub issue URL for issue-driven multi-module sync. This path is not OAuth-only friendly because its generate phase uses LiteLLM; configure an API key even if your agentic CLI has a stored OAuth login.

Options:

  • --max-attempts INT: Maximum number of fix attempts in any iterative loop (default is 3)
  • --model NAME: Override the base model for this sync run (sets PDD_MODEL_DEFAULT for the invocation, e.g. chatgpt/gpt-5.3-codex, claude-fable-5, or claude-opus-5). Opus 5 and Fable 5 are distinct Anthropic models and each identifier executes its matching model; neither selection changes PDD's ordinary default model. The override is restored after the run. It affects the local llm_invoke route; for a chatgpt/* subscription model on a cloud-enabled install, also pass --local.
  • --budget FLOAT: Maximum total cost allowed for the entire sync process (default is $20.0)
  • --skip-verify: Skip the functional verification step
  • --skip-tests: Skip unit test generation and fixing
  • --target-coverage FLOAT: Desired code coverage percentage (default is 90.0)
  • --compress: Use AST-based compression for Python few-shot examples (strips docstrings and logic-external comments). Helps fit more context into limited LLM windows without losing executable logic.
  • --fresh: Disable the default surgical/edit-shaped regeneration of a mature module. By default, when a module already has non-empty code and its prompt changed, pdd sync edits the existing code in place (feeding the current code plus the prompt delta to the generator) so declared public symbols are preserved rather than dropped by a from-scratch rewrite. With --fresh, sync uses standard generation, which regenerates the module from scratch when the prompt change is large — use it when you intend a large rewrite rather than an in-place edit. New/empty modules are always generated fresh, and the public-surface / declared-interface gate still guards either path. --fresh acts on the standard multi-step single-module sync; in one-session/agentic sync the code is regenerated by the agent session, so --fresh only affects from-scratch (re)generation there. Single-module sync only: passing --fresh to project-wide (no-argument) or GitHub-issue agentic sync raises a UsageError.
  • --dry-run: Display real-time sync analysis instead of running sync operations. For no-argument project-wide sync, this prints the dependency-ordered module list and estimated cost without executing any module syncs, plus a single compact roll-up of modules outside the Tier 1 (generate / auto-deps) scope — bucketed by reason (e.g. Out of Tier 1 scope: 42 example, 31 test, 18 verify, 12 update, 74 no-prompt fixture) instead of one warning line per skipped entry. When zero modules are stale, the 0 stale module(s) fragment is rendered in green so the success signal is visually unambiguous. Actionable architecture-graph warnings (ambiguous or unresolved cross-arch dependencies) are still printed individually in yellow. For single-module sync, it performs the same state analysis as a normal sync run but without acquiring exclusive locks or executing operations. Passing the top-level pdd --verbose flag (see above) restores the legacy per-module enumeration after the compact roll-up — one yellow warning line per module outside the Tier 1 scope — for debugging.
  • --snapshot-context: Capture the fully expanded prompt context used for generation, including nondeterministic <shell>, <web>, and <include ... query="..."> outputs. The run manifest is .pdd/evidence/runs/<run_id>.json; snapshot artifacts are in .pdd/evidence/runs/<run_id>/. Replay can later reconstruct the same prompt/context from the recorded run artifact.
  • --compressed-context / --no-compressed-context: Enable or disable compressed sync context for generation and repair phases. This option is tri-state internally: omitting it lets .pddrc defaults.compressed_context apply, --compressed-context forces it on, and --no-compressed-context forces it off. When enabled, sync builds bounded phase packages from the prompt, existing tests, examples when present, contract sections, and recent repair evidence, then passes those packages to generate, verify, test, and fix attempts. The sync result records whether compression was used and whether any agentic fallback was needed.
  • --one-session / --no-one-session: Run sync in a single agentic session instead of separate sessions for each step. Cannot be combined with --skip-tests or --skip-verify.
  • --no-steer: Disable interactive steering of sync operations.
  • --steer-timeout FLOAT: Timeout in seconds for steering prompts (default: 8.0).
  • --compress-examples: Automatically apply mode="interface" to example files in the <include> graph for this sync operation.
  • --compress-test-context: Rank and select test files under PDD_TEST_TOKEN_BUDGET (default 2 000 tokens) for this sync operation. Failing tests are packed first; remaining candidates are ranked by import distance, symbol overlap, and recency. Emits a TestPackingManifest in telemetry.
  • --context-compression {off,test,examples,contracts,all}: Set a global compression mode for this sync operation (default: off). test and examples mirror the legacy flags; contracts extracts contract rules and metadata from prompts and documentation; all enables all compression modes.
  • --compression-fallback {full,error}: Strategy for when a file cannot be compressed (default: full).
  • --durable: Issue-sync only. Run each module in an isolated git worktree under .pdd/worktrees/sync-issue-<N>-<module>/ and checkpoint successful module output to a dedicated durable branch worktree under .pdd/worktrees/durable-issue-<N>/. Default issue-sync behavior (shared parallel worktree) is unchanged unless this flag is passed.
  • --durable-branch TEXT: Durable mode only. Override the durable checkpoint branch name. Default is sync/issue-<N> derived from the GitHub issue. Refused if it resolves to main, master, or the repository default branch.
  • --no-resume: Durable mode only. Ignore existing PDD-Sync-Checkpoint-V1 commit trailers on the durable branch and re-run every selected module. By default, durable sync reads checkpoint trailers (PDD-Sync-Checkpoint-V1: issue=<N> module=<basename>) and skips modules already checkpointed for the same issue, which is what makes a cloud rerun safely resume completed work after a partial failure.
  • --durable-max-parallel INT: Durable mode only. Cap how many module worktrees run concurrently. Defaults to the standard runner concurrency. A total budget still forces sequential execution.

Estimate-mode note: global --estimate currently supports pdd generate only. pdd sync and agentic sync do not expose cost estimates in this first version because downstream prompts depend on generated artifacts that do not exist during a side-effect-free preview.

Durable Issue Sync (--durable):

Standard issue sync runs all modules in one shared worktree. If the worker exits before every module completes (timeout, crash, ephemeral cloud checkout deletion), the work that already succeeded is lost and a rerun starts over from the original branch state. Durable mode is the opt-in fix: each module runs in its own git worktree, and on success its diff is applied to a separate durable branch worktree as a checkpoint commit carrying a PDD-Sync-Checkpoint-V1: issue=<N> module=<basename> trailer. Independent modules still run in parallel (capped by --durable-max-parallel); the serialization guarantee is narrower — a module is only marked successful, and its dependents only become eligible to schedule, after its checkpoint commit has been pushed. Any rerun then reads the trailers and skips modules already checkpointed for the same issue. Failed module worktrees are left in place for inspection; successful ones are cleaned up after their checkpoint pushes. Durable sync requires a git repository with an origin remote and refuses to operate on main, master, or the repository default branch. Module-scoped .pdd/meta/<module>_*.json is included in checkpoints; secrets, lock files, cost CSVs, .pdd/worktrees/, and .pdd/agentic_sync_state.json are not.

# Cloud-friendly issue sync: resumable across reruns
pdd --force sync --durable https://github.com/myorg/myrepo/issues/1328

# Rerun every module fresh on the same durable branch (ignores existing trailers)
pdd --force sync --durable --no-resume \
  https://github.com/myorg/myrepo/issues/1328

The dedicated durable-branch worktree path is keyed on the issue number (.pdd/worktrees/durable-issue-<N>/), not the branch name. A given issue's first durable run claims that path for whichever branch it picked (default sync/issue-<N> or an explicit --durable-branch). To switch a later run for the same issue to a different durable branch, remove the existing worktree first (git worktree remove .pdd/worktrees/durable-issue-<N>) before re-invoking with the new --durable-branch. Different issue numbers do not collide.

Real-time Progress Animation: The sync command provides live visual feedback modeled on the real execution pipeline — Entry → Inspect → Plan → Execute → Output — rendered at a fixed height so the display never jumps as it advances:

  • An execute-step strip that spells out the full command names being run (auto-deps, generate, example, verify, test, fix, update), marking each step as it completes. The strip adapts to the terminal width: full names at wide widths, tighter separators as it narrows, and a rotating marquee at very narrow widths.
  • File status indicators with color coding:
    • Green: File exists and up-to-date
    • Yellow: File being processed
    • Red: File has errors or missing
    • Blue: File analysis in progress
  • Running cost totals and time elapsed
  • Progress through the pipeline stages

Color in the animation (and all other CLI output) follows the global --color / --no-color preference and NO_COLOR; see Global Options.

Language Detection: The sync command automatically detects the programming language by scanning for existing development prompt files for the requested basename. In classic layouts this is typically {basename}_{language}.prompt; in architecture-driven layouts it can also resolve nested prompt paths whose filenames mirror the target output path. For example:

  • factorial_calculator_python.prompt → generates factorial_calculator.py
  • factorial_calculator_typescript.prompt → generates factorial_calculator.ts
  • factorial_calculator_javascript.prompt → generates factorial_calculator.js
  • src/models/user_Python.prompt → generates src/models/user.py

If multiple development language prompt files exist for the same basename, sync will process all of them.

Language Filtering: The sync command only processes development languages (python, javascript, typescript, java, cpp, etc.) and excludes runtime languages (LLM). Files ending in _llm.prompt are used for internal processing only and cannot form valid development units since they lack associated code, examples, and tests required for the sync workflow.

Advanced Configuration Integration:

  • Automatic Context Detection: Detects project structure and applies appropriate settings from .pddrc
  • Configuration Hierarchy: CLI options > .pddrc context > environment variables > defaults
  • Multi-language Support: Automatically processes all language variants of a basename
  • Intelligent Path Resolution: Uses sophisticated directory management for complex project structures
  • Architecture-Aware Outputs: When architecture.json provides an explicit filepath for a prompt entry, sync honors it according to whether that filepath includes a directory component:
    • If filepath includes a directory (e.g. backend/api/widget.py), that explicit directory structure wins and is preserved as-is — .pddrc output paths are not applied to it.
    • If filepath is a bare filename at the project root (e.g. widget.py), the filename is preserved but its parent directory is taken from .pddrc generate_output_path. This makes the code path resolve consistently with example_output_path and test_output_path, which are always sourced from .pddrc defaults (Issue #1201). When no generate_output_path is configured, the bare filename resolves at the project root as before.
  • Runner-aware test paths (Issue #1903): When PDD would otherwise write a module's test to its derived default location and a single existing co-located test already exists (a jest/vitest/Next.js __test__/{name}.test.tsx-style sibling, or a Python test_{name}.py sibling), pdd test/change/sync adopt that existing test as the canonical path instead of maintaining a separate runner-blind tests/ shadow — so PDD updates and verifies the test your runner actually collects. Adoption never overrides an explicit pin (CLI --output, PDD_TEST_OUTPUT_PATH, or .pddrc test_output_path/outputs.test.path), and never fires when more than one co-located test exists. Greenfield (Issue #1903 §A): when no co-located test exists yet but the project configures a jest/vitest runner, PDD writes the FIRST test to the location the runner will actually collect instead of a runner-blind tests/ shadow. The write path honors JSON-readable config — testMatch/testRegex pick the .test/.spec + __test__/__tests__ convention, and roots/rootDir/testPathIgnorePatterns are enforced so a custom layout never yields an uncollected test. For a centralized layout (tests only under a configured roots/testMatch directory) PDD derives a collected path under that directory, mirroring the module's relative sub-path so two same-stem modules never collapse onto one file (never fork/overwrite), rather than falling back to a runner-blind shadow. Jest testMatch is evaluated with ordered include/exclude semantics (a leading-! negation removes matches). Both the jest and vitest dialects are covered. A JS-only config (jest.config.js/vitest.config.ts, unparseable in Python) is handled by whole-word text-inspection: it uses the default convention ONLY when the config is a plain literal that customizes nothing discovery-related; if it customizes discovery, or composes/delegates it in a way a static scan can't follow (require/import/spread/preset/extends/function config), or a parseable config uses projects/include/exclude we can't fully resolve, PDD conservatively refuses to write (sets the test path to None and emits a needs-review signal) rather than guess or fall back to the derived path. It also only co-locates for an extension the default discovery collects — .mjs/.cjs are version-aware (vitest and jest 30+ collect them; jest ≤29 / unknown versions do not, so they're refused) — and evaluates testMatch with jest's ordered include/exclude semantics (a negated character class [!x] means "not x"; an explicit-empty or both-testMatch-and-testRegex config matches nothing → refuse). Repo-controlled runner patterns are matched under a strict per-match timeout plus an aggregate pattern-count cap (ReDoS/DoS-safe, fail-closed). Python keeps its pytest-idiomatic tests/ default.
  • Opaque runner safety: When Jest/Vitest configuration is detected but PDD cannot prove a runner-collected output, PDD does not fall back to a derived path. It sets the test path to None, emits a needs-review signal, and performs no test write until the configuration is made resolvable.
  • Context-specific settings include output paths, default language, model parameters, coverage targets, and budgets

Workflow Logic:

The sync command automatically detects what files exist and executes the appropriate workflow:

  1. auto-deps: Find and inject relevant dependencies into the prompt — both code examples and documentation files (schema docs, API docs, etc.). Removes redundant inline content that duplicates included documents.
  2. generate: Create or update the code module from the prompt. When compressed context is enabled, this phase receives a generated phase package containing compressed prompt/test/example/contract context instead of the raw boolean option value or repeatedly expanded full context. After generation an architecture conformance gate validates the output against both architecture.json and the prompt's <pdd-interface> block:
    • Each declared symbol must exist in the generated code (architecture.json symbol-existence check).
    • Python naming convention: Python exports should be snake_case, so a camelCase export (e.g. processData) fails the gate — UNLESS its exact name is a declared interface symbol (declared in architecture.json module.functions or the prompt's own <pdd-interface>), in which case it is treated as intentional public API (e.g. Firebase Cloud Function exports like generateCode) and allowed. Honoring the prompt — the source of truth — means a name you declare there is accepted even before architecture.json is regenerated to match. Only undeclared/accidental camelCase is rejected.
    • For interface entries that declare a paren-list signature (module, cli, and command types), each declared parameter name must appear in the matching function/method signature (dotted names like ContentSelector.select are resolved through the class body; variadic *args/**kwargs do not satisfy a declared named parameter).
    • Signature drift is checked per parameter: annotation drift fires only when both sides specify and differ (conservative — gradually-typed code does not churn), while default drift fires whenever the prompt declares a default and the generated code drops or changes it (strict — a missing default is a runtime contract break for callers omitting the optional kwarg).
    • Public-surface regression gate: when a module already has a generated code file in the working tree (i.e., not a first-time generation), the gate ALSO snapshots the pre-generation public surface and rejects a generation that removes, renames, or changes the callable signature of any public symbol. For Python the snapshot covers top-level functions, classes, class.method symbols (including nested classes), module-level constants (PUBLIC_FLAG = ..., including bound AnnAssign like PUBLIC_FLAG: bool = True), and re-exported imports (import git exposes git; from .helpers import load exposes load). from __future__ import … directives and bare type-only annotations are not part of the surface. Intentional removals/signature changes must be scoped, e.g. BREAKING-CHANGE: remove calculate_sha256 or BREAKING-CHANGE: change signature calculate; listing a top-level class (BREAKING-CHANGE: remove Service) implicitly authorizes removing every Service.method / Service.Inner.method descendant captured in the snapshot. A bare BREAKING-CHANGE: does not disable the gate. Prompt-declared interface as the contract (#1900): when the prompt's <pdd-interface> declares a type: module interface, each declared top-level function is validated against its DECLARED signature — a stable contract — instead of against the previous generation, so an intended interface change is authorized simply by editing the declaration (reviewable in the prompt diff) and the standard pdd change → pdd sync flow no longer needs a BREAKING-CHANGE: prose permit for declared symbols. Undeclared symbols keep the previous-generation baseline above (and its BREAKING-CHANGE: opt-out), so protection for helpers/re-exports is unchanged. Any declared symbol with a parseable paren signature — a top-level function, a dotted method (Class.method), or a constructor (Class.__init__), including declared _-prefixed helpers — is validated against its DECLARED signature (methods/constructors are receiver-stripped to match the snapshot: a leading self/cls is dropped, and Class.__init__ compares against the class's constructor ABI), so editing the declaration authorizes an intended function/method/constructor change too. Binding-kind/async — which the declaration cannot express — stay anchored to the previous generation, so a @staticmethod→instance flip or an async↔sync change is still caught, with BREAKING-CHANGE: change signature relaxing only those un-declarable facets (never the declared parameters). A declared symbol WITHOUT a parseable paren signature (a description-only entry, or a class declared as class Service) is presence-only and falls back to the previous-generation baseline (an existing symbol's ABI drift is still caught there). On a declared-surface violation the failure lists the full declared-expected-vs-actual signature. First-time generation (no prior code file) is exempt. Set PDD_SKIP_PUBLIC_SURFACE_GATE=1 to disable only this gate, or PDD_SKIP_CONFORMANCE=1 to skip all conformance gates.
    • Test-churn gate: if pdd sync is about to overwrite an existing test file through the code-generation writer, cmd_test_main, or one-session agentic sync, and the unified-diff churn ratio between the pre-sync and proposed test file exceeds PDD_TEST_CHURN_THRESHOLD (default 0.40, i.e., 40%), the gate fails fast with TestChurnError so a small prompt change cannot land a thousand-line test rewrite that drops broad existing coverage. Pure additive test growth is allowed, first-time test generation is exempt, and intentional rewrites require an explicit marker such as BREAKING-CHANGE: rewrite tests. Set PDD_SKIP_TEST_CHURN_GATE=1 to disable only this gate. One-session auto-recovery: when the one-session sync retry loop exhausts on test churn, instead of hard-failing it accepts the rewrite IFF it is coverage-preserving — every pre-existing test file keeps at least as many test cases AND assertions (with at least one real assertion), deletes nothing, and is in a measurable language (Python via AST, TS/JS via a comment/string/regex-aware scanner); otherwise the strict gate still hard-fails. This lets a legitimate large rewrite driven by a real prompt change complete instead of forcing manual intervention, while still blocking silent coverage loss. An accepted rewrite prints a PDD_TEST_CHURN_ACCEPTED marker; set PDD_DISABLE_TEST_CHURN_AUTOACCEPT=1 to force the strict gate. Issue-driven never-block (issue #1903 §B.4): when the coverage-preserving auto-accept refuses (a genuinely coverage-losing rewrite) inside the agentic issue-driven sync (a GitHub issue URL, which opens a PR) AND the churned test is an adopted co-located human test (a jest/vitest .test./.spec. file, a file under __test__/__tests__, or a Python sibling test_<stem>.py / <stem>_test.py outside the top-level tests/ shadow — classified by _is_adopted_collocated_test_path), the workflow does NOT hand work back to the user by failing the command. The human-authored test is kept unchanged, a PDD_TEST_CHURN_NEEDS_REVIEW marker is emitted, the module is reported as synced, and the PR is opened with that test flagged needs review in the progress comment / PR body (ModuleState.needs_review, persisted across durable resumes). THREE independent guards keep this from ever masking coverage loss, and ALL must hold: (1) the runner is issue-driven — self.issue_url is set only for a GitHub issue → PR sync; a project-wide pdd sync builds the runner with issue_url=None, opens no PR, and keeps the strict hard-fail (there is no PR to flag against); (2) structured adoption provenance — the child sync stamps adopted: true on the churn block only when the test was adopted from an existing human co-located test, unpinned, decided at path resolution before generation (a pinned path, a greenfield test PDD created, or an older child with no marker reads false); and (3) the churned path is an in-repo co-located shape — not a PDD-owned tests/ shadow, traversal, or out-of-root path. Standalone pdd test / pdd sync <module> never run through the issue-driven runner at all, so they always keep the strict hard-fail above.
    • Prose/empty-output classification gate: when the extractor returns empty or whitespace-only content for a code generation request — for example, because the provider returned a planning sentence or reasoning trace instead of a code block — pdd sync raises ProseOutputError before reaching the architecture conformance gate. This prevents an empty extraction from being misdiagnosed as a missing-symbol architecture failure. The repair directive on retry instructs the model to "return the complete source file only, inside a single code block; do not include planning text, prose explanation, or partial snippets outside the code block." Prose retries are limited to 1 additional attempt; a repeated prose response triggers a structured === generation output extraction failure === hard-failure block naming the provider/model, prompt, output path, extractor result, raw-output excerpt, and directing the user to check provider configuration. The target file is never overwritten. Set PDD_ALLOW_EMPTY_GENERATION=1 to bypass. Providers that tend to return planning-style responses (e.g., local lm_studio/*, ollama/*, or ChatGPT/Codex interactive providers flagged interactive_only in llm_model.csv) are most likely to trigger this path.
    • Empty-generation guard: when the LLM provider returns an empty (or whitespace-only) body and the output path already has non-empty existing content, the writer refuses to truncate the file. Python public modules / test files trip PublicSurfaceRegressionError / TestChurnError through the normal gates; non-Python artifacts (JSON, YAML, prompts, etc.) raise a click.UsageError("Refusing to overwrite ...") instead. Set PDD_ALLOW_EMPTY_GENERATION=1 for the rare case where empty output is intentional.
    • On failure, sync retries the generation step up to MAX_CONFORMANCE_ATTEMPTS with a PDD_REPAIR_DIRECTIVE that names the function to fix and the parameters/annotations/defaults to add or restore. Prose/empty-output failures (ProseOutputError) use a separate output-shape retry limited to 1 additional attempt. Public-surface and test-churn failures use the same repair loop only on the generate and one-session paths; surface regressions detected after a crash/fix/verify write are hard failures (no retry) because each of those operations already runs its own internal fix loop and a second outer retry would compound retries (N × M) without converging. .pddrc context/strength are pinned across the entire retry sequence so a retry never silently switches model or context. The retry stops early when the missing-symbol/signature set repeats across attempts, and the final failure is surfaced as a structured === generation output extraction failure ===, === architecture conformance failure ===, === public surface regression ===, or === test churn threshold exceeded === block listing the offending symbols / churn ratio / provider context plus a Reproduce locally: pdd sync <basename> line.
  3. example: Generate usage example if it doesn't exist or is outdated
  4. crash: Fix any runtime errors to make code executable
  5. verify: Run functional verification against prompt intent (unless --skip-verify). When compressed context is enabled, verification receives its own phase-aware compressed context package built from the same bounded prompt/test/example/contract evidence.
  6. test: Generate comprehensive unit tests if they don't exist (unless --skip-tests). Auth modules get auth-specific test patterns (mock OAuth servers, JWT fixtures, token lifecycle testing)
  7. fix: Resolve any bugs found by unit tests (unless --skip-tests). Because --skip-tests skips both unit test generation (step 6) and fixing, the fix step is skipped along with the test step. When the requested operation is an isolated code repair or generation replay, sync consumes existing examples if present but must not detour into unrelated example generation just to construct repair context.
  8. update: Back-propagate any learnings to the prompt file

One-Session Mode (--one-session):

By default, sync runs each step (example, crash-fix, verify, test, fix) as a separate LLM session. One-session mode runs all these steps in a single agentic session. This results in faster and cheaper sync runs.

One-session mode is enabled by default for agentic sync (GitHub issue URLs) and disabled by default for single-module sync. Use --one-session or --no-one-session to override.

# Project-wide sync dry run
pdd sync --dry-run

# Single-module sync with one-session mode
pdd sync --one-session factorial_calculator

# Agentic sync (one-session is the default)
pdd sync https://github.com/myorg/myrepo/issues/100
pdd sync calculator --model chatgpt/gpt-5.3-codex  # force a model on the local route; for chatgpt/* on a cloud-enabled install add --local
pdd sync calculator --local --model chatgpt/gpt-5.3-codex  # local route: required for a chatgpt/* subscription model when PDD Cloud is configured

# Disable one-session for agentic sync
pdd sync --no-one-session https://github.com/myorg/myrepo/issues/100

Advanced Decision Making:

  • Fingerprint-based Change Detection: Uses content hashes and timestamps to precisely detect what changed
  • LLM-powered Conflict Resolution: For complex scenarios with multiple file changes, uses AI to determine the best approach
  • Persistent State Tracking: Maintains sync history and learns from previous operations
  • Smart Lock Management: Prevents concurrent sync operations with automatic stale lock cleanup
  • Detects which files already exist and are up-to-date
  • Skips unnecessary steps (e.g., won't regenerate code if prompt hasn't changed)
  • Uses git integration to detect changes; regenerates mature modules surgically (edit-shaped) by default so declared symbols are preserved, falling back to full regeneration for new modules or when --fresh is passed
  • Accumulates tests over time rather than replacing them (in a single test file per target)
  • Automatically handles dependencies between steps
  • Compressed Context Telemetry: Sync results and logs record whether compressed context was requested, the effective value after CLI and .pddrc resolution, whether it was actually applied for each phase, the source inputs used to build it, and whether the run fell back to agentic repair. This makes replay and benchmark comparisons distinguish normal sync from compressed-context sync.

Robust State Management:

  • Fingerprint Files: Maintains .pdd/meta/{basename}_{language}.json with operation history. All fingerprint writes across every mutating command (sync, generate, example, update, fix, auto-deps, ci-heal) route through a single FingerprintTransaction context manager; writes are atomic (temp-file + os.replace) and enforced — a finalization failure is a command failure, not a silent warning.
  • Run Reports: Tracks test results, coverage, and execution status
  • Lock Management: Prevents race conditions with file-descriptor based locking
  • Git Integration: Leverages version control for change detection and rollback safety

The .pdd Directory: PDD uses a .pdd directory in your project root to store various metadata and configuration files:

  • .pdd/meta/ - Contains fingerprint files, run reports, and sync logs
  • .pdd/locks/ - Stores lock files to prevent concurrent operations
  • .pdd/llm_model.csv - Project-specific LLM model configuration (optional)
  • .pdd/worktrees/ - Transient git worktrees used by pdd sync --durable (per-module execution sandboxes and the dedicated durable-branch worktree). Local scratch state, not project state.

This directory should typically be added to version control (except for .pdd/locks/ and .pdd/worktrees/), as it contains important project state information.

Environment Variables: All existing PDD output path environment variables are respected, allowing the sync command to save files in the appropriate locations for your project structure.

Sync State Analysis: The sync command maintains detailed decision-making logs which you can view using the --dry-run option:

# View current sync state analysis (non-blocking)
pdd sync --dry-run calculator

# View detailed LLM reasoning for complex scenarios
pdd --verbose sync --dry-run calculator

Analysis Contents Include:

  • Current file state and fingerprint comparisons
  • Real-time decision reasoning (heuristic-based vs LLM-powered analysis)
  • Operation recommendations with confidence levels
  • Estimated costs for recommended operations
  • Lock status and potential conflicts
  • State management details

The --dry-run option performs live analysis of the current project state, making it safe to run even when another sync operation is in progress. This differs from viewing historical logs - it shows what sync would decide to do right now based on current file states.

Use --verbose with --dry-run to see detailed LLM reasoning for complex multi-file change scenarios and advanced state analysis.

When to use: This is the recommended starting point for most PDD workflows. Use sync when you want to ensure all artifacts (code, examples, tests) are up-to-date and synchronized with your prompt files. The command embodies the PDD philosophy by treating the workflow as a batch process that developers can launch and return to later, freeing them from constant supervision.

Examples:

# Complete workflow with progress animation and intelligent decision-making
pdd --force sync factorial_calculator

# Advanced sync with higher budget, custom coverage, and full visual feedback
pdd --force sync --budget 15.0 --target-coverage 95.0 data_processor

# Quick sync with animation showing real-time status updates
pdd --force sync --skip-verify --budget 5.0 web_scraper

# Multi-language sync with fingerprint-based change detection
pdd --force sync multi_language_module

# View comprehensive sync analysis with decision analysis
pdd sync --dry-run factorial_calculator

# View detailed sync analysis with LLM reasoning for complex conflict resolution
pdd --verbose sync --dry-run factorial_calculator

# Monitor what sync would do without executing (with state analysis)
pdd sync --dry-run calculator

# Context-aware examples with automatic configuration detection
cd backend && pdd --force sync calculator     # Uses backend context settings with animation
cd frontend && pdd --force sync dashboard     # Uses frontend context with real-time feedback
pdd --context backend --force sync calculator # Explicit context override with visual progress

Agentic Multi-Module Sync (GitHub Issue Mode):

When a GitHub issue URL is passed instead of a basename, sync enters agentic mode:

  1. Module Identification: Fetches the issue content and identifies which modules need syncing using a four-strategy hierarchy: (a) branch-diff detection (deterministic, free), (b) runtime-template-only short-circuit (no-op when all diff files are *_LLM.prompt templates), (c) PDD_CHANGED_MODULES env-var bypass (deterministic, free — skips LLM when branch-diff returned empty), (d) LLM fallback
  2. Dependency Validation: Validates architecture.json dependencies and applies corrections if needed
  3. Parallel Execution: Dispatches parallel sync via AsyncSyncRunner with dependency-aware scheduling (up to 4 concurrent workers by default; set PDD_SYNC_MAX_WORKERS to cap concurrency lower — e.g. 1 on memory-constrained runners)
  4. Live Progress: Posts and updates a GitHub comment with real-time module sync status
# Sync modules identified from a GitHub issue (parallel, dependency-aware)
pdd sync https://github.com/myorg/myrepo/issues/100

# Extend the per-module timeout for a very large module
pdd sync --timeout-adder 600 https://github.com/myorg/myrepo/issues/100

Options (agentic mode):

  • --timeout-adder FLOAT: Add seconds to the per-module timeout (default: 0.0).
  • --no-github-state: Disable GitHub state persistence, use local-only

Cross-Machine Resume: Workflow state is stored in a hidden GitHub comment, enabling resume from any machine. Use --no-github-state to disable.

1a. sync-architecture

Sync architecture.json from prompt metadata tags (<pdd-reason>, <pdd-interface>, and <pdd-dependency>). This is useful after editing prompt metadata directly, or after backfilling prompt tags, so the architecture graph and command metadata stay aligned with the prompts.

# Preview architecture updates for all prompts
pdd sync-architecture --dry-run

# Update architecture.json from all prompt metadata tags
pdd sync-architecture

# Update architecture.json from specific prompt entries
pdd sync-architecture commands/maintenance_python.prompt

Arguments:

  • No argument: Scan all prompt files known to the current project.
  • FILENAMES: Optional prompt filenames as they appear in architecture.json or under the configured prompts directory.

Options:

  • --dry-run: Report which architecture entries would change without writing architecture.json.

The command prints updated prompt entries and validation errors or warnings. It exits non-zero when validation fails, even if it was able to write requested metadata updates before validation.

Note: Validation is repo-wide and runs even when you target a single prompt. If your architecture.json already has unrelated missing-dependency errors elsewhere, the exit code stays non-zero on --dry-run even for an otherwise-clean target prompt. Fix the repo-wide errors (or scope your check) before relying on the exit code in scripts.

2. generate

Create runnable code from a prompt file. This command produces the full implementation code that fulfills all requirements in the prompt. When changes are detected between the current prompt and its last committed version, it can automatically perform incremental updates rather than full regeneration.

# Basic usage
pdd [GLOBAL OPTIONS] generate [OPTIONS] PROMPT_FILE

Arguments:

  • PROMPT_FILE: The filename of the prompt file used to generate the code.

Options:

  • --output LOCATION: Specify where to save the generated code. Supports ${VAR}/$VAR expansion from -e/--env. The default file name is <basename>.<language_file_extension>. If an environment variable PDD_GENERATE_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --original-prompt FILENAME: The original prompt file used to generate the existing code. If not specified, the command automatically uses the last committed version of the prompt file from git.
  • --incremental: For prompt-to-code generation, force incremental patching when an output location is specified and the file exists. To run the experimental PRD-to-architecture workflow, combine it with --experimental-prd.
  • --experimental-prd: Explicitly opt in to experimental Incremental PRD Mode for PRD-like files (.md, .markdown, .txt, .rst, .adoc) or GitHub issue URLs. Requires --incremental.
  • --unit-test FILENAME: Path to a unit test file. If provided, automatic test discovery is disabled and only the content of this file is included in the prompt, instructing the model to generate code that passes the specified tests.
  • --exclude-tests: Do not automatically include test files found in the default tests directory.
  • Context compression: use global --context-compression / --compression-fallback before generate (see Global Options); generate does not accept these flags after the subcommand.
  • --snapshot-context: Capture the expanded prompt and dynamic context outputs used for this generation. The run manifest is .pdd/evidence/runs/<run_id>.json; snapshot artifacts are in .pdd/evidence/runs/<run_id>/. This is recommended when a prompt uses <shell>, <web>, or <include ... query="..."> for contract-relevant context.

Parameter Variables (-e/--env): Pass key=value pairs to parameterize a prompt so one prompt can generate multiple variants (e.g., multiple files) by invoking generate repeatedly with different values.

  • Syntax: -e KEY=VALUE or --env KEY=VALUE (repeatable).
  • Docker-style env fallback: -e KEY reads VALUE from the current process environment variable KEY.
  • Scope: Applies to generate.
  • Precedence: Values passed with -e/--env override same‑named OS environment variables during template expansion for this command.

Templating: Prompt files and --output values may reference variables using $VAR or ${VAR}. Only variables explicitly provided via -e/--env (or via env fallback with -e KEY) are substituted; all other dollar-prefixed text is left unchanged. No escaping is required for ordinary $ usage.

  • In prompt content: $VAR and ${VAR} are replaced only when VAR was provided.
  • In output path: When using --output, PDD also expands $VAR/${VAR} using the same variable set.
  • Unknowns: Placeholders without a provided value are left unchanged. If you pass -e KEY (no value) and KEY exists in the OS environment, that environment value is used.

Examples:

# Basic parameterized generation (Python module)
pdd generate -e MODULE=orders --output 'src/${MODULE}.py' prompts/module_python.prompt

# Generate multiple files from the same prompt
pdd generate -e MODULE=orders   --output 'src/${MODULE}.py' prompts/module_python.prompt
pdd generate -e MODULE=payments --output 'src/${MODULE}.py' prompts/module_python.prompt
pdd generate -e MODULE=customers --output 'src/${MODULE}.py' prompts/module_python.prompt

# Multiple variables
pdd generate -e MODULE=orders -e PACKAGE=core --output 'src/${PACKAGE}/${MODULE}.py' prompts/module_python.prompt

# Docker-style env fallback (reads MODULE from your shell env)
export MODULE=orders
pdd generate -e MODULE --output 'src/${MODULE}.py' prompts/module_python.prompt
pdd generate prompts/refund_python.prompt --output src/refund.py --snapshot-context

Shell quoting options:

  • Quote KEY=VALUE if the value contains spaces or shell-special characters: -e "DISPLAY_NAME=Order Processor".
  • PDD-side expansion (portable): prevent shell expansion and let PDD expand using -e/--env — e.g., --output 'src/${MODULE}.py'.
  • Shell-side expansion (familiar): set an env var and let the shell expand --output, while still passing -e KEY so prompts get the same value — e.g.,
    • export MODULE=orders && pdd generate -e MODULE --output "src/$MODULE.py" prompts/module_python.prompt
    • Or inline for POSIX shells: MODULE=orders pdd generate -e MODULE --output "src/$MODULE.py" prompts/module_python.prompt
    • Note: PowerShell/Windows shells differ; PDD-side expansion is more portable across shells.

Git Integration:

  • When the command detects changes between the current prompt and its last committed version, it automatically considers incremental generation if the output file exists.
  • If incremental generation is performed, both the current prompt and code files are staged with git add (if not already committed/added) to ensure you can roll back if needed.
  • Full regeneration always happens for new files (when there's no existing output file to update) or when the existing output file is deleted.

When to use: Choose this command when implementing new functionality from scratch or updating existing code based on prompt changes. The command will automatically detect changes and determine whether to use incremental patching or full regeneration based on the significance of the changes.

Examples:

# Basic generation with automatic git-based change detection
# (incremental if output file exists, full generation if it doesn't)
pdd [GLOBAL OPTIONS] generate --output src/calculator.py calculator_python.prompt 

# Force incremental patching (requires output file to exist)
pdd [GLOBAL OPTIONS] generate --incremental --output src/calculator.py calculator_python.prompt

# Force full regeneration (just delete the output file first)
rm src/calculator.py  # Delete the file
pdd [GLOBAL OPTIONS] generate --output src/calculator.py calculator_python.prompt

# Specify a different original prompt (bypassing git detection)
pdd [GLOBAL OPTIONS] generate --output src/calculator.py  --original-prompt old_calculator_python.prompt calculator_python.prompt

Agentic Architecture Mode:

When the positional argument is a GitHub issue URL instead of a prompt file, generate enters agentic architecture mode. The issue body serves as the PRD (Product Requirements Document), and an 11-step agentic workflow generates architecture.json, .pddrc, and prompt files automatically.

pdd generate https://github.com/owner/repo/issues/42

The 11-step workflow:

Analysis & Generation (Steps 1-8):

  1. Analyze PRD: Extract features, tech stack, and requirements from the issue content
  2. Deep Analysis: Feature decomposition, module boundaries, shared concerns
  3. Research: Web search for tech stack documentation and best practices
  4. Design: Module breakdown with dependency graph and priority ordering (auth modules are separated into dedicated concerns with low priority numbers)
  5. Research Dependencies: Find relevant API docs and code examples per module
  6. Generate: Produce complete architecture.json and scaffolding files
  7. Generate .pddrc: Create project configuration with context-specific paths
  8. Generate Prompts: Create prompt files for each module in architecture.json

Validation (Steps 9-11): 9. Completeness Validation: Verify all modules have prompts and dependencies 10. Sync Validation: Run pdd sync --dry-run on each module to catch prompt-discovery and output path issues, including architecture-driven nested paths 11. Dependency Validation: Preprocess prompts to verify <include> tags resolve under the same rules used at runtime, and reject fabricated example-file include paths

Each validation step retries up to 3 times with automatic fixes before proceeding.

Options:

  • --skip-prompts: Skip prompt file generation (steps 8-11), only generate architecture.json and .pddrc
  • --project-root <path>: Explicit project-root override. Use the given path as the resolved project root instead of walking up from cwd. Useful when the cwd is a self-contained pdd project nested inside an unrelated outer git repo.

Project Root Detection:

pdd generate <issue-url> (and pdd generate --incremental --experimental-prd) resolves the project root by walking up from cwd. Tier A, Tier B, and Tier C are all project boundaries — the nearest boundary found while walking upward wins. This lets a nested PDD marker beat an enclosing outer .git, but prevents an enclosing outer PDD marker from overriding a nearer inner git repository:

  1. Tier A (PDD-explicit): a directory containing .pddrc or a .pdd/ directory.
  2. Tier B (PDD-conventional): a directory containing sources/ plus PRD/spec markdown (prd*.md, spec*.md, or *_prd.md/*_spec.md).
  3. Tier C (git): a directory containing .git.

Path.home() (the user's $HOME) is skipped for the PDD-marker check — ~/.pdd and ~/.pddrc are user-global config (created by pdd setup), not project markers. So a normal repo under $HOME without its own marker still falls through to its enclosing .git rather than resolving to $HOME.

A self-contained pdd project nested inside an unrelated outer git repo is correctly identified as its own project root. A separate git repository nested inside an outer PDD project is also correctly identified as its own root. When the resolved project root is a strict descendant of the enclosing git toplevel, the remote-vs-issue mismatch warning is suppressed (it would be a false positive). Pass --project-root <path> to bypass marker-based discovery entirely; this is most useful for CI scripts and unusual layouts where automatic detection cannot infer the right root, since marker-based detection already handles the nested-project case.

Prerequisites:

  • gh CLI must be installed and authenticated
  • The issue must contain a PRD describing the project scope

Workflow Resumption: Re-running pdd generate <issue-url> resumes from the last completed step. State is persisted to GitHub issue comments for cross-machine resume.

Hard Stops: The workflow stops if the PRD content is insufficient, the tech stack is ambiguous, or clarification is needed. Address the issue and re-run.

Example:

pdd generate https://github.com/myorg/myrepo/issues/42
# Generates: architecture.json, architecture_diagram.html, .pddrc, prompts/*.prompt

# Skip prompt generation (faster, just architecture)
pdd generate --skip-prompts https://github.com/myorg/myrepo/issues/42
# Generates: architecture.json, architecture_diagram.html, .pddrc

Experimental Incremental PRD Mode (--incremental --experimental-prd with a PRD file or issue URL):

After the initial architecture has been generated, pdd generate --incremental --experimental-prd <prd_file_or_issue_url> produces a targeted, validated patch instead of regenerating from scratch. The flow diffs the PRD against a hash/provenance record in .pdd/meta/prd_hashes.json plus an ignored local raw-baseline cache in .pdd/cache/prd_snapshots/, asks the LLM for a structured ArchitecturePatch (add/remove/modify modules + dependency updates), validates it deterministically (rejecting unknown modules, dangling dependencies, removals that leave dependents, unsupported fields, path traversal, and dependency cycles), and on success applies it atomically with .bak backups, propagates Requirements changes into affected prompts via detect_change + change, and generates new prompt files for added modules. Tracked metadata never stores raw PRD text, GitHub issue bodies, or issue comments; the command also writes .pdd/cache/.gitignore so raw baselines stay local even in projects without a root ignore rule.

# Diff PRD vs last fingerprint, patch architecture.json + prompts
pdd generate --incremental --experimental-prd docs/prd.md

# Same, sourced from a GitHub issue
pdd generate --incremental --experimental-prd https://github.com/owner/repo/issues/42

# Preview without writing — dry-run is safe (no files modified)
pdd generate --incremental --experimental-prd --dry-run docs/prd.md

# Suppress GitHub issue status comments during agentic runs
pdd generate --incremental --experimental-prd --no-github-state docs/prd.md

# Patch a subproject architecture/prompts directory
pdd generate --incremental --experimental-prd --output-dir service docs/prd.md

This mode is never selected by suffix alone: --experimental-prd is required. --incremental with a .prompt file remains the legacy code-patching mode (see "Force incremental patching" example above), and .md/.markdown/.txt/.rst/.adoc inputs also stay in legacy code generation when options such as --output, --original-prompt, --template, or --unit-test are present. Re-running with no PRD changes is a free no-op ("No PRD changes detected"). On invalid LLM patches the orchestrator retries up to 3 times with concrete validation feedback before failing without writes.

Current limitations (this experimental mode is intentionally narrower than pdd generate <issue-url>):

  • Starter prompts for new modules. When the LLM patch adds a new module, this command generates a lightweight starter prompt (PDD metadata tags, architecture-target-relative <include> per dependency, Role / Requirements / Interface Specification / Dependencies skeleton) — not the richer artifacts produced by the full agentic Step 9 prompt-generation flow. If you used --output-dir service or an issue-derived target directory, run follow-up sync from that target directory (cd service && pdd sync) because generated includes resolve there. Run pdd sync from the repo root only for root-level architectures.
  • Hidden/config file targets are blocked. Incremental mode refuses LLM-proposed filepath values with hidden path components or secret-like names such as .env, .github/..., private keys, credentials, and secrets files. Use full agentic generation or a manual architecture edit for legitimate hidden/config-file modules.
  • No shared-context-doc merge. Step 8.5's merge across data_dictionary.yaml / api_contracts.yaml / integration_points.yaml is not invoked. Update those files manually if the PRD change affects them.
  • No pdd sync --dry-run validation. New or modified modules are not validated against the wider sync pipeline before this command writes; run pdd sync after the experimental PRD update to catch any downstream issues.

These are tracked as follow-ups under #859. The architecture-side propagation (patch validation, transactional commit with rollback, concurrent-modification guard, <pdd-*> tag preservation, Requirements updates via detect_change + change) is fully implemented and live-verified.

Prompt Templates

Templates are reusable prompt files that generate a specific artifact (code, JSON, tests, etc.). Templates carry human/CLI metadata in YAML front matter (parsed by the CLI and not sent to the LLM), while the body stays concise and model‑focused.

  • Front matter (human/CLI):
    • name, description, version, tags, language, output
    • variables: schema for -e/--env (required/optional, type, examples)
    • usage: copyable pdd generate commands
    • discover (optional): CLI‑executed file discovery (root, patterns, exclude, caps)
    • output_schema (optional): JSON shape used by the CLI for validation and by pdd templates show
  • Prompt body (LLM):
    • Includes to hydrate context: <include>${VAR}</include>, <include-many>${LIST}</include-many>
    • Crisp instructions and an explicit output contract; no human usage notes or discovery logic

Quick examples (templates)

# Minimal (PRD required)
pdd generate -e PRD_FILE=docs/specs.md --output architecture.json \
  pdd/templates/architecture/architecture_json.prompt

# With extra context
pdd generate -e PRD_FILE=docs/specs.md -e TECH_STACK_FILE=docs/tech_stack.md \
  -e DOC_FILES='docs/ux.md,docs/components.md' \
  -e INCLUDE_FILES='src/app.py,src/api.py,frontend/app/layout.tsx' \
  --output architecture.json pdd/templates/architecture/architecture_json.prompt

# Multiple variants
pdd generate -e PRD_FILE=docs/specs.md -e APP_NAME=Shop   --output apps/shop/architecture.json   pdd/templates/architecture/architecture_json.prompt
pdd generate -e PRD_FILE=docs/specs.md -e APP_NAME=Admin  --output apps/admin/architecture.json  pdd/templates/architecture/architecture_json.prompt
pdd generate -e PRD_FILE=docs/specs.md -e APP_NAME=Public --output apps/public/architecture.json pdd/templates/architecture/architecture_json.prompt

# 4) Use variables in the output path
# 5) Use shell env fallback for convenience
export APP=shop
pdd generate -e APP -e PRD_FILE=docs/specs.md --output 'apps/${APP}/architecture.json' pdd/templates/architecture/architecture_json.prompt

Tips for authoring templates

  • Put human guidance in YAML front matter (variables with examples, usage, notes); keep the prompt body model‑focused.
  • Use <include>/<include-many> for curated context; prefer specs/configs over large code dumps.
  • Parameterized includes: pass file paths via -e, e.g. <include>${PRD_FILE}</include>; the engine resolves includes after variable expansion.
  • If your template outputs a specific filename, show example commands with --output.

Behavior notes

  • Variable expansion only applies to variables explicitly passed via -e/--env (or via the env fallback with -e KEY). Other $NAME occurrences remain unchanged.
  • --output also accepts $VAR/${VAR} from the same set of variables.
  • If you omit --output, PDD derives the filename from the prompt basename and detected language extension; set PDD_GENERATE_OUTPUT_PATH to direct outputs to a common directory.

Templates: Commands

  • Front matter is parsed (not sent to the LLM) and powers:
    • Variables schema and validation
    • Usage examples (rendered by pdd templates show)
    • Optional discover settings (executed by the CLI with caps)
    • Optional output_schema for validation
  • Commands:
    • pdd templates list [--json] [--filter tag=...]
    • pdd templates show <name>
    • pdd templates copy <name> --to prompts/
    • pdd generate --template <name> [-e KEY=VALUE...] [--output PATH]

Built-In Templates

PDD can distribute a curated set of popular templates as part of the package to help you get started quickly (e.g., frontend/Next.js, backend/Flask, data/ETL).

Where built-ins live (packaged)

  • Under the installed package at pdd/templates/<category>/**/*.prompt (plus optional README/index files). When installed from PyPI, these are included as package data.

Included starter templates

  • architecture/architecture_json.prompt: Universal architecture generator (requires -e PRD_FILE=...; supports optional TECH_STACK_FILE, DOC_FILES, INCLUDE_FILES).

LLM Toggle Functionality:

All templates support the llm parameter to control whether LLM generation runs:

  • llm=true (default): Full generation with LLM + post-processing
  • llm=false: Skip LLM generation, run only post-processing

Architecture JSON Template Features:

The architecture/architecture_json template includes automatic Mermaid diagram generation:

  • Post-processing: Automatically converts the generated JSON into an interactive HTML Mermaid diagram
  • Visualization: Creates architecture_diagram.html with color-coded modules (frontend/backend/shared)
  • Interactive: Hover tooltips show module details, dependencies, and descriptions
  • Self-contained: HTML file works offline with embedded Mermaid library

Example Commands:

# Full generation (LLM + post-processing + Mermaid HTML)
pdd generate --template architecture/architecture_json \
  -e PRD_FILE=docs/specs.md \
  -e APP_NAME="MyApp" \
  --output architecture.json
# Results in: architecture.json + architecture_diagram.html

# Post-processing only (skip LLM, generate HTML from existing JSON)
pdd generate --template architecture/architecture_json \
  -e APP_NAME="MyApp" \
  -e llm=false \
  --output architecture.json
# Results in: architecture_diagram.html (from existing architecture.json)

Context URLs (optional field):

Architecture entries support an optional context_urls array that associates web documentation references with each module. When prompts are generated from the architecture (via generate_prompt), these URLs are emitted as <web> tags in the Dependencies section, enabling the LLM to fetch relevant API documentation during code generation.

{
  "filename": "orders_api_Python.prompt",
  "dependencies": ["models_Python.prompt"],
  "context_urls": [
    {"url": "https://fastapi.tiangolo.com/tutorial/first-steps/", "purpose": "FastAPI routing patterns"},
    {"url": "https://docs.pydantic.dev/latest/concepts/models/", "purpose": "Pydantic model validation"}
  ],
  ...
}

The context_urls field is populated automatically by the agentic architecture workflow (step 5: research dependencies) but can also be added manually to any architecture entry.

Front Matter (YAML) metadata

  • Templates include YAML front matter with human-readable metadata:
    • name, description, version, tags: docs and discovery
    • language, output: defaults for generate
    • variables: parameter schema for -e/--env (type, required, default)

Example (architecture template):

---
name: architecture/architecture_json
description: Unified architecture template for multiple stacks
version: 1.0.0
tags: [architecture, template, json]
language: json
output: architecture.json
variables:
  TECH_STACK:
    required: false
    type: string
    description: Target tech stack for interface shaping and conventions.
    examples: [nextjs, python, fastapi, flask, django, node, go]
  API_STYLE:
    required: false
    type: string
    description: API style for backends.
    examples: [rest, graphql]
  APP_NAME:
    required: false
    type: string
    description: Optional app name for context.
    example: Shop
  PRD_FILE:
    required: true
    type: path
    description: Primary product requirements document (PRD) describing scope and goals.
    example_paths: [PRD.md, docs/specs.md, docs/product/prd.md]
    example_content: |
      Title: Order Management MVP
      Goals: Enable customers to create and track orders end-to-end.
      Key Features:
        - Create Order: id, user_id, items[], total, status
        - View Order: details page with status timeline
        - List Orders: filter by status, date, user
      Non-Functional Requirements:
        - P95 latency < 300ms for read endpoints
        - Error rate < 0.1%
  TECH_STACK_FILE:
    required: false
    type: path
    description: Tech stack overview (languages, frameworks, infrastructure, and tools).
    example_paths: [docs/tech_stack.md, docs/architecture/stack.md]
    example_content: |
      Backend: Python (FastAPI), Postgres (SQLAlchemy), PyTest
      Frontend: Next.js (TypeScript), shadcn/ui, Tailwind CSS
      API: REST
      Auth: Firebase Auth (GitHub Device Flow), JWT for API
      Infra: Vercel (frontend), Cloud Run (backend), Cloud SQL (Postgres)
      Observability: OpenTelemetry traces, Cloud Logging
  DOC_FILES:
    required: false
    type: list
    description: Additional documentation files (comma/newline-separated).
    example_paths: [docs/ux.md, docs/components.md]
    example_content: |
      Design overview, patterns and constraints
  INCLUDE_FILES:
    required: false
    type: list
    description: Specific source files to include (comma/newline-separated).
    example_paths: [src/app.py, src/api.py, frontend/app/layout.tsx, frontend/app/page.tsx]
  usage:
    generate:
      - name: Minimal (PRD only)
        command: pdd generate -e PRD_FILE=docs/specs.md --output architecture.json pdd/templates/architecture/architecture_json.prompt
      - name: With tech stack overview
        command: pdd generate -e PRD_FILE=docs/specs.md -e TECH_STACK_FILE=docs/tech_stack.md --output architecture.json pdd/templates/architecture/architecture_json.prompt
  discover:
    enabled: false
    max_per_pattern: 5
    max_total: 10
---

Notes

  • YAML front matter is parsed and not sent to the LLM. Use pdd templates show to view variables, usage, discover, and output schema. Pass variables via -e at the CLI.

Template Variables (reference)

  • Architecture (architecture/architecture_json.prompt)
    • PRD_FILE (path, required): Primary spec/PRD file path
    • TECH_STACK_FILE (path, optional): Tech stack overview file (includes API style; e.g., docs/tech_stack.md)
    • APP_NAME (string, optional): App name for context
    • DOC_FILES (list, optional): Comma/newline-separated list of additional doc paths
    • INCLUDE_FILES (list, optional): Comma/newline-separated list of source files to include
    • SCAN_PATTERNS (list, optional): Discovery patterns defined in front matter discover and executed by the CLI
    • SCAN_ROOT (path, optional): Discovery root defined in front matter discover

Notes

  • These variables are declared in YAML front matter at the top of each template for clarity and future CLI discovery. Until the CLI parses front matter, pass values via -e as shown in examples.

Copy-and-generate

  • Copy the desired template(s) into your project’s prompts/ folder, then use pdd generate as usual. This keeps prompts versioned with your repo so you can edit and evolve them.
  • Quick copy (Python one‑liner; run from your project root):
python - <<'PY'
from importlib.resources import files
import shutil, os

dst_dir = 'prompts/architecture'
src_dir = files('pdd').joinpath('templates/architecture')
os.makedirs(dst_dir, exist_ok=True)

for p in src_dir.rglob('*.prompt'):
    shutil.copy(p, dst_dir)
print(f'Copied built-in templates from {src_dir} -> {dst_dir}')
PY

# Then generate from the copied prompt(s)
pdd generate --output architecture.json prompts/architecture/architecture_json.prompt

Unified template examples

# Frontend (Next.js) — interface.page.route and component props
pdd generate \
  -e APP_NAME=Shop \
  # (routes are inferred from PRD/tech stack/files)
  -e PRD_FILE=docs/specs.md \
  -e DOC_FILES='docs/ux.md,docs/components.md' \
  -e TECH_STACK_FILE=docs/tech_stack.md \
  # discovery, if needed, is configured in template YAML and executed by the CLI
  --output architecture.json \
  pdd/templates/architecture/architecture_json.prompt

# Backend (Python) — interface.module.functions or interface.api.endpoints
pdd generate \
  -e PRD_FILE=docs/backend-spec.md \
  -e TECH_STACK_FILE=docs/tech_stack.md \
  -e INCLUDE_FILES='src/app.py,src/api.py,pyproject.toml' \
  --output architecture.json \
  pdd/templates/architecture/architecture_json.prompt

Interface Schema

  • Core keys (every item):
    • reason, description, dependencies, priority, filename, optional tags.
  • Interface object (typed, include only what applies):
    • type: component | page | module | api | graphql | cli | job | message | config | entrypoint
    • component: props[], optional emits[], context[]
    • page: route, optional params[], layout, and dataSources[] where each entry is an object with required kind (e.g., api, query) and source (URL or identifier), plus optional method, description, auth, inputs[], outputs[], refreshInterval, notes
    • module: functions[] with name, signature, optional returns, errors, sideEffects
    • api: endpoints[] with method, path, optional auth, requestSchema, responseSchema, errors
    • graphql: optional sdl, or operations with queries[], mutations[], subscriptions[]
    • cli: commands[] with name, optional args[], flags[], exitCodes[]; optional io (stdin, stdout)
    • job: trigger (cron/event), optional inputs[], outputs[], retryPolicy
    • message: topics[] with name, direction (publish|subscribe), optional schema, qos
    • config: keys[] with name, type, optional default, required, source (env|file|secret)
    • entrypoint: empty object {} for framework/runtime-discovered entry files that expose no named exports (e.g. main.py, app/layout.tsx)
    • Optional: version, stability (experimental|stable)

Examples:

{
  "reason": "Top-level products page",
  "description": "...",
  "dependencies": ["layout_tsx.prompt"],
  "priority": 1,
  "filename": "page_tsx.prompt",
  "tags": ["frontend","nextjs"],
  "interface": {
    "type": "page",
    "page": {"route": "/products", "params": [{"name":"id","type":"string"}]},
    "component": {"props": [{"name":"initialProducts","type":"Product[]","required":true}]}
  }
}
{
  "reason": "Order service module",
  "description": "...",
  "dependencies": ["db_python.prompt"],
  "priority": 1,
  "filename": "orders_python.prompt",
  "tags": ["backend","python"],
  "interface": {
    "type": "module",
    "module": {
      "functions": [
        {"name": "load_orders", "signature": "def load_orders(user_id: str) -> list[Order]"},
        {"name": "create_order", "signature": "def create_order(dto: OrderIn) -> Order"}
      ]
    }
  }
}
{
  "reason": "Orders HTTP API",
  "description": "...",
  "dependencies": ["orders_python.prompt"],
  "priority": 2,
  "filename": "api_python.prompt",
  "tags": ["backend","api"],
  "interface": {
    "type": "api",
    "api": {
      "endpoints": [
        {
          "method": "GET",
          "path": "/orders/{id}",
          "auth": "bearer",
          "responseSchema": {"type":"object","properties":{"id":{"type":"string"}}},
          "errors": ["404 Not Found","401 Unauthorized"]
        }
      ]
    }
  }
}

Notes and recommendations

  • Treat copied templates as a starting point; edit them to match your stack and conventions.
  • Keep templates under version control along with your code to preserve the prompt‑as‑source‑of‑truth model.
  • If you maintain your own template set, store them under prompts/<org_or_team>/... and compose with <include> to maximize reuse.

Templates: additional UX

  • Goals:

    • Discover, inspect, and vendor templates without manual file paths.
    • Validate required variables and surface defaults from template metadata.
    • Support a search order so project templates can override packaged ones.
  • Commands:

    • pdd templates list [--json] [--filter tag=frontend] to discover templates
    • pdd templates show <name> [--raw] to view metadata and variables
    • pdd templates copy <name> --to prompts/ to vendor into your repo
    • pdd generate --template <name> [-e KEY=VALUE...] [--output PATH]
  • Example usage:

# Discover and inspect
pdd templates list --filter tag=frontend
pdd templates show frontend/nextjs_architecture_json

# Vendor and customize
pdd templates copy frontend/nextjs_architecture_json --to prompts/frontend/

# Generate without specifying a file path
pdd generate --template frontend/nextjs_architecture_json \
  -e APP_NAME=Shop \
  # routes are inferred from PRD/tech stack/files
  --output architecture.json
  • Search order:

    • Project: ./prompts/** (allows team overrides)
    • .pddrc paths: any configured templates.paths
    • Packaged: pdd/templates/** (built‑ins)
    • Optional: $PDD_PATH/prompts/** (org‑level packs)
  • Template front matter:

    • YAML metadata at the top of .prompt files to declare name, description, tags, version, language, default output, and variables (with required, default, type such as string or json).
    • Variable precedence: values from -e/--env override front‑matter defaults; unknowns are validated and surfaced to the user.
    • Output path precedence: --output (CLI) > output: (front matter) > generate_output_path (.pddrc). If front‑matter output: cannot be resolved, the CLI emits a yellow warning and falls back to the default path instead of failing silently.
    • Example:
      ---
      name: frontend/nextjs_architecture_json
      description: Generate a Next.js architecture.json file from app metadata
      tags: [frontend, nextjs, json]
      version: 1.0.0
      language: json
      output: architecture.json
      variables:
        APP_NAME: { required: true }
        ROUTES:   { type: json, default: [] }
      ---
      ...prompt body...
      

3. example

Create a compact example demonstrating how to use functionality defined in a prompt. Similar to a header file or API documentation, this produces minimal, token-efficient code that shows the interface without implementation details.

pdd [GLOBAL OPTIONS] example [OPTIONS] PROMPT_FILE CODE_FILE

Arguments:

  • PROMPT_FILE: The filename of the prompt file that generated the code.
  • CODE_FILE: The filename of the existing code file.

Options:

  • --output LOCATION: Specify where to save the generated example code. The default file name is <basename>_example.<language_file_extension>. If an environment variable PDD_EXAMPLE_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --format FORMAT: Output format for the generated example (default: code). Valid values:
    • code: Uses the language-specific file extension (e.g., .py for Python, .js for JavaScript) when no suffix is supplied on --output. If --output includes a suffix (.yml, .m, .txt, …), that suffix is honored verbatim — pass --format md to force a .md extension.
    • md: Generates markdown content; the resolved output path will always end in lowercase .md, replacing any other suffix (including upper-case variants like .MD) on --output. When --format md overrides an explicit non-.md output suffix, the wrapper prints a warning naming both the requested and resolved paths unless --quiet is set. If any wrapper-rewritten output path already exists (--format md suffix override, or a bare name under --format code), you will also be prompted to confirm the overwrite unless --force is set.

Where used:

  • Dependency references: Examples serve as lightweight (token efficient) interface references for other prompts and can be included as dependencies of a generate target.
  • Sanity checks: The example program is typically used as the runnable program for crash and verify, providing a quick end-to-end sanity check that the generated code runs and behaves as intended.
  • Auto-deps integration: The auto-deps command can scan example files (e.g., examples/**/*.py) and insert relevant references into prompts. Based on each example’s content (imports, API usage, filenames), it identifies useful development units to include as dependencies.
  • Metadata finalization: A successful pdd example updates the affected module's fingerprint and clears its stale .pdd/meta/<basename>_<language>_run.json runtime-verification report, so a regenerated example never leaves runtime state describing the pre-mutation output. The fingerprint write is atomic (temp-file + rename via FingerprintTransaction); a finalization failure exits non-zero rather than being surfaced as a warning.

When to use: Choose this command when creating reusable references that other prompts can efficiently import. This produces token-efficient examples that are easier to reuse across multiple prompts compared to including full implementations.

Example:

pdd [GLOBAL OPTIONS] example --output examples/factorial_calculator_example.py factorial_calculator_python.prompt src/factorial_calculator.py

4. test

Generate or enhance unit tests for a given code file and its corresponding prompt file. Also supports agentic mode for generating UI tests from GitHub issues.

Agentic Mode (UI Test Generation)

Generate UI tests from a GitHub issue. The issue describes what needs to be tested (a webpage, CLI, or desktop app), and an agentic workflow analyzes the target, creates a test plan, and generates comprehensive UI tests.

pdd [GLOBAL OPTIONS] test <github-issue-url>

How it works (18-step workflow with GitHub comments):

  1. Duplicate check - Search for existing issues describing the same test requirements. If found, merge content and close the duplicate.

  2. Documentation check - Review repo documentation and codebase to understand what needs to be tested. Identifies OpenAPI/Swagger specs if present.

  3. Analyze & clarify - Determine if enough information exists in the issue to create tests. Posts comment requesting clarification if needed.

  4. Detect frontend - Identify the test type: web UI, CLI, desktop app, or API. Determines the appropriate testing framework.

  5. Create test plan - Design a comprehensive test plan and verify it's achievable.

5b. Enhance test plan - Add contract validation test cases (from OpenAPI/Swagger specs) and accessibility test cases (for web apps using @axe-core/playwright at WCAG 2.1 AA level).

  1. Assess coverage (web only, requires playwright-cli) - Compare requirements against the enhanced test plan to identify gaps needing manual testing.

  2. Create manual testing checklist (web only) - Generate a checklist using three strategies: page-by-page exhaustive testing, user-story walkthroughs, and accessibility spot-checks.

  3. Manual testing execution (web only) - Execute checklist items via playwright-cli commands. Runs serially in CLI mode or in parallel via Cloud Batch when PDD_CLOUD_RUN=true.

  4. Create regression tests (web only) - Generate automated tests that reproduce bugs found in Step 8.

  5. Validate regression tests (web only) - Confirm regression tests fail against current code (proving bugs exist).

  6. Loop check (web only) - Check checklist completion. Loops back to Step 8 if items remain (max 3 iterations).

  7. Generate tests - Create tests in a worktree from the enhanced plan, including behavioral, contract, and accessibility tests.

  8. Run tests - Execute all generated tests against the target.

  9. Fix & iterate - Fix any failing tests and re-run until they pass.

  10. Validate tests against plan - Cross-reference the enhanced plan against generated tests. Generate missing tests for any unimplemented cases.

  11. Run newly generated tests - Run and fix tests created in Step 15 (if any).

  12. Submit PR - Create a draft PR with enhanced description including test plan coverage ratio, contract test summary, accessibility audit summary, and manual testing summary.

Execution Modes:

ModeSteps 6-11 behavior
CLI (pdd test <url>)Serial: Runs each checklist chunk one at a time
GitHub App (PDD_CLOUD_RUN=true)Parallel: Fans out to Cloud Batch spot VMs

Prerequisites:

  • Steps 6-11 (manual/exploratory testing) require playwright-cli in PATH. If not found, these steps are skipped with a warning.
  • Steps 6-11 only run for web test types (TEST_TYPE: web).

Agentic Options:

  • --timeout-adder FLOAT: Add additional seconds to each step's timeout (default: 0.0)
  • --no-github-state: Disable GitHub issue comment-based state persistence, use local-only
  • --clean-restart: Discard saved agentic test state and start the 18-step workflow fresh
  • --manual: Use legacy prompt-based mode instead of agentic mode

Environment Variables:

  • PDD_CLOUD_RUN=true: Enable parallel execution mode for manual testing (Steps 6-11)
  • PDD_NO_GITHUB_STATE=1: Disable GitHub state persistence

Cross-Machine Resume: By default, workflow state is stored in a hidden comment on the GitHub issue, enabling resume from any machine. Use --no-github-state to disable this feature, or --clean-restart to discard saved state and rerun from the beginning.

Example (Agentic Mode):

# Generate UI tests from a GitHub issue
pdd test https://github.com/myorg/myrepo/issues/789

# Resume after answering clarifying questions
pdd test https://github.com/myorg/myrepo/issues/789

# Start fresh and ignore saved workflow state
pdd test --clean-restart https://github.com/myorg/myrepo/issues/789

Next Step - Fixing Test Issues:

If the generated tests reveal issues that need code fixes, use pdd fix with the same issue URL:

pdd fix https://github.com/myorg/myrepo/issues/789

Manual Mode (Prompt-Based)

Generate or enhance unit tests for a given code file and its corresponding prompt file.

Test organization:

  • For each target <basename>, PDD maintains a single test file (by default named test_<basename>.<language_extension> and typically placed under a tests directory).
  • New tests accumulate in that same file over time rather than being regenerated from scratch. When augmenting tests, PDD can merge additions into the existing file (see --merge).
pdd [GLOBAL OPTIONS] test [OPTIONS] PROMPT_FILE CODE_OR_EXAMPLE_FILE
pdd [GLOBAL OPTIONS] test --manual [OPTIONS] PROMPT_FILE CODE_OR_EXAMPLE_FILE

Arguments:

  • PROMPT_FILE: The filename of the prompt file that generated the code.
  • CODE_OR_EXAMPLE_FILE: The filename of the code implementation or example file. Files ending with _example are treated as example files for TDD-style test generation.

Options:

  • --output LOCATION: Specify where to save the generated test file. The default file name is test_<basename>.<language_file_extension>. If an output file with the specified name already exists, a new file with a numbered suffix (e.g., test_calculator_1.py) will be created instead of overwriting.
  • --language: Specify the programming language. Defaults to the language specified by the prompt file name.
  • --coverage-report PATH: Path to the coverage report file for existing tests. When provided, generates additional tests to improve coverage.
  • --existing-tests PATH [PATH...]: Path(s) to the existing unit test file(s). Required when using --coverage-report. Multiple paths can be provided.
  • --target-coverage FLOAT: Desired code coverage percentage to achieve (default is 90.0).
  • --merge: When used with --existing-tests, merges new tests with existing test file instead of creating a separate file.

When the prompt contains a contract_rules section, unit test generation uses those rule IDs for planning: MUST rules should receive behavioral tests, MUST NOT rules should receive negative tests when fixtures allow, and generated test names or comments should reference the relevant rule ID where practical. If a rule cannot be exercised with the available fixtures, the generated test file should include a TODO or skipped-test reason instead of silently omitting the rule.

Story Mode

Generate issue-derived user stories or update story prompt metadata.

pdd [GLOBAL OPTIONS] test --issue https://github.com/myorg/myrepo/issues/789 prompts/upload_python.prompt prompts/notify_python.prompt
pdd [GLOBAL OPTIONS] test --issue ./issues/upload.md prompts/upload_python.prompt
pdd [GLOBAL OPTIONS] test user_stories/story__my_flow.md

Behavior:

  • If input is one or more .prompt files, --issue is required. The issue source can be a GitHub issue/PR URL, an issue number resolvable from the current repo, or a local issue markdown file.
  • PDD resolves the issue first and authors user_stories/story__<name>.md from that issue text. Prompt file content is withheld from the story author so the story can catch prompt drift from the issue intent.
  • The prompt files passed on the command line are linked directly in pdd-story-prompts metadata. Story generation does not run detect_change or auto-detect touched prompts.
  • Missing/unresolvable issue sources or invalid LLM story output fail the command instead of writing a prompt-derived fallback story.
  • pdd test user_stories/story__*.md updates metadata for an existing story file. If metadata is missing or stale, PDD runs prompt detection and writes: <!-- pdd-story-prompts: prompt_a_python.prompt, prompt_b_python.prompt -->
  • This enables deterministic prompt-subset validation in pdd detect --stories.

Providing Command-Specific Context

While prompts are the primary source of instructions, some PDD commands (like test and example) can be further guided by project-specific context files. These commands may automatically look for conventional files (e.g., context/test.prompt, context/example.prompt) in the current working directory during their internal prompt preprocessing phase.

If found, the content of these context files is included (using the <include> mechanism described in the preprocess section) into the internal prompt used by the command. This allows you to provide specific instructions tailored to your project, such as:

  • Specifying required import statements.
  • Suggesting preferred testing frameworks or libraries.
  • Providing project-specific coding conventions or patterns.

Example: Creating a file named context/test.prompt with the content:

Please ensure all tests use the 'unittest' framework and import the main module as 'from my_module import *'.

could influence the output of the pdd test command when run in the same directory.

Note: This feature relies on the internal implementation of specific PDD commands incorporating the necessary <include> tags for these conventional context files. It is primarily used by test and example but may be adopted by other commands in the future. Check the specific command documentation or experiment to confirm if a command utilizes this pattern.

Basic Examples:

  1. Generate initial unit tests:
pdd [GLOBAL OPTIONS] test --output tests/test_factorial_calculator.py factorial_calculator_python.prompt src/factorial_calculator.py
  1. Generate tests from an example file (TDD-style):
pdd [GLOBAL OPTIONS] test --output tests/test_calculator.py calculator_python.prompt examples/calculator_example.py
  1. Generate additional tests to improve coverage (with multiple existing test files):
pdd [GLOBAL OPTIONS] test --coverage-report coverage.xml --existing-tests tests/test_calculator.py --existing-tests tests/test_calculator_edge_cases.py --output tests/test_calculator_enhanced.py calculator_python.prompt src/calculator.py
  1. Improve coverage and merge with existing tests:
pdd [GLOBAL OPTIONS] test --coverage-report coverage.xml --existing-tests tests/test_calculator.py --merge --target-coverage 95.0 calculator_python.prompt src/calculator.py

Coverage Analysis Strategy

When coverage options are provided, the test command will:

  1. Analyze the coverage report to identify:

    • Uncovered lines and branches
    • Partially tested conditions
    • Missing edge cases
  2. Generate additional test cases prioritizing:

    • Complex uncovered code paths
    • Error conditions
    • Boundary values
    • Integration points
  3. Maintain consistency with:

    • Existing test style and patterns
    • Project's testing conventions
    • Original prompt's intentions

5. preprocess

Preprocess prompt files and save the results.

pdd [GLOBAL OPTIONS] preprocess [OPTIONS] PROMPT_FILE

Arguments:

  • PROMPT_FILE: The filename of the prompt file to preprocess.

Options:

  • --output LOCATION: Specify where to save the preprocessed prompt file. The default file name is <basename>_<language>_preprocessed.prompt.
  • --xml: Automatically insert XML delimiters for long and complex prompt files to structure the content better. With this option prompts are only preprocessed to insert in XML delimiters, but not preprocessed otherwise.
  • --recursive: Recursively preprocess all prompt files in the prompt file.
  • --double: Curly brackets will be doubled.
  • --exclude: List of keys to exclude from curly bracket doubling.
  • Context compression: use global --context-compression / --compression-fallback before preprocess (see Global Options); preprocess does not accept these flags after the subcommand.
  • --snapshot: Write the expanded prompt plus a snapshot manifest for any dynamic context resolved during preprocessing. The manifest records hashes and artifact paths for captured <shell>, <web>, and semantic query= include outputs so a later replay can reconstruct the same prompt context.
pdd preprocess prompts/refund_python.prompt --snapshot

Use snapshots when dynamic tags are needed for durable behavior. Static prompts with only deterministic includes report that no nondeterministic context was captured. Do not pass --recursive with --snapshot when the prompt uses <shell>, <web>, or query= includes (recursive mode defers those tags). Enforce captured snapshots in CI with pdd checkup snapshot prompts/refund_python.prompt (see docs/ci.md).

XML-like Tags

PDD supports the following XML-like tags in prompt files. Note: XML-like tags (<include>, <include-many>, <shell>, <web>) are left untouched inside fenced code blocks (``` or ~~~) or inline single backticks so documentation examples remain literal.

  1. include: Includes file content into the prompt. The file path is always the tag body. Optional attributes extract specific parts instead of the full file:

    <include>./path/to/file.txt</include>
    <include select="def:foo,class:Bar">src/utils.py</include>
    <include select="pytest:test_my_feature">tests/test_existing.py</include>
    <include select="class:Handler" mode="interface">src/api.py</include>
    <include query="authentication flow">docs/api_reference.md</include>
    
    • select= — deterministic structural extraction (functions, classes, pytest tests, API contract slices (contract:symbol), line ranges, headings, regex, JSON/YAML paths). Composable via comma-separation; values like pytest:test_a,test_b stay grouped.
    • mode="interface" — Python-only. Extracts signatures and docstrings with bodies replaced by ....
    • query= — LLM-powered semantic extraction, cached in .pdd/extracts/.
    • optional — when present on an <include ...> tag, a missing file resolves to an empty string ("") during non-recursive preprocessing (while still logging a warning).
    • When both select= and query= are present, select= wins (no LLM cost).

    This mechanism is also used internally by some commands (like test and example) to automatically incorporate project-specific context files if they exist in conventional locations (e.g., context/test.prompt). See 'Providing Command-Specific Context' for details. For the full selector reference, see the Prompting Guide.

  2. pdd: Indicates a comment that will be removed from the preprocessed prompt, including the tags themselves.

    <pdd>This is a comment that won't appear in the preprocessed output</pdd>
    
  3. shell: Executes shell commands and includes their output in the prompt, removing the shell tags.

    <shell>ls -la</shell>
    
  4. web: Scrapes a web page and includes its markdown content in the prompt, removing the web tags.

    <web>https://example.com</web>
    

Triple Backtick Includes

PDD supports two ways of including external content:

  1. Triple backtick includes: Replaces angle brackets in triple backticks with the content of the specified file.
    ```
    <./path/to/file.txt>
    ```
    This will be recursively processed until there are no more angle brackets in triple backticks.
    
    
  2. XML include tags: As described above.

Curly Bracket Handling

When using the --double option:

  • Single curly brackets are doubled if they're not already doubled
  • Already doubled brackets are preserved
  • Nested curly brackets are properly handled
  • Special handling is applied for code blocks (JSON, JavaScript, TypeScript, Python)
  • Multiline variables with curly brackets receive special handling

Use the --exclude option to specify keys that should be excluded from curly bracket doubling. This option only applies if the entire string inside a pair of single curly braces exactly matches one of the excluded keys.

For example, with --exclude model:

  • {model} remains {model} (excluded due to exact match).
  • {model_name} is doubled, as 'model_name' is not an exact match for 'model'.
  • {api_model} is doubled, not an exact match.
  • Braces containing other content, even if related to the key (e.g., var={key}_value), will generally still follow doubling rules unless the inner {key} itself is excluded.

Example command usage:

pdd [GLOBAL OPTIONS] preprocess --output preprocessed/factorial_calculator_python_preprocessed.prompt --recursive --double --exclude model,temperature factorial_calculator_python.prompt

5a. replay

Reconstruct and audit the expanded prompt context recorded by a snapshot-enabled run.

pdd replay .pdd/evidence/runs/<run_id>.json

Replay verifies that the expanded prompt hash can be reconstructed from the run artifact and its captured context snapshots. It does not promise identical generated code, because model execution may remain nondeterministic; the replay contract is identical prompt/context reconstruction.

5b. context

Show context-window usage broken down by source for a preprocessed prompt, rendered like Claude Code's /context display.

pdd context <prompt_path> [--model MODEL] [--json] [--table] [--threshold N]

Preprocesses the prompt the same way generation does and counts tokens per source segment without making an LLM call.

Arguments

  • prompt_path: Path to the prompt file to audit.

Options

  • --model MODEL: Model name used for context-limit lookup. Defaults to PDD_MODEL_DEFAULT env var, or gpt-4o if unset.
  • --json: Emit machine-readable JSON output to stdout instead of the usage box.
  • --table: Show the raw per-source token-attribution table instead of the usage box.
  • --threshold N: Integer percentage (0–100, default 80) above which the command exits with code 2 to signal context budget exceeded. Set to 0 to disable.

Output

By default it prints a Claude-Code /context-style usage box:

  • A grid of cells showing used context-window space split by category against free space ().
  • The model name and total/limit tokens (percent%) summary.
  • An Estimated usage by category breakdown — one line per source (prompt body, each <include> file, tests, examples, grounding) — followed by a Free space line.

--table instead prints a table with a header (total tokens, model, context-limit size, percentage used) and rows sorted by token count descending (largest consumer first).

Attribution follows the real hydration path, so a targeted include (lines=, select=, mode=, or a literal <include-many> list) is counted by the content it actually contributes — not the whole source file. Nested includes roll up into their top-level parent, while independent top-level includes each keep their own row even when their text overlaps.

Unresolved/missing includes are surfaced as a warning and a 0-token row instead of being silently folded into the prompt body, but only when preprocess would treat the syntax as a real directive. Include examples inside code fences are not expanded or reported, and optional missing includes are skipped silently.

In both modes, warnings are printed for any dynamic tags (<shell>, <web>, semantic query= includes) — in the prompt or inside an included file — that were detected but not expanded (nondeterministic, deferred); their markup is excluded from the token total.

JSON output (--json) emits a single object with keys: total_tokens, context_limit, percent_used, model, rows, warnings, and threshold_exceeded.

The context command suppresses global PDD command footers for all modes. In --json mode stdout is only the JSON object, so CI and dashboards can parse it directly.

Exit codes

  • 0: audit completed within threshold.
  • 2: total tokens exceed --threshold percent of the model's context limit (useful for CI and dashboards).

Examples

# Claude-Code /context-style usage box with default 80% threshold
pdd context prompts/my_module_python.prompt

# Raw per-source attribution table
pdd context prompts/my_module_python.prompt --table

# Audit against a specific model
pdd context prompts/my_module_python.prompt --model claude-sonnet-4-6

# JSON output for CI dashboards
pdd context prompts/my_module_python.prompt --json

# Fail CI when prompt uses more than 60% of context
pdd context prompts/my_module_python.prompt --threshold 60

6. fix

Fix errors in code and unit tests. Supports two modes: Agentic E2E Fix (default when given a GitHub URL) for multi-dev-unit test fixing, and Manual mode for single dev-unit fixing with explicit file arguments.

Agentic E2E Fix Mode (GitHub URL):

pdd [GLOBAL OPTIONS] fix [OPTIONS] <GITHUB_ISSUE_URL>

Manual Mode (file arguments):

pdd [GLOBAL OPTIONS] fix --manual [OPTIONS] PROMPT_FILE CODE_FILE UNIT_TEST_FILE ERROR_FILE

Manual Mode Arguments

  • PROMPT_FILE: The filename of the prompt file that generated the code under test.
  • CODE_FILE: The filename of the code file to be fixed.
  • UNIT_TEST_FILES: The filename(s) of the unit test file(s). Multiple files can be provided, and each will be processed individually.
  • ERROR_FILE: The filename containing the unit test runtime error messages. Optional and does not need to exist when used with the --loop command.

Common Options

  • --manual: Use manual mode with explicit file arguments (required for legacy/single dev-unit fixing).
  • --verbose: Show detailed output during processing.
  • --quiet: Suppress all output except errors.
  • --protect-tests/--no-protect-tests: When enabled, prevents the LLM from modifying test files. The LLM will treat tests as read-only specifications and only fix the code. This is especially useful when tests created by pdd bug are known to be correct. Default: --no-protect-tests.

Passing tests are also checked against repository-backed data contracts. When a fix introduces a literal query field or a generated mock fabricates a field for an existing query, pdd fix compares that shape with the exact resource section in schema Markdown/JSON and independent production readers/writers. A real contradiction (for example, querying user_waitlist.userId when the user_waitlist schema has no userId field while the test mocks one) is a hard non-zero failure before manual outputs are written or agentic changes are committed. If no exact contract exists, the result is surfaced as inconclusive instead of guessing from the field name.

Agentic E2E Fix Options

  • --timeout-adder FLOAT: Additional seconds to add to each step's timeout (default: 0.0).
  • --max-cycles INT: Maximum number of outer loop cycles before giving up (default: 5).
  • --resume/--no-resume: Resume from saved state if available (default: --resume).
  • --clean-restart: Discard saved agentic E2E fix state and ignore sibling pdd bug analysis state before starting fresh. Implies --no-resume.
  • --context-compression {off,test,examples,contracts,all}: Command-local on pdd fix (and also available globally before the subcommand). Unlike generate and preprocess, fix accepts these flags after fix in the argv list.
  • --compression-fallback {full,error}: Same placement as --context-compression on fix (command-local or global before fix).
  • --force: Override the branch mismatch safety check. By default, the command aborts if the current git branch doesn't match the expected branch from the issue (to prevent accidentally modifying the wrong codebase).

Manual Mode Options

  • --output-test LOCATION: Specify where to save the fixed unit test file. The default file name is test_<basename>_fixed.<language_file_extension>. Warning: If multiple UNIT_TEST_FILES are provided along with this option, only the fixed content of the last processed test file will be saved to this location, overwriting previous results. For individual fixed files, omit this option.
  • --output-code LOCATION: Specify where to save the fixed code file. The default file name is <basename>_fixed.<language_file_extension>. If an environment variable PDD_FIX_CODE_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --output-results LOCATION: Specify where to save the results of the error fixing process. The default file name is <basename>_fix_results.log. If an environment variable PDD_FIX_RESULTS_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --loop: Enable iterative fixing process.
    • --verification-program PATH: Specify the path to a Python program that verifies if the code still runs correctly.
    • --max-attempts INT: Set the maximum number of fix attempts before giving up (default is 3).
    • --budget FLOAT: Set the maximum cost allowed for the fixing process (default is $5.0).
  • --auto-submit: Automatically submit the example if all unit tests pass during the fix loop.
  • --context-compression / --compression-fallback: Same command-local fix options as in Agentic E2E Fix Options above (not accepted after generate or preprocess).

When the --loop option is used, the fix command will attempt to fix errors through multiple iterations. It will use the specified verification program to check if the code runs correctly after each fix attempt. The process will continue until either the errors are fixed, the maximum number of attempts is reached, or the budget is exhausted.

Outputs:

  • Fixed unit test file(s).
  • Fixed code file.
  • Results file containing the LLM model's output with unit test results.
  • Print out of results when using '--loop' containing:
    • Success status (boolean)
    • Total number of fix attempts made
    • Total cost of all fix attempts
  • This will also create intermediate versions of the unit test and code files for the different iterations with timestamp-based naming (e.g., basename_1_0_3_0_20250402_124442.py, standalone_test_1_0_3_0_20250402_124442.py).

Example:

pdd [GLOBAL OPTIONS] fix --output-code src/factorial_calculator_fixed.py --output-results results/factorial_fix_results.log factorial_calculator_python.prompt src/factorial_calculator.py tests/test_factorial_calculator.py tests/test_factorial_calculator_edge_cases.py errors.log

In this example, pdd fix will be run for each test file, and the fixed test files will be saved as tests/test_factorial_calculator_fixed.py and tests/test_factorial_calculator_edge_cases_fixed.py.

Focused Repair for Large Dev Units

For dev units where the code file exceeds 500 lines or the test file exceeds 1000 lines, pdd fix automatically switches to a two-phase focused-repair strategy instead of sending the entire file to the LLM in one shot.

How it Works:

  1. Fast-path: If the pytest traceback directly names 1–3 functions, those function slices plus their failing tests are sent to the LLM immediately — no diagnosis step needed.
  2. Phase 1 — Diagnose: For all other large dev units, a code skeleton (function signatures only, no bodies) is sent along with the error log so the LLM can identify which functions are likely broken.
  3. Phase 2 — Fix: Only the identified function slices plus their failing tests are sent for the actual fix. The repaired bodies are spliced back into the original file at their original line offsets.
  4. Automatic fallback: If the focused-repair path encounters a parse error or returns an empty result, pdd fix silently falls back to the standard full-file behavior.

This strategy is fully automatic and requires no flags. The threshold check and focused-repair path are internal to pdd fix; its public interface and all existing flags remain unchanged.

Agentic Fallback Mode

(This feature is also available for the crash and verify command.)

For particularly difficult bugs that the standard iterative fix process cannot resolve, pdd fix offers a powerful agentic fallback mode. When activated, it invokes a project-aware CLI agent to attempt a fix with a much broader context.

How it Works: If the standard fix loop completes all its attempts and fails to make the tests pass, the agentic fallback will take over. It constructs a detailed set of instructions and delegates the fixing task to a dedicated CLI agent like Google's Gemini, Anthropic's Claude, OpenAI's Codex, or OpenCode.

How to Use:

This feature only takes effect when --loop is set.

When the --loop flag is set, agentic fallback is enabled by default:

pdd [GLOBAL OPTIONS] fix --manual --loop [OTHER OPTIONS] PROMPT_FILE CODE_FILE UNIT_TEST_FILE

Or you may want to enable it explicitly

pdd [GLOBAL OPTIONS] fix --manual --loop --agentic-fallback [OTHER OPTIONS] PROMPT_FILE CODE_FILE UNIT_TEST_FILE

To disable this feature while using --loop, add --no-agentic-fallback to turn it off.

pdd [GLOBAL OPTIONS] fix --manual --loop --no-agentic-fallback [OTHER OPTIONS] PROMPT_FILE CODE_FILE UNIT_TEST_FILE

Prerequisites: For the agentic fallback to function, you need to have at least one of the supported agent CLIs installed with valid credentials. Each CLI has its own credential store and falls back to environment-variable API keys if you don't have a stored login. The agents are tried in the following order of preference:

  1. Anthropic Claude:
    • Requires the claude CLI to be installed and in your PATH.
    • Authenticates with your stored Claude Max/Pro OAuth login if you've run claude auth login (recommended), otherwise with ANTHROPIC_API_KEY from your environment.
    • Issue #813: under CI=1 (which pdd always sets) the claude CLI normally prefers ANTHROPIC_API_KEY over OAuth — pdd auto-detects this and drops a stale env key when an OAuth login is present so your subscription is used. Set PDD_KEEP_ANTHROPIC_API_KEY=1 to force API-key billing instead.
  2. Google (Antigravity agy / legacy gemini):
    • Requires either the agy CLI (preferred, install via curl -fsSL https://antigravity.google/cli/install.sh | bash) or the legacy gemini CLI (npm install -g @google/gemini-cli) to be on your PATH. When both are installed, auto mode picks agy when an Antigravity-compatible key/OAuth/Vertex credential is configured; if the only Google auth signal is legacy ~/.gemini/oauth_creds.json, it uses gemini so rollback OAuth keeps working. PDD_GOOGLE_CLI=gemini is the explicit rollback to the old binary. PDD_AGENTIC_PROVIDER=antigravity pins agy and overrides any prior PDD_GOOGLE_CLI.
    • Authenticates with Antigravity OAuth or keyring-backed Google subscription sign-in (~/.gemini/antigravity-cli/ state), API keys (ANTIGRAVITY_API_KEY/GOOGLE_API_KEY, plus PDD maps GEMINI_API_KEY to GOOGLE_API_KEY for the agy subprocess), or Vertex AI env auth. Legacy gemini uses its own OAuth file (~/.gemini/oauth_creds.json) plus GEMINI_API_KEY/GOOGLE_API_KEY. Google announced consumer-tier Gemini CLI cutoff on 2026-06-18.
  3. OpenAI Codex/GPT:
    • Requires the codex CLI to be installed and in your PATH.
    • Authenticates with ~/.codex/auth.json ChatGPT login (run codex login once) or OPENAI_API_KEY from your environment.
  4. OpenCode (provider-agnostic):
    • Requires the opencode CLI to be installed and in your PATH (npm install -g opencode-ai).
    • Authenticates with OpenCode provider credentials from opencode auth login (stored in ~/.local/share/opencode/auth.json), OpenCode JSON config (~/.config/opencode/opencode.json or project opencode.json), or underlying provider env vars such as ANTHROPIC_API_KEY, OPENAI_API_KEY, OPENROUTER_API_KEY, GITHUB_TOKEN, etc.
    • Recommended: set OPENCODE_MODEL=provider/model (for example, anthropic/claude-sonnet-4-5) to avoid relying on default model resolution.
    • Optional: set OPENCODE_AGENT and OPENCODE_VARIANT for OpenCode agent/variant selection.

You can configure environment-variable keys using pdd setup or by setting them in your shell. For OAuth/subscription auth, run each CLI's login command once interactively.

Provider-limit marker for automation:

When an agentic provider or credential hits a real rate, usage, session, or credential limit, PDD emits a single secret-safe marker line on plain stdout that automation can parse without scraping raw provider stderr. Quiet mode may suppress the explanatory diagnostic, but it does not suppress this scheduling marker.

PDD_PROVIDER_LIMIT provider=<anthropic|openai|google|antigravity|opencode> status=<429|credential_limit> reason=<rate_limit|usage_limit|session_limit|credential_limit> reset_at=<UTC ISO-8601 timestamp or empty> reset_source=<provider|parsed_text|estimated|none>

reset_at is normalized to UTC (YYYY-MM-DDTHH:MM:SSZ) when PDD can read or infer a reset time, for example from Claude Code limit text — reset_source=parsed_text for an explicit date/timestamp, estimated when only a time-of-day was given and the date was inferred. Generic provider 429s without reset metadata still emit the marker with an empty reset_at and reset_source=none. The marker fires once per provider after its retry budget is spent (a 429 that recovers on retry emits nothing). It is a per-provider detection signal, not a job-failure signal: in a multi-provider run PDD can emit a marker for a limited provider and still succeed via the next provider, so consumers should combine the marker with the command's exit status before rescheduling. It is additive: existing credential-limit classification text remains for backward compatibility. The marker never includes raw provider stderr, tokens, API keys, user prompt content, or other untrusted provider text. (Antigravity runs under the google provider slot; PDD reports provider=antigravity only when the selected Google CLI is agy. An unmappable provider is reported as the literal unknown rather than any raw text.)

Agentic E2E Fix Mode

For fixing end-to-end tests that span multiple dev units, use the agentic E2E fix mode by passing a GitHub issue URL (typically created by pdd bug). This mode orchestrates an iterative 11-step workflow, fixing both unit tests and e2e tests across your codebase, validating CI, and cleaning up code.

How it Works:

The workflow analyzes the GitHub issue to extract test information, then iteratively fixes failing tests:

  1. Run Unit Tests: Execute unit tests from the issue and run pdd fix on each failing test sequentially
  2. Run E2E Tests: Execute end-to-end tests to identify failures; stop if all pass
  3. Root Cause Analysis: Analyze failures against documentation to determine if issues are in code, tests, or both
  4. Fix E2E Tests: If e2e tests themselves are incorrect, fix them and return to step 2
  5. Identify Dev Units: Determine which dev units are involved in the failures
  6. Create Unit Tests: For code bugs, create or append unit tests for the affected dev units
  7. Verify Tests: Run new unit tests to confirm they detect the bugs and will pass once fixed
  8. Run PDD Fix: Execute pdd fix sequentially on failing unit tests for each dev unit
  9. Verify All: Final verification that all tests pass locally. The orchestrator independently re-runs the discovered test files (not the agent's possibly-targeted selection); if that independent verification rejects an agent-reported pass, PDD posts a trusted ## Step 9/11: rejection comment on the issue with the exact verifier command and bounded output, and the cycle is not recorded as a success. Before terminal success, the shared mock-contract gate checks every workflow-owned Python query/mock change against real repository schema and sibling evidence; a divergence blocks commit/push even when all tests pass
  10. CI Validation: First poll external CI, retrieve logs on failure, and run an LLM fix loop to remediate any CI-specific issues (lint, artifacts, build). Once CI is green, run a real pre-checkup gate (the fix path's first drift-sync step) that blocks on any mechanical failure (build/smoke — compile, import, caller-compat, targeted tests) or unhealable update-drift. (Architecture-sync residuals and example-only drift are advisory in default mode — not hard blocks — because they are frequently spurious on a clean tree; strict mode promotes them.) It first drift-syncs code ↔ prompt ↔ architecture.json.pdd/meta in the worktree (the prompt/code sync is committed to the PR (an example regenerated as a side effect of an update-heal is committed and validated too; example-only drift is advisory — the gate does not auto-heal it, to avoid the #1243 null-hash heal loop); .pdd/meta fingerprint finalization is intentionally left to the post-merge sync — see #1317 — so the PR tree itself may still show fingerprint drift until then), then executes its own deterministic build/smoke checks — compile touched files, import changed modules, probe changed router/app modules for route/router objects (a non-blocking note, not a hard block — best-effort app-wiring smoke that stays with checkup), lint, caller-compatibility sweep, and run targeted unit tests by git-diff (Python tests are executed; a changed JS/TS test is reported, not run). It runs these checks itself rather than relying solely on GitHub required checks (which are often absent or vacuous)
  11. Code Cleanup: Review all changes from the workflow and clean up code quality issues (debug statements, unused imports, duplicated code); revert if tests or the mock-contract gate fail

After Step 11 the workflow clears state and returns. pdd fix does not run pdd checkup (no Layer-1 PR-mode checkup, no Layer-2 review-loop) as a final gate — verification is the workflow's own Step 7/9 plus the deterministic pre-checkup build/smoke gate in Step 10. pdd checkup remains a separate command you run on its own (the semantic ship-verdict is available there via --final-gate). Removing the agentic gate stops a transient checkup verdict (an empty/garbled review output, or a provider rate-limit) from failing an already-committed, correct fix. Note that CI is treated as best-effort: a pending / manually-triggered / ACTION_REQUIRED / timed-out required check the bot cannot run is inconclusive, not fatal — so a successful pdd fix run may mean external CI was inconclusive (still pending or waiting for manual action), not confirmed green. Failed required checks remain fail-closed by default and can still drive the CI-fix loop; repos that intentionally want pure external setup/auth failures such as missing GitHub Actions/Firebase credentials to be treated as inconclusive must opt in with .pddrc ci.external_setup_fail_open: true.

For repos with comment-gated CI, configure the trigger in .pddrc so pdd fix can post each matching trigger once and repoll before falling back to an inconclusive manual-action note:

ci:
  manual_trigger_comment: "/gcbrun"
  manual_triggers:
    "auto-heal-pr": "/gcbrun"

For repos that intentionally want missing-secret external setup failures to be reported as inconclusive instead of repairable CI failures:

ci:
  external_setup_fail_open: true

Resumable Operations:

State is automatically persisted, allowing you to resume interrupted workflows. Use --clean-restart to discard saved workflow state and sibling pdd bug analysis before starting fresh. Use --no-resume only when you want to ignore the E2E fix checkpoint while still allowing reusable bug-analysis context.

Cross-Machine Resume: By default, workflow state is stored in a hidden comment on the GitHub issue, enabling resume from any machine. If you start the workflow on machine A, you can continue from machine B by checking out the branch and running pdd fix again. Use --no-github-state to disable this feature and use local-only state persistence. You can also set PDD_NO_GITHUB_STATE=1 environment variable.

Example:

# Fix tests from a GitHub issue (agentic mode)
pdd fix https://github.com/myorg/myrepo/issues/42

# With custom timeout and max cycles
pdd fix --timeout-adder 30 --max-cycles 10 https://github.com/myorg/myrepo/issues/42

# Configure CI retries and validation
pdd fix --ci-retries 5 https://github.com/myorg/myrepo/issues/42

# Skip post-push CI validation entirely
pdd fix --skip-ci https://github.com/myorg/myrepo/issues/42

# Start fresh (ignore saved state and sibling bug analysis)
pdd fix --clean-restart https://github.com/myorg/myrepo/issues/42

# Disable GitHub state persistence (local-only)
pdd fix --no-github-state https://github.com/myorg/myrepo/issues/42

# Protect tests from modification (only fix code, not tests)
pdd fix --protect-tests https://github.com/myorg/myrepo/issues/42

Prerequisites:

  • The gh CLI must be installed and authenticated
  • At least one supported agent CLI (Claude, Gemini/Antigravity, Codex, or OpenCode) with valid credentials — either a stored OAuth/subscription/config credential (recommended) or an API key in the environment
  • For CI validation, the current branch must have an open PR on GitHub

Relationship with pdd bug:

This feature works seamlessly with issues processed by pdd bug. The typical workflow is:

  1. Use pdd bug <issue_url> to analyze a bug and generate failing unit tests
  2. Use pdd fix <issue_url> to iteratively fix the failing tests across all affected dev units

7. split

Diagnose whether a PDD dev unit has an architectural problem, and if so, split the full dev unit (prompt + code + example + tests) into smaller PDD-native dev units. The 15-step agentic workflow classifies intent, surveys the codebase, diagnoses the problem, proposes options with a responsibility-based rubric, extracts children with phase decomposition (and a per-child verify gate as a sub-step within extraction), runs deterministic verification gates (including test-seam resolution and parent-wiring checks), proves the new prompts can regenerate via pdd sync, derives architecture.json from prompt metadata tags, and checks architecture↔include drift after that derivation.

Agentic Mode (default):

pdd [GLOBAL OPTIONS] split [OPTIONS] TARGET_FILE

Arguments:

  • TARGET_FILE: The source file to diagnose and potentially split (e.g., pdd/large_module.py).

The 15-step workflow (with 6v running as a per-child sub-step inside step 6): 0. Intent: Classify the goal (REDUCE_MONOLITH / ENABLE_PARALLEL_WORK / EXTRACT_REUSABLE_LAYER / REDUCE_TEST_TIME); re-weights step 4's rubric

  1. Survey: Neighborhood survey + target-file scan (architecture, siblings, churn, health signals, co-change)
  2. Diagnose: Classify architectural problem; can return LEAVE_ALONE (stops here)
  3. Investigate: Extend with test-seam data, test ownership classification, "stays put" rules, shared-layer candidates
  4. Propose Options: 2-4 SplitPlan options with responsibility-based scoring; auto-pick winner
  5. Setup Worktree: Create isolated git worktree for extraction 6a. Phase Extract (planning): For each child, judge whether its dominant symbol has multi-phase structure worth extracting as sibling-file helpers
  6. Extract: One child per call, full dev unit (prompt + code + example + tests); applies phase plan from 6a when present 6v. Per-Child Verify Gate: After each child extracts in step 6, run validate_extraction() filtered to that child's files only and route any error-severity failures to a bounded step-8 repair sub-loop (max 2 attempts per child). Status is tracked per child in state["children_extracted_status"] (pending / extracted / verified / failed_extract / failed_verify / failed) so a crash mid-pipeline never silently re-bills already-verified children. 7a. Verify Local: Final cross-cutting deterministic check across all children — tests, lint, parent line reduction, and test-seam resolution. Catches issues only visible at full-package scope (e.g. circular imports between children). 7b. Regen Gate: Deterministic — pdd sync must regenerate each new prompt 7c. Arch Sync: Deterministic — derive architecture.json from <pdd-*> prompt metadata tags 7d. Post-Arch Checkup: Run pdd checkup --validate-arch-includes --project-root <worktree> after 7c so architecture↔include drift is checked against freshly synced metadata.
  7. Assess: LLM qualitative verdict; feeds improvement gate alongside 7a/7d metrics
  8. Repair: Fix cross-cutting verification failures from 7a/7d (max 5 iterations across the whole plan), re-running arch sync before each checkup retry. Per-child gate failures (6v, max 2 attempts per child) are repaired inline within step 6 and DO NOT enter step 8 — once the per-child budget is exhausted the child enters terminal failed status, step 8 is short-circuited entirely (the global loop cannot recover what the per-child gate already gave up on). The improvement gate downgrades AUTO_SHIP to HUMAN_REVIEW_REQUIRED for ANY non-verified child (including failed_extract from exhausted file-existence retries and failed from exhausted per-child repair). Per-child reason strings are persisted in state["terminal_child_failures"] (covering both failed_extract missing-file detail and failed ValidationFailure.message detail) and surfaced in the final message + console output so the user knows which child broke and why.
  9. Refine Check: Ask the agent whether any child is still too monolithic; if yes, run one focused phase-extraction pass

Options:

  • --diagnose: Run steps 0-2 only, return diagnosis report
  • --propose-only: Run steps 0-4 only, show all options with scores (cheap plan preview)
  • --intent [reduce|parallel|reuse|tests]: Skip step 0 and set intent explicitly (reduce = REDUCE_MONOLITH, etc.)
  • --no-phase-extraction: Skip step 6a (only move whole symbols, no refactoring inside functions)
  • --strangler: Use the first proposed plan only to determine N (number of children), then run N independent full orchestrator passes (each pass starts fresh, picks its own plan, and extracts whatever children that pass's plan contains); see issue #1402 for true one-child-per-PR enforcement
  • --delete-dead: Opt-in dead symbol deletion (default: surface candidates for human review)
  • --force-split: Override LEAVE_ALONE diagnosis
  • --no-verify: Skip step 7a test gate (dev only)
  • --skip-regen-gate: Skip step 7b regen gate (dev only, logged loudly)
  • --experimental-language: Opt-in for non-Python languages (Python is the only supported tier in this release)
  • --no-github-state: Disable GitHub state persistence (local-only)
  • --timeout-adder FLOAT: Add seconds to each step timeout (default: 0.0)
  • --max-cost FLOAT: Abort if total cost would cross USD threshold. State is persisted, so re-running without --max-cost (or with a higher cap) resumes from the same step. Useful as a budget guardrail on long strangler runs (default: no cap)

Resume: State is persisted after every per-child status transition (in state["children_extracted_status"], keyed by child name). On resumption, pdd split picks up at the first non-terminal child — terminal statuses are verified (success) and failed (per-child repair budget exhausted), both of which are skipped without re-billing tokens. Children in failed_verify (verify failed but repair budget remaining) are re-extracted on resume; the saved repair_attempts count is carried forward (not reset), so the per-child gate continues from where it left off rather than re-spending the full N=2 budget.

Example (agentic mode — full pipeline):

pdd split pdd/large_module.py

Example (with budget cap):

# Stop cleanly if the run would cross $50; state is saved so you can
# resume later by re-running without --max-cost (or with a higher cap).
pdd split --max-cost 50 pdd/large_module.py

Example (diagnosis only):

pdd split --diagnose pdd/large_module.py

Example (compare options without extracting):

pdd split --propose-only pdd/large_module.py

Example (extract reusable shared layer across sibling workers):

pdd split pdd/big_worker.py --intent=reuse

Legacy Mode:

pdd [GLOBAL OPTIONS] split --legacy [OPTIONS] INPUT_PROMPT INPUT_CODE EXAMPLE_CODE

Arguments:

  • INPUT_PROMPT: The filename of the large prompt file to be split.
  • INPUT_CODE: The filename of the code generated from the input prompt.
  • EXAMPLE_CODE: The filename of the example code that serves as the interface to the sub-module prompt file.

Options:

  • --output-sub LOCATION: Specify where to save the generated sub-prompt file. The default file name is sub_<basename>.prompt. If an environment variable PDD_SPLIT_SUB_PROMPT_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --output-modified LOCATION: Specify where to save the modified prompt file. The default file name is modified_<basename>.prompt. If an environment variable PDD_SPLIT_MODIFIED_PROMPT_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --legacy: Use the legacy 2-LLM-call splitting path. When omitted, split() acts as the prompt-splitting primitive for the agentic split orchestrator. This flag is kept for one release for backward compatibility.

Example (legacy mode):

pdd [GLOBAL OPTIONS] split --legacy --output-sub prompts/sub_data_processing.prompt --output-modified prompts/modified_main_pipeline.prompt data_processing_pipeline_python.prompt src/data_pipeline.py examples/pipeline_interface.py

8. change

Implement a change request from a GitHub issue using a 13-step agentic workflow. The workflow researches the feature, ensures requirements are clear (asking clarifying questions if needed), reviews architecture (asking for decisions if needed), analyzes documentation changes, identifies affected dev units, designs prompt modifications, implements them, runs a review loop to identify and fix issues, and creates a PR.

Do not use pdd change as the first step for a reported runtime defect. If an issue says "the prompt should be updated because the generated CLI crashes" or includes a stack trace, failing command, wrong runtime output, or regression, start with pdd bug <issue-url> and then run pdd fix <issue-url>. pdd change is for source-truth/spec/product changes that do not require reproducing a current failure.

Agentic Mode (default):

pdd [GLOBAL OPTIONS] change GITHUB_ISSUE_URL

Arguments:

  • GITHUB_ISSUE_URL: The URL of the GitHub issue describing the change request.

The 13-step workflow:

  1. Duplicate Check: Search for duplicate issues
  2. Documentation Check: Verify feature isn't already implemented
  3. Research: Web search to clarify specifications and find best practices
  4. Clarification: Ensure requirements are clear; ask questions with options if not (stops workflow until answered)
  5. Documentation Changes: Analyze what documentation updates are needed (including associated documents discovered via the prompt <include> graph)
  6. Identify Dev Units: Find affected prompts, code, examples, and tests
  7. Architecture Review: Identify architectural decisions; ask questions with options if needed (stops workflow until answered)
  8. Analyze Changes: Design prompt modifications
  9. Implement Changes: Modify prompts in an isolated git worktree, atomically apply drafted associated-document edits, and emit MANUAL_REVIEW: lines for conflicts that cannot be auto-resolved
  10. Architecture & Doc Sync: Update architecture.json metadata and synchronize associated documents (verified by the doc-sync contract; see Step 10.5)
  11. Identify Issues: Review changes for problems (part of review loop)
  12. Fix Issues: Fix identified issues (part of review loop, max 5 iterations) 12.5. Pre-PR Build/Smoke Gate (issue #1293): Before creating the PR, run the same shared pre-checkup gate the fix path uses. It first drift-syncs code ↔ prompt ↔ architecture.json.pdd/meta in the worktree (largely a no-op here since Step 8.5/10 already healed prompt + architecture drift; .pdd/meta finalization is completed canonically by the post-merge sync, see #1317), then runs a blocking build/smoke pass over the changed files — compile touched files, import changed modules, probe changed router/app modules for route/router objects (a non-blocking note, not a hard block — best-effort app-wiring smoke that stays with checkup), lint, caller-compatibility sweep, and targeted unit tests by git-diff (Python tests are executed under a hardened, credential-free env; a changed JS/TS test is reported, not run) — so the change/feature PR enters checkup --pr already building and wired. A red gate blocks PR creation in both default and strict mode (issue #1293: "block — don't hand off to checkup until green"); it does not create the PR and surface the findings for later review
  13. Create PR: Create a pull request linking to the issue and surface any unresolved MANUAL_REVIEW: flags in the PR body

Workflow Resumption: Steps 4 and 7 may pause the workflow to ask clarifying or architectural questions. When this happens, answer the questions in the GitHub issue and run pdd change again. The workflow will resume from where it left off, skipping already-completed steps to save tokens.

Cross-Machine Resume: By default, workflow state is stored in a hidden comment on the GitHub issue, enabling resume from any machine. If you start the workflow on machine A, you can continue from machine B by checking out the branch and running pdd change again. Use --no-github-state to disable this feature and use local-only state persistence. You can also set the PDD_NO_GITHUB_STATE=1 environment variable to disable GitHub state globally.

Clean Restart (--clean-restart, issue #1149): For pdd change, discards any persisted solving state for the issue and runs a fresh 13-step pdd-issue flow from the default base branch, ignoring any previously generated change/issue-N branch or PR. Use when recovering from a stopped or wrong-model run (e.g. you cancelled a Gemini-based run and want to rerun cleanly under Opus on the same issue). The orchestrator posts a ## Step 0/13: Workflow Startup comment on the issue naming the mode, model, base branch, and command so reviewers can tell at a glance whether a run is resuming or clean-starting. The same restart intent is also available for pdd bug, pdd test, and pdd fix agentic GitHub issue workflows. If the standard issue branch ({command}/issue-N) is checked out in another local worktree (e.g. a concurrent runner), the clean restart does not fail: it prunes stale worktree registrations and, if the branch is still genuinely locked, creates a fresh unique fallback branch ({command}/issue-N-job-<id>) from the base branch, pushes and opens/updates the PR on that branch, and leaves the locked worktree untouched. Cannot be combined with --manual.

Review Loop: Steps 11-12 form a review loop that identifies and fixes issues iteratively. The loop runs until no issues are found (max 5 iterations).

Worktree Branching Behavior: When running pdd change, pdd bug, or pdd split, a new git worktree is created based on your current HEAD:

  • From main/master: Branch is based on latest main - creates independent PR
  • From feature branch: Branch inherits commits from that branch - useful for stacked/dependent PRs

If you want independent changes, run the command from the main branch. A warning will be displayed when running from a non-main branch.

Example (agentic mode):

pdd change https://github.com/myorg/myrepo/issues/239

After the workflow completes, a PR is automatically created linking to the issue. The PR includes a sync_order.sh script that runs pdd sync commands in dependency order. Review the PR and run ./sync_order.sh after merge to regenerate code.

Manual Mode (legacy):

pdd [GLOBAL OPTIONS] change --manual [OPTIONS] CHANGE_PROMPT_FILE INPUT_CODE INPUT_PROMPT_FILE

Arguments:

  • CHANGE_PROMPT_FILE: The filename containing the instructions on how to modify the input prompt file.
  • INPUT_CODE: The filename of the code that was generated from the input prompt file, or the directory containing the code files when used with the '--csv' option.
  • INPUT_PROMPT_FILE: The filename of the prompt file that will be modified. Required in standard mode; not used when using the '--csv' option.

Options:

  • --budget FLOAT: Set the maximum cost allowed for the change process (default is $5.0).
  • --output LOCATION: Specify where to save the modified prompt file. The default file name is modified_<basename>.prompt. If an environment variable PDD_CHANGE_OUTPUT_PATH is set, the file will be saved in that path unless overridden by this option.
  • --csv: Use a CSV file for the change prompts instead of a single change prompt file. The CSV file should have columns: prompt_name and change_instructions. When this option is used, INPUT_PROMPT_FILE is not needed, and INPUT_CODE should be the directory where the code files are located. The command expects prompt names in the CSV to follow the <basename>_<language>.prompt convention. For each prompt_name, it derives the corresponding code file (for example, <basename>.<language_extension>) under the specified INPUT_CODE directory. If the prompt is in a prompt-root subdirectory such as prompts/pkg/widget_python.prompt or pdd/prompts/pkg/widget_python.prompt, CSV mode first strips the prompt root and looks for INPUT_CODE/pkg/widget.py, then falls back to the preserved-subpath and historical flat lookups. Code lookup is constrained to remain inside the resolved INPUT_CODE directory, including symlink targets. Output files will overwrite existing files unless --output LOCATION is specified. If LOCATION is a directory, the modified prompt files will be saved inside this directory using the default naming convention otherwise, if a csv filename is specified the modified prompts will be saved in that CSV file with columns 'prompt_name' and 'modified_prompt'.

Example (manual single prompt change):

pdd [GLOBAL OPTIONS] change --manual --output modified_factorial_calculator_python.prompt changes_factorial.prompt src/factorial_calculator.py factorial_calculator_python.prompt

Example (manual batch change using CSV):

pdd [GLOBAL OPTIONS] change --manual --csv --output modified_prompts/ changes_batch.csv src/

9. update

Update prompts based on code changes. This command operates in two primary modes:

Agentic Prompt Optimization (Default)

The update command uses an agentic AI (Claude Code, Gemini/Antigravity, Codex, or OpenCode) by default to produce compact, high-quality prompts. The agent has full file access and performs a 4-step optimization:

  1. Assess Differences: Reads the prompt (including all <include> files) and compares against the modified code
  2. Filter Using Guide + Tests: Consults docs/prompting_guide.md and existing tests to determine what belongs in the prompt
  3. Remove Duplication: Eliminates redundant content that duplicates included files
  4. Validate: Ensures the prompt is human-readable and can reliably regenerate the code

This produces prompts that are more concise while remaining clear to developers and reliable for code generation.

Prerequisites: Requires one of these CLI tools installed and configured:

  • claude (Anthropic Claude Code)
  • agy (Google Antigravity CLI, preferred for Google provider) or gemini (legacy Google Gemini CLI, rollback)
  • codex (OpenAI Codex CLI)
  • opencode (OpenCode CLI)

If no agentic CLI is available, the command automatically falls back to the legacy 2-stage LLM update process.

Test-Aware Updates: When tests exist for a module (e.g., test_my_module.py, test_my_module_1.py), the agentic update automatically discovers and considers them. Behaviors verified by tests don't need to be explicitly specified in the prompt, resulting in more compact prompts.

Modes:

  1. Repository-Wide Mode (Default): When run with no file arguments, pdd update scans the entire repository. It finds all code/prompt pairs, creates any missing prompt files, and updates all of them based on the latest Git changes. This is the easiest way to keep your entire project in sync.

  2. Single-File Mode: When you provide file arguments, the command operates on a specific file. There are three distinct use cases for this mode:

    A) Prompt Generation / Regeneration To generate a brand new prompt for a code file from scratch, or to regenerate an existing prompt, simply provide the path to that code file. This will create a new prompt file or overwrite an existing one.

    pdd update <path/to/your_code_file.py>
    

    B) Prompt Update (using Git) To update an existing prompt by comparing the modified code against the version in your last commit. This requires the prompt file and the modified code file.

    pdd update --git <path/to/prompt.prompt> <path/to/modified_code.py>
    

    C) Prompt Update (Manual) To update an existing prompt by manually providing the original code, the modified code, and the prompt. This is for scenarios where Git history is not available or desired.

    pdd update <path/to/prompt.prompt> <path/to/modified_code.py> <path/to/original_code.py>
    
# Repository-Wide Mode (no arguments)
pdd [GLOBAL OPTIONS] update

# Single-File Mode: Examples
# Generate/Regenerate a prompt for a code file
pdd [GLOBAL OPTIONS] update src/my_new_module.py

# Update an existing prompt using Git history
pdd [GLOBAL OPTIONS] update --git factorial_calculator_python.prompt src/modified_factorial_calculator.py

# Update an existing prompt by manually providing original code
pdd [GLOBAL OPTIONS] update factorial_calculator_python.prompt src/modified_factorial_calculator.py src/original_factorial_calculator.py

# Repository-wide update filtered by extension
pdd [GLOBAL OPTIONS] update --extensions py,js

Arguments:

  • MODIFIED_CODE_FILE: The filename of the code that was modified or for which a prompt should be generated/regenerated.
  • INPUT_PROMPT_FILE: (Optional) The filename of the prompt file that generated the original code. Required for true update scenarios (B and C).
  • INPUT_CODE_FILE: (Optional) The filename of the original code. Required for manual update (C), not required when using --git (B), and not applicable for generation (A).

Important: By default, this command overwrites the original prompt file to maintain the core PDD principle of "prompts as source of truth."

Options:

  • --output LOCATION: Specify where to save the updated prompt file. If not specified, the original prompt file is overwritten to maintain it as the authoritative source of truth. If an environment variable PDD_UPDATE_OUTPUT_PATH is set, it will be used only when --output is explicitly omitted and you want a different default location.
  • --git: Use git history to find the original code file, eliminating the need for the INPUT_CODE_FILE argument.
  • --extensions EXTENSIONS: In repository-wide mode, filter the update to only include files with the specified comma-separated extensions (e.g., py,js,ts).
  • --simple: Use the legacy 2-stage LLM update process instead of the default agentic mode. Useful when agentic CLIs are not available or for faster updates.
  • --sync-metadata: After the prompt update, run the shared metadata-sync orchestrator so prompt PDD tags, architecture.json entries, run reports, and fingerprint state are reconciled in one step. Works in single-file, regeneration, and repo modes. Fingerprint note: without this flag, every successful single-file/regeneration update and every successful --repo pair finalizes through the shared FingerprintTransaction path. The command first resolves the complete unit path set, clears the affected stale _run.json, verifies it is gone, and atomically writes the new fingerprint. Identity, cleanup, hashing, or persistence failure is a hard non-zero command failure; the update cannot return a false-green success tuple after mutating an artifact. With --sync-metadata, the orchestrator owns that fingerprint stage, so the default finalizer intentionally skips instead of double-writing. The stale-report warning still surfaces under --quiet because it describes a real consistency failure. Without this flag, the broader prompt-tag/architecture stages are not run and must be reconciled separately. Scope note: the tags stage currently preserves existing PDD tags and only seeds tags from the matching architecture.json entry when a prompt has none — LLM-first refresh of stale-but-present tags is tracked at issue #870 and is not invoked by this orchestrator. When a prompt has zero PDD tags AND no architecture entry, the tags stage reports skipped (never ok) so operators see honest status. On any stage failed, pdd update --sync-metadata exits non-zero so CI auto-heal does not treat a half-finalized update as healed.

Example (Metadata Sync):

# Update a single prompt and reconcile metadata (preserve/seed tags,
# architecture entry, run reports, fingerprint) in one step
pdd update --sync-metadata src/my_module.py

# Repo-wide update with metadata sync — each updated pair is finalized via the shared orchestrator
pdd update --sync-metadata

When --sync-metadata is enabled, the summary table shows a metadata column with one of:

  • synced — every metadata stage wrote successfully.
  • partial:<stage> — orchestration succeeded but one or more stages were skipped (for example, the prompt is not registered in architecture.json); the first skipped stage is named.
  • failed:<stage> — a stage hit a hard failure; the failing stage is named.
  • skipped — the orchestrator did not run for this pair (e.g. the pair was unchanged or the per-pair call returned no result).
  • dry-run — the call was made with dry_run=True; no on-disk state was written.

If any layer is incomplete, the relevant stage is named explicitly so it is obvious whether tags, architecture, run reports, or the fingerprint is the unresolved gap.

Example (overwrite original prompt - default behavior):

pdd [GLOBAL OPTIONS] update factorial_calculator_python.prompt src/modified_factorial_calculator.py src/original_factorial_calculator.py
# This overwrites factorial_calculator_python.prompt in place

Example (agentic vs simple mode):

# Default: Agentic mode (uses claude/agy/gemini/codex/opencode for intelligent optimization)
pdd update --git my_module_python.prompt src/my_module.py

# Legacy: Simple 2-stage LLM update (faster, no agentic CLI required)
pdd update --simple --git my_module_python.prompt src/my_module.py

10. detect

Analyze a list of prompt files and a change description to determine which prompts need t

Truncated — view the full README on GitHub.

Contributors

gltanaka

898 commits

Serhan-Asad

678 commits

DianaTao

528 commits

sohni-tagirisa

380 commits

Languages

Python

95.5%

TypeScript

3.2%

Shell

1.0%