program-context-protocol 0.12.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. pcp/__init__.py +3 -0
  2. pcp/assertions.py +152 -0
  3. pcp/attest.py +111 -0
  4. pcp/build_loop_bypass.py +76 -0
  5. pcp/build_report.py +54 -0
  6. pcp/capture.py +339 -0
  7. pcp/cli.py +104 -0
  8. pcp/commands/__init__.py +0 -0
  9. pcp/commands/amend.py +283 -0
  10. pcp/commands/architect_review.py +291 -0
  11. pcp/commands/architecture_justification.py +164 -0
  12. pcp/commands/audit.py +371 -0
  13. pcp/commands/build.py +4523 -0
  14. pcp/commands/build_plan.py +153 -0
  15. pcp/commands/build_status.py +83 -0
  16. pcp/commands/capture.py +72 -0
  17. pcp/commands/check.py +584 -0
  18. pcp/commands/context.py +151 -0
  19. pcp/commands/control_audit_cmd.py +54 -0
  20. pcp/commands/correct_objective.py +160 -0
  21. pcp/commands/dashboard.py +732 -0
  22. pcp/commands/deploy.py +199 -0
  23. pcp/commands/deploy_check.py +134 -0
  24. pcp/commands/design_audit.py +323 -0
  25. pcp/commands/diff.py +153 -0
  26. pcp/commands/diff_reduce.py +355 -0
  27. pcp/commands/docs.py +538 -0
  28. pcp/commands/doctor.py +820 -0
  29. pcp/commands/escalations_cmd.py +64 -0
  30. pcp/commands/gate.py +209 -0
  31. pcp/commands/import_project.py +404 -0
  32. pcp/commands/init.py +1634 -0
  33. pcp/commands/install_hook.py +283 -0
  34. pcp/commands/install_skill.py +48 -0
  35. pcp/commands/kickoff.py +772 -0
  36. pcp/commands/narrative_lint.py +54 -0
  37. pcp/commands/objective_conflicts_cmd.py +68 -0
  38. pcp/commands/pm.py +504 -0
  39. pcp/commands/pressure_test_cmd.py +72 -0
  40. pcp/commands/provenance.py +313 -0
  41. pcp/commands/prune.py +179 -0
  42. pcp/commands/report.py +49 -0
  43. pcp/commands/run_log_cmd.py +122 -0
  44. pcp/commands/scan.py +346 -0
  45. pcp/commands/self_update.py +125 -0
  46. pcp/commands/status.py +180 -0
  47. pcp/commands/takeover.py +55 -0
  48. pcp/commands/telemetry_cmd.py +167 -0
  49. pcp/commands/validate_module.py +153 -0
  50. pcp/commands/validate_strategy.py +413 -0
  51. pcp/commands/verify.py +166 -0
  52. pcp/commands/verify_syntax_fix.py +74 -0
  53. pcp/commands/watch.py +372 -0
  54. pcp/config_audit.py +141 -0
  55. pcp/context_map.py +124 -0
  56. pcp/control_audit.py +159 -0
  57. pcp/coupling.py +178 -0
  58. pcp/coverage_audit.py +77 -0
  59. pcp/decision_log.py +134 -0
  60. pcp/discovery/__init__.py +0 -0
  61. pcp/discovery/clusters.py +124 -0
  62. pcp/discovery/graph.py +110 -0
  63. pcp/discovery/scanner.py +109 -0
  64. pcp/escalations.py +193 -0
  65. pcp/evidence.py +30 -0
  66. pcp/evidence_chain.py +56 -0
  67. pcp/impact.py +164 -0
  68. pcp/install_approvals.py +44 -0
  69. pcp/integrity_audit.py +176 -0
  70. pcp/librarian.py +89 -0
  71. pcp/llm/__init__.py +0 -0
  72. pcp/llm/client.py +183 -0
  73. pcp/llm/coding_agent_contract.py +104 -0
  74. pcp/llm/harness/__init__.py +12 -0
  75. pcp/llm/harness/agy.py +121 -0
  76. pcp/llm/harness/agy_coding_loop.py +180 -0
  77. pcp/llm/harness/claude.py +241 -0
  78. pcp/llm/ledger.py +47 -0
  79. pcp/narrative_lint.py +229 -0
  80. pcp/nav_graph.py +226 -0
  81. pcp/objective_conflicts.py +129 -0
  82. pcp/operational.py +70 -0
  83. pcp/orphaned_work.py +262 -0
  84. pcp/pcp_dir.py +35 -0
  85. pcp/pcp_status.py +313 -0
  86. pcp/policy.py +81 -0
  87. pcp/pressure_test.py +196 -0
  88. pcp/qa.py +445 -0
  89. pcp/run_log.py +225 -0
  90. pcp/schema/__init__.py +0 -0
  91. pcp/schema/ci_rules.schema.json +106 -0
  92. pcp/schema/controls.schema.json +39 -0
  93. pcp/schema/module_acceptance.schema.json +144 -0
  94. pcp/schema/module_spec.schema.json +78 -0
  95. pcp/schema/sdlc_phase.schema.json +52 -0
  96. pcp/schema/validator.py +77 -0
  97. pcp/skill_data/pcp/SKILL.md +1897 -0
  98. pcp/spec_write.py +269 -0
  99. pcp/spend.py +77 -0
  100. pcp/symbols.py +86 -0
  101. pcp/telemetry.py +308 -0
  102. pcp/uat.py +271 -0
  103. pcp/version_drift.py +222 -0
  104. program_context_protocol-0.12.4.dist-info/METADATA +123 -0
  105. program_context_protocol-0.12.4.dist-info/RECORD +109 -0
  106. program_context_protocol-0.12.4.dist-info/WHEEL +4 -0
  107. program_context_protocol-0.12.4.dist-info/entry_points.txt +2 -0
  108. program_context_protocol-0.12.4.dist-info/licenses/LICENSE-APACHE +202 -0
  109. program_context_protocol-0.12.4.dist-info/licenses/LICENSE-MIT +21 -0
