prd-plugin
PRD Plugin is a method delivered as a plugin: it installs a disciplined product-development workflow (idea → PRD → architecture → plan → implementation → evidence) into any repo that a host AI coding agent works in, and enforces that discipline with stable IDs, a JSON state store, cross-host hooks, and a verification gate. This document is chunked by heading for shared-knowledge indexing — each section is written to be read correctly on its own, with no surrounding context.
1. What this repo is
PRD Plugin (prd-plugin on npm) is a method-as-a-plugin
for host AI coding agents — primarily Claude Code, with parity support for OpenAI
Codex and opencode. It gives an agent a repeatable way to turn an idea into a
requirement, a requirement into architecture and an implementation plan, and code
into verified, evidence-backed work — with every artifact carrying a stable ID so
the chain is traceable and no record can be silently invented. It solves the
problem that agents drift, hallucinate "done", skip verification, and lose the
thread across sessions and compactions; the plugin replaces recollection with
on-disk state, skills the agent must consult, and hooks that run checks it cannot
forget.
This repository is the hub (the source of truth), located at
D:\Projects\prd-plugin / github.com/markusuk1/prd-plugin.
It authors the skills, templates, scripts, MCP server, and hooks, and publishes
them to npm. Downstream repos consume the plugin by running
npx prd-install, which lays down a .prd_plugin/ tree
(method docs, state store, ID registry, hooks, config) plus host-specific skill
mirrors. The hub is edited with the same method it ships (it dogfoods itself:
its own work is tracked as REQ-*/TRK-*/EV-*
records under .prd_plugin/state/).
What it is not. It is not a library or framework you import at runtime — nothing in a downstream app links against it. It is not an orchestrator: it does not spawn or manage subagents; the host agent runs the method itself and may manage its own parallelism. It is not project-specific — the skills and schema are domain-agnostic. And it is not a replacement for the host agent's own tools; it is a governance and memory layer on top of whatever agent is driving.
2. Capability map
Everything PRD Plugin provides, and where it lives in this repo. Counts are as of version 0.15.0.
| Capability | What it does | Where |
|---|---|---|
| Workflow skills (29) | Markdown skill files the host agent invokes to run each stage of the method (router, planning, TDD, debugging, verification, decision ledger, wiki, session close, …). The primary interface an agent touches. | skills/<name>/SKILL.md |
| State store & ID registry | Per-repo JSON files holding all durable records (requests, tracking, decisions, evidence, health, changelog) plus a monotonic ID registry so IDs never collide or get invented. | .prd_plugin/state/*.json, .prd_plugin/ids/registry.json |
| MCP server (35 tools) | A Model Context Protocol server exposing bounded canonical and DBR discovery, duplicate-safe ordinary record management, config-enforced branch-first parallel tracking, guarded goal/request/evidence/decision/change workflows, unified configuration management, reflection-bank CRUD, and persistent deterministic workflow operations. | mcp/server.cjs |
| Slash commands (13) | Host slash commands that wrap the scripts (/prd-status, /prd-new, /prd-track, /prd-report, /prd-drift, /prd-config, /prd-reflections, /prd-workflow, /prd-autonomy, /prd-graph, /prd-hooks, /prd-version, /prd-close). | commands/*.md |
| Deterministic workflow authority | A strict catalog and allowlisted action engine turns bounded mechanics, policy, validation, state, evidence, lifecycle, and release work into resumable WFR-* runs with stable plans, receipts, postconditions, idempotency, retry safety, cancellation, and hash-bound judgment requests. AI-Collab executes only the explicit external judgment contract; it cannot write canonical state directly. | scripts/prd_workflows.py, .prd_plugin/workflows.json, .prd_plugin/state/workflow-runs.json |
| Cross-host hooks | Shared hook scripts wired into all three hosts (Claude via settings.json, Codex via hooks.json 5 events, OpenCode via a JS plugin) — session nudge, gate on commit, drift on Stop, and optional bounded reflection questions on Stop. | .prd_plugin/hooks/, .claude/hooks/, .codex/hooks.json, .opencode/plugins/prd-hooks.js |
| Stop reflections | An off-by-default, categorized question bank whose categories and questions can be individually edited or activated; one local session marker prevents recursive Stop loops and reflection answers never become canonical project state automatically. | .prd_plugin/config.json, .prd_plugin/hooks/prd_reflection.py, scripts/prd_reflections.py |
| The gate | A single composable validator that blocks a commit / flags a session when state is inconsistent: duplicate IDs, version markers out of sync, implemented-without-graduation, tier violations, and more. Reads the config policy flags. | scripts/prd_gate.py |
| Drift monitor | Runs the validator suite, snapshots results to JSONL, emits a compact drift-event feed, and (optionally) a cheap on-Stop check. Detects when docs, state, the wiki, or the ingest manual have drifted from the code, and (for fork-consumer repos) when a newer fork version is available. | scripts/drift_monitor.py, scripts/ingest_manual_drift.py, scripts/fork_version_check.py |
| LLM wiki | A compounding, navigable knowledge base (Karpathy-style) the agent queries before re-deriving a fact and ingests into as work closes; with backfill and drift detection. | wiki/, scripts/prd_wiki_backfill.py |
| Version check | Compares the installed plugin version against npm (TTL-cached, fail-open, cross-platform) and surfaces "update available" in-session. | scripts/prd_version_check.py |
| Config toggles | A typed registry of on/off and value knobs (autonomy tier, tracking branches, drift monitoring, version check, wiki, gate) readable and settable as a JSON contract so external apps can toggle features. | scripts/prd_config.py, .prd_plugin/config.json |
| Delegated reporting | An off-by-default control plane for bounded non-deterministic prose: PRD Plugin builds source-referenced bundles and validates results; AI-Collab resolves and executes the configured fast-capable model profile. | scripts/prd_reporting.py, reporting.delegation config, utcp.json |
| AI-Collab Substrate adapter | An off-by-default, versioned projection contract with observe and coordinate modes. AI-Collab mirrors canonical records and graph edges while every project-truth mutation remains behind PRD MCP. | scripts/prd_substrate.py, integrations.substrate config, utcp.json |
| Request intake & auto-submit | Turns a bug/change proposal into a REQ-* record; downstream plugin-bug reports self-submit upstream rather than relying on the agent to remember. | skills/project-request-intake/, skills/project-local-integration/ |
| Installer | The npx prd-install entrypoint: copies the skeleton into a target repo, mirrors skills per host, refreshes plugin files with --force while preserving state, and idempotently maintains a bounded root .gitignore block without replacing project-owned rules. | scripts/prd_install.py, index.js |
3. Interfaces — how to call it
PRD Plugin is driven five ways: the install CLI, MCP tools, host slash
commands, the Python scripts directly, and a UTCP tool surface.
The UTCP manual (utcp.json, generated by
scripts/prd_tools.py --utcp-manual) describes a set of read-only
observe/recall tools (status, tracking,
decisions, evidence, wiki,
drift, gate, reporting) as cli call templates that run
this repo's own scripts. A UTCP host such as the AI-Collab hub mounts the manual
with a cli provider and bridges it to MCP — so the tools are
defined and owned here, not re-implemented downstream. Writes are deliberately
excluded: they stay on the validated MCP/script path (branch-first parallel
tracking, serialized canonical promotion, and the consent floor).
3.1 Install CLI
The npm package's bin runs the installer. Invoked in a target repo:
npx prd-install [target-dir] # first-time install into a repo (default: cwd)
npx prd-install . --force # refresh plugin files, PRESERVE .prd_plugin/state + config.json
npx prd-install . --force --yes # DESTRUCTIVE reset request; interactive confirmation required
npx prd-install . --host codex # choose host wiring (claude | codex | opencode)
--force is the update path: it re-lays hooks, skills, scripts, and
templates but never overwrites .prd_plugin/state/,
.prd_plugin/ids/, .prd_plugin/local/, or
.prd_plugin/config.json (the state-protected set), and never
overwrites a downstream README.md. The report labels each file
copied, skipped, or preserved.
Every install also creates or refreshes the lines between
# BEGIN PRD Plugin managed ignores and
# END PRD Plugin managed ignores in the repo-root
.gitignore. It preserves surrounding lines and line-ending style;
malformed markers or a non-UTF-8 file are reported and left untouched. The block
ignores runtime/transport state, reports, local command adapters, secrets,
caches, logs, temporary files, and OS metadata while leaving committed state,
tracking branches, drift exports, evidence, MCP configuration, and the shipped
Codex environment trackable.
3.2 MCP tools
Exposed by mcp/server.cjs over the Model Context Protocol. Read
tools are side-effect-free; write tools allocate IDs from the registry and append
to the state store under the owner-token lock. The thirty-five tools:
| Tool | Kind | Purpose |
|---|---|---|
prd_status | read | Summarize state: requests, active tracking, DBR branches, open health, stale items, skills used. |
prd_find | read | Return compact bounded canonical or DBR records filtered by kind, status, link, or text. |
prd_get | read | Return one exact full canonical or DBR record by ID. |
prd_create | write | Create ordinary TRK/REQ/HLT state with allocation inside the locked write. |
prd_update | write | Update only kind-specific mutable fields and valid lifecycle states. |
prd_link | write | Verify and symmetrically link two existing record-backed IDs. |
prd_open_tracking_branch | write | Before fan-out, the lead allocates one assigned DBR tracking file without changing canonical TRK state. |
prd_update_tracking_branch | write | A worker records progress only in its assigned branch file and allocates no IDs. |
prd_promote_tracking_branch | write | After worker merges, the lead serially applies a conflict-checked, idempotent branch promotion to canonical TRK state. |
prd_next_id | write | Consume the next globally unused embedded planning ID; ordinary record creation allocates internally. |
prd_open_goal | write | Open a tracking goal (TRK-*) with summary and links. |
prd_update_goal | write | Update a tracking goal's status/summary/links. |
prd_close_goal | write | Close a tracking goal and record the outcome. |
prd_file_request | write | File a REQ-* (bug/change/feature) with severity, risk, and provenance. |
prd_record_evidence | write | Append an EV-* evidence record backing a completion claim. |
prd_record_decision | write | Append a DEC-* decision with rationale, options, consequences, provenance. |
prd_log_change | write | Append a CHG-* changelog record. |
prd_validate | read | Run the consistency/gate checks and return findings. |
prd_reflection_list | read | List categories and questions with configured and effective activation; optional category and enabled filters are bounded and side-effect-free. |
prd_reflection_create | write | Create a unique category or atomically allocate a collision-free RFQ-* question under the shared state lock. |
prd_reflection_update | write | Rename or activate a category; edit, activate, deactivate, or move a question while rejecting normalized duplicates. |
prd_reflection_delete | write | Delete a question or an empty category; deleting a non-empty category requires explicit cascade: true. |
prd_config_list | read | List and filter the complete persistent setting catalog with current/default values, ownership, activation, latency, and dependency metadata. |
prd_config_get | read | Describe one configured setting or explain its effective state and blocking dependencies. |
prd_config_set | write | Atomically set, enable, or disable one operator-mutable setting after type and policy validation. |
prd_config_profile | read/write | List, show, diff, dry-run/apply, save, or delete built-in and custom latency profiles. |
prd_workflow_list | read | List shipped workflows, step counts, judgment boundaries, and effective enablement. |
prd_workflow_actions | read | List the code-owned action allowlist with determinism, mutation, and idempotency metadata. |
prd_workflow_audit | read | Audit catalog schema, provenance, inputs, actions, postconditions, and duplicates. |
prd_workflow_plan | read | Validate inputs and return a stable dry-run plan without executing or allocating. |
prd_workflow_run | write | Allocate and start a persistent run whose completion requires every postcondition. |
prd_workflow_status | read | Read steps, receipts, attempts, pending judgment, and terminal outcome for one run. |
prd_workflow_resume | write | Validate a hash-bound judgment result and resume deterministic execution. |
prd_workflow_cancel | write | Cancel a non-terminal run with an auditable reason. |
prd_workflow_retry | write | Retry a safely retryable failure within policy; outcome-unknown mutations remain blocked. |
3.3 Slash commands
Thin host-command wrappers over the scripts (files under commands/):
| Command | Does |
|---|---|
/prd-status | Print the state summary (wraps prd_status.py). |
/prd-new | Start a new piece of tracked work. |
/prd-track | Open/update a tracking goal. |
/prd-report | Generate deterministic reports and optionally delegate source-validated summary prose to AI-Collab under the configured fallback. |
/prd-drift | Run the drift monitor and show findings. |
/prd-config | Get/set/list config toggles, including delegated reporting and the Substrate adapter switch, mode, and capabilities (wraps prd_config.py). |
/prd-reflections | List and manage reflection categories/questions through the validated CRUD script or MCP tools. |
/prd-workflow | List, audit, plan, run, inspect, resume, cancel, or safely retry persistent deterministic workflows. |
/prd-autonomy | Show or set the autonomy tier. |
/prd-graph | Render the traceability graph. |
/prd-hooks | Inspect/repair host hook wiring. |
/prd-version | Check installed vs npm-latest plugin version. |
/prd-close | Run the session-close flow (user-invoked). |
3.4 Scripts
The Python scripts under scripts/ are the real implementation;
commands, hooks, and MCP tools all call into them. Stdlib-only, cross-platform.
| Script | Role |
|---|---|
prd_gate.py | The composite verification gate; also set-autonomy <level>. |
prd_status.py | Human-readable state summary. |
prd_config.py | Unified setting catalog and profile manager: list/get/describe/set/enable/disable, effective-state explanation, audit/inventory, and built-in/custom profile CRUD with atomic writes. |
prd_reflections.py | Validated reflection-bank list/create/update/delete CLI with atomic config writes and duplicate-safe RFQ-* allocation. |
prd_reporting.py | Provider-neutral delegated-reporting control plane: effective policy, deterministic sanitized bundles, fallback decisions, and strict result validation. It makes no model call and writes no project state. |
prd_substrate.py | Versioned read-only handshake, complete canonical-record snapshot, and repo-qualified graph export consumed by the AI-Collab adapter. |
prd_workflows.py | Strict workflow catalog validator and execution authority with persistent WFR-* state, receipts, postconditions, resumable judgment boundaries, idempotency, and retry/cancel safety. |
workflow_chml_audit.py | Deterministic C/H/M/L completeness audit across engine, catalog, config, interfaces, lifecycle hooks, installer, skills, docs, and release wiring. |
drift_monitor.py | Validator suite runner, snapshots, drift-event feed, on-Stop check. |
prd_version_check.py | npm-vs-installed version check (cached, fail-open). |
prd_wiki_backfill.py | Wiki build/backfill and --drift detection. |
ingest_manual_drift.py | Source-path-aware drift detection for this manual (--drift): flags when a cited file changed since the manual's commit stamp, or it is unstamped / non-conformant. |
fork_version_check.py | Generic fork/upstream version drift check (--drift): polls a configured JSON URL (static manifest or a node /v1/status) and compares to a local marker; inert unless the repo is a configured fork consumer. |
prd_tools.py | The UTCP tool surface: read-only observe/recall tools over a repo's method state, plus --utcp-manual discovery. The tools a UTCP host (AI-Collab hub) mounts and bridges to MCP. |
state_consistency_check.py | Required default downstream runtime for cross-record and tracking-branch integrity; prd_gate.py fails if it is unavailable. |
release_check.py | Version markers and release-ledger consistency, compared with the prior v* release tag by default (or HEAD~1 before the first tag). |
gap_audit.py | Coverage/gap audit against a target version. |
prd_self_audit.py | Rule/state/downstream-template audit. Registry counters are monotonic allocation cursors rather than continuity ledgers; explicitly guarded hub-helper references are allowed while unguarded downstream commands remain findings. |
3.5 Reflection CRUD example
The CLI and MCP CRUD tools operate on the same
.prd_plugin/config.json#reflection store and use the same local lock
as canonical state writes. They require local repository write access but no
network authentication. Invalid IDs, duplicate normalized text/category names,
unknown targets, and non-empty category deletion without an explicit cascade
return an error without partially editing the bank. Real read output at commit
c5bab8c:
$ python scripts/prd_reflections.py list --json --category harness_friction
{
"enabled": false,
"on_stop": true,
"max_questions_per_stop": 5,
"categories": [
{
"id": "harness_friction",
"name": "Harness friction",
"enabled": true,
"question_count": 2
}
],
"questions": [
{
"id": "RFQ-004",
"text": "What harness friction points made this work more difficult?",
"enabled": true,
"category_id": "harness_friction",
"category_name": "Harness friction",
"effective_enabled": false
},
{
"id": "RFQ-005",
"text": "What up to three changes would most improve friction in the harness?",
"enabled": true,
"category_id": "harness_friction",
"category_name": "Harness friction",
"effective_enabled": false
}
]
}
3.6 Worked example
Running the status script in this repo prints the current state summary. Real output at commit f7d182d:
$ python scripts/prd_status.py
# PRD Plugin Status
Autonomy: `autonomous`
## Requests
- accepted: 1
- deferred: 1
- implemented: 54
- proposed: 3
- rejected: 1
## Active tracking (1)
- TRK-063
## Open health findings (1)
- HLT-001
## Stale items
- 1
## Skills used this repo
- project-decision-policy: 1
- project-request-intake: 1
- project-test-driven-implementation: 1
- project-verification-before-completion: 1
Architecture — how the pieces fit
PRD Plugin has four structural layers: the skill mirrors, the per-repo state store, the MCP server, and the host hooks — all authored once in the hub and projected outward by the installer. This section reads on its own; it describes how a change made in the hub reaches a downstream agent.
Skill delivery: one canonical set, seven mirrors
The 29 skills are authored in skills/<name>/SKILL.md. Because
each host discovers skills from a different directory, the canonical set is copied
byte-identically into per-host mirrors: hub-level
.agents/skills, .opencode/skill, and
.claude/skills, plus three skeleton copies under
templates/repo-skeleton/ that ship downstream. Parity tests assert
the mirrors are identical. Two skills
(project-verification-before-completion,
project-prd-plugin-setup) have adapted skeleton variants that
strip hub-only scripts — a blanket copy would clobber them, so those two are
excluded from the byte-identical sweep.
State store: branch-first parallel writes, serialized promotion
Every durable record lives in .prd_plugin/state/*.json
(requests.json, tracking.json, decisions.json,
evidence, health.json, changelog). IDs are allocated only
from .prd_plugin/ids/registry.json, which holds a next
counter per type — this is what makes "no inventing records" enforceable: a
referenced ID that was never allocated is a gate failure. Before parallel
fan-out, the lead pre-allocates one DBR tracking branch per worker and commits
the distinct files under .prd_plugin/state/tracking-branches/.
It launches workers with PRD_WORKER_SESSION=1,
PRD_TRACKING_BRANCH_ID, and PRD_TRACKING_BRANCH_OWNER.
When tracking.branching.require_for_parallel_agents is true, the MCP
dispatcher rejects every canonical state/registry write and any branch assignment
mismatch. Workers update only their assigned files, allocate no IDs, and leave
non-TRK closeout requests as notes for the lead. After worktree
merges, the lead promotes branches serially; canonical state and registry
allocation therefore remain single-authority and duplicate-safe.
Hooks: shared scripts, thin per-host wiring
Hook logic is host-neutral and lives once in .prd_plugin/hooks/
(byte-identical to .claude/hooks/). Each host wires the same scripts
differently: Claude Code via .claude/settings.json; Codex via
.codex/hooks.json across all five events (SessionStart,
UserPromptSubmit, PreToolUse, PostToolUse, Stop) with the same payload shape and
exit-2 block semantics as Claude; opencode via a JavaScript plugin
(.opencode/plugins/prd-hooks.js) mapping session.idle to
Stop-like behavior and tool.execute.before to PreToolUse. opencode's
session.idle is non-blocking, so opencode alone cannot enforce
run-until-done; the gate and CI are the portable backstop.
The gate: composition, not reimplementation
prd_gate.py composes the existing validators
(state_consistency_check, release_check) and adds checks
seeded by real past failures (duplicate IDs, version markers out of sync
including already-published-on-npm, implemented-without-graduated_to,
stranded outbox, autonomy-tier violations). It reads the config policy flags that
would otherwise be dormant, so the gate is where advisory policy becomes
enforced. state_consistency_check.py is installed by default beside
the downstream gate; a missing validator is itself an error rather than a silent
skip.
Recipes — common tasks end to end
Copy-pasteable paths for the things operators and agents do most. Each recipe stands alone.
Install PRD Plugin into a repo
cd my-repo
npx prd-install . # also creates/merges the managed root .gitignore block
python .prd_plugin/scripts/prd_status.py # confirm the state store is live
Update the plugin without losing state
npm update prd-plugin
npx prd-install . --force # refreshes hooks/skills/scripts/templates; preserves state + config
Turn on drift detection with an on-Stop check
python scripts/prd_config.py set drift.monitoring.enabled true
python scripts/prd_config.py set drift.monitoring.on_stop true
python scripts/drift_monitor.py # run it now
Turn on Stop reflections and inspect the question bank
python scripts/prd_config.py set reflection.enabled true
python scripts/prd_reflections.py list --json
python scripts/prd_reflections.py update question RFQ-005 --disabled
The first eligible Stop asks the active questions and writes only a hashed local session marker. The immediately following Stop consumes that marker and allows completion, preventing an infinite reflection loop.
Enable the AI-Collab Substrate adapter in observe mode
python .prd_plugin/scripts/prd_config.py set integrations.substrate.enabled true
python .prd_plugin/scripts/prd_config.py set integrations.substrate.mode observe
python .prd_plugin/scripts/prd_substrate.py handshake --repo-root .
Use coordinate only with the additional capability names the
runtime needs. Substrate remains a derived mirror; writes still use PRD MCP.
Check for a newer plugin version
python scripts/prd_version_check.py # npm-vs-installed, cached, fail-open
Plan and run a deterministic workflow
python scripts/prd_workflows.py --repo-root . audit --json
python scripts/prd_workflows.py --repo-root . plan engineering.verify --inputs '{}'
python scripts/prd_workflows.py --repo-root . run engineering.verify --inputs '{}'
Use the equivalent prd_workflow_* MCP tools from an agent. If a run
reaches waiting_judgment, AI-Collab receives only the declared,
source-hashed request and result schema; deterministic validation must accept the
result before the run can continue.
Build or query the LLM wiki
python scripts/prd_wiki_backfill.py # build/backfill articles
python scripts/prd_wiki_backfill.py --drift --format json # detect stale/unstamped/missing articles
File a request (bug/change/feature)
Invoke the project-request-intake skill (or the
prd_file_request MCP tool). It allocates the next REQ-*
from the registry and appends to requests.json with severity, risk,
and provenance — never a hand-typed ID.
4. Operations — run, deploy, configure
PRD Plugin runs as files in a repo, not a service; "operating" it means installing/updating it, setting config knobs, and running its release ceremony in the hub. There is nothing to stand up on a server.
Stand it up
One command in a target repo: npx prd-install .. Update with
npm update prd-plugin && npx prd-install . --force (state- and
config-preserving). Never add --yes to an update: it requests a
destructive reset, is refused in non-interactive sessions, and requires the exact
interactive phrase RESET PRD STATE. The hub itself needs Python 3
(stdlib only) and Node for the MCP server and installer.
Configuration knobs and defaults
Managed by scripts/prd_config.py and stored in
.prd_plugin/config.json. The unified catalog covers every shipped
persistent setting and reports type, owner, mutability, activation,
dependencies, and latency. inventory also reports environment,
installer, host-wiring, specialized-CRUD, and invocation-only controls.
Validated writes are atomic and formatting-preserving; lean, balanced, and
thorough profiles can be previewed before apply and never auto-enable external
integrations. Core runtime hook controls include:
| Key | Default | Controls |
|---|---|---|
hooks.enabled | true | Master switch for all host hook behavior. |
hooks.nudge.on_user_prompt | true | Per-prompt routing nudge and its TTL-gated update checks. |
hooks.session_report.enabled | true | Configured Stop reporting work. |
hooks.skill_log.enabled | true | High-frequency post-tool skill logging. |
hooks.workflow.enabled | true | Permit lifecycle events to dispatch the configured deterministic start/stop workflows. |
workflows.enabled | true | Master switch for workflow planning and execution. |
workflows.enabled_workflow_ids | shipped catalog | Explicit workflow allowlist for this use case/profile. |
workflows.allow_state_mutations | true | Permit only allowlisted MCP mutation actions from workflows. |
workflows.judgment.executor | ai-collab | External runtime responsible for declared non-deterministic judgment requests. |
workflows.judgment.profile | fast-capable | Configurable AI-Collab model profile for source-backed judgment. |
workflows.judgment.fallback | fail | External-runtime fallback policy; the deterministic engine never silently substitutes an LLM. |
automation.autonomy_level | autonomous | How much the agent decides vs. asks; the ship-consent tier. |
automation.autonomous_run_until_done | true | The Stop guard keeps working toward the active goal in autonomous. |
automation.autonomous_continue_cap | 25 | Max consecutive auto-continues per session before allowing a stop. |
automation.precommit_gate | true | Block git commit when the gate has error-severity findings. |
automation.graph_auto_refresh | false | Regenerate the traceability graph on Stop. |
automation.version_check.enabled | true | Auto-check npm for a newer plugin version (cached, fail-open). |
automation.version_check.ttl_hours | 1 | How long the version-check result is cached before re-querying npm. |
drift.monitoring.enabled | false | The drift monitor (validators + snapshots/events). |
drift.monitoring.on_stop | false | Run a cheap drift check on every Stop and surface a summary. |
drift.monitoring.export.enabled | false | Also append drift events to a committed/shared feed. |
drift.monitoring.export.path | .prd_plugin/drift/events.jsonl | Where the exported (committed) drift-event feed is written. |
reflection.enabled | false | Master switch for categorized reflection questions when the host reaches Stop/idle. |
reflection.on_stop | true | Permit the reflection hook to run on Stop when the master switch is enabled. |
reflection.max_questions_per_stop | 5 | Bound the number of effectively active questions included in one reflection pass (1–50). |
integrations.substrate.enabled | false | Master switch for the AI-Collab Substrate adapter. |
integrations.substrate.mode | off | Select inert, read-only observe, or capability-gated coordinate behavior. |
integrations.substrate.capabilities | records, graph, events | Explicit allowlist; coordinate-only functions are unavailable unless named. |
knowledge.llm_wiki.enabled | true | The LLM wiki (query-before-re-derive, ingest-on-close, backfill). |
python scripts/prd_config.py inventory --json and
list --json are machine contracts. Agents use the equivalent
prd_config_list, prd_config_get,
prd_config_set, and prd_config_profile MCP tools.
Each host event launches one dispatcher process, which checks these switches
before importing disabled behavior.
Autonomy tiers
Three tiers set by automation.autonomy_level (change via
python scripts/prd_gate.py set-autonomy <level>): guided
and key_decision require explicit consent before push/merge/publish;
autonomous makes the tier itself the standing consent — the
agent ships the work end-to-end (commit, push, merge to the work's own main, tag,
publish) provided the gate is green, and never ships red. What never unlocks in
any tier: committing/exposing secrets, force-push or history destruction, editing
an unrelated repo, or irreversible external spend. Local commits on a work branch
never need consent in any tier.
Release ceremony (hub only)
Cutting a version bumps every version marker (the marker set plus
package.json and index.js), adds entries to the releases
ledgers, graduates the driving REQ-* to implemented with a
graduated_to, appends CHG-*/EV-*, and updates
the registry counters — then runs the full gate green before merge/tag/publish
to npm. In this hub the remote v* tag push is the publication action:
.github/workflows/npm-publish.yml checks out the tag, runs tests and
package verification, and publishes to npm. Agents must not run
npm publish locally or treat missing local npm credentials as a
release blocker. After a successful tag push, treat the release as published
unless the owner reports otherwise. Only then inspect or rerun the GitHub
Actions Publish to npm workflow to distinguish workflow failure
from registry lag.
5. Design decisions & re-open triggers
The load-bearing decisions behind PRD Plugin's shape, and what would make each worth revisiting. These are the choices a newcomer most often questions.
| Decision | Why | Re-open when |
|---|---|---|
| Tiered consent floor with a never-unlock set | Some actions (secrets, history destruction, unrelated repos, external spend) must stay blocked regardless of tier. | A new class of irreversible action appears that the floor does not name. |
| Stable IDs from a single registry; no invented records | Traceability and grounding depend on IDs that were actually allocated; the gate can then reject phantom references. | Never for the core; only to add a new record type (extend the registry, not bypass it). |
| One canonical skill set, byte-identical mirrors | Each host discovers skills from a different path; identical mirrors keep behavior consistent and testable. | Hosts converge on a single shared skills location, or a host needs genuinely divergent skill content beyond the two adapted variants. |
| Host-neutral hook scripts, thin per-host wiring | Write the check once; only the tiny wiring differs per host, so parity is cheap to maintain. | A host's hook model diverges enough that shared scripts no longer fit. |
| Stop reflections are opt-in and recursion-bounded | Reflection can improve behaviour and expose harness friction, but enabling it silently on every downstream upgrade would interrupt existing workflows. A local one-pass marker makes the feature useful without creating an endless Stop/re-prompt cycle. | Hosts provide a portable native reflection lifecycle with equivalent recursion protection and explicit persistence semantics. |
| Substrate is a derived runtime, not project truth | PRD Plugin retains schemas, IDs, locking, source references, and validation; AI-Collab can index and coordinate without creating a second writer or exposing local state. | A future substrate can prove equivalent canonical allocation, locking, validation, and audit guarantees. |
| Deterministic authority below explicit judgment | Bounded mechanics are more reliable, faster, auditable, and cheaper as validated workflows. Irreducible judgment is isolated in source-hashed, schema-bound requests executed by AI-Collab, while canonical mutations remain deterministic. | A currently judgment-bound decision gains a complete deterministic policy, or the external runtime cannot honor the request/hash/schema contract. |
| opencode cannot enforce run-until-done | session.idle is non-blocking, so the Stop guard can't hold opencode in the loop; accepted as a host limitation. | opencode adds a blocking idle/stop hook — then wire run-until-done there too. |
| Complexity/confidence ratings, never time estimates | Time estimates from an agent are false precision; complexity + confidence + risk carry the real signal. | Never — this is a hard method rule. |
| LLM wiki separate from the state store | State records durable facts/records (IDs, decisions); the wiki holds durable knowledge queried before re-derivation. Different lifecycles. | The two collapse into one representation without losing the query-before-re-derive workflow. |
Generate/merge downstream .gitignore in the installer, not the skeleton | npm packing excludes files named .gitignore; a skeleton file silently fails to reach npm consumers. A marked installer-owned block is package-safe, upgradeable, idempotent, and preserves project rules. | npm gains a reliable way to transport dot-ignore files, or downstream repositories adopt another shared ignore mechanism. |
6. Verification — how claims are proven
Every claim in this manual is backed by a test, a script, or a reproducible command. PRD Plugin holds itself to the same grounding rule it ships: verify before claiming done, cite real output.
Test suite
The hub carries a stdlib unittest suite. Release-wide verification
for version 0.15.0 runs the complete discovered suite:
$ python -m unittest discover -s tests
...
OK
Included are data-driven parity tests that assert the seven skill mirrors are
byte-identical (except the two adapted skeleton variants), Windows-console-safety
tests that reject non-ASCII in Python source (a real past crash class), and
installer tests that assert --force preserves state/config while
refreshing plugin files. The installer suite also invokes
git check-ignore --no-index to prove generated/runtime paths are
ignored while committed PRD Plugin truth stays trackable.
The five gates
Before any release the following must be green, and the same checks compose
into prd_gate.py for commit-time enforcement:
python -m unittest discover -s tests # unit + parity + safety
python scripts/state_consistency_check.py --repo-root . # cross-record integrity -> ok
python scripts/release_check.py # version markers / ledger
python scripts/gap_audit.py --target-version 0.15.0 # coverage gaps
python scripts/workflow_chml_audit.py --repo-root . --format json # C/H/M/L -> 0
python scripts/prd_gate.py # composite gate (reads policy flags)
Drift detection
The drift monitor re-runs the validators and flags when documentation, state,
the wiki, or this ingest manual have fallen behind the code. Wiki drift is
measured by commit-stamp staleness; ingest-manual drift is source-path-aware —
it flags precisely when a file the manual cites has changed since the manual's
commit stamp (silent for unrelated churn), and immediately if the manual becomes
unstamped or non-conformant. A repo that consumes an external fork can also enable
a fork-version check that polls a configured source (a static manifest or a node
/v1/status) and surfaces a newer fork version on Stop — inert unless
configured. It writes snapshots and a compact drift-event feed and can run a cheap
subset on every Stop.
Evidence records
Completion claims in this repo are backed by EV-* records in the
state store, linked from the REQ-*/TRK-* that drove the
work. A claim of "done" with no evidence record and no reproduction command does
not pass the method — and this manual follows that rule: its counts (29 skills,
35 MCP tools, 13 commands, version 0.15.0) were each
captured by running the command shown, not recalled.