From 4fb1035be0ad70c9c913c31b05be372e2d9571a2 Mon Sep 17 00:00:00 2001 From: ParkerES Date: Fri, 20 Feb 2026 15:31:55 -0500 Subject: [PATCH] feat: enforce plan tracking protocol with docs/features// convention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move plan files from docs/plans/ to docs/features//plan.md - Add "Plan Tracking Protocol" section to CLAUDE.md — every plan MUST have a tracker entry, matching slug across folder/branch/tracker key - Update validate-tracker.mjs to scan docs/features/ for orphan folders - Update check-docs.mjs to accept docs/features/ as doc path - Update event-wiring.ts plan detection to scan docs/features/*/plan.md - Update all ai-docs and .claude/commands references - Clean up 37 stale .claude/progress/ entries (untracked, runtime only) - Delete empty docs/plans/ directory Co-Authored-By: Claude Opus 4.6 --- .claude/commands/implement-feature.md | 7 ++- .claude/commands/plan-feature.md | 7 +-- .claude/commands/resume-feature.md | 2 +- CLAUDE.md | 54 +++++++++++++++++-- ai-docs/ARCHITECTURE.md | 2 +- ai-docs/CODEBASE-GUARDIAN.md | 2 +- ai-docs/FEATURES-INDEX.md | 2 +- ai-docs/TASK-PLANNING-PIPELINE.md | 8 +-- .../PROGRESS-FILE-TEMPLATE.md | 2 +- .../prompts/implementing-features/README.md | 2 +- .../future-roadmap/plan.md} | 0 .../separation-of-concerns/plan.md} | 0 docs/tracker.json | 4 +- scripts/check-docs.mjs | 2 +- scripts/validate-tracker.mjs | 19 +++---- src/main/bootstrap/event-wiring.ts | 23 ++++---- 16 files changed, 95 insertions(+), 41 deletions(-) rename docs/{plans/2026-02-16-future-roadmap.md => features/future-roadmap/plan.md} (100%) rename docs/{plans/2026-02-16-codebase-separation-of-concerns-design.md => features/separation-of-concerns/plan.md} (100%) diff --git a/.claude/commands/implement-feature.md b/.claude/commands/implement-feature.md index 2e76a72..b20fb2a 100644 --- a/.claude/commands/implement-feature.md +++ b/.claude/commands/implement-feature.md @@ -28,7 +28,7 @@ MANDATORY READS: If a design document exists, read it too: ``` -docs/plans/.md +docs/features//plan.md ``` --- @@ -188,9 +188,8 @@ When ALL tasks have QA PASS: ## Phase 9: Cleanup -- Update `docs/progress/-progress.md` → status: COMPLETE -- Update `docs/plans/.md` → status: IMPLEMENTED -- Move design doc to `doc-history/` if requested +- Update `docs/tracker.json → status: IMPLEMENTED +- Update `docs/features//plan.md` → status: IMPLEMENTED - Clean up worktrees: `git worktree remove ` - Report completion summary to user diff --git a/.claude/commands/plan-feature.md b/.claude/commands/plan-feature.md index d582622..dcf05c4 100644 --- a/.claude/commands/plan-feature.md +++ b/.claude/commands/plan-feature.md @@ -87,10 +87,10 @@ Identify which tasks can run **in parallel** (no shared files). ## Phase 5: Write the Plan -Write the complete plan to: `docs/plans/-plan.md` +Write the complete plan to: `docs/features//plan.md` The feature slug should be derived from the description: lowercase, hyphens, no special chars. -Example: "Add user authentication" becomes `docs/plans/add-user-authentication-plan.md` +Example: "Add user authentication" becomes `docs/features/add-user-authentication/plan.md` ### Plan File Format @@ -145,7 +145,8 @@ After writing the plan file, output the **absolute file path** as the very last Example final line: ``` -PLAN_FILE:docs/plans/add-user-authentication-plan.md +PLAN_FILE:docs/features/add-user-authentication/plan.md +nAlso add a tracker entry to `docs/tracker.json` with the slug as key and status `DRAFT`. ``` --- diff --git a/.claude/commands/resume-feature.md b/.claude/commands/resume-feature.md index aa9769b..cc389cb 100644 --- a/.claude/commands/resume-feature.md +++ b/.claude/commands/resume-feature.md @@ -87,7 +87,7 @@ Based on your analysis: - Check if a plan file was partially written - If yes, review and complete it - If no, start the planning process fresh using the `/plan-feature` approach -- Write the plan to `docs/plans/-plan.md` +- Write the plan to `docs/features//plan.md` ### If resuming an execution phase: - Identify which tasks from the plan are complete vs incomplete diff --git a/CLAUDE.md b/CLAUDE.md index 83fe2ba..9fa0fc0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -112,7 +112,7 @@ If tests don't exist for the area you're modifying, **that doesn't exempt you fr > that future agents read. If agent docs are stale, agents produce wrong code, which wastes time and money. > **Failing to update docs is the same as shipping broken code. Treat it that way.** -`npm run check:docs` enforces that source changes include doc updates. Accepted doc paths: `ai-docs/`, `docs/plans/`, `.claude/agents/`, `docs/tracker.json`, and `CLAUDE.md`. Use this mapping to know which docs to update: +`npm run check:docs` enforces that source changes include doc updates. Accepted doc paths: `ai-docs/`, `docs/features/`, `.claude/agents/`, `docs/tracker.json`, and `CLAUDE.md`. Use this mapping to know which docs to update: | Change Type | Docs to Update | |-------------|----------------| @@ -123,8 +123,8 @@ If tests don't exist for the area you're modifying, **that doesn't exempt you fr | UI layout changes | `user-interface-flow.md` (UX flow sections), `FEATURES-INDEX.md` (layouts) | | New feature module | `FEATURES-INDEX.md` (feature table), `ARCHITECTURE.md` (system diagram if applicable) | | New pattern or convention | `PATTERNS.md` (pattern example with code), **ALL relevant agent files** | -| Feature plan or design doc | `docs/plans/-plan.md` (implementation plan) | -| Plan lifecycle changes | `docs/tracker.json` | +| Feature plan or design doc | `docs/features//plan.md` (implementation plan) | +| Plan lifecycle changes | `docs/tracker.json` (update status + add entry) | | Any change to file structure, imports, or conventions | **ALL `.claude/agents/*.md` files that reference the affected area** | **Checklist before committing — ALL items are mandatory:** @@ -370,3 +370,51 @@ Raw hex/rgb/hsl values are **ONLY** allowed inside theme variable definitions: **Plan lifecycle tracking:** `docs/tracker.json` (single source of truth for all plan/progress status) +## Plan Tracking Protocol — MANDATORY + +**Every plan, feature, or design doc MUST be tracked.** No exceptions — ad-hoc plans, on-the-fly features, and formal design docs all follow the same convention. + +### The Naming Convention + +One **slug** (lowercase, hyphen-separated) used everywhere: + +| Artifact | Location | +|----------|----------| +| Tracker entry key | `docs/tracker.json` → `plans.` | +| Plan/design doc | `docs/features//plan.md` | +| Feature branch | `feature/` | +| Runtime progress | `.claude/progress//` (gitignored, workflow plugin) | + +### When Creating a New Plan or Feature + +1. **Choose a slug** — short, descriptive, hyphenated: `custom-theme-editor`, `tracking-consolidation` +2. **Create the folder**: `docs/features//` +3. **Write the plan**: `docs/features//plan.md` +4. **Add to tracker**: Add an entry to `docs/tracker.json` with the slug as key +5. **Create the branch**: `feature/` + +### Tracker Entry Format (v2) + +```json +{ + "": { + "title": "Human-Readable Title", + "status": "DRAFT | APPROVED | IN_PROGRESS | IMPLEMENTED | ARCHIVED | TRACKING", + "planFile": "docs/features//plan.md", + "created": "YYYY-MM-DD", + "statusChangedAt": "YYYY-MM-DD", + "branch": "feature/", + "pr": null, + "tags": ["category"] + } +} +``` + +### Rules + +- **No plan without a tracker entry.** If you create `docs/features/X/plan.md`, add `X` to `docs/tracker.json`. +- **No feature branch without a tracker entry.** If you create `feature/X`, add `X` to tracker. +- **Slug = folder = key = branch suffix.** They MUST match. `docs/features/foo/` + tracker key `foo` + branch `feature/foo`. +- **`npm run validate:tracker`** catches orphan folders (in `docs/features/` but not in tracker) and missing plan files. +- **On-the-fly plans** still need a tracker entry with status `DRAFT` or `IN_PROGRESS` — you can skip the plan.md file by setting `planFile: null`, but the entry MUST exist. + diff --git a/ai-docs/ARCHITECTURE.md b/ai-docs/ARCHITECTURE.md index 403d174..0c5d5f8 100644 --- a/ai-docs/ARCHITECTURE.md +++ b/ai-docs/ARCHITECTURE.md @@ -857,4 +857,4 @@ For exploratory testing, the AI QA agent uses MCP Electron tools to interact wit - Reads console logs for error detection - Follows natural language test scenarios in `tests/qa-scenarios/` -See `docs/plans/2026-02-14-test-suite-design.md` for the full testing strategy. +See the test suite design document for the full testing strategy. diff --git a/ai-docs/CODEBASE-GUARDIAN.md b/ai-docs/CODEBASE-GUARDIAN.md index 3dcd16a..9928309 100644 --- a/ai-docs/CODEBASE-GUARDIAN.md +++ b/ai-docs/CODEBASE-GUARDIAN.md @@ -40,7 +40,7 @@ |------|----------|------| | `tracker.json` | `docs/tracker.json` | Single source of truth for plan status. MUST be updated when plans change status. | | `validate-tracker.mjs` | `scripts/validate-tracker.mjs` | Validation script — do not move. | -| Active plans | `docs/plans/` | Plans with status DRAFT, APPROVED, IN_PROGRESS, TRACKING | +| Active plans | `docs/features//plan.md` | Plans with status DRAFT, APPROVED, IN_PROGRESS, TRACKING | **Cleanup rules:** - Plans for features with status `IMPLEMENTED` that are older than 14 days should be deleted and their tracker entry removed diff --git a/ai-docs/FEATURES-INDEX.md b/ai-docs/FEATURES-INDEX.md index ecb6f30..111f5c8 100644 --- a/ai-docs/FEATURES-INDEX.md +++ b/ai-docs/FEATURES-INDEX.md @@ -615,7 +615,7 @@ npm run format # Prettier format ### File Organization -- **Plans**: `docs/plans/` — design docs for active and recently completed features +- **Plans**: `docs/features//plan.md` — design docs for active and recently completed features - **Tracker**: `docs/tracker.json` — single source of truth for plan status (v2 schema) --- diff --git a/ai-docs/TASK-PLANNING-PIPELINE.md b/ai-docs/TASK-PLANNING-PIPELINE.md index 2072cb4..7d853a0 100644 --- a/ai-docs/TASK-PLANNING-PIPELINE.md +++ b/ai-docs/TASK-PLANNING-PIPELINE.md @@ -33,7 +33,7 @@ Agent writes plan file → exits ▼ event-wiring.ts detects plan file │ ├── Scan log for PLAN_FILE: marker - │ └── Fallback: scan docs/plans/*-plan.md (most recent) + │ └── Fallback: scan docs/features/*/plan.md (most recent) │ ▼ taskRepository: planning → plan_ready (local + Hub mirror) @@ -164,7 +164,7 @@ Contract source: `src/shared/ipc/agents/contract.ts` When a planning-phase agent completes (exit code 0), `event-wiring.ts` runs `detectPlanFile()`: 1. **Strategy 1 — Log marker:** Scans the agent's log file (last line first) for `PLAN_FILE:`. The `/plan-feature` command is instructed to output this marker. -2. **Strategy 2 — Filesystem fallback:** Scans `docs/plans/` for files matching `*-plan.md`, sorted reverse-alphabetically (most recent first). +2. **Strategy 2 — Filesystem fallback:** Scans `docs/features/` for subdirectories containing `plan.md`, sorted reverse-alphabetically (most recent first). If found: - Reads the plan file content @@ -230,9 +230,9 @@ For Claude instances and developers working **on** the application: - `CODEBASE-GUARDIAN.md` — Structural rules - `user-interface-flow.md` — UX flow and gap analysis -### Runtime Docs (`.claude/commands/`, `docs/plans/`) +### Runtime Docs (`.claude/commands/`, `docs/features/`) Used **by** the application at runtime (Claude CLI reads these): - `.claude/commands/plan-feature.md` — Planning agent instructions - `.claude/commands/resume-feature.md` — Resume agent instructions - `.claude/commands/implement-feature.md` — Execution agent instructions -- `docs/plans/*-plan.md` — Generated plan files (output of planning agents) +- `docs/features//plan.md` — Generated plan files (output of planning agents) diff --git a/ai-docs/prompts/implementing-features/PROGRESS-FILE-TEMPLATE.md b/ai-docs/prompts/implementing-features/PROGRESS-FILE-TEMPLATE.md index ff7deaa..0ca19ce 100644 --- a/ai-docs/prompts/implementing-features/PROGRESS-FILE-TEMPLATE.md +++ b/ai-docs/prompts/implementing-features/PROGRESS-FILE-TEMPLATE.md @@ -11,7 +11,7 @@ **Team**: **Base Branch**: master **Feature Branch**: feature/ -**Design Doc**: docs/plans/.md +**Design Doc**: docs/features//plan.md **Started**: **Last Updated**: **Updated By**: diff --git a/ai-docs/prompts/implementing-features/README.md b/ai-docs/prompts/implementing-features/README.md index fc1610f..4ca0140 100644 --- a/ai-docs/prompts/implementing-features/README.md +++ b/ai-docs/prompts/implementing-features/README.md @@ -108,7 +108,7 @@ Progress is tracked via the team's TaskList and the `.claude/progress/` runtime **Status**: IN_PROGRESS | BLOCKED | QA_REVIEW | INTEGRATING | COMPLETE **Team**: **Branch**: feature/ -**Design Doc**: docs/plans/.md +**Design Doc**: docs/features//plan.md **Started**: **Last Updated**: diff --git a/docs/plans/2026-02-16-future-roadmap.md b/docs/features/future-roadmap/plan.md similarity index 100% rename from docs/plans/2026-02-16-future-roadmap.md rename to docs/features/future-roadmap/plan.md diff --git a/docs/plans/2026-02-16-codebase-separation-of-concerns-design.md b/docs/features/separation-of-concerns/plan.md similarity index 100% rename from docs/plans/2026-02-16-codebase-separation-of-concerns-design.md rename to docs/features/separation-of-concerns/plan.md diff --git a/docs/tracker.json b/docs/tracker.json index 041b836..926fdfe 100644 --- a/docs/tracker.json +++ b/docs/tracker.json @@ -5,7 +5,7 @@ "future-roadmap": { "title": "Future Roadmap", "status": "TRACKING", - "planFile": "docs/plans/2026-02-16-future-roadmap.md", + "planFile": "docs/features/future-roadmap/plan.md", "created": "2026-02-16", "statusChangedAt": "2026-02-16", "branch": null, @@ -15,7 +15,7 @@ "separation-of-concerns": { "title": "Codebase Separation of Concerns", "status": "IMPLEMENTED", - "planFile": "docs/plans/2026-02-16-codebase-separation-of-concerns-design.md", + "planFile": "docs/features/separation-of-concerns/plan.md", "created": "2026-02-16", "statusChangedAt": "2026-02-19", "branch": null, diff --git a/scripts/check-docs.mjs b/scripts/check-docs.mjs index 8c36158..da57a8c 100644 --- a/scripts/check-docs.mjs +++ b/scripts/check-docs.mjs @@ -188,7 +188,7 @@ function isSrcFile(file) { function isDocFile(file) { return ( file.startsWith('ai-docs/') || - file.startsWith('docs/plans/') || + file.startsWith('docs/features/') || file.startsWith('.claude/agents/') || file === 'docs/tracker.json' || file === 'CLAUDE.md' diff --git a/scripts/validate-tracker.mjs b/scripts/validate-tracker.mjs index dd77b4d..54c4792 100644 --- a/scripts/validate-tracker.mjs +++ b/scripts/validate-tracker.mjs @@ -7,7 +7,7 @@ import { join, resolve } from 'node:path'; * 5 checks: * 1. Schema validation (required fields, valid status enum) * 2. File existence (planFile paths exist on disk) - * 3. Orphan detection (every .md in docs/plans/ is tracked) + * 3. Orphan detection (every folder in docs/features/ is tracked) * 4. Staleness warning (APPROVED entries older than 7 days) * 5. Archive candidates (IMPLEMENTED entries older than 14 days) * @@ -117,14 +117,15 @@ const entries = Object.entries(plans); } } - // Check docs/plans/ - const plansDir = join(ROOT, 'docs', 'plans'); - if (existsSync(plansDir)) { - const planFiles = readdirSync(plansDir).filter((f) => f.endsWith('.md')); - for (const file of planFiles) { - const relativePath = `docs/plans/${file}`; - if (!trackedFiles.has(relativePath)) { - console.warn(` WARN: Orphan plan file not tracked: ${relativePath}`); + // Check docs/features/ — each subfolder should have a matching tracker key + const featuresDir = join(ROOT, 'docs', 'features'); + if (existsSync(featuresDir)) { + const featureSlugs = readdirSync(featuresDir, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => d.name); + for (const slug of featureSlugs) { + if (!plans[slug]) { + console.warn(` WARN: Orphan feature folder not tracked: docs/features/${slug}/`); orphanCount++; } } diff --git a/src/main/bootstrap/event-wiring.ts b/src/main/bootstrap/event-wiring.ts index fcb8af8..fc80377 100644 --- a/src/main/bootstrap/event-wiring.ts +++ b/src/main/bootstrap/event-wiring.ts @@ -37,7 +37,7 @@ interface EventWiringDeps { * * Checks two locations in order: * 1. The agent's log file for a `PLAN_FILE:` output line - * 2. The `docs/plans/` directory for recently created `*-plan.md` files + * 2. The `docs/features/` directory for subdirectories containing `plan.md` * * Returns `{ filePath, content }` or `null` if no plan file found. */ @@ -67,18 +67,23 @@ function detectPlanFile( // Log may be gone if cleanup ran first — continue to fallback } - // Strategy 2: Scan docs/plans/ for *-plan.md files (most recent first) - const plansDir = join(projectPath, 'docs', 'plans'); + // Strategy 2: Scan docs/features/ for subdirectories containing plan.md (most recent first) + const featuresDir = join(projectPath, 'docs', 'features'); try { - if (existsSync(plansDir)) { - const planFiles = readdirSync(plansDir) - .filter((f) => f.endsWith('-plan.md')) + if (existsSync(featuresDir)) { + const featureDirs = readdirSync(featuresDir, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => d.name) .sort() .reverse(); - if (planFiles.length > 0) { - const filePath = `docs/plans/${planFiles[0]}`; - const fullPath = join(plansDir, planFiles[0]); + const dirWithPlan = featureDirs.find((d) => + existsSync(join(featuresDir, d, 'plan.md')), + ); + + if (dirWithPlan) { + const filePath = `docs/features/${dirWithPlan}/plan.md`; + const fullPath = join(featuresDir, dirWithPlan, 'plan.md'); return { filePath, content: readFileSync(fullPath, 'utf-8'),