PDCA quality-cycle wrapping Wyrd's cargo xtask gates
One command takes an issue from a brief all the way to a human-signed-off, verified
change — Plan → Do → Check → sign-off → Act — pausing only where a human belongs.
The driver is deterministic (state machine + gates + the C6 accept-guard are plain code); a model is invoked only at the five leaves. See PCDA/quality-cycle.md for the model and docs/INTEGRATION.md for this project's concretizations.
make install-check (or pdca doctor once installed) reports the harness-universal
tools and the configured leaf CLIs and prints the exact fix for anything missing. (Your gate
toolchain is only checked if you declare it — see the last bullet.)
- Python 3.11+ — the driver is stdlib-only (
tomllib). - git and make — per-cycle worktree isolation, and the bootstrap / front-door target
runner (on Windows use
scripts/install.ps1instead ofmake). - a pip-capable venv (
python3-venv; a clean Debian/Ubuntu lacksensurepip) —make installprovisions it viaapt, or falls back toget-pip.py(needscurl). - gh, authenticated (
gh auth login) — draft-PR publish/merge and the tracker scrape. - the leaf-backend CLI(s) you wire in
pdca.toml[leaves.*]— e.g.claudeand/orcodex— for a liveflow; the--rehearse/ stub slice needs none.make installauto-installs a backend with an official installer (currentlyclaude); for others (e.g.codex) it reports the CLI as missing with a hint, and you install it yourself. - whatever your gates shell out to (
pdca.toml[[gates.checks]]) — provision it via[install].extra_bootstrap(survivescopier update). Notemake install-checkdoesn't run that command; declare the tools as[[doctor.checks]]rows sopdca doctorverifies them.
Bootstrap once (per platform), then drive the cycle with the console script —
pdca, the cross-platform run interface:
make install # Ubuntu/macOS: .venv + the `pdca` console script
# pwsh -File scripts/install.ps1 # Windows equivalent
make setup # ONCE: grant Claude read of the workspacepdca flow 123 --rehearse # offline dry-run: PLANNED → … → COMPLETE on stubs
pdca flow 123 # run the whole cycle for issue 123 (live)
pdca flow 123 124 125 # several ids → batch (lanes + cheap-first sign-off)
pdca # the status dashboard (bare invocation)Before make install, run it from source as python -m pdca_harness.cli flow 123
(with PYTHONPATH=src).
Run pdca flow in a real terminal — the Plan, sign-off, publish and Act
steps open Claude interactively. Trust: the first interactive session asks once to
trust the project — a one-time global setting (~/.claude.json), not something
make setup can write (setup handles file permissions). Accept it.
What happens, step by step (the cycle has four beats; review/sign-off/publish are steps within Check):
- Plan (interactive) — Claude reads your input documents (e.g. a tracker CSV
via
--from-csv) and, with you, writesresults/issue_<id>/brief.md. An unbriefed id is auto-planned; already-briefed ids go straight to Do. - Do (headless) — Claude implements the brief:
patch.diff, the test,build-notes.md. - Check — the deterministic gates run (
→ … still workingheartbeats while they do), then a headless advisory reviewer. - Sign-off (Check step, interactive) — Claude reviews the result with you; you
clear the §6 items and decide
accept/iterate-do/iterate-plan. The driver records §9 under the C6 guard. - Publish (Check step, interactive, on accept) — Claude drafts the contribution
artifacts (commit-msg + PR description) and the driver opens a draft PR — the
closing work of Check.
--no-publishskips it;--rehearsedry-runs it. - Act (interactive, on by default after COMPLETE;
--no-actto skip) — Claude reviews the frozen cycle and suggests process improvements if any are warranted.
When a Plan/sign-off/publish session ends, exit Claude (Ctrl-D) to let the flow continue.
Run the cycle through pdca (the console script). make is bootstrap-only.
| Command | What it does |
|---|---|
pdca |
The status dashboard (bare invocation). |
pdca flow <id> [--from-csv PATH] [--no-publish] [--no-act] [--by NAME] [--lanes N] |
Run the full cycle for one issue. On an accept it opens a draft PR (--no-publish stops at COMPLETE); Act runs by default (--no-act skips); --by sets §9 attribution. |
pdca flow <id> <id> … |
Batch: several ids fan out across lanes; unbriefed ids are auto-planned (one shared Plan session); sign off cheap-first. |
pdca flow --from-csv PATH |
Plan a batch the planner picks from a tracker export, then drive it. |
pdca flow <id> … --rehearse |
Dry-run the same control flow on stub leaves + stub gates in an isolated bundle root — no Claude, no live gates, instant. |
pdca flow <id> … --from-briefs DIR |
Init any missing bundle from DIR/<id>.md before driving. |
pdca status / queue |
List bundle states / the cheap-first sign-off burn-down. |
pdca publish <id> [--dry-run] |
Re-publish an accepted bundle as a draft PR (the flow does this on accept). |
pdca signoff <id> --accept |
Record the human Check sign-off (refused while §6 NEEDS-HUMAN is open). |
pdca try <id> |
Launch the patched build from the bundle's worktree so you can hands-on test it during Check (needs [manual_test].cmd + [driver].worktree). |
pdca act index / act log --date <d> |
Cross-cycle Act tooling. |
make / make check |
Self-test (full / fast offline). |
make install / make setup |
Bootstrap: console script in .venv/ / Claude read-permissions. |
If something looks stuck, it isn't — a headless claude -p and a long gate print
nothing until they finish, so the flow shows a … still working (NmSSs elapsed)
heartbeat. Let it run.
Configured in pdca.toml [[gates.checks]], single-sourced for the
local driver and CI (pdca gates / pdca gates --working-tree). Until you add real
rows the driver uses an all-PASS stub fallback — fill the gates first (see
docs/INTEGRATION.md §4). Guidance learned the hard way:
- The per-fix correctness gate (apply the bundle's
patch.diff, run only its test, assert red-without / green-with) is what makes a cycle mean something — make itgating = true,scope = "bundle". - A whole-suite runtime gate on the unmodified tree can't gate a single fix (a
pre-existing failure makes it red regardless) — ship it
gating = false(advisory) until the suite is green-baseline.
The planner picks the Plan template with you: ordinary fixes and most new functionality use templates/brief.md.tpl; a change big enough to warrant a design proposal uses templates/design-proposal.md.tpl. Not every feature is a design proposal — it's the exception, authored at Plan.
src/pdca_harness/ the deterministic driver (state machine, gates, leaves, flow)
engine/ your verification engine — the gate runners gates invoke (you fill in)
templates/ brief / design-proposal / SUMMARY templates
results/issue_<id>/ one bundle per issue — the state IS the files here
pdca.toml project config: leaves, gates, tracker, paths
docs/INTEGRATION.md this project's concretizations
PCDA/ the generic model (reference docs)
.claude/agents/ the five leaf agents (planner, builder, reviewer, signoff, act)
- Iteration is built in.
iterate-dorebuilds against the same brief;iterate-planre-opens Plan. The flow loops untilCOMPLETE(bounded). - Nothing is pushed for you. The builder may open a draft PR for CI but can
never mark it ready/merge — enforced by
.claude/hooks/builder_guard.py. - Rendered from a template. This project was generated from a Copier PDCA
template; run
copier updateto pull upstream harness improvements.
Licensed under Apache-2.0 (LICENSE, NOTICE). The PDCA
harness this project was generated from is Apache-2.0, which carries no copyleft into
this repo. Contributions are gated on the Developer Certificate of Origin —
sign off with git commit -s (see CONTRIBUTING.md).