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
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:
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 bugspdd fix <issue-url> - Fix the failing testspdd 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.
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.
On macOS, you'll need to install some prerequisites before installing PDD:
Install Xcode Command Line Tools (required for Python compilation):
xcode-select --install
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)"
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:
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/).
If you prefer using pip, you can install PDD with:
pip install pdd-cli
# 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
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:
pdd change, pdd bug, pdd fix, pdd sync etc. visually--local-only to disable)For CLI enthusiasts, implement GitHub issues directly:
Prerequisites:
GitHub CLI - Required for issue access:
brew install gh && gh auth login
One Agentic CLI - Required to run the workflows (install at least one):
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)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).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.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)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
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.
If you want to understand PDD fundamentals, follow this manual example to see it in action.
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
Clone repo
# Clone the repository (if not already done)
git clone https://github.com/promptdriven/pdd.git
cd pdd/examples/hello
Set one API key (choose your provider):
export GEMINI_API_KEY="your-gemini-key"
# OR
export OPENAI_API_KEY="your-openai-key"
Run the comprehensive setup wizard:
pdd setup
The setup wizard runs these steps:
.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.data/llm_model.csv of top ranked models across all LiteLLM-supported providers based on your available API keyspdd --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).pddrc project configThe wizard can be re-run at any time to update keys, add providers, or reconfigure settings.
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):
~/.pdd/llm_model.csv.backup.<timestamp> so the change is always reversible.~/.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 shellNew 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.
Run Hello:
cd ../hello
pdd --force generate hello_python.prompt
python3 hello.py
✅ Expected output:
hello
PDD commands can be run either in the cloud or locally. By default, all commands run in the cloud mode, which provides several advantages:
When running in cloud mode (default), PDD uses GitHub Single Sign-On (SSO) for authentication. On first use, you'll be prompted to authenticate:
The authentication token is securely stored locally and automatically refreshed as needed.
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:
When keys are missing, PDD will prompt for them interactively and securely store them in your local .env file.
PDD uses a CSV file to configure model selection and capabilities. This configuration is loaded from:
~/.pdd/llm_model.csv (takes precedence if it exists)<PROJECT_ROOT>/.pdd/llm_model.csvThe 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 tokenscoding_arena_elo: Raw Arena/static ELO metadatamodel_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 Copilotstructured_output: Whether the model supports structured JSON outputreasoning_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").
PDD supports two Z.AI API endpoints:
https://api.z.ai/api/paas/v4) — standard prepaid/resource billing, suitable for general use.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.
Command not found
# Add to PATH if needed
export PATH="$HOME/.local/bin:$PATH"
Permission errors
# Install with user permissions
pip install --user pdd-cli
macOS-specific issues
xcode-select --install to install the required development toolsbrew install pythonbrew install uvpython3 points to Python 3.12+: which python3 && python3 --versionTo 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).
PDD supports a wide range of programming languages, including but not limited to:
The specific language is often determined by the prompt file's naming convention or specified in the command options.
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 projectExamples:
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.pyapp/api/orders/route_TypeScript.prompt → generates app/api/orders/route.tsPDD 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 (PDD) inverts traditional software development by treating prompts as the primary artifact - not code. This paradigm shift has profound implications:
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.
Natural Language Over Code: Prompts are written primarily in natural language, making them more accessible to non-programmers and clearer in expressing intent.
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.
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.
To work effectively with PDD, adopt these mental shifts:
Prompt-First Thinking: Always start by defining what you want in a prompt before generating any code.
Bidirectional Flow:
Modular Prompts: Just as you modularize code, you should modularize prompts into self-contained units that can be composed.
Integration via Examples: Modules integrate through their examples, which serve as interfaces, allowing for token-efficient references.
Each workflow in PDD addresses a fundamental development need:
Initial Development Workflow
This workflow embodies the prompt-to-code pipeline, moving from concept to tested implementation.
Code-to-Prompt Update Workflow
This workflow ensures the information flow from code back to prompts, preserving prompts as the source of truth.
Debugging Workflows
These workflows recognize that different errors require different resolution approaches.
Refactoring Workflow
This workflow parallels code refactoring but operates at the prompt level.
Multi-Prompt Architecture Workflow
This workflow addresses the complexity of managing multiple interdependent prompts.
Enhancement Phase: Use Feature Enhancement when adding capabilities to existing modules.
The choice of workflow should be guided by your current development phase:
Creation Phase: Use Initial Development when building new functionality.
Maintenance Phase: Use Code-to-Prompt Update when existing code changes.
Problem-Solving Phase: Choose the appropriate Debugging workflow based on the issue type:
Restructuring Phase: Use Refactoring when prompts grow too large or complex.
System Design Phase: Use Multi-Prompt Architecture when coordinating multiple components.
Enhancement Phase: Use Feature Enhancement when adding capabilities to existing modules.
Effective PDD employs these recurring patterns:
Dependency Injection via Auto-deps: Automatically including relevant dependencies in prompts.
Interface Extraction via Example: Creating minimal reference implementations for reuse.
Bidirectional Traceability: Maintaining connections between prompt sections and generated code.
Test-Driven Prompt Fixing: Using tests to guide prompt improvements when fixing issues.
Hierarchical Prompt Organization: Structuring prompts from high-level architecture to detailed implementations.
pdd [GLOBAL OPTIONS] COMMAND [OPTIONS] [ARGS]...
Here is a brief overview of the main commands provided by PDD. Click the command name to jump to its detailed section:
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 <url>"]
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 <url>"]
test_url["pdd test <url>"]
bug_url["pdd bug <url>"]
fix_url["pdd fix <url>"]
change["pdd change <url>"]
sync_url["pdd sync <url>"]
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:
pdd connect (web UI), direct CLI, or the GitHub Apppdd generate <url> scaffolds architecture, prompts, and .pddrc from a PRD GitHub issuepdd sync runs the full auto-deps → generate → example → crash → verify → test → fix → update cycle for each modulepdd 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)test <url> or bug <url> surfaces failing tests → fix <url> resolves themchange <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.connect: [RECOMMENDED] Launch web interface for visual PDD interactionsetup: Configure API keys and shell completionchange: Implement feature requests from GitHub issues (13-step workflow)bug: Analyze bugs and create failing tests from GitHub issuescheckup: 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)sync: [PRIMARY FOR PROMPT WORKFLOWS] Automated prompt-to-code cyclegenerate: Creates runnable code from a prompt file; supports parameterized prompts via -e/--envexample: Generates a compact example showing how to use functionality defined in a prompttest: Generates or enhances unit tests for a code file and its promptupdate: Updates the original prompt file based on modified codeverify: Verifies functional correctness by running a program and judging output against intentcrash: Fixes errors in a code module and its calling program that caused a crashpreprocess: Preprocesses prompt files, handling includes, comments, and other directivesreplay: Reconstructs and audits expanded prompt context from a snapshot-enabled run artifactcontext: Shows context-window usage by source for a hydrated prompt, Claude-Code /context-stylesplit: Splits large prompt files into smaller, more manageable onesextracts prune: Garbage-collect orphaned extracts cache entriesauto-deps: Analyzes and inserts needed dependencies into a prompt filesync-architecture: Updates architecture.json from prompt metadata tagsdetect: Analyzes prompts to determine which ones need changes based on a descriptionconflicts: Finds and suggests resolutions for conflicts between two prompt filestrace: Finds the corresponding line number in a prompt file for a given code lineauth: Manages authentication with PDD Cloudsessions: Manage remote sessions for connectreport-core: Create a GitHub issue from a debug snapshotcontracts check: Run deterministic contract section checks; see docs/contract_check.mdtemplates: List, inspect, and copy packaged prompt templateswhich: Print resolved configuration values and search pathsinstall_completion: Refresh shell completion scriptsPDD 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:
user_stories/ and match story__*.md.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.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:
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.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:
<!-- pdd-story-prompts: prompts/a_python.prompt, prompts/b_python.prompt -->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.--stories mode, existing story metadata scopes validation; when metadata is missing, validation falls back to the full prompt set.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:
user_stories/story__template.md for a starter format.Contract coverage:
## Covers section (for example R1 or
prompts/module_python.prompt#R2). See docs/coverage_contracts.md and
docs/contract_check.md.Executable regression suite:
@pytest.mark.story. Run the suite with make regression-stories
(i.e. pytest -m story) in the public-safe, no-secrets lane.pdd test --from-story user_stories/story__<slug>.md.generate, sync, fix, change,
update) plus a batch of previously-fixed-bug regressions. See
docs/generating_user_stories.md.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).
--time FLOAT: Controls the reasoning allocation for LLM models supporting reasoning capabilities (0.0 to 1.0, default is 0.25).
1.0 utilizes the maximum available tokens.1.0 corresponds to the highest effort level.--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.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:
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 CommandThe 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:
gh auth token (recommended)GITHUB_TOKEN or GH_TOKENPDD_GITHUB_TOKENFile Tracking & Gists:
When using --api, PDD will:
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.
--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..pddrc context > environment variables > defaults. See Configuration for details.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:
PDD uses a large language model to generate and manipulate code. The --strength and --temperature options allow you to control the model's output:
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.--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:
model_rank_score values for selection and raw Arena/static coding_arena_elo metadataPDD 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.
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.
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.
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:
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.
The generated CSV file includes the following columns:
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.PDD_MODEL_DEFAULT or the model argument), before provider resolution or fallback.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).importlib.metadata).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.
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.
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.
Here are the main commands provided by PDD:
[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:
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:
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.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.pyfactorial_calculator_typescript.prompt → generates factorial_calculator.tsfactorial_calculator_javascript.prompt → generates factorial_calculator.jssrc/models/user_Python.prompt → generates src/models/user.pyIf 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:
.pddrcarchitecture.json provides an explicit filepath for a prompt entry, sync honors it according to whether that filepath includes a directory component:
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.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.__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.None, emits a needs-review signal, and performs no test write until the configuration is made resolvable.Workflow Logic:
The sync command automatically detects what files exist and executes the appropriate workflow:
architecture.json and the prompt's <pdd-interface> block:
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.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).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.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.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.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.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.--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.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:
--fresh is passed.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:
.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.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:
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:
*_LLM.prompt templates), (c) PDD_CHANGED_MODULES env-var bypass (deterministic, free — skips LLM when branch-diff returned empty), (d) LLM fallbackAsyncSyncRunner 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)# 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-onlyCross-Machine Resume: Workflow state is stored in a hidden GitHub comment, enabling resume from any machine. Use --no-github-state to disable.
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:
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.jsonalready has unrelated missing-dependency errors elsewhere, the exit code stays non-zero on--dry-runeven for an otherwise-clean target prompt. Fix the repo-wide errors (or scope your check) before relying on the exit code in scripts.
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 / --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.
-e KEY=VALUE or --env KEY=VALUE (repeatable).-e KEY reads VALUE from the current process environment variable KEY.generate.-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.
$VAR and ${VAR} are replaced only when VAR was provided.--output, PDD also expands $VAR/${VAR} using the same variable set.-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:
KEY=VALUE if the value contains spaces or shell-special characters: -e "DISPLAY_NAME=Order Processor".-e/--env — e.g., --output 'src/${MODULE}.py'.--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.promptMODULE=orders pdd generate -e MODULE --output "src/$MODULE.py" prompts/module_python.promptGit Integration:
git add (if not already committed/added) to ensure you can roll back if needed.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):
architecture.json and scaffolding filesarchitecture.jsonValidation (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:
.pddrc or a .pdd/ directory.sources/ plus PRD/spec markdown (prd*.md, spec*.md, or *_prd.md/*_spec.md)..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 authenticatedWorkflow 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>):
<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.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.data_dictionary.yaml / api_contracts.yaml / integration_points.yaml is not invoked. Update those files manually if the PRD change affects them.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.
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.
-e/--env (required/optional, type, examples)pdd generate commandspdd templates show<include>${VAR}</include>, <include-many>${LIST}</include-many>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
<include>/<include-many> for curated context; prefer specs/configs over large code dumps.-e, e.g. <include>${PRD_FILE}</include>; the engine resolves includes after variable expansion.--output.Behavior notes
-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.--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
pdd templates show)discover settings (executed by the CLI with caps)output_schema for validationpdd templates list [--json] [--filter tag=...]pdd templates show <name>pdd templates copy <name> --to prompts/pdd generate --template <name> [-e KEY=VALUE...] [--output PATH]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)
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-processingllm=false: Skip LLM generation, run only post-processingArchitecture JSON Template Features:
The architecture/architecture_json template includes automatic Mermaid diagram generation:
architecture_diagram.html with color-coded modules (frontend/backend/shared)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
name, description, version, tags: docs and discoverylanguage, output: defaults for generatevariables: 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
pdd templates show to view variables, usage, discover, and output schema. Pass variables via -e at the CLI.Template Variables (reference)
architecture/architecture_json.prompt)
PRD_FILE (path, required): Primary spec/PRD file pathTECH_STACK_FILE (path, optional): Tech stack overview file (includes API style; e.g., docs/tech_stack.md)APP_NAME (string, optional): App name for contextDOC_FILES (list, optional): Comma/newline-separated list of additional doc pathsINCLUDE_FILES (list, optional): Comma/newline-separated list of source files to includeSCAN_PATTERNS (list, optional): Discovery patterns defined in front matter discover and executed by the CLISCAN_ROOT (path, optional): Discovery root defined in front matter discoverNotes
-e as shown in examples.Copy-and-generate
prompts/ folder, then use pdd generate as usual. This keeps prompts versioned with your repo so you can edit and evolve them.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
reason, description, dependencies, priority, filename, optional tags.type: component | page | module | api | graphql | cli | job | message | config | entrypointcomponent: 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, notesmodule: functions[] with name, signature, optional returns, errors, sideEffectsapi: endpoints[] with method, path, optional auth, requestSchema, responseSchema, errorsgraphql: 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[], retryPolicymessage: topics[] with name, direction (publish|subscribe), optional schema, qosconfig: 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)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
prompts/<org_or_team>/... and compose with <include> to maximize reuse.Templates: additional UX
Goals:
Commands:
pdd templates list [--json] [--filter tag=frontend] to discover templatespdd templates show <name> [--raw] to view metadata and variablespdd templates copy <name> --to prompts/ to vendor into your repopdd 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:
./prompts/** (allows team overrides).pddrc paths: any configured templates.pathspdd/templates/** (built‑ins)$PDD_PATH/prompts/** (org‑level packs)Template front matter:
.prompt files to declare name, description, tags, version, language, default output, and variables (with required, default, type such as string or json).-e/--env override front‑matter defaults; unknowns are validated and surfaced to the user.--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.---
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...
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:
crash and verify, providing a quick end-to-end sanity check that the generated code runs and behaves as intended.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.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
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.
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):
Duplicate check - Search for existing issues describing the same test requirements. If found, merge content and close the duplicate.
Documentation check - Review repo documentation and codebase to understand what needs to be tested. Identifies OpenAPI/Swagger specs if present.
Analyze & clarify - Determine if enough information exists in the issue to create tests. Posts comment requesting clarification if needed.
Detect frontend - Identify the test type: web UI, CLI, desktop app, or API. Determines the appropriate testing framework.
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).
Assess coverage (web only, requires playwright-cli) - Compare requirements against the enhanced test plan to identify gaps needing manual testing.
Create manual testing checklist (web only) - Generate a checklist using three strategies: page-by-page exhaustive testing, user-story walkthroughs, and accessibility spot-checks.
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.
Create regression tests (web only) - Generate automated tests that reproduce bugs found in Step 8.
Validate regression tests (web only) - Confirm regression tests fail against current code (proving bugs exist).
Loop check (web only) - Check checklist completion. Loops back to Step 8 if items remain (max 3 iterations).
Generate tests - Create tests in a worktree from the enhanced plan, including behavioral, contract, and accessibility tests.
Run tests - Execute all generated tests against the target.
Fix & iterate - Fix any failing tests and re-run until they pass.
Validate tests against plan - Cross-reference the enhanced plan against generated tests. Generate missing tests for any unimplemented cases.
Run newly generated tests - Run and fix tests created in Step 15 (if any).
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:
| Mode | Steps 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:
playwright-cli in PATH. If not found, these steps are skipped with a warning.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 modeEnvironment Variables:
PDD_CLOUD_RUN=true: Enable parallel execution mode for manual testing (Steps 6-11)PDD_NO_GITHUB_STATE=1: Disable GitHub state persistenceCross-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
Generate or enhance unit tests for a given code file and its corresponding prompt file.
Test organization:
<basename>, PDD maintains a single test file (by default named test_<basename>.<language_extension> and typically placed under a tests directory).--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.
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:
.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.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.pdd-story-prompts metadata. Story generation does not run detect_change or auto-detect touched prompts.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 -->pdd detect --stories.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:
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.
pdd [GLOBAL OPTIONS] test --output tests/test_factorial_calculator.py factorial_calculator_python.prompt src/factorial_calculator.py
pdd [GLOBAL OPTIONS] test --output tests/test_calculator.py calculator_python.prompt examples/calculator_example.py
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
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
When coverage options are provided, the test command will:
Analyze the coverage report to identify:
Generate additional test cases prioritizing:
Maintain consistency with:
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 / --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).
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.
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).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.
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>
shell: Executes shell commands and includes their output in the prompt, removing the shell tags.
<shell>ls -la</shell>
web: Scrapes a web page and includes its markdown content in the prompt, removing the web tags.
<web>https://example.com</web>
PDD supports two ways of including external content:
```
<./path/to/file.txt>
```
This will be recursively processed until there are no more angle brackets in triple backticks.
When using the --double option:
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.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
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.
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.
prompt_path: Path to the prompt file to audit.--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.By default it prints a Claude-Code /context-style usage box:
⛶).total/limit tokens (percent%) summary.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.
0: audit completed within threshold.2: total tokens exceed --threshold percent of the model's context limit (useful for CI and dashboards).# 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
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
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.--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.
--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).--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:
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.
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:
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.
(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:
claude CLI to be installed and in your PATH.claude auth login (recommended), otherwise with ANTHROPIC_API_KEY from your environment.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.agy / legacy gemini):
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.~/.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.codex CLI to be installed and in your PATH.~/.codex/auth.json ChatGPT login (run codex login once) or OPENAI_API_KEY from your environment.opencode CLI to be installed and in your PATH (npm install -g opencode-ai).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.OPENCODE_MODEL=provider/model (for example, anthropic/claude-sonnet-4-5) to avoid relying on default model resolution.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.)
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:
pdd fix on each failing test sequentiallypdd fix sequentially on failing unit tests for each dev unit## 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 passarchitecture.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)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:
gh CLI must be installed and authenticatedRelationship with pdd bug:
This feature works seamlessly with issues processed by pdd bug. The typical workflow is:
pdd bug <issue_url> to analyze a bug and generate failing unit testspdd fix <issue_url> to iteratively fix the failing tests across all affected dev unitsDiagnose 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
LEAVE_ALONE (stops here)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.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.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
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:
<include> graph)MANUAL_REVIEW: lines for conflicts that cannot be auto-resolvedarchitecture.json metadata and synchronize associated documents (verified by the doc-sync contract; see Step 10.5)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 reviewMANUAL_REVIEW: flags in the PR bodyWorkflow 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:
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/
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:
<include> files) and compares against the modified codedocs/prompting_guide.md and existing tests to determine what belongs in the promptThis 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:
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.
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
Analyze a list of prompt files and a change description to determine which prompts need t
Truncated — view the full README on GitHub.
Python
95.5%
TypeScript
3.2%
Shell
1.0%
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
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:
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 bugspdd fix <issue-url> - Fix the failing testspdd 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.
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.
On macOS, you'll need to install some prerequisites before installing PDD:
Install Xcode Command Line Tools (required for Python compilation):
xcode-select --install
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)"
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:
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/).
If you prefer using pip, you can install PDD with:
pip install pdd-cli
# 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
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:
pdd change, pdd bug, pdd fix, pdd sync etc. visually--local-only to disable)For CLI enthusiasts, implement GitHub issues directly:
Prerequisites:
GitHub CLI - Required for issue access:
brew install gh && gh auth login
One Agentic CLI - Required to run the workflows (install at least one):
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)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).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.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)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
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.
If you want to understand PDD fundamentals, follow this manual example to see it in action.
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
Clone repo
# Clone the repository (if not already done)
git clone https://github.com/promptdriven/pdd.git
cd pdd/examples/hello
Set one API key (choose your provider):
export GEMINI_API_KEY="your-gemini-key"
# OR
export OPENAI_API_KEY="your-openai-key"
Run the comprehensive setup wizard:
pdd setup
The setup wizard runs these steps:
.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.data/llm_model.csv of top ranked models across all LiteLLM-supported providers based on your available API keyspdd --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).pddrc project configThe wizard can be re-run at any time to update keys, add providers, or reconfigure settings.
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):
~/.pdd/llm_model.csv.backup.<timestamp> so the change is always reversible.~/.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 shellNew 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.
Run Hello:
cd ../hello
pdd --force generate hello_python.prompt
python3 hello.py
✅ Expected output:
hello
PDD commands can be run either in the cloud or locally. By default, all commands run in the cloud mode, which provides several advantages:
When running in cloud mode (default), PDD uses GitHub Single Sign-On (SSO) for authentication. On first use, you'll be prompted to authenticate:
The authentication token is securely stored locally and automatically refreshed as needed.
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:
When keys are missing, PDD will prompt for them interactively and securely store them in your local .env file.
PDD uses a CSV file to configure model selection and capabilities. This configuration is loaded from:
~/.pdd/llm_model.csv (takes precedence if it exists)<PROJECT_ROOT>/.pdd/llm_model.csvThe 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 tokenscoding_arena_elo: Raw Arena/static ELO metadatamodel_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 Copilotstructured_output: Whether the model supports structured JSON outputreasoning_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").
PDD supports two Z.AI API endpoints:
https://api.z.ai/api/paas/v4) — standard prepaid/resource billing, suitable for general use.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.
Command not found
# Add to PATH if needed
export PATH="$HOME/.local/bin:$PATH"
Permission errors
# Install with user permissions
pip install --user pdd-cli
macOS-specific issues
xcode-select --install to install the required development toolsbrew install pythonbrew install uvpython3 points to Python 3.12+: which python3 && python3 --versionTo 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).
PDD supports a wide range of programming languages, including but not limited to:
The specific language is often determined by the prompt file's naming convention or specified in the command options.
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 projectExamples:
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.pyapp/api/orders/route_TypeScript.prompt → generates app/api/orders/route.tsPDD 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 (PDD) inverts traditional software development by treating prompts as the primary artifact - not code. This paradigm shift has profound implications:
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.
Natural Language Over Code: Prompts are written primarily in natural language, making them more accessible to non-programmers and clearer in expressing intent.
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.
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.
To work effectively with PDD, adopt these mental shifts:
Prompt-First Thinking: Always start by defining what you want in a prompt before generating any code.
Bidirectional Flow:
Modular Prompts: Just as you modularize code, you should modularize prompts into self-contained units that can be composed.
Integration via Examples: Modules integrate through their examples, which serve as interfaces, allowing for token-efficient references.
Each workflow in PDD addresses a fundamental development need:
Initial Development Workflow
This workflow embodies the prompt-to-code pipeline, moving from concept to tested implementation.
Code-to-Prompt Update Workflow
This workflow ensures the information flow from code back to prompts, preserving prompts as the source of truth.
Debugging Workflows
These workflows recognize that different errors require different resolution approaches.
Refactoring Workflow
This workflow parallels code refactoring but operates at the prompt level.
Multi-Prompt Architecture Workflow
This workflow addresses the complexity of managing multiple interdependent prompts.
Enhancement Phase: Use Feature Enhancement when adding capabilities to existing modules.
The choice of workflow should be guided by your current development phase:
Creation Phase: Use Initial Development when building new functionality.
Maintenance Phase: Use Code-to-Prompt Update when existing code changes.
Problem-Solving Phase: Choose the appropriate Debugging workflow based on the issue type:
Restructuring Phase: Use Refactoring when prompts grow too large or complex.
System Design Phase: Use Multi-Prompt Architecture when coordinating multiple components.
Enhancement Phase: Use Feature Enhancement when adding capabilities to existing modules.
Effective PDD employs these recurring patterns:
Dependency Injection via Auto-deps: Automatically including relevant dependencies in prompts.
Interface Extraction via Example: Creating minimal reference implementations for reuse.
Bidirectional Traceability: Maintaining connections between prompt sections and generated code.
Test-Driven Prompt Fixing: Using tests to guide prompt improvements when fixing issues.
Hierarchical Prompt Organization: Structuring prompts from high-level architecture to detailed implementations.
pdd [GLOBAL OPTIONS] COMMAND [OPTIONS] [ARGS]...
Here is a brief overview of the main commands provided by PDD. Click the command name to jump to its detailed section:
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 <url>"]
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 <url>"]
test_url["pdd test <url>"]
bug_url["pdd bug <url>"]
fix_url["pdd fix <url>"]
change["pdd change <url>"]
sync_url["pdd sync <url>"]
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:
pdd connect (web UI), direct CLI, or the GitHub Apppdd generate <url> scaffolds architecture, prompts, and .pddrc from a PRD GitHub issuepdd sync runs the full auto-deps → generate → example → crash → verify → test → fix → update cycle for each modulepdd 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)test <url> or bug <url> surfaces failing tests → fix <url> resolves themchange <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.connect: [RECOMMENDED] Launch web interface for visual PDD interactionsetup: Configure API keys and shell completionchange: Implement feature requests from GitHub issues (13-step workflow)bug: Analyze bugs and create failing tests from GitHub issuescheckup: 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)sync: [PRIMARY FOR PROMPT WORKFLOWS] Automated prompt-to-code cyclegenerate: Creates runnable code from a prompt file; supports parameterized prompts via -e/--envexample: Generates a compact example showing how to use functionality defined in a prompttest: Generates or enhances unit tests for a code file and its promptupdate: Updates the original prompt file based on modified codeverify: Verifies functional correctness by running a program and judging output against intentcrash: Fixes errors in a code module and its calling program that caused a crashpreprocess: Preprocesses prompt files, handling includes, comments, and other directivesreplay: Reconstructs and audits expanded prompt context from a snapshot-enabled run artifactcontext: Shows context-window usage by source for a hydrated prompt, Claude-Code /context-stylesplit: Splits large prompt files into smaller, more manageable onesextracts prune: Garbage-collect orphaned extracts cache entriesauto-deps: Analyzes and inserts needed dependencies into a prompt filesync-architecture: Updates architecture.json from prompt metadata tagsdetect: Analyzes prompts to determine which ones need changes based on a descriptionconflicts: Finds and suggests resolutions for conflicts between two prompt filestrace: Finds the corresponding line number in a prompt file for a given code lineauth: Manages authentication with PDD Cloudsessions: Manage remote sessions for connectreport-core: Create a GitHub issue from a debug snapshotcontracts check: Run deterministic contract section checks; see docs/contract_check.mdtemplates: List, inspect, and copy packaged prompt templateswhich: Print resolved configuration values and search pathsinstall_completion: Refresh shell completion scriptsPDD 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:
user_stories/ and match story__*.md.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.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:
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.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:
<!-- pdd-story-prompts: prompts/a_python.prompt, prompts/b_python.prompt -->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.--stories mode, existing story metadata scopes validation; when metadata is missing, validation falls back to the full prompt set.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:
user_stories/story__template.md for a starter format.Contract coverage:
## Covers section (for example R1 or
prompts/module_python.prompt#R2). See docs/coverage_contracts.md and
docs/contract_check.md.Executable regression suite:
@pytest.mark.story. Run the suite with make regression-stories
(i.e. pytest -m story) in the public-safe, no-secrets lane.pdd test --from-story user_stories/story__<slug>.md.generate, sync, fix, change,
update) plus a batch of previously-fixed-bug regressions. See
docs/generating_user_stories.md.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).
--time FLOAT: Controls the reasoning allocation for LLM models supporting reasoning capabilities (0.0 to 1.0, default is 0.25).
1.0 utilizes the maximum available tokens.1.0 corresponds to the highest effort level.--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.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:
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 CommandThe 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:
gh auth token (recommended)GITHUB_TOKEN or GH_TOKENPDD_GITHUB_TOKENFile Tracking & Gists:
When using --api, PDD will:
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.
--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..pddrc context > environment variables > defaults. See Configuration for details.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:
PDD uses a large language model to generate and manipulate code. The --strength and --temperature options allow you to control the model's output:
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.--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:
model_rank_score values for selection and raw Arena/static coding_arena_elo metadataPDD 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.
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.
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.
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:
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.
The generated CSV file includes the following columns:
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.PDD_MODEL_DEFAULT or the model argument), before provider resolution or fallback.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).importlib.metadata).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.
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.
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.
Here are the main commands provided by PDD:
[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:
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:
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.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.pyfactorial_calculator_typescript.prompt → generates factorial_calculator.tsfactorial_calculator_javascript.prompt → generates factorial_calculator.jssrc/models/user_Python.prompt → generates src/models/user.pyIf 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:
.pddrcarchitecture.json provides an explicit filepath for a prompt entry, sync honors it according to whether that filepath includes a directory component:
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.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.__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.None, emits a needs-review signal, and performs no test write until the configuration is made resolvable.Workflow Logic:
The sync command automatically detects what files exist and executes the appropriate workflow:
architecture.json and the prompt's <pdd-interface> block:
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.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).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.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.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.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.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.--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.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:
--fresh is passed.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:
.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.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:
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:
*_LLM.prompt templates), (c) PDD_CHANGED_MODULES env-var bypass (deterministic, free — skips LLM when branch-diff returned empty), (d) LLM fallbackAsyncSyncRunner 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)# 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-onlyCross-Machine Resume: Workflow state is stored in a hidden GitHub comment, enabling resume from any machine. Use --no-github-state to disable.
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:
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.jsonalready has unrelated missing-dependency errors elsewhere, the exit code stays non-zero on--dry-runeven for an otherwise-clean target prompt. Fix the repo-wide errors (or scope your check) before relying on the exit code in scripts.
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 / --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.
-e KEY=VALUE or --env KEY=VALUE (repeatable).-e KEY reads VALUE from the current process environment variable KEY.generate.-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.
$VAR and ${VAR} are replaced only when VAR was provided.--output, PDD also expands $VAR/${VAR} using the same variable set.-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:
KEY=VALUE if the value contains spaces or shell-special characters: -e "DISPLAY_NAME=Order Processor".-e/--env — e.g., --output 'src/${MODULE}.py'.--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.promptMODULE=orders pdd generate -e MODULE --output "src/$MODULE.py" prompts/module_python.promptGit Integration:
git add (if not already committed/added) to ensure you can roll back if needed.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):
architecture.json and scaffolding filesarchitecture.jsonValidation (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:
.pddrc or a .pdd/ directory.sources/ plus PRD/spec markdown (prd*.md, spec*.md, or *_prd.md/*_spec.md)..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 authenticatedWorkflow 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>):
<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.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.data_dictionary.yaml / api_contracts.yaml / integration_points.yaml is not invoked. Update those files manually if the PRD change affects them.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.
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.
-e/--env (required/optional, type, examples)pdd generate commandspdd templates show<include>${VAR}</include>, <include-many>${LIST}</include-many>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
<include>/<include-many> for curated context; prefer specs/configs over large code dumps.-e, e.g. <include>${PRD_FILE}</include>; the engine resolves includes after variable expansion.--output.Behavior notes
-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.--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
pdd templates show)discover settings (executed by the CLI with caps)output_schema for validationpdd templates list [--json] [--filter tag=...]pdd templates show <name>pdd templates copy <name> --to prompts/pdd generate --template <name> [-e KEY=VALUE...] [--output PATH]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)
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-processingllm=false: Skip LLM generation, run only post-processingArchitecture JSON Template Features:
The architecture/architecture_json template includes automatic Mermaid diagram generation:
architecture_diagram.html with color-coded modules (frontend/backend/shared)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
name, description, version, tags: docs and discoverylanguage, output: defaults for generatevariables: 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
pdd templates show to view variables, usage, discover, and output schema. Pass variables via -e at the CLI.Template Variables (reference)
architecture/architecture_json.prompt)
PRD_FILE (path, required): Primary spec/PRD file pathTECH_STACK_FILE (path, optional): Tech stack overview file (includes API style; e.g., docs/tech_stack.md)APP_NAME (string, optional): App name for contextDOC_FILES (list, optional): Comma/newline-separated list of additional doc pathsINCLUDE_FILES (list, optional): Comma/newline-separated list of source files to includeSCAN_PATTERNS (list, optional): Discovery patterns defined in front matter discover and executed by the CLISCAN_ROOT (path, optional): Discovery root defined in front matter discoverNotes
-e as shown in examples.Copy-and-generate
prompts/ folder, then use pdd generate as usual. This keeps prompts versioned with your repo so you can edit and evolve them.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
reason, description, dependencies, priority, filename, optional tags.type: component | page | module | api | graphql | cli | job | message | config | entrypointcomponent: 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, notesmodule: functions[] with name, signature, optional returns, errors, sideEffectsapi: endpoints[] with method, path, optional auth, requestSchema, responseSchema, errorsgraphql: 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[], retryPolicymessage: topics[] with name, direction (publish|subscribe), optional schema, qosconfig: 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)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
prompts/<org_or_team>/... and compose with <include> to maximize reuse.Templates: additional UX
Goals:
Commands:
pdd templates list [--json] [--filter tag=frontend] to discover templatespdd templates show <name> [--raw] to view metadata and variablespdd templates copy <name> --to prompts/ to vendor into your repopdd 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:
./prompts/** (allows team overrides).pddrc paths: any configured templates.pathspdd/templates/** (built‑ins)$PDD_PATH/prompts/** (org‑level packs)Template front matter:
.prompt files to declare name, description, tags, version, language, default output, and variables (with required, default, type such as string or json).-e/--env override front‑matter defaults; unknowns are validated and surfaced to the user.--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.---
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...
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:
crash and verify, providing a quick end-to-end sanity check that the generated code runs and behaves as intended.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.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
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.
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):
Duplicate check - Search for existing issues describing the same test requirements. If found, merge content and close the duplicate.
Documentation check - Review repo documentation and codebase to understand what needs to be tested. Identifies OpenAPI/Swagger specs if present.
Analyze & clarify - Determine if enough information exists in the issue to create tests. Posts comment requesting clarification if needed.
Detect frontend - Identify the test type: web UI, CLI, desktop app, or API. Determines the appropriate testing framework.
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).
Assess coverage (web only, requires playwright-cli) - Compare requirements against the enhanced test plan to identify gaps needing manual testing.
Create manual testing checklist (web only) - Generate a checklist using three strategies: page-by-page exhaustive testing, user-story walkthroughs, and accessibility spot-checks.
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.
Create regression tests (web only) - Generate automated tests that reproduce bugs found in Step 8.
Validate regression tests (web only) - Confirm regression tests fail against current code (proving bugs exist).
Loop check (web only) - Check checklist completion. Loops back to Step 8 if items remain (max 3 iterations).
Generate tests - Create tests in a worktree from the enhanced plan, including behavioral, contract, and accessibility tests.
Run tests - Execute all generated tests against the target.
Fix & iterate - Fix any failing tests and re-run until they pass.
Validate tests against plan - Cross-reference the enhanced plan against generated tests. Generate missing tests for any unimplemented cases.
Run newly generated tests - Run and fix tests created in Step 15 (if any).
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:
| Mode | Steps 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:
playwright-cli in PATH. If not found, these steps are skipped with a warning.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 modeEnvironment Variables:
PDD_CLOUD_RUN=true: Enable parallel execution mode for manual testing (Steps 6-11)PDD_NO_GITHUB_STATE=1: Disable GitHub state persistenceCross-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
Generate or enhance unit tests for a given code file and its corresponding prompt file.
Test organization:
<basename>, PDD maintains a single test file (by default named test_<basename>.<language_extension> and typically placed under a tests directory).--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.
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:
.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.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.pdd-story-prompts metadata. Story generation does not run detect_change or auto-detect touched prompts.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 -->pdd detect --stories.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:
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.
pdd [GLOBAL OPTIONS] test --output tests/test_factorial_calculator.py factorial_calculator_python.prompt src/factorial_calculator.py
pdd [GLOBAL OPTIONS] test --output tests/test_calculator.py calculator_python.prompt examples/calculator_example.py
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
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
When coverage options are provided, the test command will:
Analyze the coverage report to identify:
Generate additional test cases prioritizing:
Maintain consistency with:
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 / --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).
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.
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).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.
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>
shell: Executes shell commands and includes their output in the prompt, removing the shell tags.
<shell>ls -la</shell>
web: Scrapes a web page and includes its markdown content in the prompt, removing the web tags.
<web>https://example.com</web>
PDD supports two ways of including external content:
```
<./path/to/file.txt>
```
This will be recursively processed until there are no more angle brackets in triple backticks.
When using the --double option:
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.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
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.
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.
prompt_path: Path to the prompt file to audit.--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.By default it prints a Claude-Code /context-style usage box:
⛶).total/limit tokens (percent%) summary.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.
0: audit completed within threshold.2: total tokens exceed --threshold percent of the model's context limit (useful for CI and dashboards).# 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
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
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.--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.
--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).--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:
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.
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:
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.
(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:
claude CLI to be installed and in your PATH.claude auth login (recommended), otherwise with ANTHROPIC_API_KEY from your environment.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.agy / legacy gemini):
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.~/.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.codex CLI to be installed and in your PATH.~/.codex/auth.json ChatGPT login (run codex login once) or OPENAI_API_KEY from your environment.opencode CLI to be installed and in your PATH (npm install -g opencode-ai).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.OPENCODE_MODEL=provider/model (for example, anthropic/claude-sonnet-4-5) to avoid relying on default model resolution.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.)
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:
pdd fix on each failing test sequentiallypdd fix sequentially on failing unit tests for each dev unit## 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 passarchitecture.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)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:
gh CLI must be installed and authenticatedRelationship with pdd bug:
This feature works seamlessly with issues processed by pdd bug. The typical workflow is:
pdd bug <issue_url> to analyze a bug and generate failing unit testspdd fix <issue_url> to iteratively fix the failing tests across all affected dev unitsDiagnose 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
LEAVE_ALONE (stops here)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.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.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
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:
<include> graph)MANUAL_REVIEW: lines for conflicts that cannot be auto-resolvedarchitecture.json metadata and synchronize associated documents (verified by the doc-sync contract; see Step 10.5)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 reviewMANUAL_REVIEW: flags in the PR bodyWorkflow 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:
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/
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:
<include> files) and compares against the modified codedocs/prompting_guide.md and existing tests to determine what belongs in the promptThis 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:
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.
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
Analyze a list of prompt files and a change description to determine which prompts need t
Truncated — view the full README on GitHub.
Python
95.5%
TypeScript
3.2%
Shell
1.0%