@@ -0,0 +1,1897 @@
1
+ ---
2
+ name: pcp
3
+ version: "1.0.0"
4
+ description: "Program Context Protocol — full autonomous software factory. PM describes vision; PCP runs structured discovery, generates BRD, translates to modular specs, builds via the Workflow tool's native parallelism (pcp build-plan computes the schedule, the harness governs concurrency), runs all gates (TDD, architect-review, CI), auto-fixes failures, merges, deploys. PM only touches: vision input, visual approvals, escalations. Invoke with /pcp."
5
+ ---
6
+
7
+ # /pcp
8
+
9
+ Autonomous software factory. PM describes what to build. PCP builds it.
10
+
11
+ **Three modes:**
12
+ 1. `/pcp new` — Vision workshop → BRD → spec scaffold
13
+ 2. `/pcp build` — Parallel autonomous build (concurrency governed by the Workflow tool, not a manual count)
14
+ 3. `/pcp status` — Project health across all projects
15
+
16
+ **The contract:** PM inputs vision and approves milestones. PCP handles everything else. "Build" means deployed and verified — not written.
17
+
18
+ ---
19
+
20
+ ## Usage
21
+
22
+ ```
23
+ /pcp new # start vision workshop → BRD → .pcp/ scaffold (greenfield)
24
+ /pcp new --from-brd <file> # skip workshop, generate .pcp/ from existing BRD
25
+ /pcp import "<description>" # brownfield: graphify → clusters → draft specs → PM review
26
+ /pcp build # build next wave via pcp build-plan + Workflow tool
27
+ /pcp build --module <name> # build one module
28
+ /pcp build --all # build entire backlog, full wave scheduling
29
+ # (no --agents flag: Workflow's own concurrency cap
30
+ # governs how many run at once, not a manual number)
31
+ /pcp status # current project: phase, %, CI, deferred queue
32
+ /pcp status --all # all projects under ~/Claude-code/
33
+ /pcp watch # watch Railway + GitHub Actions
34
+ /pcp fix # diagnose + fix current CI failure
35
+ /pcp approve <module>/<id> # unblock a deferred criterion (manual/visual)
36
+ /pcp feedback <module>/<id> "<text>" # give feedback on a visual criterion, rebuild
37
+ /pcp accept-adr <id> # accept a DRAFT ADR written autonomously
38
+ /pcp override-adr <id> "<decision>" # override PCP's autonomous architecture decision
39
+ /pcp review <module> # architect-review on module spec
40
+ /pcp review <type> # architecture | logic | design | security | qa — see REVIEW ROUTER below
41
+ /pcp diff # target vs current gap
42
+ ```
43
+
44
+ **Language rule — non-negotiable:** Everything the PM reads is in product language. Technical terms (module, spec, coupling, AST, CI, YAML, schema, criterion, pre-commit, branch, commit hash, coverage %) never appear in PM-facing output. Translate before presenting. Technical language is internal — it lives in files and logs, not in conversation.
45
+
46
+ | Technical | Product language |
47
+ |---|---|
48
+ | "3 CI failures" | "3 things broke — fixing now" |
49
+ | "coupling violation: payments ↔ webhooks" | "payments and notifications are too tangled — I'm separating them" |
50
+ | "acceptance criterion BF_001 pending" | "still working on: [feature name]" |
51
+ | "coverage 72%" | "28% of what you described isn't built yet" |
52
+ | "merge conflict on feat/auth" | "two parts of the build clashed — resolving" |
53
+ | "pcp validate-strategy failed" | "the build plan doesn't fully cover what you described — adjusting" |
54
+
55
+ **Unattended operation:** PCP runs fully autonomously while you are away. Escalations go to Slack — not to a blocking prompt. `/pcp watch` monitors CI and Railway for failures and auto-fixes them. When you return, run `/pcp` to see what was built, what is deferred, and what needs your input. Build never stops for input that can be deferred.
56
+
57
+ ---
58
+
59
+ ## REVIEW ROUTER — the PM should never need to remember a command name
60
+
61
+ Real gap found dogfooding: PCP has grown ~32 CLI commands across the whole lifecycle
62
+ (architecture, logic-tier decisions, design/UI, security, QA, deploy). A PM asking to
63
+ "review the UI strategy" or "check the security posture" shouldn't need to know the
64
+ exact command (`design-audit`, `architecture-justification`, `check`...) exists, let
65
+ alone spell it correctly. This section is PCP's own lookup table — read it, don't guess
66
+ a command name, and don't tell the PM the technical name unless they ask (same
67
+ Language Rule as above applies here too).
68
+
69
+ ### Intent → command lookup
70
+
71
+ | PM says something like... | Run this |
72
+ |---|---|
73
+ | "review the architecture" / "does this still make sense structurally" / "check coupling" | `pcp architect-review` (advisory, per-diff), `pcp validate-strategy` (coverage_score + coupling_score, Pass 2), `pcp validate-module <name>` (Pass 1) |
74
+ | "review the logic" / "are we using the right tool for this" / "check build-vs-buy" / "did we reinvent something that already exists" | `pcp architecture-justification` — rolls up every criterion's `logic_tier` (the 6-rung deterministic→deep-think ladder) and `build_vs_buy` decision |
75
+ | "review the design" / "review the UI" / "is this discoverable" / "does this look consistent across screens" | `pcp design-audit` (Feature Exposure Ladder — how discoverable each UI-facing criterion actually is) — for the design-thinking pass on one specific screen, use the `pcp-ui-design` skill (`~/.claude/skills/pcp-ui-design/SKILL.md`), not this rollup |
76
+ | "review security" / "any secrets" / "check for vulnerabilities" | `pcp check` (Layer 1 — deterministic, hard block: hardcoded secrets, eval/exec, disabled TLS, string-built SQL, plus any project-specific `hard_block` rules in `ci_rules.yaml`) |
77
+ | "check before merging" / "PR review" / "does this align with what we asked for" | `pcp gate` (Layer 2 — LLM alignment score, advisory, never hard-blocks) |
78
+ | "are we ready to deploy" / "check the deploy gate" | `pcp deploy-check` (Layer 3 — SDLC phase exit criteria, hard block) |
79
+ | "review QA" / "how's the build going" / "any flaky retries" / "what's this costing" | `pcp telemetry` (per-module retries, QA error rate, cost, languages), `pcp provenance` (full audit-evidence document — SSDF crosswalk, bypass ledger, chain integrity) |
80
+ | "any dead code" / "bloat check" | `pcp audit` (advisory, never blocks) |
81
+ | "what's the overall status" / "show me everything" | `pcp dashboard` — single HTML, 5 tabs (Overview / Objective & Gaps / Audit Trail / Architecture Justification / Design), already visualizes most of the rows above. Open this first before running things piecemeal. |
82
+ | "what's blocked or bypassed" | `pcp report` (bypass history, coverage score, gate outcomes) |
83
+ | "give me a plain-English status" | `pcp status --pm` |
84
+ | "what changed in this module" / "module history" / "drift ledger for X" | `pcp docs [--module <name>]` — per-module vision/BRD/built/changelog, `changelog.md` is a drift ledger with a computed drift score (in-flight spec changes, bypasses, retries) |
85
+ | "clean up old logs" / "disk is full" / "prune old evidence" | `pcp prune [--evidence-days N] [--transcript-days N]` — deletes stale `.pcp/evidence/`/`.pcp/transcripts/` past a retention window; no-op unless configured, `--dry-run` to preview, mandatory confirmation unless `--yes` |
86
+
87
+ ### Full command reference, by lifecycle stage (all current as of this skill's own version — re-check `pcp --help` if something here feels stale)
88
+
89
+ **Setup / onboarding**
90
+ - `pcp init` — scaffold `.pcp/`
91
+ - `pcp kickoff <vision.md>` — generate specs from a vision doc
92
+ - `pcp import "<description>"` — brownfield onboarding (graphify clusters → draft specs)
93
+ - `pcp takeover` — end-to-end: preflight + kickoff + build everything pending
94
+ - `pcp doctor` — check/configure environment tool integrations
95
+ - `pcp install-hook` / `pcp install-skill` — one-time wiring
96
+
97
+ **Strategy / architecture**
98
+ - `pcp validate-strategy` — coverage_score + coupling_score (Pass 2: modules vs objective)
99
+ - `pcp validate-module <name>` — module vs objective/decomposition (Pass 1)
100
+ - `pcp architect-review` — architecture principle review against persona + KB (advisory)
101
+ - `pcp architecture-justification [--json]` — `logic_tier`/`build_vs_buy` rollup
102
+
103
+ **Design** (see CLAUDE.md's "PCP Design as a Hard Constraint" for the full 5-stage lifecycle this fits into)
104
+ - `pcp design-audit [--json]` — Feature Exposure Ladder rollup
105
+ - skill `pcp-ui-design` — design-thinking pass on one UI-facing criterion, establishes/reuses `.pcp/design_system.md`
106
+
107
+ **Build**
108
+ - `pcp build [--module <name> | --all]` — autonomous coding loops per pending criterion
109
+ - `pcp pm "<intent>"` — translate natural-language feature intent to spec/acceptance changes
110
+
111
+ **Gates — the 3-tier system**
112
+ - `pcp check` — Layer 1, pre-commit, deterministic, hard block, no LLM
113
+ - `pcp gate` — Layer 2, PR, LLM alignment score, advisory
114
+ - `pcp deploy-check` — Layer 3, deploy, SDLC phase-exit criteria, hard block
115
+
116
+ **QA / audit / evidence**
117
+ - `pcp telemetry` — build-efficiency rollup (retries, QA error rate, cost, languages)
118
+ - `pcp provenance [--json]` — audit-evidence document (SSDF crosswalk, bypass ledger, chain integrity)
119
+ - `pcp audit` — dead-code/bloat scan, advisory, never blocks
120
+ - `pcp report` — bypass history, coverage score, gate outcomes
121
+ - `pcp capture [--transcript-file <path>]` — classify a session transcript into BRD/decision-log drift
122
+
123
+ **Status / drift**
124
+ - `pcp scan [--coverage]` — regenerate `.pcp/current_state.md`
125
+ - `pcp diff` — target vs current state gap
126
+ - `pcp status [--pm] [--rescan] [--print]` — `pcp.md` snapshot, or a plain-English PM report
127
+ - `pcp dashboard` — unified 5-tab HTML view (see above)
128
+ - `pcp context` — dump `.pcp/` context for LLM consumption at session start
129
+ - `pcp docs [--module <name>]` — per-module doc kit (vision/BRD/built/changelog); `changelog.md` is a chronological drift ledger with a computed drift score, not just a build log
130
+
131
+ **Deploy / ops**
132
+ - `pcp deploy [--yes] [--rollout N]` — checklist → Layer 3 gate → approval → trigger → smoke test → auto-rollback
133
+ - `pcp watch [--once] [--interval N]` — continuous CI/deploy monitoring, auto-fix on failure
134
+ - `pcp prune [--evidence-days N] [--transcript-days N] [--dry-run] [--yes]` — retention cleanup for `.pcp/evidence/`/`.pcp/transcripts/` (the two directories that actually grow unbounded); does nothing unless a retention window is configured or passed; mandatory confirmation like `pcp deploy`, `--yes` opts out
135
+
136
+ **Narrow / utility**
137
+ - `pcp verify-syntax-fix <file>` — deterministic SAFE/UNSAFE verdict for a protected-path syntax-only edit (used by the `verify-syntax-fix` PreToolUse hook, not typically invoked directly by a PM)
138
+
139
+ ---
140
+
141
+ ## BROWNFIELD IMPORT (`/pcp import "<description>"`)
142
+
143
+ For existing codebases with no `.pcp/` context. PM provides one paragraph describing what the codebase delivers — that's the only required input.
144
+
145
+ ### Step 1 — Write objective.md
146
+
147
+ PM description → `.pcp/objective.md`. Done immediately. No workshop needed.
148
+
149
+ ### Step 2 — Graphify cluster detection
150
+
151
+ Invoke `/graphify` on the entire codebase. Input: all source files (imports, function calls, class references, shared state). Output: knowledge graph with cluster detection.
152
+
153
+ ```
154
+ Clusters = tightly coupled file groups = natural module candidates
155
+ Cross-cluster edges = inter-module dependencies = contract boundaries
156
+ Dense cross-cluster edges = coupling violations (flagged immediately)
157
+ ```
158
+
159
+ Why graphify instead of directory scan: flat repos with 300 files across mixed dirs have no meaningful directory structure. Graphify finds real boundaries from actual code relationships, not assumed from folder names.
160
+
161
+ ### Step 3 — Present module map to PM
162
+
163
+ ```
164
+ Graphify found 7 clusters:
165
+
166
+ auth-cluster auth.py, session.py, jwt_utils.py, bcrypt_helper.py
167
+ payments-cluster stripe_client.py, charge.py, refund.py, invoice.py
168
+ webhooks-cluster webhook.py, event_queue.py, retry.py
169
+ api-cluster routes.py, middleware.py, serializers.py
170
+ db-cluster models.py, migrations/, connection.py
171
+ tasks-cluster celery.py, workers/, scheduler.py
172
+ shared config.py, utils.py, constants.py ← infrastructure, not a module
173
+
174
+ Suggested module names (from PM description + file names):
175
+ auth-cluster → auth
176
+ payments-cluster → payments
177
+ webhooks-cluster → webhooks
178
+ api-cluster → api-gateway
179
+ db-cluster → data-layer
180
+ tasks-cluster → task-runner
181
+
182
+ Cross-cluster edges (coupling violations — fix in Wave 0):
183
+ payments ↔ webhooks: 14 direct calls
184
+ api-gateway ↔ db-cluster: direct model access (bypasses data-layer)
185
+
186
+ Rename, split, or merge any modules before I generate specs.
187
+ ```
188
+
189
+ Wait for PM review. Iterate until approved.
190
+
191
+ ### Step 4 — Baseline scan
192
+
193
+ ```bash
194
+ pcp scan # current_state.md = existing code as-is
195
+ pcp check --baseline # catalog pre-existing violations → .pcp/baseline_violations.yaml
196
+ # NOT blocking. Counting what's already broken.
197
+ pcp validate-strategy # coverage score + coupling score on day 1
198
+ ```
199
+
200
+ Report to PM:
201
+ ```
202
+ Baseline: <project>
203
+
204
+ Objective coverage: 72% (28% of your description has no code yet)
205
+ Coupling score: 0.3 (high — pivots will be expensive)
206
+ Pre-existing violations: 23 MOD_001, 4 circular deps, 11 SEC_001
207
+ Test coverage: 34%
208
+
209
+ Recommended wave order:
210
+ Wave 0 — characterization tests + decouple (no new features)
211
+ Wave 1+ — new features per objective gaps
212
+ ```
213
+
214
+ ### Step 5 — Generate draft `.pcp/`
215
+
216
+ ```
217
+ .pcp/objective.md ← from PM description (immutable now)
218
+ .pcp/architecture.md ← detected stack + patterns
219
+ .pcp/strategy/decomposition.md ← approved cluster→module map
220
+ .pcp/strategy/modules/<name>/spec.yaml ← _generated: true, PM must review
221
+ .pcp/strategy/modules/<name>/acceptance.yaml ← mined from test files if exist, else empty
222
+ .pcp/baseline_violations.yaml ← pre-existing violations, shrinks as Wave 0 completes
223
+ ```
224
+
225
+ All generated spec files have `_generated: true`. PM reviews each, removes the flag when correct. Once flag removed: spec is immutable — agents never modify it.
226
+
227
+ ### Step 6 — Auto-generate Wave 0 criteria
228
+
229
+ From baseline scan, PCP generates brownfield-specific acceptance criteria:
230
+
231
+ ```yaml
232
+ # auto-generated in each module's acceptance.yaml
233
+ - id: BF_001
234
+ description: "Write characterization tests for <module> (golden master — no code changes)"
235
+ check: test_passes
236
+ test: "tests/characterization/test_<module>_baseline.py"
237
+ status: pending
238
+
239
+ - id: BF_002 # only if coupling violations exist
240
+ description: "Remove direct <moduleA>→<moduleB> calls, route through interface"
241
+ check: ast_pattern
242
+ pattern: "from ...<moduleB> import" # must not appear in moduleA after fix
243
+ status: pending
244
+
245
+ - id: BF_003 # one per god module detected
246
+ description: "Extract <domain> from <god_module> into standalone boundary"
247
+ check: file_exists
248
+ target: "src/<domain>/__init__.py"
249
+ status: pending
250
+ ```
251
+
252
+ Wave 0 has no new features. Code behaves identically before and after. Tests prove it.
253
+
254
+ ---
255
+
256
+ ### Brownfield TDD — three criterion types
257
+
258
+ | Type | Code exists? | TDD behavior |
259
+ |---|---|---|
260
+ | **Existing behavior** | Yes, working | Write tests → GREEN immediately. If RED → code broken, fix it. |
261
+ | **New feature** | No | Normal TDD: RED → write code → GREEN |
262
+ | **Refactor/decouple** | Yes, but wrong shape | Characterization tests first → refactor → tests still GREEN |
263
+
264
+ Criterion agent detects which type before writing any code:
265
+ ```bash
266
+ # Check if criterion target already exists
267
+ ls <target_file> 2>/dev/null && echo "EXISTS" || echo "NEW"
268
+ # Check if tests already pass
269
+ pytest tests/test_<criterion>.py -q 2>/dev/null && echo "GREEN" || echo "RED"
270
+ ```
271
+
272
+ ---
273
+
274
+ ### Brownfield `pcp check` — staged-only mode
275
+
276
+ Existing code has violations everywhere. Full-codebase check would block immediately.
277
+
278
+ ```bash
279
+ # Greenfield pcp check: entire codebase
280
+ # Brownfield pcp check: staged changes only (new code must be clean, old code tracked separately)
281
+ git diff --staged | pcp check --staged-only
282
+ ```
283
+
284
+ Violations in `baseline_violations.yaml` are excluded from block gate. As Wave 0 decoupling criteria complete, violations are removed from baseline. When `baseline_violations.yaml` reaches zero: project automatically switches to full greenfield `pcp check` rules.
285
+
286
+ ---
287
+
288
+ ### Full brownfield lifecycle
289
+
290
+ ```
291
+ /pcp import "<description>"
292
+ → objective.md written
293
+ → /graphify → clusters → module map → PM approves
294
+ → baseline scan → current_state.md + baseline_violations.yaml
295
+ → draft .pcp/ generated, PM reviews specs
296
+
297
+ Wave 0 (brownfield only — no new features)
298
+ → characterization tests per module
299
+ → decouple cross-cluster violations
300
+ → extract god modules
301
+ → baseline_violations.yaml shrinks toward zero
302
+
303
+ Wave 1+ (same as greenfield)
304
+ → TDD for new features / objective gaps
305
+ → parallel agents, CI gates, merge coordinator
306
+
307
+ baseline_violations.yaml = empty
308
+ → full greenfield rules apply, brownfield mode retired
309
+ ```
310
+
311
+ ---
312
+
313
+ ## PHASE 1: VISION WORKSHOP (`/pcp new`)
314
+
315
+ Triggered by `/pcp new` in any directory (with or without existing `.pcp/`).
316
+
317
+ ### Step 1 — Product Discovery Interview
318
+
319
+ Target user: technically aware, product-thinking, non-coding. PCP is their engineering team. They are the PM/founder. All questions are product questions — no technical jargon. PCP makes all technology decisions autonomously after the interview.
320
+
321
+ Ask ONE AT A TIME. Wait for answers. Do not batch. Follow up on vague answers before moving on.
322
+
323
+ ```
324
+ 1. What problem are you solving? Tell me about a real moment when you
325
+ or someone you know ran into this problem.
326
+
327
+ 2. Who is the person with this problem? What do they do today to
328
+ work around it — before your product exists?
329
+
330
+ 3. Walk me through your product step by step from the user's point
331
+ of view. What happens when they first open it? What do they do next?
332
+
333
+ 4. What are the 3-5 things this product MUST do for it to be useful?
334
+ (outcomes, not features — what does the user achieve?)
335
+
336
+ 5. Who creates content or data in your product? Who views or uses it?
337
+ (e.g. "sellers list products, buyers browse and purchase")
338
+
339
+ 6. Do users need accounts? How do they sign up or log in?
340
+ (e.g. "sign in with Google", "email + password", "invite-only")
341
+
342
+ 7. Is money involved? How does it work?
343
+ (subscriptions, one-time payment, marketplace take-rate, free)
344
+
345
+ 8. Does your product connect to anything the user already uses?
346
+ (e.g. "pulls from their Google Calendar", "sends Slack messages")
347
+
348
+ 9. What is explicitly NOT in version 1?
349
+ (what are you leaving out on purpose)
350
+
351
+ 10. Show me "done": describe the moment you demo this to someone and
352
+ they say "yes, this is exactly what I need."
353
+
354
+ 11. Is there a deadline or launch event driving timing?
355
+ ```
356
+
357
+ Follow-up questions based on answers — no fixed limit. Keep going until the picture is complete. If the user mentions something ambiguous ("some kind of dashboard"), drill in: "What exactly does that show? Who looks at it? How often?"
358
+
359
+ After all answers, synthesise in product language only:
360
+
361
+ ```
362
+ Here's what I understood:
363
+
364
+ Problem: <one line — the pain>
365
+ User: <one line — who they are and what they do today>
366
+ Core outcomes:
367
+ - <what user achieves, not feature name>
368
+ - ...
369
+ User flows:
370
+ - <flow 1: actor does X → sees Y → achieves Z>
371
+ - <flow 2: ...>
372
+ Accounts: <yes/no, how>
373
+ Money: <yes/no, model>
374
+ Integrations: <external systems named>
375
+ Out of scope: <list>
376
+ Done looks like: <demo scenario>
377
+ Timeline: <constraint or "ship when ready">
378
+
379
+ Is this right? Tell me anything I missed or got wrong.
380
+ ```
381
+
382
+ Iterate until PM says "yes" / "correct" / "go". Do not proceed until confirmed.
383
+
384
+ After confirmed: PCP decides all technology internally. Do NOT ask about stack, framework, database, deployment target, or hosting. Infer from what's being built:
385
+ - Web app with auth + data → modern web stack, Railway deploy
386
+ - API-only product → lightweight backend, Railway deploy
387
+ - Mobile-first → cross-platform mobile
388
+ - Desktop tool → native desktop
389
+ Present the choice to PM in one plain sentence after BRD is written: "I'll build this as a web app you can use in any browser, hosted so anyone with the link can access it." No technical details unless PM asks.
390
+
391
+ ### Step 2 — Generate BRD
392
+
393
+ Using confirmed answers, generate a structured BRD as `brd.md` in the project root.
394
+
395
+ BRD sections — product language throughout, no technical terms visible to PM:
396
+ 1. Problem Statement
397
+ 2. Target User (persona + current workaround)
398
+ 3. Core User Flows (step-by-step, from user's point of view)
399
+ 4. Features (what the product does — plain English, no tech)
400
+ 5. Out of Scope
401
+ 6. How Users Access It (web / mobile / desktop — one sentence)
402
+ 7. Money Model (if any)
403
+ 8. Integrations (external services)
404
+ 9. Success: what "done" looks like in observable, testable terms
405
+ 10. Open Questions
406
+
407
+ PCP appends internally (not shown to PM):
408
+ - Technology stack decision (PCP's choice, not PM's)
409
+ - Architecture principles (derived from product requirements)
410
+ - Module decomposition (internal planning)
411
+
412
+ After writing `brd.md`, present module breakdown in product language:
413
+
414
+ ```
415
+ BRD written.
416
+
417
+ Here's how I'll build this — each part does one job:
418
+
419
+ User accounts → sign-up, login, profile
420
+ [feature name] → <what it does for the user, one line>
421
+ [feature name] → <what it does for the user, one line>
422
+ Payments → <if applicable>
423
+ ...
424
+
425
+ Does this cover everything? Tell me if anything's missing or wrong
426
+ before I start building.
427
+ ```
428
+
429
+ Never use: module, spec, acceptance criteria, coupling, AST, CI, YAML, schema — in anything the PM reads.
430
+
431
+ Wait for PM approval. Iterate until PM says "yes" / "looks right" / "go".
432
+
433
+ ### Step 3 — Generate `.pcp/` Scaffold
434
+
435
+ Once BRD and module list are approved:
436
+
437
+ **3a. Write core files.**
438
+ ```
439
+ .pcp/objective.md — distilled from BRD problem + use cases
440
+ .pcp/target_state.md — distilled from BRD "done looks like"
441
+ .pcp/architecture.md — from BRD technical constraints + architecture principles
442
+ .pcp/ci_rules.yaml — derive rules from architecture principles
443
+ .pcp/SDLC_phase.yaml — phases: planning → alpha → beta → v1
444
+ .pcp/architect_persona.md — derive BLOCK/WARN/NOTE rules from architecture principles
445
+ .pcp/strategy/decomposition.md
446
+ .pcp/strategy/dependency_map.md
447
+ ```
448
+
449
+ **3b. For each module: generate spec + acceptance.**
450
+ ```
451
+ .pcp/strategy/modules/<module>/spec.yaml
452
+ .pcp/strategy/modules/<module>/acceptance.yaml
453
+ .pcp/strategy/modules/<module>/plan.md
454
+ ```
455
+
456
+ Every module spec must include these non-negotiable criteria regardless of module type:
457
+ - One criterion for structured logging (`check: ast_pattern` targeting `logger.` or `logging.` or `log.`)
458
+ - One criterion for error handling (`check: test_passes` on a failure-path test)
459
+ - For modules with external interfaces: one criterion for health/readiness endpoint or contract schema
460
+
461
+ Acceptance criteria must be MEASURABLE. For each criterion, choose the right check type:
462
+ - `check: file_exists` — verifiable by path
463
+ - `check: ast_pattern` — verifiable by grep/regex
464
+ - `check: dom_contains` — verifiable by Playwright selector
465
+ - `check: url_responds` — verifiable by HTTP status
466
+ - `check: railway_deploy` — verifiable by Railway API
467
+ - `check: github_actions` — verifiable by gh CLI
468
+ - `check: visual` — requires PM visual approval
469
+ - `check: manual` — requires PM explicit confirmation
470
+ - `check: test_passes` — verifiable by running named test
471
+
472
+ Avoid `check: manual` where a programmatic check is possible.
473
+
474
+ **3c. Run `pcp validate-strategy`.**
475
+ ```bash
476
+ pcp validate-strategy
477
+ ```
478
+
479
+ If coverage < 80%: identify gap, add module or expand spec, re-run. Iterate until ≥ 80%.
480
+
481
+ **3d. Confirm with PM — product language only.**
482
+
483
+ ```
484
+ Ready to build.
485
+
486
+ Here's what I'm building and in what order:
487
+
488
+ Round 1 (starting now, all in parallel):
489
+ User accounts — sign-up, login, profile management
490
+ [feature] — <plain English>
491
+ [feature] — <plain English>
492
+
493
+ Round 2 (starts when Round 1 is complete):
494
+ [feature depending on Round 1]
495
+ ...
496
+
497
+ Estimated time to first working version: <N> hours.
498
+ I'll update you when each part is ready to test.
499
+
500
+ Say /pcp build --all to start, or tell me to change anything first.
501
+ ```
502
+
503
+ Never surface: module names, criterion IDs, coverage %, coupling score, YAML structure, CI status codes, branch names, commit hashes — in anything the PM reads. Translate all build status to product language before presenting.
504
+
505
+ ---
506
+
507
+ ## PHASE 2: PARALLEL BUILD
508
+
509
+ ### Dependency Analysis
510
+
511
+ Before spawning agents, read `.pcp/strategy/dependency_map.md`.
512
+
513
+ Build the dependency graph:
514
+ - Modules with no dependencies → Wave 1
515
+ - Modules whose deps are all in Wave 1 → Wave 2
516
+ - And so on
517
+
518
+ Example output:
519
+ ```
520
+ Wave 1 (no deps, build in parallel):
521
+ auth, logging, config-service
522
+
523
+ Wave 2 (deps: Wave 1 complete):
524
+ payments, notifications, api-gateway, admin-dashboard
525
+
526
+ Wave 3 (deps: Wave 2 complete):
527
+ reporting, billing-reconciliation
528
+ ```
529
+
530
+ ### Stage 1 — Pre-Build Spec Review (per module, before any criterion agent spawns)
531
+
532
+ Run `pcp architect-review` against the module spec before touching code. Catches design-level violations when they're still cheap to fix — not after 8 criterion agents have built the wrong thing.
533
+
534
+ ```bash
535
+ for module in <wave_modules>; do
536
+ pcp architect-review --spec .pcp/strategy/modules/$module/spec.yaml 2>&1
537
+ done
538
+ ```
539
+
540
+ **Results:**
541
+ - `BLOCK` → **do not spawn any agents for this module**. Spec must be fixed first. Write to deferred queue, notify PM: "spec for `<module>` violates architect persona: `<finding>`. Fix spec before build can start." Continue build on other modules.
542
+ - `WARN` → spawn agents, but include the warning in every criterion brief: "Persona WARN on this module: `<warning>`. Account for it in your implementation."
543
+ - Clean → proceed normally.
544
+
545
+ Spec files are human-**authorized** — a build agent never fixes a spec violation on its own. Route it to the PM, who applies it through the gated write path for that file (`pcp correct-objective` / `pcp pm` / `pcp amend`): the change is proposed, the PM sees a real diff, approves, then it's written. "Authorized" means unattended writes are forbidden, not that the PM hand-types the diff.
546
+
547
+ ### Branch Isolation Protocol
548
+
549
+ Each parallel agent works on its own feature branch + git worktree.
550
+
551
+ ```bash
552
+ # For each module being built in parallel:
553
+ git worktree add "../<project>-<module>" -b "feat/<module>"
554
+ ```
555
+
556
+ This gives each agent:
557
+ - Isolated working directory
558
+ - Own branch (no conflicts with other agents)
559
+ - Full copy of the repo at that point
560
+
561
+ Worktree cleanup after merge:
562
+ ```bash
563
+ git worktree remove "../<project>-<module>"
564
+ git branch -d feat/<module>
565
+ ```
566
+
567
+ ### Agent Sizing Principle — Non-Negotiable
568
+
569
+ **One agent per criterion. Not one agent per module.**
570
+
571
+ Why: a module with 8 criteria accumulates 8 × (code + tests + CI output + error logs) in one context window. By criterion 4 the context is saturated. The agent starts hallucinating file contents, missing earlier test failures, and losing track of what was committed. This is why context blows up during builds.
572
+
573
+ The fix: each criterion is an independent job. Agent starts clean, does exactly one criterion, commits, exits. Orchestrator spawns the next agent with a fresh context for the next criterion.
574
+
575
+ **Depth limit: one. Non-negotiable, reference-pattern borrowed from Grok Build's subagent model 2026-07-16** (its `spawn_subagent` tool hard-errors if a subagent tries to call it again — "maximum nesting depth is one"). A criterion agent MUST NOT call the `Agent` or `Workflow` tool itself. Only the top-level orchestrator session spawns criterion agents. This is enforced here as an explicit instruction, not a harness-level denial the way Grok's Rust runtime enforces it structurally — be explicit about that gap rather than implying a guarantee that doesn't exist. Why it matters: a criterion agent that spawns its own helper subagent reintroduces exactly the unbounded-growth failure the orchestrator-session-bound section below exists to prevent, one level down and outside the orchestrator's own turn-count/checkpoint visibility.
576
+
577
+ **Context budget per agent (strict):**
578
+ ```
579
+ objective.md — always included (short)
580
+ architecture.md — always included (short)
581
+ module/spec.yaml — always included (this module only)
582
+ ONE criterion entry — from acceptance.yaml, this criterion only
583
+ architect_persona.md — BLOCK rules section only, not full document
584
+ Relevant ADRs — ONLY ADRs whose domain matches files this criterion touches
585
+ (check ADR title vs file paths — if no match, omit)
586
+ Prior criterion note — 1 line: "<module>/<prev-id> done. commit: <hash>. added: <what>"
587
+ (not the code, not the tests, just the summary)
588
+ ```
589
+
590
+ **Excluded from every agent brief:**
591
+ - Other modules' specs
592
+ - All criteria except the current one
593
+ - Full KB domain files (load snippet only if directly relevant)
594
+ - Full ci_rules.yaml (agent runs `pcp check` — doesn't need to read rules)
595
+ - Full build loop protocol (summarised to 7 steps in the agent brief)
596
+
597
+ ### Execution Engine — `pcp build-plan` + Workflow tool
598
+
599
+ **Rewritten 2026-07-30, real incident.** `pcp build`'s Python execution engine
600
+ (worktree-per-criterion, merge-then-retry-on-conflict) and this skill's own
601
+ Workflow-based execution were two INDEPENDENT orchestration implementations of
602
+ the same job, reinventing coordination the harness already provides natively.
603
+ Measured cost on Project O: 5 of 5 completed `query-eval-harness`
604
+ criteria collided on merge in one run, 99% of that run's spend sat on the
605
+ conflicted criteria, two criteria were still stuck mid-retry two hours in. Root
606
+ cause, read directly out of the colliding file: every criterion in a module
607
+ adds one method to a shared facade class in `__init__.py` and removes one entry
608
+ from a shared `_PENDING` dict — small, non-overlapping in MEANING, but landing
609
+ at the same insertion point in the same file, so git's diff calls it a conflict
610
+ where nothing semantically conflicts. No criterion ever declares `__init__.py`
611
+ as its `target`, so a target-only scheduler can never see this collision coming.
612
+
613
+ **The split now:** Python plans, the harness executes. `pcp build-plan
614
+ [--module X]` computes the schedule (module waves, criterion waves, each
615
+ module's `shared_surface_files`) exactly as before — same
616
+ `_compute_criterion_waves`/dependency logic, nothing new — and emits it as JSON.
617
+ It spawns nothing and writes nothing. Run it first, always:
618
+
619
+ ```bash
620
+ pcp build-plan --module <name> # or omit --module for the whole program
621
+ ```
622
+
623
+ Each module in the plan carries `shared_surface_files`: its own
624
+ `src/modules/<module>/__init__.py`, plus any file a `MOD_A00x` criterion in that
625
+ module declares as `target` (the app-registry entry, the interface file).
626
+ **Every criterion in the module is scheduled as implicitly touching these**,
627
+ regardless of what its own `target` says — an `A00x` criterion's own new file
628
+ IS genuinely disjoint from a sibling's own new file (real parallelism is safe
629
+ there), but both still touch the shared facade to register.
630
+
631
+ **Two different things, two different primitives — do not conflate them:**
632
+
633
+ 1. **Each criterion's own file(s) — build in real `parallel()`.** True
634
+ independence; worktree isolation is warranted here (Workflow's own
635
+ guidance: use isolation ONLY when agents would otherwise conflict — this is
636
+ exactly that case, criteria genuinely writing different files at once).
637
+ 2. **`shared_surface_files` — single writer, never parallel edits.** A worker
638
+ agent NEVER edits a module's `__init__.py`/interface/registry directly — it
639
+ returns a small STRUCTURED registration request instead (method name,
640
+ delegate-to call, `_PENDING` key to drop — the same shape every criterion in
641
+ this module already needs, visible in any existing `__init__.py` of this
642
+ kind). One step applies all pending requests to the shared file(s), in
643
+ order, after (or as) each worker finishes. Since only that one step ever
644
+ writes those files, there is nothing to merge and nothing to conflict —
645
+ not "conflicts resolved faster", genuinely no conflict is possible.
646
+ Prefer a **deterministic** apply step over another agent call for this: the
647
+ edit shape (add one method with a fixed pattern, remove one dict key) is
648
+ regular enough not to need judgment. Escalate to an actual agent step only
649
+ when a shared-file edit genuinely can't be expressed as that structured
650
+ request (e.g. two criteria both want to restructure the same class
651
+ differently) — rare, not the routine case.
652
+
653
+ `depends_on` still means ORDER only (declared → later wave, absent/empty →
654
+ wave 0, runs together) — `pcp build-plan`'s `criterion_waves` already reflects
655
+ this, don't re-derive it.
656
+
657
+ ```javascript
658
+ export const meta = {
659
+ name: 'pcp-wave',
660
+ description: 'Build one module wave from pcp build-plan\'s output',
661
+ phases: [
662
+ { title: 'Build' },
663
+ { title: 'Gate' },
664
+ { title: 'Register' }, // the single-writer step — see above
665
+ ]
666
+ }
667
+
668
+ // plan = JSON.parse(shell(`pcp build-plan --module ${moduleName}`))
669
+ // One pipeline() call per criterion wave (plan.modules[i].criterion_waves[w]) —
670
+ // waves run in order, criteria within a wave run together.
671
+ for (const wave of plan.modules[0].criterion_waves) {
672
+ const results = await pipeline(
673
+ wave,
674
+ // Stage 1: build ONLY this criterion's own file(s) — never the shared surface.
675
+ criterion => agent(buildBrief(criterion, plan.modules[0].shared_surface_files), {
676
+ label: `build:${criterion.id}`, phase: 'Build',
677
+ isolation: wave.length > 1 ? 'worktree' : undefined, // isolation only when it's buying something
678
+ }),
679
+ // Stage 2: gate, streams in as each build finishes — no barrier.
680
+ (buildResult, criterion) => agent(
681
+ `Run pcp gate on ${criterion.id}. commit: ${buildResult.commit}. advisory only.`,
682
+ { label: `gate:${criterion.id}`, phase: 'Gate' },
683
+ ),
684
+ )
685
+
686
+ // Stage 3: single-writer registration — a REAL barrier, deliberately.
687
+ // Every criterion in this wave returned a registration request; apply them
688
+ // to shared_surface_files ONE AT A TIME, here, the only place these files
689
+ // are ever touched. Deterministic template insertion where the shape
690
+ // allows (see module docstring); escalate to agent() only if a request
691
+ // can't be expressed that way.
692
+ phase('Register')
693
+ for (const r of results.filter(Boolean)) {
694
+ await applyRegistration(r.registrationRequest, plan.modules[0].shared_surface_files)
695
+ }
696
+ }
697
+ ```
698
+
699
+ **The `buildBrief(criterion, sharedSurfaceFiles)` function** — compact, no bloat:
700
+ ```
701
+ Build criterion ${criterion.id}: "${criterion.description}"
702
+ Module: ${criterion.module} | check: ${criterion.check}
703
+ Working dir: worktree for feat/${criterion.module}
704
+
705
+ ## Objective
706
+ ${objective_md} ← full (it's short)
707
+
708
+ ## Architecture
709
+ ${architecture_md} ← full (it's short)
710
+
711
+ ## Module spec
712
+ ${module_spec_yaml} ← full (this module only)
713
+
714
+ ## Persona BLOCK rules
715
+ ${persona_block_section} ← BLOCK section only, not full document
716
+
717
+ ${relevant_adr ? `## Relevant ADR\n${relevant_adr}` : ''}
718
+ ${criterion.prevCommit ? `## Prior work\n${criterion.module}/${criterion.prevId} done. commit: ${criterion.prevCommit}. added: ${criterion.prevSummary}.` : ''}
719
+
720
+ ## Files you may NOT edit — single-writer, someone else applies these
721
+ ${sharedSurfaceFiles.join('\n')}
722
+ If your criterion needs a new export/registration entry in one of these, do NOT
723
+ touch the file. Instead include a registrationRequest in your return value (see
724
+ below) describing exactly what to add. This is not a style preference — two
725
+ agents editing these files at once is how a real incident happened (2026-07-30,
726
+ 5 of 5 criteria in one module collided on merge because everyone edited the
727
+ same shared facade class directly). The file will be updated for you, after you
728
+ finish, by the one step that's allowed to touch it.
729
+
730
+ ## Steps (in order, no skipping)
731
+ 1. Write tests → verify RED
732
+ 2. Write code → verify GREEN (your own file(s) only — never a file listed above)
733
+ 3. lint → pcp check → pcp architect-review --staged
734
+ 4. Fix all BLOCK findings
735
+ 5. commit: feat(${criterion.module}): ${criterion.id} — ${criterion.description}
736
+ 6. echo "${criterion.module}:${criterion.id}:$(git rev-parse HEAD)" >> .pcp/.build_progress
737
+
738
+ Return: {
739
+ commit: "<hash>", summary: "<one line what was added>", escalation: null | "<what>",
740
+ registrationRequest: null | {
741
+ file: "<one of the files listed above>",
742
+ method_name: "<name>", delegates_to: "<module.path.function>",
743
+ pending_key_to_remove: "<key, or null if this module has no _PENDING dict>"
744
+ }
745
+ }
746
+ Do NOT read other modules. Do NOT continue to next criterion. Exit after step 6.
747
+ Do NOT call the Agent or Workflow tool yourself — depth limit is one level, you are the leaf.
748
+ ```
749
+
750
+ ### Escalation Bubbling
751
+
752
+ When a subagent hits an escalation trigger, it returns it to the orchestrator.
753
+ Orchestrator collects all escalations, presents them to PM as a batch:
754
+
755
+ ```
756
+ Build in progress — 3 escalations need your input:
757
+
758
+ 1. exports/A004 (check: manual)
759
+ Verify: run export against a test dataset, confirm output matches spec
760
+ Action: test and say "exports A004 verified"
761
+
762
+ 2. payments
763
+ Architecture decision needed: which webhook signing scheme for the payment provider?
764
+ Options: (a) HMAC-SHA256 shared secret (b) provider SDK-managed verification
765
+ Action: say "pcp decision: payment-webhook-signing = <choice>"
766
+
767
+ 3. notifications
768
+ Missing API credential for the push-notification provider
769
+ Requires provider dashboard signup, 1-2 day lead time
770
+ Action: provision and say "push credential added"
771
+
772
+ Build continues on all non-blocked modules.
773
+ Reply to each escalation by number to unblock.
774
+ ```
775
+
776
+ PM responds, orchestrator unblocks the relevant agents.
777
+
778
+ ---
779
+
780
+ ## SINGLE-AGENT BUILD LOOP PROTOCOL
781
+
782
+ **Scope: one criterion per agent session.** This section describes what one agent does for one criterion. Agents do not loop. They do not continue to the next criterion. One criterion → commit → exit. The orchestrator spawns the next agent.
783
+
784
+ Why: each criterion accumulates code + test output + CI logs + error messages in context. Looping through multiple criteria in one session causes context saturation by criterion 3-4. The agent starts missing earlier failures, misremembering file contents, and losing spec alignment. One agent per criterion eliminates this entirely.
785
+
786
+ **Completion Definition — all must be true before marking done:**
787
+ - Tests written that FAIL before code exists (red proven)
788
+ - Tests passing after code written (green proven)
789
+ - Full regression suite green (no regressions)
790
+ - Build succeeds (compiled languages)
791
+ - Lint clean
792
+ - Secret scan clean — no credentials in staged files
793
+ - `pcp check` clean (no BLOCK)
794
+ - `pcp architect-review --staged` clean (no BLOCK)
795
+ - Acceptance `check:` type passes (file_exists / test_passes / dom_contains / manual)
796
+ - Self-QA: code matches criterion description exactly
797
+ - `acceptance.yaml` status updated to `complete` for this criterion
798
+ - Checkpoint written: `echo "<module>:<id>:<git-hash>" >> .pcp/.build_progress`
799
+
800
+ **Not required per-criterion (run at wave merge, not per agent):**
801
+ - CI green (runs on PR)
802
+ - Staging smoke test (runs after wave merge)
803
+ - Production smoke test (runs after staging)
804
+ - `pcp scan` (runs after all criteria complete)
805
+
806
+ ### Module pre-flight (once per module, before first criterion agent — run by orchestrator)
807
+
808
+ **Dep audit** — dependencies checked once per module, not per criterion:
809
+ ```bash
810
+ # Python
811
+ safety check 2>/dev/null || pip-audit 2>/dev/null
812
+
813
+ # JavaScript/TypeScript
814
+ npm audit --audit-level=high 2>/dev/null
815
+
816
+ # Rust
817
+ cargo audit 2>/dev/null
818
+ ```
819
+ High-severity CVE: fix dependency version in manifest before spawning any criterion agents. Criterion agents inherit the fixed manifest.
820
+
821
+ **Spec security review** (Stage 1 — security dimension):
822
+ Does spec describe auth model, input validation, data classification for user-facing or API modules?
823
+ ```bash
824
+ pcp architect-review --module <name> --fail-on-block
825
+ ```
826
+ BLOCK on spec → do not spawn criterion agents. Notify PM. Continue other modules.
827
+
828
+ ### Per-criterion agent pre-flight (once per agent, takes 30 seconds)
829
+
830
+ **Spec lock.** Hash all spec files. Store in `.pcp/.build_lock`.
831
+ ```bash
832
+ find .pcp/strategy/modules -name "*.yaml" | sort | xargs sha256sum > .pcp/.build_lock
833
+ ```
834
+ If `.pcp/.build_lock` already exists and differs: specs changed during build — escalate before continuing.
835
+
836
+ **Install pre-commit hooks** if not present:
837
+ ```bash
838
+ # Secret scanning
839
+ pip install detect-secrets 2>/dev/null || true
840
+ pre-commit install 2>/dev/null || true
841
+ # If no pre-commit config, add minimal secret hook:
842
+ if [ ! -f .pre-commit-config.yaml ]; then
843
+ cat > .pre-commit-config.yaml << 'EOF'
844
+ repos:
845
+ - repo: https://github.com/Yelp/detect-secrets
846
+ rev: v1.4.0
847
+ hooks:
848
+ - id: detect-secrets
849
+ EOF
850
+ fi
851
+ ```
852
+
853
+ **Conflict pre-check** (for parallel builds on feature branches):
854
+ ```bash
855
+ BRANCH=$(git branch --show-current)
856
+ git fetch origin main --quiet
857
+ CONFLICTS=$(git merge-tree $(git merge-base HEAD origin/main) HEAD origin/main 2>/dev/null | grep -c "<<<<<<" || echo 0)
858
+ if [ "$CONFLICTS" -gt "0" ]; then
859
+ echo "CONFLICT: $CONFLICTS conflicting sections vs main. Rebase before continuing."
860
+ # attempt auto-rebase
861
+ git rebase origin/main 2>/dev/null || echo "REBASE_NEEDED"
862
+ fi
863
+ ```
864
+ If rebase fails: escalate to orchestrator.
865
+
866
+ ### For your assigned criterion (one only — stop after commit):
867
+
868
+ **1. Announce:** `Building <module>/<id> — <description>`
869
+
870
+ **2. Context already loaded in your brief.** Do NOT speculatively read other modules' files, other criteria, or the full KB. Read only files directly relevant to implementing this criterion. If you need an ADR that wasn't in your brief: read it, note it, do not load the rest.
871
+
872
+ **3. Resolve dependencies.** Check packages exist before writing imports. Add to manifest first.
873
+
874
+ **4. Write tests first (TDD).**
875
+ Tests must FAIL before code exists. Verify red before writing code.
876
+ ```bash
877
+ pytest tests/test_<module>.py -x 2>&1 | tail -5 # Python
878
+ npx jest <module>.test.ts 2>&1 | tail -5 # TypeScript
879
+ cargo test <module> 2>&1 | tail -5 # Rust
880
+ swift test --filter <Module>Tests 2>&1 | tail -5 # Swift
881
+ ```
882
+
883
+ **5. Write code.** Ground in spec.yaml constraints + architecture.md + persona BLOCK rules + ADRs.
884
+ If architectural decision needed that's not in ADRs: STOP, return escalation, do not guess.
885
+
886
+ **6. Build check (compiled languages).**
887
+ ```bash
888
+ xcodebuild build -scheme <S> -destination 'generic/platform=macOS' 2>&1 | grep -E "error:|BUILD" | tail -5
889
+ cargo build 2>&1 | tail -10
890
+ npx tsc --noEmit 2>&1 | tail -10
891
+ ```
892
+ Fix until build passes.
893
+
894
+ **7. Tests green + regression.**
895
+ One run — unit tests for this module with coverage, plus full suite to catch regressions. Not two separate runs.
896
+ ```bash
897
+ pytest --tb=short -q --cov=src/<module> --cov-report=term-missing # Python
898
+ npx jest --coverage 2>/dev/null # TypeScript (all tests)
899
+ cargo test 2>/dev/null # Rust (all tests)
900
+ swift test 2>/dev/null # Swift
901
+ ```
902
+ Fix until all pass. Cannot proceed with broken existing tests.
903
+
904
+ **9. QA self-review.** Re-read criterion description. Ask:
905
+ - Does my code actually do what this says?
906
+ - Will `check:` type pass on my code?
907
+ - Any BLOCK rule from persona violated?
908
+ - Any ADR boundary touched without following the ADR pattern?
909
+
910
+ **10. `pcp check`** — fix any BLOCK before proceeding.
911
+
912
+ **11. `pcp architect-review --staged`** — fix BLOCK, fix WARN, log NOTE.
913
+
914
+ **11a. Lint gate.**
915
+ ```bash
916
+ # Python
917
+ black --check src/ tests/ 2>/dev/null && ruff check src/ 2>/dev/null
918
+ # TypeScript/JS
919
+ npx eslint src/ --max-warnings 0 2>/dev/null && npx prettier --check src/ 2>/dev/null
920
+ # Rust
921
+ cargo fmt --check 2>/dev/null && cargo clippy -- -D warnings 2>/dev/null
922
+ # Swift
923
+ swiftformat --lint Sources/ 2>/dev/null
924
+ # C
925
+ # clang-format check handled by pcp check AST rules
926
+ ```
927
+ Lint failures → fix code, re-run. Do not commit with lint violations.
928
+
929
+ **11b. Secret scan.**
930
+ ```bash
931
+ detect-secrets scan --baseline .secrets.baseline 2>/dev/null || \
932
+ git diff --staged | grep -E "(password|secret|api_key|token|private_key)\s*=\s*['\"][^'\"]{8,}" -i
933
+ ```
934
+ If secrets detected: STOP. Remove secret. Add to `.env.example` instead. Commit clean version.
935
+ Never commit credentials, tokens, or API keys.
936
+
937
+ **11c. SAST (code patterns only — dep audit runs once at module pre-flight, not per criterion).**
938
+ ```bash
939
+ # Python
940
+ bandit -r src/ -ll 2>/dev/null # SAST, skip low-severity
941
+
942
+ # Any: semgrep (if installed)
943
+ semgrep --config=auto src/ --error 2>/dev/null
944
+ ```
945
+ SAST finding: fix code. If false positive: add `# nosec` / `// nosemgrep` with comment explaining why.
946
+ Dependency CVEs are checked once at module pre-flight — not repeated here.
947
+
948
+ **11d. Error handling test coverage.**
949
+ At least one test per criterion must test a failure path — what happens when:
950
+ - Input is malformed or missing
951
+ - Downstream dependency is unavailable
952
+ - Timeout occurs
953
+ - Permission is denied
954
+
955
+ If criterion spec has no failure mode described: derive from spec constraints and common sense.
956
+
957
+ **11e. ~~Contract validation~~**
958
+ Moved to post-module-complete (after ALL criteria for this module pass), just before PR creation. Validating a contract after one criterion when the module has 8 criteria is premature — the output isn't representative yet. Skip here.
959
+
960
+ **12. E2E (only if criterion check type is NOT dom_contains / url_responds).**
961
+ If criterion has `check: dom_contains` or `check: url_responds` — skip this step. Step 16 IS the E2E for those types.
962
+ If criterion has `check: manual` or `check: test_passes` with integration scope:
963
+ ```bash
964
+ npx playwright test tests/e2e/<module>.spec.ts 2>/dev/null # web
965
+ tests/integration/<module>_integration.sh 2>/dev/null # CLI/API
966
+ ```
967
+
968
+ **13. Commit.**
969
+ ```bash
970
+ git add <specific files>
971
+ git commit -m "<type>(<module>): <what>"
972
+ ```
973
+ No Co-Authored-By. No attribution. Specific files only, never `git add -A`.
974
+
975
+ **14. Push.**
976
+ ```bash
977
+ git push origin feat/<module>
978
+ ```
979
+
980
+ **15. Watch CI.**
981
+ ```bash
982
+ BRANCH=$(git branch --show-current)
983
+ RUN_ID=$(gh run list --branch "$BRANCH" --limit 1 --json databaseId --jq '.[0].databaseId')
984
+ gh run watch "$RUN_ID" --exit-status
985
+ ```
986
+ Failure → auto-fix loop (max 3 retries, exponential backoff: wait 2s, 4s, 8s between retries).
987
+
988
+ **Auto-fix loop:**
989
+ ```bash
990
+ gh run view "$RUN_ID" --log-failed | head -300
991
+ # diagnose → fix code → re-run tests locally → lint → secret scan → commit → push → watch CI
992
+ ```
993
+ After 3 retries still failing: return escalation to orchestrator.
994
+
995
+ **15a. ~~Staging deploy~~**
996
+ Moved to wave merge — one staging deploy after all wave modules merge to main. Deploying to staging after every criterion (8 deploys for an 8-criterion module) is waste. Skip here.
997
+
998
+ **16. Visual/URL checks.**
999
+ - `check: dom_contains` → Playwright selector, automated
1000
+ - `check: url_responds` → curl HTTP status, automated
1001
+ - `check: visual` → screenshot + return to orchestrator → PM approves
1002
+
1003
+ **16b. Production smoke test** (after Railway prod deploy, if `check: railway_deploy`):
1004
+ ```bash
1005
+ # Wait for prod deploy
1006
+ for i in $(seq 1 30); do
1007
+ STATUS=$(railway status --json 2>/dev/null | python3 -c \
1008
+ "import sys,json; print(json.load(sys.stdin).get('deploymentStatus','unknown'))")
1009
+ [ "$STATUS" = "SUCCESS" ] && break
1010
+ [ "$STATUS" = "FAILED" ] && echo "PROD_DEPLOY_FAILED" && break
1011
+ sleep 30
1012
+ done
1013
+
1014
+ # Smoke test production
1015
+ PROD_URL=$(railway domain 2>/dev/null | head -1)
1016
+ if [ -n "$PROD_URL" ]; then
1017
+ HTTP=$(curl -s -o /dev/null -w "%{http_code}" "https://$PROD_URL/health" 2>/dev/null)
1018
+ echo "Production smoke: HTTP $HTTP"
1019
+ if [ "$HTTP" != "200" ]; then
1020
+ echo "PRODUCTION_DOWN — initiating rollback"
1021
+ railway rollback 2>/dev/null || echo "manual rollback needed"
1022
+ echo "PROD_SMOKE_FAILED"
1023
+ fi
1024
+ fi
1025
+ ```
1026
+ If production smoke fails: auto-rollback, escalate immediately. Never leave production broken silently.
1027
+
1028
+ **17. Checkpoint + exit.**
1029
+ ```bash
1030
+ # Update acceptance.yaml: set this criterion's status to complete
1031
+ # Write checkpoint (orchestrator reads this to know where to resume)
1032
+ HASH=$(git rev-parse HEAD)
1033
+ echo "<module>:<criterion-id>:$HASH" >> .pcp/.build_progress
1034
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) COMPLETE <module>/<criterion-id> $HASH" >> .pcp/audit.log
1035
+ ```
1036
+
1037
+ Report to orchestrator: `DONE <module>/<criterion-id> | commit <hash> | next: <next-criterion-id or WAVE_COMPLETE>`
1038
+
1039
+ **Stop here. Do not continue to the next criterion.** The orchestrator spawns a fresh agent for the next criterion with a clean context window. This is how context limits are prevented — not by checkpointing mid-loop, but by never looping in the first place.
1040
+
1041
+ ---
1042
+
1043
+ ## MERGE COORDINATOR PROTOCOL
1044
+
1045
+ After each wave completes, orchestrator runs merge sequence:
1046
+
1047
+ ```bash
1048
+ for module in <wave_modules>; do
1049
+ # Pre-merge: rebase feature branch on main to surface conflicts before PR
1050
+ git -C "../$(basename $(pwd))-$module" fetch origin main --quiet
1051
+ git -C "../$(basename $(pwd))-$module" rebase origin/main 2>/dev/null
1052
+ if [ $? -ne 0 ]; then
1053
+ echo "CONFLICT: $module cannot rebase cleanly — escalating"
1054
+ continue # skip this module, escalate, continue others
1055
+ fi
1056
+
1057
+ # Contract validation — runs here (module complete, all criteria done, full output available)
1058
+ if [ -f ".pcp/contracts/${module}_output.schema.json" ]; then
1059
+ echo "Validating $module output contract..."
1060
+ python3 -m pytest "tests/contracts/test_${module}_contract.py" -q 2>/dev/null || \
1061
+ echo "CONTRACT_FAIL: $module — escalating"
1062
+ else
1063
+ # Generate contract schema from actual module output if it has dependents
1064
+ grep -q "$module" .pcp/strategy/dependency_map.md 2>/dev/null && \
1065
+ echo "WARN: $module has dependents but no contract schema — generate .pcp/contracts/${module}_output.schema.json"
1066
+ fi
1067
+
1068
+ # Create PR
1069
+ gh pr create \
1070
+ --base main \
1071
+ --head "feat/$module" \
1072
+ --title "feat($module): complete all acceptance criteria" \
1073
+ --body "$(pcp status --module $module --markdown 2>/dev/null || echo 'Module complete')"
1074
+
1075
+ # Layer 2 gate (advisory, not blocking)
1076
+ pcp gate --branch "feat/$module" 2>/dev/null
1077
+
1078
+ # Merge
1079
+ gh pr merge "feat/$module" --merge --auto
1080
+
1081
+ # Cleanup worktree
1082
+ git worktree remove "../$(basename $(pwd))-$module" 2>/dev/null || true
1083
+ git branch -d "feat/$module" 2>/dev/null || true
1084
+ done
1085
+
1086
+ # Integration test after all wave merges
1087
+ git checkout main && git pull
1088
+ npm test 2>/dev/null || pytest --tb=short -q 2>/dev/null || cargo test 2>/dev/null || swift test 2>/dev/null || make test 2>/dev/null
1089
+
1090
+ # Staging deploy + smoke (once per wave, not per criterion)
1091
+ if grep -q "STAGING_URL\|staging" .pcp/architecture.md 2>/dev/null; then
1092
+ railway up --environment staging 2>/dev/null
1093
+ for i in $(seq 1 20); do
1094
+ STATUS=$(railway status --environment staging --json 2>/dev/null | python3 -c \
1095
+ "import sys,json; print(json.load(sys.stdin).get('deploymentStatus','unknown'))" 2>/dev/null)
1096
+ [ "$STATUS" = "SUCCESS" ] && break
1097
+ [ "$STATUS" = "FAILED" ] && echo "STAGING_DEPLOY_FAILED" && break
1098
+ sleep 30
1099
+ done
1100
+ STAGING_URL=$(railway domain --environment staging 2>/dev/null | head -1)
1101
+ [ -n "$STAGING_URL" ] && \
1102
+ HTTP=$(curl -s -o /dev/null -w "%{http_code}" "https://$STAGING_URL/health" 2>/dev/null) && \
1103
+ echo "Staging smoke: $HTTP" && \
1104
+ [ "$HTTP" != "200" ] && echo "STAGING_SMOKE_FAILED — fix before starting next wave"
1105
+ fi
1106
+
1107
+ # Validate strategy coverage still holds after wave
1108
+ pcp validate-strategy
1109
+ # If coverage dropped or coupling violations increased: flag to PM before starting next wave
1110
+
1111
+ # Stage 3 — Wave-level architect review
1112
+ # Reviews ALL files changed since this wave started (not just per-criterion diffs)
1113
+ # Catches emergent violations: individual modules clean, but combined they violate a principle
1114
+ # WAVE_START_COMMIT is written to .pcp/.active_workflow at wave start
1115
+ WAVE_BASE=$(python3 -c "import yaml; d=yaml.safe_load(open('.pcp/.active_workflow')); print(d.get('wave_start_commit','main'))" 2>/dev/null || echo "main")
1116
+ pcp architect-review --base $WAVE_BASE --fail-on-block 2>&1
1117
+ # BLOCK findings here → do NOT start next wave. Fix before proceeding.
1118
+ # WARN findings → log, include in next wave's module briefs, proceed.
1119
+
1120
+ # Audit log
1121
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) WAVE_COMPLETE modules=[<wave_modules>]" >> .pcp/audit.log
1122
+ ```
1123
+
1124
+ If integration test fails after merge: bisect to find which module caused regression.
1125
+ ```bash
1126
+ # Bisect: revert merges one by one until green
1127
+ git log --oneline -10 # find merge commits
1128
+ git revert <merge-commit> --no-edit # revert suspect, re-run tests
1129
+ ```
1130
+ Revert culprit module, open escalation, continue next wave without that module.
1131
+
1132
+ ---
1133
+
1134
+ ## PERSISTENCE
1135
+
1136
+ PCP build state survives session end, session crash, and laptop close.
1137
+
1138
+ ### State files (all in `.pcp/`, all committed to git)
1139
+
1140
+ ```
1141
+ .pcp/.active_workflow — Workflow run ID + current wave state (written at build start, deleted at completion)
1142
+ .pcp/.build_progress — append-only log: <module>:<criterion-id>:<git-hash> per completed criterion
1143
+ .pcp/deferred_queue.yaml — blocked/deferred items (manual, visual, architecture decisions)
1144
+ .pcp/notifications.log — escalations sent when PM was away
1145
+ .pcp/audit.log — timestamped full audit trail
1146
+ ```
1147
+
1148
+ ### Writing state on build start
1149
+
1150
+ Immediately after launching a Workflow, write `.pcp/.active_workflow`:
1151
+ ```yaml
1152
+ workflow_run_id: <Workflow tool returned run ID>
1153
+ started: <ISO timestamp>
1154
+ wave: 1
1155
+ wave_modules: [module-a, module-b, module-c]
1156
+ wave_start_commit: <git rev-parse HEAD at wave start>
1157
+ criteria_total: 24
1158
+ criteria_done: 0
1159
+ last_updated: <ISO timestamp>
1160
+ ```
1161
+
1162
+ Update `criteria_done` and `last_updated` as each agent checkpoint is written to `.build_progress`.
1163
+
1164
+ Delete `.pcp/.active_workflow` when the full build completes cleanly.
1165
+
1166
+ ### Two resume paths
1167
+
1168
+ **Hot resume (same Claude session, Workflow run ID still valid):**
1169
+ ```
1170
+ Workflow({
1171
+ scriptPath: '.pcp/.workflow_script.js',
1172
+ resumeFromRunId: '<run_id from .active_workflow>'
1173
+ })
1174
+ ```
1175
+ Completed agents return cached results instantly. Build continues from where it stopped.
1176
+
1177
+ **Cold resume (new Claude session, run ID expired):**
1178
+ ```
1179
+ # Read which criteria are already done
1180
+ done = parse .pcp/.build_progress # set of "<module>:<id>" strings
1181
+
1182
+ # Compute pending criteria
1183
+ pending = all criteria in acceptance.yaml files WHERE status != complete
1184
+ AND "<module>:<id>" NOT IN done
1185
+
1186
+ # Start fresh Workflow with only pending criteria
1187
+ ```
1188
+ Cold resume rebuilds the work list from file state, not from memory. Idempotent — re-running a criterion that's already committed is safe (agent sees the commit, marks done immediately).
1189
+
1190
+ ---
1191
+
1192
+ ## ORCHESTRATOR SESSION BOUND — NON-NEGOTIABLE
1193
+
1194
+ **Found 2026-07-01** after a real incident: an orchestrator session ran 36 hours, 1725 turns, 133M cache_read tokens, in one continuous session — no cap ever fired because nothing was watching the orchestrator itself.
1195
+
1196
+ The Agent Sizing Principle bounds *subagents* (one criterion, fresh context, exit). It does not bound the **orchestrator** — this session, the one running `/pcp build --all` or `/pcp watch` — which dispatches, polls CI/Railway, and handles escalations for the entire build or monitoring run. Left unbounded, the orchestrator's own transcript accumulates every poll cycle, every dispatch decision, every dashboard render, forever. That's the same context-saturation failure the per-criterion design exists to prevent, one level up, and it was missed because "runs indefinitely" (see `/pcp watch` above) was read as license for one session to stay open the whole time. It isn't — indefinite describes the monitoring/build *job*, not the *session*.
1197
+
1198
+ **Hard caps, enforced by the orchestrator on itself:**
1199
+
1200
+ - **`/pcp watch`:** stop the poll loop after 200 iterations (~15h at the default 270s interval — matches `PCP_WATCH_MAX_ITERATIONS` in the Python CLI; keep both in sync if either changes). On hitting the cap: write `.pcp/.watch_last_poll` as usual, notify PM (`"pcp watch: reached iteration cap (200) — restart with /pcp watch to keep monitoring"`), then end the session. Do not silently keep looping past it.
1201
+ - **`/pcp build --all`:** at every wave boundary (already a checkpoint — `.active_workflow` is written there), check this session's own turn count / elapsed time. Past ~4 hours or a large turn count, checkpoint and hand off instead of continuing into the next wave: tell PM `"wave <N> complete, checkpointing here — run /pcp build --resume in a fresh session for the remaining waves."` Cold resume (above) already rebuilds the work list from `.build_progress` idempotently — handoff is safe, so there's no reason to keep one session alive just to avoid restarting it.
1202
+ - **General rule:** if the orchestrator ever notices its own session is running long (large turn count, many hours elapsed, cache growing), that is itself a trigger to checkpoint and hand off — do not wait for a wave/poll boundary if it's clearly overdue.
1203
+
1204
+ ---
1205
+
1206
+ ## ON INVOCATION (bare `/pcp`)
1207
+
1208
+ **Step 1 — Find project root.** Walk up from cwd looking for `.pcp/`. If not found: offer to start vision workshop.
1209
+
1210
+ **Step 2 — Check for active workflow first.**
1211
+ ```bash
1212
+ [ -f .pcp/.active_workflow ] && cat .pcp/.active_workflow
1213
+ ```
1214
+ If `.active_workflow` exists:
1215
+ ```
1216
+ Active build found.
1217
+ Started: <started>
1218
+ Wave: <wave> — <wave_modules>
1219
+ Progress: <criteria_done>/<criteria_total>
1220
+
1221
+ Options:
1222
+ (1) Resume — /pcp build --resume (hot: reattach to Workflow run, cold: rebuild from .build_progress)
1223
+ (2) Status — show what completed so far
1224
+ (3) Abandon — /pcp build --abandon (clears .active_workflow, keeps .build_progress)
1225
+ ```
1226
+
1227
+ **Step 3 — Load into working memory.** Read: objective.md, architecture.md, SDLC_phase.yaml. Do NOT load all ADRs upfront — load them lazily when a build agent needs them.
1228
+
1229
+ **Step 4 — Scan.**
1230
+ ```bash
1231
+ pcp scan
1232
+ ```
1233
+
1234
+ **Step 5 — CI + deferred queue.**
1235
+ ```bash
1236
+ gh run list --limit 3 --json status,name,conclusion,updatedAt 2>/dev/null
1237
+ railway status 2>/dev/null || true
1238
+ # deferred items waiting for PM
1239
+ [ -f .pcp/deferred_queue.yaml ] && grep "status: deferred" .pcp/deferred_queue.yaml | wc -l
1240
+ ```
1241
+
1242
+ **Step 6 — Present dashboard.**
1243
+ ```
1244
+ Project: <name>
1245
+ Phase: <phase>
1246
+ Progress: X/Y criteria complete (Z%)
1247
+
1248
+ Waves:
1249
+ Wave 1 — <modules> [complete / in-progress / pending]
1250
+ Wave 2 — <modules> [pending]
1251
+
1252
+ CI: GitHub Actions <status> | Railway <status>
1253
+ Deferred: <N> items waiting for you (run /pcp status for details)
1254
+ Agents: 25 available
1255
+
1256
+ /pcp build --all start full parallel build
1257
+ /pcp build --resume resume active build
1258
+ ```
1259
+
1260
+ ---
1261
+
1262
+ ## MULTI-PROJECT STATUS (`/pcp status --all`)
1263
+
1264
+ ```bash
1265
+ find ~/Claude-code -name "objective.md" -path "*/.pcp/*" 2>/dev/null | sed 's|/.pcp/objective.md||'
1266
+ ```
1267
+
1268
+ For each project: read SDLC_phase.yaml + latest pcp.md + .active_workflow if present.
1269
+
1270
+ ```
1271
+ All Projects — <date>
1272
+
1273
+ project-a alpha 0% Wave 1 ready CI: — [no active build]
1274
+ project-b alpha 17% Wave 1 ready CI: green [no active build]
1275
+ project-c alpha 34% Wave 2 active CI: failing [BUILDING: 8/24 done]
1276
+ project-d planning 0% needs /pcp new [no active build]
1277
+
1278
+ Agents: 25 available
1279
+ Building: project-c (resume with: cd project-c && /pcp build --resume)
1280
+ Most urgent: project-c CI failing — /pcp fix (in project-c dir)
1281
+ ```
1282
+
1283
+ ---
1284
+
1285
+ ## `/pcp watch` — CI AND RAILWAY MONITORING
1286
+
1287
+ Triggered by `/pcp watch`. Uses `ScheduleWakeup` to run a polling loop every 270 seconds (stays within prompt cache TTL). Runs until PM says `/pcp stop` OR the iteration cap below is hit — "runs indefinitely" describes the monitoring job, not license for one session to stay open forever. See ORCHESTRATOR SESSION BOUND.
1288
+
1289
+ ### What it monitors (every poll cycle)
1290
+
1291
+ **1. GitHub Actions — CLI**
1292
+ ```bash
1293
+ gh run list --limit 10 --json databaseId,status,conclusion,name,updatedAt,headBranch \
1294
+ --jq '.[] | select(.conclusion == "failure" or .status == "in_progress")'
1295
+ ```
1296
+ Failed run → proceed to auto-fix (see below).
1297
+
1298
+ **2. Railway — CLI**
1299
+ ```bash
1300
+ railway status --json 2>/dev/null
1301
+ ```
1302
+ Failed deploy → proceed to auto-fix.
1303
+
1304
+ **3. Railway logs (proactive scan for errors)**
1305
+ ```bash
1306
+ railway logs --tail 50 2>/dev/null | grep -iE "error|exception|crash|oom|timeout" | tail -10
1307
+ ```
1308
+
1309
+ ### Auto-fix loop (triggered by any failure source)
1310
+
1311
+ ```
1312
+ 1. Fetch full failure log
1313
+ gh run view <run-id> --log-failed | head -500
1314
+ OR: railway logs --deployment <id> | head -500
1315
+
1316
+ 2. Diagnose: what failed?
1317
+ - Test failure → identify which test, which assertion
1318
+ - Build failure → identify which file, which error
1319
+ - Deploy failure → identify which service, which config
1320
+ - Dependency error → identify which package, which version
1321
+
1322
+ 3. Fix:
1323
+ - Code fix → edit file → run tests locally → commit → push
1324
+ - Config fix → edit railway.toml or Dockerfile → commit → push
1325
+ - Dep fix → update manifest → commit → push
1326
+
1327
+ 4. Watch new run:
1328
+ RUN_ID=$(gh run list --branch $(git branch --show-current) --limit 1 --json databaseId --jq '.[0].databaseId')
1329
+ gh run watch $RUN_ID --exit-status
1330
+
1331
+ 5. On resolution:
1332
+ slack-notify "PCP fixed: <what failed> → <what was fixed>. CI green. Commit: <hash>"
1333
+ Update .pcp/.watch_last_poll
1334
+
1335
+ 6. On 3 failed fix attempts:
1336
+ slack-notify "PCP stuck on <failure>. 3 fix attempts failed. Needs you."
1337
+ Add to deferred queue, continue monitoring other projects
1338
+ ```
1339
+
1340
+ ### State file
1341
+ ```bash
1342
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > .pcp/.watch_last_poll
1343
+ ```
1344
+ Read on each cycle to know which emails/runs are new since last check.
1345
+
1346
+ ### `/pcp watch --all`
1347
+ Monitors ALL projects under `~/Claude-code/` in a single loop. Checks each project's CI + Railway + shared email inbox. One loop, all projects.
1348
+
1349
+ ---
1350
+
1351
+ ## UNATTENDED AUTONOMY PROTOCOL
1352
+
1353
+ **Rule: escalation ≠ stop.** Every blocked item goes to the deferred queue + Slack notification. Build continues on everything that doesn't depend on the blocked item. Only two things are true stops: missing production credentials with no workaround, and production incident.
1354
+
1355
+ ### Notification setup (read once at session start)
1356
+
1357
+ Read `.pcp/config.yaml` for notification config:
1358
+ ```yaml
1359
+ notifications:
1360
+ slack_command: slack-notify # default: ~/bin/slack-notify
1361
+ channel: "#pcp-builds" # default channel
1362
+ webhook: "" # optional webhook URL
1363
+ on: [deferred, blocked, complete, error, production-incident]
1364
+ ```
1365
+ If config absent: use `slack-notify` with default channel if available, else write to `.pcp/notifications.log`.
1366
+
1367
+ Every notification:
1368
+ ```bash
1369
+ slack-notify "PCP [<project>/<module>]: <one-line summary>. Build continuing." 2>/dev/null || \
1370
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) <summary>" >> .pcp/notifications.log
1371
+ ```
1372
+
1373
+ ### Deferred queue
1374
+
1375
+ File: `.pcp/deferred_queue.yaml` — created if absent, appended atomically.
1376
+
1377
+ ```yaml
1378
+ deferred:
1379
+ - id: "<module>/<criterion-id>"
1380
+ type: manual | visual | architecture-decision | blocked-ci | blocked-secret
1381
+ summary: "<one sentence what is needed>"
1382
+ detail: "<exact instruction for PM>"
1383
+ screenshot: "<path if visual>"
1384
+ draft_adr: "<path if architecture-decision>"
1385
+ blocked_since: "<ISO timestamp>"
1386
+ retry_at: "<ISO timestamp, for blocked-ci>"
1387
+ unblocks: ["<module>/<id>", ...] # criteria waiting on this
1388
+ status: deferred | resolved
1389
+ ```
1390
+
1391
+ ### How each blocker is handled autonomously
1392
+
1393
+ **Architecture decision not in ADRs:**
1394
+ 1. Apply heuristics: existing ADRs, architecture.md principles, language/framework best practices
1395
+ 2. Make the decision and write `.pcp/kb/adr/ADR-<N>-<slug>-DRAFT.md`
1396
+ 3. Continue building with that decision
1397
+ 4. Add to deferred queue (type: architecture-decision)
1398
+ 5. Notify: "Made autonomous architecture decision: <decision>. Draft ADR written. Approve with `/pcp accept-adr <N>` or override with `/pcp override-adr <N> <your-decision>`"
1399
+ 6. If PM overrides later: revert affected code, rebuild with correct decision
1400
+
1401
+ **`check: manual` criterion:**
1402
+ 1. Write code that satisfies the criterion (treat as `check: file_exists` for the implementation)
1403
+ 2. Add to deferred queue. Record `deferred_at` timestamp.
1404
+ 3. Notify: "Manual verification needed: <what to check and how>"
1405
+ 4. Continue all other criteria
1406
+ 5. When PM says `/pcp approve <module>/<id>`: mark complete, log intervention:
1407
+ ```python
1408
+ _log_intervention(pcp_dir, {
1409
+ "type": "manual_approval",
1410
+ "module": module, "criterion_id": criterion_id,
1411
+ "criterion_description": description,
1412
+ "deferred_at": deferred_at, "resolved_at": now,
1413
+ "time_to_resolve_minutes": elapsed,
1414
+ "feedback": None, "outcome": "approved"
1415
+ })
1416
+ ```
1417
+
1418
+ **`check: visual` criterion:**
1419
+ 1. Start dev server
1420
+ 2. Try `dom_contains` fallback if selector is determinable from spec — if passes, auto-approve (no intervention log entry — fully automated)
1421
+ 3. If no auto-check: take screenshot → `.pcp/previews/<module>-<id>-<ts>.png`
1422
+ 4. Add to deferred queue. Record `deferred_at` timestamp.
1423
+ 5. Notify with screenshot path: "Visual approval needed. Open: `open .pcp/previews/<file>`. Approve: `/pcp approve <module>/<id>`"
1424
+ 6. Continue all other criteria
1425
+ 7. On `/pcp approve`: log intervention. On `/pcp feedback "<text>"`: log with feedback field, rebuild.
1426
+
1427
+ **CI failing after 3 retries:**
1428
+ 1. Mark criterion `blocked-ci` in deferred queue with `retry_at: <now + 30min>`
1429
+ 2. Notify: "CI blocked after 3 retries. Last error: <summary>. Auto-retry in 30min."
1430
+ 3. Continue building all criteria that don't depend on this one
1431
+ 4. At retry time (if still in same session): attempt again silently
1432
+ 5. If resolved: mark complete, notify success
1433
+
1434
+ **Missing env var / secret:**
1435
+ 1. Detect which variable is missing from error log
1436
+ 2. Check `.env.example` — if variable is documented there, note its purpose
1437
+ 3. Add to deferred queue (type: blocked-secret)
1438
+ 4. Write to `.pcp/pending_secrets.md`: exact variable name, where to set it (Railway dashboard / `.env`), why it's needed
1439
+ 5. Notify: "Missing: `<VAR_NAME>` in <environment>. Set it and run `/pcp build --module <name>`"
1440
+ 6. Continue all code-only criteria for this module (only deploy criteria are blocked by missing secrets)
1441
+
1442
+ **Merge conflict (auto-resolve):**
1443
+ 1. Identify conflicting files
1444
+ 2. For each conflict, apply resolution priority:
1445
+ - Spec files (`.pcp/`): NEVER auto-resolve — always escalate
1446
+ - Config files (package.json versions): take higher version
1447
+ - Code files: apply ADR priority — if ADR governs this file's domain, its rules win
1448
+ - Lock files (package-lock.json, Cargo.lock): regenerate (`npm install` / `cargo update`)
1449
+ 3. If auto-resolve succeeds: commit resolution, continue
1450
+ 4. If genuinely ambiguous (both branches modified same business logic): add to deferred queue, isolate module, continue others
1451
+ 5. Notify only if couldn't auto-resolve
1452
+
1453
+ **Integration test regression after wave merge:**
1454
+ 1. Identify culprit via bisect (revert merges one by one until green)
1455
+ 2. Revert culprit module's merge: `git revert <merge-commit> --no-edit`
1456
+ 3. Mark module as `blocked-regression` in deferred queue
1457
+ 4. Continue next wave without the reverted module
1458
+ 5. Notify: "<module> reverted — integration test failed. Investigating. Build continues."
1459
+ 6. Diagnose the regression and write a fix plan to `.pcp/regression_<module>.md`
1460
+
1461
+ **Production smoke test failed:**
1462
+ 1. Execute rollback immediately: `railway rollback` or `git revert + railway up`
1463
+ 2. Notify immediately (this is a production incident — highest priority Slack message)
1464
+ 3. Pause ALL deploy-related criteria
1465
+ 4. Continue code-only criteria in other modules
1466
+ 5. Write incident log to `.pcp/incidents/<ts>.md`
1467
+ 6. Do NOT auto-redeploy to production — wait for PM to investigate
1468
+
1469
+ **Spec drift detected mid-build:**
1470
+ 1. Re-read new spec
1471
+ 2. Evaluate impact: does the change invalidate already-completed criteria?
1472
+ 3. If backward-compatible (additive): adopt new spec, update draft ADR if needed, continue
1473
+ 4. If breaking (removes or contradicts completed work): add to deferred queue, notify PM with diff
1474
+ 5. Never silently build against an old spec
1475
+
1476
+ **Context window near limit:**
1477
+ This should never happen in normal operation — one agent per criterion means context never accumulates. If it does happen (agent was incorrectly briefed to loop through multiple criteria):
1478
+ 1. Stop immediately at the current criterion boundary
1479
+ 2. Commit whatever is staged with `wip(<module>/<id>): partial - context limit`
1480
+ 3. Write handoff to `.pcp/.handoff.md`: "Resume: /pcp build --module <name> --from <criterion-id>"
1481
+ 4. Notify: "Context limit — agent was running too many criteria. Resuming with corrected single-criterion model."
1482
+ Prevention: orchestrator must never brief an agent with "complete ALL criteria". Always "complete criterion <id> only".
1483
+
1484
+ ### When PM returns (`/pcp` after being away)
1485
+
1486
+ Read: `.pcp/.build_progress` + `.pcp/deferred_queue.yaml` + `.pcp/pending_secrets.md`
1487
+
1488
+ Present:
1489
+ ```
1490
+ Built while you were away:
1491
+ ✓ <module> <n>/<total> criteria complete
1492
+ ✓ <module> complete
1493
+ → <module> <n>/<total> (CI retry pending at <time>)
1494
+
1495
+ Waiting for you (<n> items):
1496
+ 1. <module>/<id> — <type>: <one-line what's needed>
1497
+ → /pcp approve <module>/<id>
1498
+
1499
+ 2. <module>/<id> — architecture decision
1500
+ Draft ADR at .pcp/kb/adr/ADR-<N>-DRAFT.md (recommendation: <decision>)
1501
+ → /pcp accept-adr <N> OR /pcp override-adr <N> "<your decision>"
1502
+
1503
+ 3. <module>/<id> — visual approval
1504
+ Screenshot: .pcp/previews/<file> (open automatically)
1505
+ → /pcp approve <module>/<id>
1506
+
1507
+ Cannot unblock autonomously:
1508
+ ⚠ <VAR_NAME> missing — set in Railway dashboard, see .pcp/pending_secrets.md
1509
+ ⚠ <External approval> — see .pcp/pending_actions.md
1510
+
1511
+ Overall: <X>/<Y> criteria complete (<Z>%). Continue? (/pcp build --all resumes)
1512
+ ```
1513
+
1514
+ ### True stops (only 2 categories)
1515
+
1516
+ | Category | Why PCP cannot self-resolve |
1517
+ |---|---|
1518
+ | Production credentials (API keys, DB passwords, OAuth secrets) | Must never generate or guess real credentials. Security boundary. |
1519
+ | Regulatory / external approval (OAuth app review, app store approval, entitlement from vendor) | External to PCP's control. Cannot be automated. |
1520
+
1521
+ For both: write to `.pcp/pending_actions.md` with exact instructions. Build everything that doesn't depend on them.
1522
+
1523
+ ---
1524
+
1525
+ ## ESCALATION RULES
1526
+
1527
+ **No blocking prompts. Build never stops for deferrable input.**
1528
+
1529
+ | Situation | PCP Action |
1530
+ |---|---|
1531
+ | Architecture decision not in ADRs | Self-decide → write DRAFT ADR → continue → notify async |
1532
+ | `check: manual` | Defer → notify → continue |
1533
+ | `check: visual` | Try dom_contains fallback → screenshot → defer → notify → continue |
1534
+ | CI fail after 3 retries | Defer with 30min retry → notify → continue other criteria |
1535
+ | Missing env var / secret | Defer deploy criteria only → write pending_secrets.md → notify → continue code |
1536
+ | Merge conflict (resolvable via ADR priority) | Auto-resolve → continue |
1537
+ | Merge conflict (ambiguous logic) | Isolate module → defer → notify → continue other modules |
1538
+ | Integration regression after merge | Auto-bisect → revert culprit → defer → notify → continue next wave |
1539
+ | Spec drift (backward-compatible) | Adopt new spec → continue |
1540
+ | Spec drift (breaking change to completed work) | Defer → notify with diff → continue unaffected modules |
1541
+ | Context near limit | Checkpoint → commit WIP → write handoff note → notify |
1542
+ | `pcp check` BLOCK after 2 self-fix attempts | Defer → notify with finding → continue unblocked criteria |
1543
+ | Spec file modified by agent | Never auto-resolve → defer immediately → notify |
1544
+ | Production smoke test failed | Rollback immediately → notify URGENT → pause deploy criteria → continue code-only |
1545
+ | **Missing production credentials** | TRUE STOP for that module's deploy — write to pending_actions.md, continue all else |
1546
+ | **External regulatory/vendor approval** | TRUE STOP for dependent criteria — write to pending_actions.md, continue all else |
1547
+
1548
+ Slack notification format (every deferred item):
1549
+ ```
1550
+ ⚠ PCP [<project>] <module>/<id>
1551
+ Type: <manual | visual | architecture-decision | blocked-ci | blocked-secret>
1552
+ Summary: <one sentence what happened>
1553
+ Your action: <exact command — /pcp approve, /pcp accept-adr, set env var, etc.>
1554
+ Build: continuing on <other modules/criteria>
1555
+ ```
1556
+
1557
+ ---
1558
+
1559
+ ## MODULARITY PROTOCOL — NON-NEGOTIABLE
1560
+
1561
+ **Philosophy baked in at every layer.**
1562
+
1563
+ Vibe coders pivot. Features get dropped. Modules get added. The codebase must absorb this without surgery.
1564
+
1565
+ **The rule:** Every module is a guest in the codebase. It can be removed by deleting its directory. It can be added without touching existing modules. Nothing else should know about it except the application registry.
1566
+
1567
+ ---
1568
+
1569
+ ### Layer 1: Application structure (enforced on every project)
1570
+
1571
+ When generating the project scaffold, PCP always creates this structure regardless of language:
1572
+
1573
+ ```
1574
+ src/
1575
+ main.<ext> ← orchestrator: loads modules from registry. knows nothing about modules.
1576
+ interfaces/ ← typed contracts. the ONLY thing modules are allowed to share.
1577
+ I<Module>.ts/.py ← interface per module (what it exposes to the world)
1578
+ modules/
1579
+ <module>/
1580
+ index.<ext> ← public surface: exports only what interface requires
1581
+ src/ ← implementation: never imported by any other module
1582
+ tests/
1583
+ feature_flag.env ← FEATURE_<MODULE>_ENABLED=false (default off)
1584
+ core/ ← infrastructure only: logging, config, db connection
1585
+ ← core is NOT a module. modules may depend on core. never on each other.
1586
+ ```
1587
+
1588
+ Language-specific patterns:
1589
+ - **TypeScript/JS**: modules register via `app.register(AuthModule)` — no `import { doAuth } from '../auth/src/service'`
1590
+ - **Python**: modules register in `app.py` via plugin pattern — no cross-module `from auth.service import ...`
1591
+ - **Rust**: modules are crate features — `[features] auth = []`
1592
+ - **Swift**: modules are Swift packages or targets — no target-to-target source imports
1593
+
1594
+ ---
1595
+
1596
+ ### Layer 2: Auto-generated modularity rules in `ci_rules.yaml`
1597
+
1598
+ PCP adds these to EVERY project's `ci_rules.yaml` during `/pcp new`:
1599
+
1600
+ ```yaml
1601
+ # Modularity rules — generated by PCP, do not remove
1602
+ - id: MOD_001
1603
+ check: ast_pattern
1604
+ description: "No direct cross-module implementation imports"
1605
+ pattern: "from \\.\\.(/\\.\\.)?/[^/]+/src/" # catches ../../other-module/src/
1606
+ severity: hard_block
1607
+ message: "Modules must communicate through interfaces/, not by importing each other's src/"
1608
+
1609
+ - id: MOD_002
1610
+ check: ast_pattern
1611
+ description: "No hardcoded module names in application orchestrator"
1612
+ pattern: "require\\(['\"]\\.\\./" # direct require of module internals
1613
+ severity: hard_block
1614
+
1615
+ - id: MOD_003
1616
+ check: file_exists
1617
+ description: "Every module must have a public interface file"
1618
+ target: "src/interfaces/I{module}.ts" # checked per module
1619
+ severity: hard_block
1620
+
1621
+ - id: MOD_004
1622
+ check: ast_pattern
1623
+ description: "No shared global mutable state between modules"
1624
+ pattern: "global\\s+\\w+\\s*=" # language-specific, adapt per stack
1625
+ severity: hard_block
1626
+
1627
+ - id: MOD_005
1628
+ check: file_exists
1629
+ description: "Every module must have a feature flag"
1630
+ target: "src/modules/{module}/feature_flag.env"
1631
+ severity: hard_block
1632
+ ```
1633
+
1634
+ ---
1635
+
1636
+ ### Layer 3: Auto-generated modularity BLOCK rules in `architect_persona.md`
1637
+
1638
+ PCP adds these to EVERY project's architect_persona.md:
1639
+
1640
+ ```markdown
1641
+ ## Modularity Invariants (always enforced, not project-specific)
1642
+
1643
+ BLOCK:
1644
+ - Any direct import of another module's `src/` directory
1645
+ - Any module that imports from another module's `index` except through the interface type
1646
+ - Any global mutable state shared between modules (singleton patterns, global stores)
1647
+ - Any module that directly instantiates another module (use dependency injection via registry)
1648
+ - Feature code shipped without a feature flag (all new modules default off)
1649
+ - A module whose tests require another module to be running (tests must be isolated)
1650
+
1651
+ WARN:
1652
+ - A module with more than 3 dependencies in dependency_map.md (God module risk)
1653
+ - A module that owns more than 3 database tables (God module risk)
1654
+ - A module that directly modifies another module's database tables
1655
+
1656
+ LENIENT:
1657
+ - Module-internal design patterns (each module can use its own patterns)
1658
+ - Module test framework choices (each module can use its preferred test tool)
1659
+ ```
1660
+
1661
+ ---
1662
+
1663
+ ### Layer 4: Mandatory acceptance criteria on every module
1664
+
1665
+ PCP auto-adds these criteria to EVERY module's `acceptance.yaml`:
1666
+
1667
+ ```yaml
1668
+ # Modularity criteria — added by PCP to every module, do not remove
1669
+ - id: MOD_A001
1670
+ description: "Module can be dropped without breaking other modules"
1671
+ check: test_passes
1672
+ test: "tests/modularity/test_drop_<module>.sh"
1673
+ notes: "Delete or disable module, run full test suite of remaining modules — must pass"
1674
+
1675
+ - id: MOD_A002
1676
+ description: "Module registers through application interface, not via direct import"
1677
+ check: ast_pattern
1678
+ target: "src/main.<ext>"
1679
+ pattern: "register\\(<Module>\\)|plugin\\(<Module>\\)|mount\\(<Module>\\)"
1680
+
1681
+ - id: MOD_A003
1682
+ description: "Module has a feature flag, default off"
1683
+ check: file_exists
1684
+ target: "src/modules/<module>/feature_flag.env"
1685
+
1686
+ - id: MOD_A004
1687
+ description: "Module interface file exists and is typed"
1688
+ check: file_exists
1689
+ target: "src/interfaces/I<Module>.<ext>"
1690
+ ```
1691
+
1692
+ ---
1693
+
1694
+ ### Layer 5: Drop test in every build cycle
1695
+
1696
+ After completing ALL criteria for a module, run the drop test before marking the module done:
1697
+
1698
+ ```bash
1699
+ # Drop test — verify module can be removed without breaking others
1700
+ echo "Running drop test for <module>..."
1701
+
1702
+ # Temporarily disable module
1703
+ git stash -- src/modules/<module>/
1704
+
1705
+ # Run full test suite of ALL OTHER modules
1706
+ pytest --ignore=src/modules/<module>/ -q 2>/dev/null || \
1707
+ npm test -- --testPathIgnorePatterns="modules/<module>" 2>/dev/null || \
1708
+ cargo test --features "$(grep -v '<module>' Cargo.toml | grep 'features' | ...)" 2>/dev/null
1709
+
1710
+ DROP_EXIT=$?
1711
+
1712
+ # Restore module
1713
+ git stash pop
1714
+
1715
+ if [ $DROP_EXIT -ne 0 ]; then
1716
+ echo "DROP TEST FAILED: removing <module> breaks other modules"
1717
+ echo "Cross-module coupling detected — must fix before marking module complete"
1718
+ # Identify which tests failed → locate the coupling → fix it
1719
+ fi
1720
+ ```
1721
+
1722
+ Drop test failure = cross-module coupling found. Fix the coupling before marking the module complete. Add the coupling fix to the current criterion's implementation.
1723
+
1724
+ ---
1725
+
1726
+ ### Layer 6: `pcp validate-strategy` extended — coupling check
1727
+
1728
+ In addition to coverage, `pcp validate-strategy` now also checks:
1729
+
1730
+ ```
1731
+ Coupling analysis:
1732
+ ✓ auth → no implementation imports from other modules
1733
+ ✓ payment → no implementation imports from other modules
1734
+ ✗ dashboard → imports directly from auth/src/session.ts (COUPLING)
1735
+ ✗ billing → bidirectional dependency with payment (CIRCULAR)
1736
+
1737
+ Coupling violations: 2
1738
+ → Fix: dashboard must use IAuthModule interface, not auth/src directly
1739
+ → Fix: billing/payment circular dep — extract shared type to interfaces/
1740
+ ```
1741
+
1742
+ If coupling violations exist: cannot proceed to next wave. Fix coupling first.
1743
+
1744
+ ---
1745
+
1746
+ ### Layer 7: Module add/drop commands
1747
+
1748
+ ```
1749
+ /pcp add-module <name> "<one-line purpose>"
1750
+ → generates spec.yaml, acceptance.yaml, interface file, feature flag, test scaffold
1751
+ → adds to dependency_map.md with no deps by default
1752
+ → runs pcp validate-strategy to check coverage impact
1753
+ → ready to /pcp build --module <name>
1754
+
1755
+ /pcp drop-module <name>
1756
+ → runs drop test to verify safe removal
1757
+ → if safe: removes module directory, updates decomposition.md, updates dependency_map.md
1758
+ → runs pcp validate-strategy to check coverage impact of removal
1759
+ → removes from acceptance tracking
1760
+ → if unsafe: shows which modules depend on it, recommends decoupling steps first
1761
+
1762
+ /pcp pivot "<new direction>"
1763
+ → runs pcp validate-strategy with new context
1764
+ → shows: which modules are still relevant, which can be dropped, what new modules are needed
1765
+ → generates add/drop plan for PM to approve
1766
+ → executes plan after approval
1767
+ ```
1768
+
1769
+ ---
1770
+
1771
+ ### Why this matters for vibe coders
1772
+
1773
+ Without this:
1774
+ ```
1775
+ PM: "actually let's drop payments for now and add a referral system"
1776
+ Dev: *3 days of refactoring* "ok done"
1777
+ ```
1778
+
1779
+ With PCP modularity protocol:
1780
+ ```
1781
+ PM: "actually let's drop payments for now and add a referral system"
1782
+ PCP: /pcp drop-module payment → drop test passes → removed
1783
+ /pcp add-module referral "track and reward user referrals" → scaffold generated
1784
+ /pcp build --module referral → builds autonomously
1785
+ Time: hours, not days. Zero surgery on existing code.
1786
+ ```
1787
+
1788
+ ---
1789
+
1790
+ ## CONTEXT DRIFT PREVENTION
1791
+
1792
+ Before writing code for any criterion:
1793
+ 1. Re-read spec.yaml constraints
1794
+ 2. Confirm tech stack vs architecture.md
1795
+ 3. Internalize architect_persona.md BLOCK rules — know the rules before writing a line
1796
+ 4. Check if files touch any ADR boundary — if yes, follow that ADR's pattern exactly
1797
+ 5. Never make a new architectural decision without first checking ADRs + persona
1798
+
1799
+ If a decision is genuinely new: self-decide using best practices, document as DRAFT ADR, continue building. Do not stop.
1800
+
1801
+ ---
1802
+
1803
+ ## HONESTY RULES
1804
+
1805
+ - Never mark `status: complete` without every Completion Definition item passing
1806
+ - Never commit with `pcp check` BLOCK
1807
+ - Never skip regression suite
1808
+ - Never skip secret scan — no credentials ever reach git
1809
+ - Never invent CI or Railway status — read from CLI output
1810
+ - Never spawn more agents than modules needing work
1811
+ - Never silently skip a deferred item — always write to deferred_queue.yaml + notify
1812
+ - Never auto-resolve a spec file conflict unattended — specs are human-approved; defer to the PM, then apply via `pcp correct-objective` / `pcp pm` / `pcp amend` (diff shown, PM approves, then written)
1813
+ - Never generate or guess production credentials — security boundary, always stop and notify
1814
+ - Never redeploy to production after rollback without PM confirmation
1815
+ - If Playwright not installed and `check: visual` required: notify and defer rather than skip
1816
+ - If `pcp` CLI not installed: fetch the latest wheel from GitHub Releases and `pip install` it (see the top-level `SKILL.md`'s Install step — there is no PyPI package yet)
1817
+ - Draft ADRs are labelled DRAFT — never present them as accepted decisions
1818
+ - If a module's build is completely blocked (all criteria depend on a true-stop item): say so clearly in status, move to next module
1819
+ - If git worktree fails: fall back to sequential build on main branch, tell PM
1820
+
1821
+ ---
1822
+
1823
+ ## INTERVENTION LOGGING
1824
+
1825
+ Every human interaction is logged to `.pcp/intervention_log.yaml`. This is the learning signal. Metadata only — no code, no secrets, no project content.
1826
+
1827
+ ### `_log_intervention(pcp_dir, entry)` — called on every human touchpoint
1828
+
1829
+ ```python
1830
+ import yaml
1831
+ from datetime import datetime, timezone
1832
+ from pathlib import Path
1833
+
1834
+ def _log_intervention(pcp_dir: Path, entry: dict) -> None:
1835
+ log_path = pcp_dir / "intervention_log.yaml"
1836
+ existing = []
1837
+ if log_path.exists():
1838
+ data = yaml.safe_load(log_path.read_text()) or {}
1839
+ existing = data.get("interventions", [])
1840
+ entry["logged_at"] = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
1841
+ existing.append(entry)
1842
+ log_path.write_text(yaml.dump({"interventions": existing}, default_flow_style=False))
1843
+ ```
1844
+
1845
+ ### Log on every human touchpoint
1846
+
1847
+ | Trigger | type field | Extra fields |
1848
+ |---|---|---|
1849
+ | `/pcp approve <module>/<id>` (manual) | `manual_approval` | module, criterion_id, criterion_description, time_to_resolve_minutes, outcome |
1850
+ | `/pcp approve <module>/<id>` (visual) | `visual_approval` | module, criterion_id, screenshot_path, time_to_resolve_minutes, outcome |
1851
+ | `/pcp feedback <module>/<id> "<text>"` | `visual_feedback` | module, criterion_id, feedback (text), retest_triggered: true |
1852
+ | `/pcp accept-adr <id>` | `adr_accepted` | adr_id, topic, time_to_resolve_minutes |
1853
+ | `/pcp override-adr <id> "<decision>"` | `adr_overridden` | adr_id, topic, original_decision, override_decision, time_to_resolve_minutes |
1854
+ | Escalation resolved (PM replied) | `escalation_resolved` | reason, module, deferred_duration_minutes, resolution |
1855
+ | UAT retest cycle completes | `uat_retest` | scenario, retest_count, root_cause, time_to_pass_minutes |
1856
+ | Deploy gate: migration approved | `migration_approved` | migration_file, time_to_resolve_minutes |
1857
+ | Deploy gate: rollout % decided | `rollout_decision` | module, rollout_pct, reason |
1858
+
1859
+ ### Schema — intervention_log.yaml
1860
+
1861
+ ```yaml
1862
+ interventions:
1863
+ - logged_at: "2026-06-29T14:23:00Z"
1864
+ type: visual_approval
1865
+ module: payments
1866
+ criterion_id: PAY_005
1867
+ criterion_description: "Payment confirmation screen looks correct"
1868
+ time_to_resolve_minutes: 3
1869
+ outcome: approved
1870
+
1871
+ - logged_at: "2026-06-29T15:10:00Z"
1872
+ type: visual_feedback
1873
+ module: auth
1874
+ criterion_id: AUTH_003
1875
+ feedback: "Button is too small on mobile"
1876
+ retest_triggered: true
1877
+
1878
+ - logged_at: "2026-06-29T16:00:00Z"
1879
+ type: adr_overridden
1880
+ adr_id: ADR-003
1881
+ topic: database_choice
1882
+ original_decision: "SQLite for simplicity"
1883
+ override_decision: "PostgreSQL — need concurrent writes"
1884
+ time_to_resolve_minutes: 5
1885
+ ```
1886
+
1887
+ ### Daily aggregation (runs via cron)
1888
+
1889
+ Cron reads all intervention logs across all PCP projects, aggregates patterns, sends to Slack, writes to `~/.pcp/global_learning.yaml`:
1890
+
1891
+ ```
1892
+ Most frequent manual criteria: auth flows (OAuth) — 4/5 projects
1893
+ Longest to resolve: missing API keys — avg 127 min deferred
1894
+ Most UAT retests: payment edge cases — avg 2.8 retests/scenario
1895
+ Most overridden ADRs: database choice — 3/5 overridden
1896
+ → Next automation targets: OAuth verification, pre-flight API key check, payment edge case criteria templates
1897
+ ```