@sallmarta/eye-hate-agent 1.0.4 → 1.0.6

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.
package/README.md CHANGED
@@ -31,11 +31,14 @@ Once initialized, EHA projects a series of interactive workflows directly into y
31
31
 
32
32
  | Slash Trigger | Primary Purpose |
33
33
  | :--- | :--- |
34
- | **`/eha-bootstrap`** | Initializes the repository's SDD document set, generating a tailored 4-layer taxonomy (Lite, Standard, Enterprise). |
35
- | **`/eha-refresh`** | Re-aligns and updates the existing documentation set when project scope, stack, or directory layouts shift. |
36
- | **`/eha-parity`** | Audits the repository to check for document drift, stale headings, structural errors, and ownership mismatches. |
37
- | **`/sdd-discuss`** | Initiates collaborative scoping and brainstorming sessions to align intent and draft specs before writing code. |
38
- | **`/sdd-execute`** | Spec-Driven Development execution—translates agreed specifications into robust, verified, and tested code. |
34
+ | **`/eha-bootstrap`** | Initializes the SDD document set for repos with **no existing documentation**. Scans codebase complexity, asks for a Taxonomy Tier (Lite/Standard/Enterprise), generates the tailored doc set. Stops and redirects to Refresh if existing docs or legacy docs are detected. |
35
+ | **`/eha-refresh`** | The main workhorse for repos with **any existing documentation**. Updates active SDD docs, migrates legacy docs, converts non-SDD docs, and creates missing SDD files — all by cross-referencing the actual codebase alongside existing material. Auto-detects the appropriate Taxonomy Tier for migration scenarios. Prompts the user to resolve any drift between codebase and docs. |
36
+ | **`/sdd-discuss`** | Collaborative brainstorming. Interviews you about edge cases, API shapes, data models, and constraints, then drafts spec snippets ready for injection into project docs. No code output. |
37
+ | **`/sdd-execute`** | Spec-Driven code generation via strict TDD. Reads specs generates tests generates code → validates against architecture. Refuses to code features not in the spec. |
38
+
39
+ > **Looking for parity audits?** Use the `parity-audit` skill directly:
40
+ > `@agent use parity-audit on this repository`
41
+ > This provides a full drift analysis without needing a dedicated command.
39
42
 
40
43
  ---
41
44
 
@@ -48,7 +51,7 @@ The EHA CLI provides a lightweight, frictionless setup and maintenance toolbelt:
48
51
  | `eha init` (or `npx...`) | Automatically scans your repo root, lets you choose your target AI agent, and projects standard rules/skills. |
49
52
  | `eha init <agent>` | Directly initiates the EHA project setup for a specific agent (e.g. `copilot`, `claude`, `antigravity`) |
50
53
  | `eha doctor` | Performs a health check verifying that all projected rules, stubs, and workflows are present and intact. |
51
- | `eha remove` | Safely deletes EHA's configuration directories, manifest registries, and generated contract files from your repository. |
54
+ | `eha remove [agent]` | Safely deletes EHA's generated contract files for the specified agent (or all agents if omitted), along with configuration files. |
52
55
 
53
56
  ---
54
57
 
@@ -67,9 +70,9 @@ in your repository. The engine will detect the version mismatch automatically, p
67
70
  To completely remove EHA from your project and device:
68
71
 
69
72
  ### 1. Remove project files
70
- Run the following command in your project root to clean up all projected AI files:
73
+ To clean up projected AI files, run the following command in your project root. You can optionally specify a target agent (e.g. `claude`, `copilot`, `antigravity`) to remove only that agent's files while preserving other active installations:
71
74
  ```bash
72
- $ eha remove
75
+ $ eha remove [agent]
73
76
  ```
74
77
 
75
78
  ### 2. Uninstall the CLI globally
package/bin/eha.js CHANGED
@@ -24,22 +24,34 @@ const pkg = require('../package.json');
24
24
  async function promptAgentChoice(currentAgent) {
25
25
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
26
26
  try {
27
- const defaultLabel = currentAgent || SUPPORTED_AGENT_IDS[0];
27
+ const runtimes = listSupportedRuntimes();
28
+ const defaultIndex = currentAgent
29
+ ? runtimes.findIndex(r => r.id === currentAgent) + 1
30
+ : 1;
31
+
32
+ console.log('');
33
+ console.log('Which agent?');
34
+ for (let i = 0; i < runtimes.length; i++) {
35
+ console.log(` ${i + 1}. ${runtimes[i].name}`);
36
+ }
37
+
28
38
  const answer = await rl.question(
29
- `Which agent? [${SUPPORTED_AGENT_IDS.join('/')}] (default: ${defaultLabel}): `,
39
+ `Choose [1-${runtimes.length}] (default: ${defaultIndex}): `,
30
40
  );
31
- const normalized = answer.trim().toLowerCase();
32
- return normalized || defaultLabel;
33
- } finally {
34
- rl.close();
35
- }
36
- }
41
+ const trimmed = answer.trim();
37
42
 
38
- async function promptOverwriteOrDiscard(message) {
39
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
40
- try {
41
- const answer = await rl.question(`${message} [O]verwrite / [D]iscard (default: D): `);
42
- return answer.trim().toLowerCase() === 'o';
43
+ // Accept number or name
44
+ if (!trimmed) return runtimes[defaultIndex - 1].id;
45
+
46
+ const num = parseInt(trimmed, 10);
47
+ if (num >= 1 && num <= runtimes.length) return runtimes[num - 1].id;
48
+
49
+ // Fallback: try to match by name (backward compat)
50
+ const normalized = trimmed.toLowerCase();
51
+ const match = runtimes.find(r => r.id === normalized);
52
+ if (match) return match.id;
53
+
54
+ return trimmed.toLowerCase(); // Let it fall through
43
55
  } finally {
44
56
  rl.close();
45
57
  }
@@ -101,7 +113,11 @@ function printDoctorSummary(result) {
101
113
  console.log(chalk.blue('EHA doctor'));
102
114
  console.log(` Root : ${result.rootDir}`);
103
115
  console.log(` Config : ${result.paths.configPath}`);
104
- console.log(` Agent : ${result.agentId ? chalk.cyan(result.agentId) : chalk.yellow('not set — run eha init')}`);
116
+ const agents = result.config.agents || (result.config.agent ? [result.config.agent] : []);
117
+ const agentDisplay = agents.length > 0
118
+ ? agents.map(a => chalk.cyan(a)).join(', ')
119
+ : chalk.yellow('not set — run eha init');
120
+ console.log(` Agents : ${agentDisplay}`);
105
121
  console.log('');
106
122
 
107
123
  if (!result.isInitialized) {
@@ -128,60 +144,60 @@ function printDoctorSummary(result) {
128
144
  async function runInitWizard(agentIdArg) {
129
145
  const rootDir = resolveRootDir();
130
146
  const config = readConfig(rootDir);
147
+ const manifest = readProjectManifest(rootDir);
131
148
 
132
149
  let agentId = agentIdArg ? String(agentIdArg).trim().toLowerCase() : null;
150
+ const isInteractive = process.stdin.isTTY && process.stdout.isTTY;
133
151
 
134
152
  if (!agentId) {
135
- if (config.agent) {
136
- const manifest = readProjectManifest(rootDir);
137
- if (manifest.packageVersion !== pkg.version && process.stdin.isTTY && process.stdout.isTTY) {
138
- const regenerate = await promptConfirm(
139
- `EHA files were generated by v${manifest.packageVersion ?? 'unknown'}, current is v${pkg.version}. Regenerate?`,
140
- true,
141
- );
142
- if (!regenerate) {
143
- console.log('Skipped.');
144
- return;
145
- }
146
- const result = initProject({ rootDir, agentId: config.agent });
147
- printInitSummary(result);
148
- return;
149
- }
150
- if (process.stdin.isTTY && process.stdout.isTTY) {
151
- const overwrite = await promptOverwriteOrDiscard(
152
- `EHA already set up (agent: ${chalk.cyan(config.agent)}).`,
153
- );
154
- if (!overwrite) {
155
- console.log('Discarded.');
156
- return;
157
- }
158
- }
159
- }
160
-
161
- if (process.stdin.isTTY && process.stdout.isTTY) {
153
+ if (isInteractive) {
162
154
  agentId = await promptAgentChoice(config.agent);
163
155
  } else {
164
156
  agentId = config.agent || SUPPORTED_AGENT_IDS[0];
165
157
  }
166
- } else if (config.agent && config.agent !== agentId) {
167
- if (process.stdin.isTTY && process.stdout.isTTY) {
168
- const overwrite = await promptOverwriteOrDiscard(
169
- `EHA already set up (agent: ${chalk.cyan(config.agent)}). Switch to ${chalk.cyan(agentId)}?`,
170
- );
171
- if (!overwrite) {
172
- console.log('Discarded.');
173
- return;
174
- }
175
- }
176
158
  }
177
159
 
178
- if (!SUPPORTED_AGENT_IDS.includes(agentId)) {
160
+ const normalized = String(agentId).trim().toLowerCase();
161
+ if (!SUPPORTED_AGENT_IDS.includes(normalized)) {
162
+ const runtimes = listSupportedRuntimes();
163
+ const list = runtimes.map((r, i) => `${i + 1}. ${r.name}`).join(', ');
179
164
  console.error(
180
- chalk.red(`Unsupported agent: ${agentId}.`) +
181
- ` Choose one of: ${SUPPORTED_AGENT_IDS.join(', ')}.`,
165
+ chalk.red(`Unsupported agent: ${agentIdArg || agentId}.`) +
166
+ ` Choose one of: ${list}.`,
182
167
  );
183
168
  process.exit(1);
184
169
  }
170
+ agentId = normalized;
171
+
172
+ const installedAgents = config.agents || (config.agent ? [config.agent] : []);
173
+ const isAlreadyInstalled = installedAgents.includes(agentId);
174
+
175
+ if (isInteractive) {
176
+ if (isAlreadyInstalled) {
177
+ const currentVer = manifest.packageVersion || 'unknown';
178
+ let msg = '';
179
+ if (currentVer !== pkg.version) {
180
+ msg = `EHA is already set up for ${chalk.cyan(agentId)} (v${currentVer}). Regenerate with v${pkg.version}?`;
181
+ } else {
182
+ msg = `EHA is already set up for ${chalk.cyan(agentId)}. Regenerate/overwrite?`;
183
+ }
184
+ const confirm = await promptConfirm(msg, true);
185
+ if (!confirm) {
186
+ console.log('Skipped.');
187
+ return;
188
+ }
189
+ } else if (installedAgents.length > 0) {
190
+ const listStr = installedAgents.map(a => chalk.cyan(a)).join(', ');
191
+ const confirm = await promptConfirm(
192
+ `EHA is set up for: ${listStr}. Add ${chalk.cyan(agentId)}?`,
193
+ true,
194
+ );
195
+ if (!confirm) {
196
+ console.log('Skipped.');
197
+ return;
198
+ }
199
+ }
200
+ }
185
201
 
186
202
  const result = initProject({ rootDir, agentId });
187
203
  printInitSummary(result);
@@ -204,34 +220,64 @@ program
204
220
  });
205
221
 
206
222
  program
207
- .command('remove')
208
- .description('Remove EHA-generated files and config from this project')
209
- .action(async () => {
223
+ .command('remove [agent]')
224
+ .description('Remove EHA-generated files and config from this project (optionally for a specific agent)')
225
+ .action(async (agentArg) => {
210
226
  const rootDir = resolveRootDir();
211
227
  const config = readConfig(rootDir);
228
+ const installedAgents = config.agents || (config.agent ? [config.agent] : []);
212
229
 
213
- if (!config.agent) {
230
+ if (installedAgents.length === 0) {
214
231
  console.log(chalk.yellow('EHA is not initialized here. Nothing to remove.'));
215
232
  return;
216
233
  }
217
234
 
218
- if (process.stdin.isTTY && process.stdout.isTTY) {
219
- const confirmed = await promptConfirm(
220
- `Remove EHA (agent: ${chalk.cyan(config.agent)}) from this project?`,
221
- );
222
- if (!confirmed) {
223
- console.log('Aborted.');
235
+ let targetAgent = agentArg ? String(agentArg).trim().toLowerCase() : null;
236
+
237
+ if (targetAgent) {
238
+ if (!installedAgents.includes(targetAgent)) {
239
+ console.log(chalk.yellow(`Agent ${chalk.cyan(targetAgent)} is not currently set up in this project.`));
224
240
  return;
225
241
  }
226
- }
227
242
 
228
- const result = removeProject({ rootDir });
229
- console.log('');
230
- console.log(chalk.green('✓ EHA removed.'));
231
- for (const f of result.removedFiles) {
232
- console.log(` ${chalk.gray(f)}`);
243
+ if (process.stdin.isTTY && process.stdout.isTTY) {
244
+ const confirmed = await promptConfirm(
245
+ `Remove EHA for agent: ${chalk.cyan(targetAgent)} from this project?`,
246
+ true,
247
+ );
248
+ if (!confirmed) {
249
+ console.log('Aborted.');
250
+ return;
251
+ }
252
+ }
253
+
254
+ const result = removeProject({ rootDir, agentId: targetAgent });
255
+ console.log('');
256
+ console.log(chalk.green(`✓ EHA files for ${chalk.cyan(targetAgent)} removed.`));
257
+ for (const f of result.removedFiles) {
258
+ console.log(` ${chalk.gray(f)}`);
259
+ }
260
+ console.log('');
261
+ } else {
262
+ if (process.stdin.isTTY && process.stdout.isTTY) {
263
+ const listStr = installedAgents.map(a => chalk.cyan(a)).join(', ');
264
+ const confirmed = await promptConfirm(
265
+ `Remove EHA (all agents: ${listStr}) from this project?`,
266
+ );
267
+ if (!confirmed) {
268
+ console.log('Aborted.');
269
+ return;
270
+ }
271
+ }
272
+
273
+ const result = removeProject({ rootDir });
274
+ console.log('');
275
+ console.log(chalk.green('✓ EHA removed.'));
276
+ for (const f of result.removedFiles) {
277
+ console.log(` ${chalk.gray(f)}`);
278
+ }
279
+ console.log('');
233
280
  }
234
- console.log('');
235
281
  });
236
282
 
237
283
  program
@@ -3,8 +3,28 @@
3
3
  Generate the **initial project documentation set** for a repository.
4
4
  You must dynamically adjust your behavior based on the current state of the repository.
5
5
 
6
- ## Step 1: State & Complexity Detection (The Adaptive Taxonomy)
7
- Before writing any documents, analyze the workspace to determine its state (Zero Docs vs. Unclear Docs vs. Mature Docs) and its complexity.
6
+ ## Step 0: Pre-Flight Check
7
+
8
+ Before analyzing complexity, scan the repository for existing documentation:
9
+
10
+ 1. Check for `docs/project-docs/` with any content.
11
+ 2. Check for `docs-legacy/`, `docs-old/`, `archive/`, or `reference/` folders with content.
12
+ 3. Check for any `docs/` folder containing structured markdown beyond a bare root README.
13
+
14
+ **If ANY of the above exist:**
15
+ STOP. Do not proceed with bootstrap. Inform the user:
16
+
17
+ "I found existing documentation in this repository:
18
+ - [list what was found]
19
+
20
+ Bootstrap is for repos with no documentation. For repos with existing docs (even legacy or non-SDD format), use the **Refresh** workflow instead — it can migrate, update, and create SDD docs from your existing content combined with codebase analysis.
21
+
22
+ Should I switch to the Refresh workflow?"
23
+
24
+ **If NONE exist (only code and/or a bare root README):** Proceed to Step 1.
25
+
26
+ ## Step 1: Complexity Detection (The Adaptive Taxonomy)
27
+ Analyze the workspace to determine its complexity by inspecting the codebase.
8
28
 
9
29
  Based on the repository's complexity, you MUST recommend one of the following **Taxonomy Tiers**:
10
30
 
@@ -37,4 +57,4 @@ Before finishing, check that:
37
57
  3. The generated documents strictly match the approved Taxonomy Tier and structural definitions cataloged in the master registry.
38
58
 
39
59
  ## Inputs
40
- Use the project brief, codebase, and constraints provided below to begin your Phase 1 analysis.
60
+ Use the project brief, codebase, and constraints provided below to begin your analysis.
@@ -1,10 +1,33 @@
1
1
  # Project Docs Refresh Reusable Prompt
2
2
 
3
- Refresh the existing project documentation after a change in scope, stack, workflow, architecture, testing policy, or product behavior.
3
+ Refresh, migrate, or create project documentation by combining the **codebase** and any **existing documentation** (active SDD docs, legacy docs, or non-SDD markdown).
4
4
 
5
5
  ## Goal
6
6
 
7
- Update **only the docs that own the changed information** while keeping the documentation set consistent.
7
+ Update **only the docs that own the changed information** while keeping the documentation set consistent. When creating docs for the first time from existing material, combine codebase evidence with legacy/existing content to produce accurate SDD-compliant documentation.
8
+
9
+ ## Step 0: Doc State Detection
10
+
11
+ Before refreshing, classify the repository's documentation state:
12
+
13
+ | State | Condition | Action Path |
14
+ |:---|:---|:---|
15
+ | **Active SDD** | `docs/project-docs/` exists with SDD-format files (stable headings, 4-layer taxonomy) | Standard refresh: update owning docs, sync dependents |
16
+ | **Legacy Only** | `docs-legacy/`, `docs-old/`, `archive/`, or `reference/` exist, but no `docs/project-docs/` | Migration refresh: create SDD docs from legacy content + codebase |
17
+ | **Non-SDD Docs** | `docs/` exists with unstructured markdown (no stable headings, no taxonomy) | Conversion refresh: treat as legacy input, create SDD docs from content + codebase |
18
+ | **Mixed** | `docs/project-docs/` exists AND legacy/reference folders also exist | Hybrid refresh: update active SDD docs + migrate unmapped legacy content + codebase |
19
+
20
+ For **Legacy Only** and **Non-SDD Docs** states, auto-detect the Taxonomy Tier:
21
+ - Examine the breadth and depth of the existing documentation + codebase complexity.
22
+ - If content covers only core concerns (identity, architecture, status) → Tier 1 (Lite).
23
+ - If content includes testing, API, database, or CI/CD concerns → Tier 2 (Standard).
24
+ - If content includes governance, security, compliance, observability, i18n → Tier 3 (Enterprise).
25
+ - When uncertain, choose the lower tier and note what would trigger upgrade.
26
+ - State the auto-detected tier in your output so the user can override it if needed.
27
+
28
+ **Dynamic Generation from Registry:** You MUST read the master registry file `docs/templates/project-docs-template/index.md` to obtain the universal stable headings schema and the unique domain-specific headings for each document type within the detected or applicable tier. Generate each document dynamically using this structural mapping.
29
+
30
+ Proceed to the applicable action path.
8
31
 
9
32
  ## Required Behavior
10
33
 
@@ -19,30 +42,48 @@ Update **only the docs that own the changed information** while keeping the docu
19
42
  9. If the change affects an optional regular doc or its metadata, update `docs/project-docs/index.md` when present.
20
43
  10. If the change affects domain-specific technical guidance, update the owning guideline and `technical-guidelines/index.md` when present.
21
44
  11. When legacy or reference docs are being mapped into the active owner-doc set, classify them by the durable concern they govern rather than by the legacy folder or filename; legacy names are hints only.
22
- 12. Normalize non-standard legacy labels by meaning when they map cleanly to an active owner. For example, `epic`, `milestone`, or `roadmap` material may map to `docs/project-docs/foundation/phases/`, while `protocol`, `procedure`, `policy`, or `standard` material may map to `docs/project-docs/technical-guidelines/` when the content is domain-specific technical guidance.
45
+ 12. Normalize non-standard legacy labels by meaning when they map cleanly to an active owner. For example, `epic`, `milestone`, or `roadmap` material may map to `docs/project-docs/foundation/phases.md`, while `protocol`, `procedure`, `policy`, or `standard` material may map to `docs/project-docs/technical-guidelines/` when the content is domain-specific technical guidance.
23
46
  13. When legacy or reference docs show that a justified optional doc should become active under `docs/project-docs/`, promote it into the active owner-doc set instead of leaving it stranded in reference-only folders.
24
47
  14. When legacy or reference docs contain domain-specific technical guidance that is still valid, create or update the relevant files under `docs/project-docs/technical-guidelines/` and create `technical-guidelines/index.md` when any guideline becomes active.
25
- 15. When legacy or reference docs contain explicit phased planning, epic tracking, or execution-map detail that should stay active, create or update the relevant files under `docs/project-docs/foundation/phases/`, including `foundation/phases/index.md`, and register the active optional doc in `docs/project-docs/index.md`.
48
+ 15. When legacy or reference docs contain explicit phased planning, epic tracking, or execution-map detail that should stay active, create or update `docs/project-docs/foundation/phases.md` and register the active optional doc in `docs/project-docs/index.md`.
26
49
  16. If a legacy artifact could plausibly map to more than one active owner, or if preserving the legacy label may be intentional, ask the user for direction instead of guessing.
27
50
  17. Preserve valuable legacy sections (e.g., 'Decision Rationale') that do not exist in the starter templates. Decide whether this information belongs as a new custom section in an existing document or warrants a new separate file entirely. Ask the user if the best approach is ambiguous. Do not discard domain-specific knowledge just because it lacks a standard template heading.
28
51
  18. When asking for that direction, prefer a concise question that states the inferred owner and the fallback choices. Example: `I found legacy "protocol" docs that look like technical guidance. Should I 1. skip them, 2. migrate them into active guideline docs, or 3. preserve "protocol" as a project-specific doc type?`
29
- 19. When docs are being created for the first time against an existing codebase with no prior documentation, inspect code, comments, configs, tests, and repository structure for valuable domain knowledge that goes beyond standard template headings. Surface these findings as new custom sections or new files where justified. Mark codebase-inferred facts as `Inferred from code` or `Open Question` until the user confirms them.
52
+ 19. When docs are being created for the first time against an existing codebase with no prior documentation, inspect code, comments, configs, tests, and repository structure for valuable domain knowledge that goes beyond standard template headings. Surface these findings as new custom sections or new files where justified. Mark codebase-inferred facts as `Inferred from codebase` or `Open Question` until the user confirms them.
53
+ 20. **Always cross-reference the codebase.** When creating or updating any SDD document, inspect the relevant source code, configs, tests, package manifests, CI/CD pipelines, and runtime artifacts to verify and enrich the documentation. Do not rely solely on existing docs or legacy material — the codebase is evidence.
54
+ 21. **When codebase evidence contradicts existing documentation or legacy material, do NOT silently choose one side.** Instead, prompt the user with a concise question and option selection. Example: `I found a drift between the codebase and the docs: [describe the conflict]. Which is correct? 1. The codebase (update the docs to match), 2. The docs (flag the code as needing a fix), or 3. Both are intentionally different (document the exception).` Always present at least these three options. Do not proceed until the user resolves the conflict.
55
+ 22. When creating SDD docs from legacy + codebase, actively mine:
56
+ - `package.json` / dependency manifests → architecture, stack, testing frameworks
57
+ - CI/CD configs (`.github/workflows/`, `Dockerfile`, etc.) → operations/ci-cd
58
+ - Test directories and test runners → development/testing
59
+ - Database schemas, migrations, ORM configs → development/database
60
+ - API route definitions, controllers, middleware → development/api-contract
61
+ - Environment variables, secrets management → operations/production-runbook
62
+ - Error handling patterns, logging setup → operations/observability-error-handling
63
+ - Auth/RBAC implementations → operations/security-compliance
64
+ - i18n config, locale files → development/internationalization
65
+ - README, inline comments, decision rationale → foundation/prd, architecture
66
+ 23. Mark all codebase-inferred facts as `Inferred from codebase` until the user confirms them.
30
67
 
31
68
  ### Review Sequence
32
69
 
33
- 1. Read the change summary.
34
- 2. Read the owning project docs.
35
- 3. Read `docs/project-docs/index.md` and `docs/project-docs/technical-guidelines/index.md` when present.
36
- 4. Read clearly named reference or archive folders such as `docs-legacy/`, `docs-old/`, `archive/`, or `reference/` when the repo is migrating from another documentation format.
37
- 5. Decide whether any legacy material should be promoted into active optional docs such as `technical-guidelines/` or `foundation/phases/` instead of staying reference-only, using content and governed concern as the primary signal rather than legacy names.
38
- 6. Read the relevant guideline docs when the change touches technical rules or implementation conventions.
39
- 7. Identify impacted dependent docs.
40
- 8. Refresh the owning docs first.
41
- 9. Refresh summary or index docs second.
42
- 10. Run a consistency pass.
70
+ 1. Run Step 0 (Doc State Detection).
71
+ 2. Read the change summary (if provided) or the user's intent.
72
+ 3. **Scan the codebase** — inspect source code, configs, tests, CI/CD pipelines, and package manifests for current truth. This step is NOT optional.
73
+ 4. Read the owning project docs (if Active SDD or Mixed state).
74
+ 5. Read `docs/project-docs/index.md` and `docs/project-docs/technical-guidelines/index.md` when present.
75
+ 6. Read legacy/reference folders when present.
76
+ 7. Read relevant guideline docs when the change touches technical rules.
77
+ 8. Identify impacted dependent docs.
78
+ 9. Cross-reference codebase findings against doc/legacy claims — resolve conflicts by prompting the user (see rule 21).
79
+ 10. Refresh/create the owning docs first (using combined codebase + docs evidence).
80
+ 11. Refresh summary or index docs second.
81
+ 12. Run a consistency pass.
43
82
 
44
83
  ## Ownership Examples
45
84
 
85
+ For each mapping below, also inspect the corresponding codebase artifacts (source files, configs, tests) to verify and enrich the documentation.
86
+
46
87
  - stack or dependency changes → `foundation/architecture.md`, `development/testing.md`
47
88
  - feature scope changes → `foundation/prd.md`, `foundation/status.md`
48
89
  - detailed requirements or acceptance changes → `foundation/prd.md`, `foundation/status.md`
@@ -63,10 +104,12 @@ Update **only the docs that own the changed information** while keeping the docu
63
104
 
64
105
  Your result should state:
65
106
 
66
- 1. which docs were updated
67
- 2. why each doc was updated
107
+ 1. which docs were updated or created
108
+ 2. why each doc was updated or created
68
109
  3. which docs were intentionally left unchanged
69
110
  4. any remaining consistency risks or open questions
111
+ 5. which codebase-vs-doc conflicts were resolved and how (per user direction)
112
+ 6. the auto-detected tier (for Legacy Only / Non-SDD states), if applicable
70
113
 
71
114
  ## Final Pass
72
115
 
@@ -75,7 +118,9 @@ Before finishing, check that:
75
118
  1. the updated docs still match the EHA Project Doc Rules above
76
119
  2. platform instruction surfaces and skills would now read the correct project-specific truth
77
120
  3. no stale summary remains in `foundation/status.md`, `docs/project-docs/index.md`, `technical-guidelines/index.md`, or other index docs
121
+ 4. codebase-inferred facts are clearly marked and do not silently override user-confirmed truths
122
+ 5. the auto-detected tier (for Legacy Only / Non-SDD states) is stated in the output so the user can override it if needed
78
123
 
79
124
  ## Inputs
80
125
 
81
- Use the change summary, affected artifacts, and current project docs provided below.
126
+ Use the change summary, affected artifacts, current project docs, legacy/reference docs, AND the current codebase (source code, configs, tests, CI/CD, package manifests) provided below.
@@ -8,7 +8,7 @@ argument-hint: "Describe the scope to audit: full repository, docs only, reusabl
8
8
 
9
9
  Performs an expert repository-wide drift audit to find contradictions, stale summaries, duplicated ownership, code-vs-doc authority conflicts, and historical artifacts that should be classified rather than confused with active truth.
10
10
 
11
- This skill is the reusable complement to the parity reusable prompt. Use it when the task is analytical rather than generative.
11
+ This skill is the dedicated parity audit capability for the EHA system. Use it when the task is analytical rather than generative.
12
12
 
13
13
  ## Required Project Inputs
14
14
 
@@ -33,17 +33,33 @@ This skill is the reusable complement to the parity reusable prompt. Use it when
33
33
  | Template maintenance | "Audit platform instruction surfaces and skills after changing the contract" |
34
34
  | Handoff preparation | "Find contradictions before handing this repo to another maintainer" |
35
35
 
36
- Check for disagreement across:
36
+ ## Scope
37
+
38
+ Check at least these areas when present:
39
+
40
+ - `docs/project-docs/`
41
+ - `docs/project-docs/index.md`
42
+ - `docs/project-docs/technical-guidelines/`
43
+ - relevant code, tests, configs, or runtime-facing artifacts when a finding depends on current implementation behavior or source-of-truth ownership
44
+ - clearly named reference or archive folders such as `docs-legacy/`, `docs-old/`, `archive/`, or `reference/`
45
+ - platform instruction surfaces (mirrored rule files)
46
+ - skills and reusable prompts
47
+ - workflow docs and handoff docs
48
+
49
+ ### High-Value Drift Categories
37
50
 
38
- - project identity and naming
39
51
  - stack and dependency choices
40
- - architecture and dependency rules
41
52
  - test commands and quality gates
42
- - roadmap, phase, or epic naming
43
- - API or integration ownership
44
- - reusable prompt outputs vs project-doc contract
45
- - rule expectations vs documented workflow
46
- - active docs vs current code, tests, configs, or runtime-facing behavior when authority is disputed
53
+ - architecture and dependency rules
54
+ - optional and conditional regular-doc inventory mismatches
55
+ - API / integration ownership
56
+ - technical guideline ownership, overlap, and missing guideline index coverage
57
+ - semantic legacy-to-owner mapping mismatches where content is relevant but naming differs
58
+ - code-vs-doc authority mismatches where current implementation and active docs disagree
59
+ - workflow expectations
60
+ - roadmap / phase naming
61
+ - project identity and naming
62
+ - undocumented domain knowledge embedded in the codebase (e.g., decision rationale in comments, architectural constraints in configs, domain rules in validation logic) that should be surfaced into project docs
47
63
 
48
64
  ## Procedure
49
65
 
@@ -51,6 +67,10 @@ Check for disagreement across:
51
67
 
52
68
  Use the active EHA rules as the default source of truth for documentation ownership unless the repository explicitly states otherwise.
53
69
 
70
+ Treat `docs/project-docs/index.md` and `docs/project-docs/technical-guidelines/index.md` as the authoritative inventories for optional regular docs and guideline docs when present.
71
+
72
+ Treat clearly named reference or archive folders such as `docs-legacy/`, `docs-old/`, `archive/`, or `reference/` as migration input only, not as owner-doc paths.
73
+
54
74
  ### Step 2 — Compare dependent layers
55
75
 
56
76
  Compare the source-of-truth docs against:
@@ -64,6 +84,8 @@ Compare the source-of-truth docs against:
64
84
 
65
85
  If code and docs conflict and the repository does not explicitly define which side is authoritative for that fact, surface the conflict and ask the user before choosing the fix path.
66
86
 
87
+ When a repo is migrating from another documentation format, use those reference folders to map legacy topics into the correct owner docs under `docs/project-docs/`.
88
+
67
89
  ### Step 3 — Classify each mismatch
68
90
 
69
91
  Every mismatch should be classified as one of:
@@ -74,7 +96,20 @@ Every mismatch should be classified as one of:
74
96
  - historical artifact
75
97
  - optional module not active in the current repo
76
98
 
77
- ### Step 4 Assess impact
99
+ When evaluating legacy material, classify it by the durable concern it governs rather than by its legacy name or path. Treat names such as `epic`, `milestone`, `roadmap`, `protocol`, `procedure`, `policy`, or `standard` as hints only.
100
+
101
+ Report likely mappings when content points to an active owner even if naming differs, such as phased-planning content that should map to `foundation/phases.md` or technical-rule content that should map to `technical-guidelines/`.
102
+
103
+ ### Step 4 — Apply structural drift rules
104
+
105
+ Check for these specific structural drift conditions:
106
+
107
+ - A missing `docs/project-docs/index.md` when optional or conditional regular docs exist beyond the always-required core set.
108
+ - A missing `technical-guidelines/index.md` when guideline files exist.
109
+ - Registry entries without matching files and files without matching registry entries, unless the registry explicitly marks them deprecated or archived.
110
+ - A missing recommended guideline only when the repo already claims that domain is covered or the repo claims to be fully documented for that domain.
111
+
112
+ ### Step 5 — Assess impact
78
113
 
79
114
  Determine whether the mismatch affects:
80
115
 
@@ -85,10 +120,16 @@ Determine whether the mismatch affects:
85
120
  - release or verification confidence
86
121
  - authority certainty between docs and implementation
87
122
 
88
- ### Step 5 — Recommend ownership-level fixes
123
+ ### Step 6 — Recommend ownership-level fixes
89
124
 
90
125
  Recommend which owning file or layer should be updated. Do not spread the same fact across more files than necessary.
91
126
 
127
+ If a legacy artifact could plausibly map to more than one active owner, or if preserving the legacy label may be intentional, ask the user for direction instead of silently classifying it.
128
+
129
+ When asking for that direction, prefer a concise question that names the fact in conflict and the likely choices. Example: `I found a conflict between the code and the docs for the active API behavior. Should I treat 1. the code as correct and update the docs, 2. the docs as correct and treat the code as drift, or 3. mark this as an intentional temporary mismatch?`
130
+
131
+ If strong repository evidence already establishes the authority order for that fact, state that evidence explicitly instead of asking.
132
+
92
133
  ## Quality Check
93
134
 
94
135
  - Do not confuse reference material with active truth
@@ -96,6 +137,8 @@ Recommend which owning file or layer should be updated. Do not spread the same f
96
137
  - Distinguish blocking contradictions from harmless historical leftovers
97
138
  - Keep the audit actionable, not just descriptive
98
139
  - Do not assume docs or code win when authority for the disputed fact is not explicit
140
+ - Treat missing code evidence the same as missing doc evidence: reduce confidence, state the limitation, and avoid guessing
141
+ - Do not fix anything unless explicitly asked
99
142
 
100
143
  ## Anti-Pattern
101
144
 
@@ -114,9 +157,10 @@ For each finding, include:
114
157
  3. source-of-truth location
115
158
  4. conflicting location
116
159
  5. classification
117
- 6. why it matters
118
- 7. recommended owner to update
119
- 8. whether user direction is required before deciding the fix path
160
+ 6. whether the conflict is doc-vs-doc, code-vs-doc, or registry-vs-file
161
+ 7. why it matters
162
+ 8. recommended owner to update
163
+ 9. whether user direction is required before deciding the fix path
120
164
 
121
165
  End with:
122
166
  1. highest-priority drift items
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sallmarta/eye-hate-agent",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Template-and-engine toolkit for AI-agent-assisted project workflows.",
5
5
  "directories": {
6
6
  "doc": "docs"
@@ -16,13 +16,17 @@
16
16
  },
17
17
  "keywords": [
18
18
  "ai-agent",
19
- "agent-workflow",
20
- "cli",
19
+ "ai-assistant",
20
+ "coding-agent",
21
21
  "claude",
22
22
  "copilot",
23
- "project-docs",
23
+ "gemini",
24
+ "sdd",
25
+ "spec-driven",
26
+ "spec-driven-development",
24
27
  "prompt-engineering",
25
- "template"
28
+ "context-engineering ",
29
+ "meta-prompting"
26
30
  ],
27
31
  "author": "SallMarta",
28
32
  "license": "MIT",
@@ -49,4 +53,4 @@
49
53
  "commander": "^12.0.0",
50
54
  "chalk": "^4.1.2"
51
55
  }
52
- }
56
+ }
@@ -27,13 +27,40 @@ function resolveAgentId(agentId) {
27
27
  }
28
28
 
29
29
  function readManifest(manifestPath) {
30
- return (
31
- readJsonIfExists(manifestPath) || {
32
- manifestVersion: 1,
30
+ const data = readJsonIfExists(manifestPath);
31
+ if (!data) {
32
+ return {
33
+ manifestVersion: 2,
33
34
  agent: null,
35
+ agents: [],
34
36
  files: [],
35
- }
36
- );
37
+ };
38
+ }
39
+
40
+ const manifestVersion = data.manifestVersion || 1;
41
+ const agent = data.agent || null;
42
+ let agents = data.agents || [];
43
+ let files = data.files || [];
44
+
45
+ if (manifestVersion === 1 && agent && agents.length === 0) {
46
+ agents = [
47
+ {
48
+ id: agent,
49
+ files: [...files],
50
+ updatedAt: data.updatedAt || new Date().toISOString(),
51
+ packageVersion: data.packageVersion || EHA_PACKAGE_VERSION,
52
+ }
53
+ ];
54
+ }
55
+
56
+ return {
57
+ manifestVersion: 2,
58
+ agent,
59
+ agents,
60
+ files,
61
+ updatedAt: data.updatedAt,
62
+ packageVersion: data.packageVersion,
63
+ };
37
64
  }
38
65
 
39
66
  function initProject({ rootDir, agentId }) {
@@ -50,41 +77,134 @@ function initProject({ rootDir, agentId }) {
50
77
  }
51
78
 
52
79
  const enginePaths = getEnginePaths(rootDir);
80
+ const existingManifest = readManifest(enginePaths.manifestPath);
81
+ const existingAgents = existingManifest.agents || [];
82
+
83
+ const agentEntry = {
84
+ id: normalizedAgentId,
85
+ files: files.map((f) => f.relativePath),
86
+ updatedAt: new Date().toISOString(),
87
+ packageVersion: EHA_PACKAGE_VERSION,
88
+ };
89
+
90
+ const updatedAgents = existingAgents.filter((a) => a.id !== normalizedAgentId);
91
+ updatedAgents.push(agentEntry);
92
+
93
+ const allFiles = new Set();
94
+ for (const agent of updatedAgents) {
95
+ for (const f of agent.files || []) {
96
+ allFiles.add(f);
97
+ }
98
+ }
99
+
53
100
  const manifest = {
54
- manifestVersion: 1,
101
+ manifestVersion: 2,
55
102
  agent: normalizedAgentId,
56
- files: files.map((f) => f.relativePath),
103
+ agents: updatedAgents,
104
+ files: [...allFiles],
57
105
  updatedAt: new Date().toISOString(),
58
106
  packageVersion: EHA_PACKAGE_VERSION,
59
107
  };
60
108
  writeJson(enginePaths.manifestPath, manifest);
61
- const config = writeConfig(rootDir, { agent: normalizedAgentId });
109
+
110
+ const existingConfig = readConfig(rootDir);
111
+ const allAgents = [...new Set([...(existingConfig.agents || []), normalizedAgentId])];
112
+ const config = writeConfig(rootDir, { agent: normalizedAgentId, agents: allAgents });
62
113
 
63
114
  return {
64
115
  rootDir,
65
116
  agentId: normalizedAgentId,
66
117
  config,
67
- files: manifest.files,
118
+ files: files.map((f) => f.relativePath),
68
119
  fileCount: files.length,
69
120
  };
70
121
  }
71
122
 
72
- function removeProject({ rootDir }) {
123
+ function removeProject({ rootDir, agentId = null }) {
73
124
  const enginePaths = getEnginePaths(rootDir);
74
125
  const manifest = readManifest(enginePaths.manifestPath);
75
126
  const removedFiles = [];
76
127
 
77
- for (const relativePath of manifest.files || []) {
78
- const absolutePath = path.join(rootDir, relativePath);
79
- removeFileIfExists(absolutePath);
80
- removeEmptyParents(path.dirname(absolutePath), rootDir);
81
- removedFiles.push(relativePath);
82
- }
128
+ if (agentId) {
129
+ const normalizedAgentId = resolveAgentId(agentId);
130
+ const agentEntry = manifest.agents.find((a) => a.id === normalizedAgentId);
131
+ if (!agentEntry) {
132
+ return { rootDir, removedFiles };
133
+ }
134
+
135
+ const otherAgents = manifest.agents.filter((a) => a.id !== normalizedAgentId);
136
+ const otherFiles = new Set();
137
+ for (const other of otherAgents) {
138
+ for (const f of other.files || []) {
139
+ otherFiles.add(f);
140
+ }
141
+ }
142
+
143
+ const filesToRemove = (agentEntry.files || []).filter((f) => !otherFiles.has(f));
83
144
 
84
- removeFileIfExists(enginePaths.manifestPath);
85
- removeEmptyParents(path.dirname(enginePaths.manifestPath), rootDir);
86
- removeFileIfExists(enginePaths.configPath);
87
- removeEmptyParents(path.dirname(enginePaths.configPath), rootDir);
145
+ for (const relativePath of filesToRemove) {
146
+ const absolutePath = path.join(rootDir, relativePath);
147
+ removeFileIfExists(absolutePath);
148
+ removeEmptyParents(path.dirname(absolutePath), rootDir);
149
+ removedFiles.push(relativePath);
150
+ }
151
+
152
+ const remainingAgents = otherAgents;
153
+ if (remainingAgents.length === 0) {
154
+ removeFileIfExists(enginePaths.manifestPath);
155
+ removeEmptyParents(path.dirname(enginePaths.manifestPath), rootDir);
156
+ removeFileIfExists(enginePaths.configPath);
157
+ removeEmptyParents(path.dirname(enginePaths.configPath), rootDir);
158
+ } else {
159
+ const lastAgent = remainingAgents[remainingAgents.length - 1].id;
160
+ const allFiles = new Set();
161
+ for (const other of remainingAgents) {
162
+ for (const f of other.files || []) {
163
+ allFiles.add(f);
164
+ }
165
+ }
166
+
167
+ const updatedManifest = {
168
+ manifestVersion: 2,
169
+ agent: lastAgent,
170
+ agents: remainingAgents,
171
+ files: [...allFiles],
172
+ updatedAt: new Date().toISOString(),
173
+ packageVersion: EHA_PACKAGE_VERSION,
174
+ };
175
+ writeJson(enginePaths.manifestPath, updatedManifest);
176
+
177
+ writeConfig(rootDir, {
178
+ agent: lastAgent,
179
+ agents: remainingAgents.map((a) => a.id),
180
+ });
181
+ }
182
+ } else {
183
+ const allFiles = new Set();
184
+ if (manifest.agents && manifest.agents.length > 0) {
185
+ for (const agentEntry of manifest.agents) {
186
+ for (const f of agentEntry.files || []) {
187
+ allFiles.add(f);
188
+ }
189
+ }
190
+ } else {
191
+ for (const f of manifest.files || []) {
192
+ allFiles.add(f);
193
+ }
194
+ }
195
+
196
+ for (const relativePath of allFiles) {
197
+ const absolutePath = path.join(rootDir, relativePath);
198
+ removeFileIfExists(absolutePath);
199
+ removeEmptyParents(path.dirname(absolutePath), rootDir);
200
+ removedFiles.push(relativePath);
201
+ }
202
+
203
+ removeFileIfExists(enginePaths.manifestPath);
204
+ removeEmptyParents(path.dirname(enginePaths.manifestPath), rootDir);
205
+ removeFileIfExists(enginePaths.configPath);
206
+ removeEmptyParents(path.dirname(enginePaths.configPath), rootDir);
207
+ }
88
208
 
89
209
  return { rootDir, removedFiles };
90
210
  }
@@ -215,7 +215,7 @@ const RUNTIME_ADAPTERS = {
215
215
  }
216
216
  files.push({
217
217
  relativePath: path.join('.claude', 'commands', 'eha', 'README.md'),
218
- content: `# EHA Claude commands\n\nGenerated by \`eha init\`. Use \`/eha-bootstrap\`, \`/eha-refresh\`, \`/eha-parity\`, or \`/eha-discuss\` in Claude.\n`,
218
+ content: `# EHA Claude commands\n\nGenerated by \`eha init\`. Use \`/eha-bootstrap\`, \`/eha-refresh\`, \`/sdd-discuss\`, or \`/sdd-execute\` in Claude.\n`,
219
219
  });
220
220
 
221
221
  for (const skill of skills) {
@@ -268,7 +268,7 @@ const RUNTIME_ADAPTERS = {
268
268
  antigravity: {
269
269
  id: 'antigravity',
270
270
  name: 'Antigravity',
271
- description: 'Generates Antigravity-compatible skills in .agents/skills/',
271
+ description: 'Generates Antigravity-compatible skills in .agents/skills/ and rules in .agents/rules/',
272
272
  generateFiles(rootDir, workflows, skills) {
273
273
  const files = [];
274
274
  for (const workflow of workflows) {
@@ -290,7 +290,7 @@ const RUNTIME_ADAPTERS = {
290
290
  }
291
291
 
292
292
  files.push({
293
- relativePath: path.join('.agents', 'skills', 'eha-agent-rules', 'SKILL.md'),
293
+ relativePath: path.join('.agents', 'rules', 'eha-agent-rules.md'),
294
294
  content: buildAntigravityRuleFile(),
295
295
  });
296
296
 
@@ -3,8 +3,9 @@ const path = require('node:path');
3
3
 
4
4
  const ROOT_MARKERS = ['package.json', '.git'];
5
5
  const DEFAULT_CONFIG = {
6
- configVersion: 1,
6
+ configVersion: 2,
7
7
  agent: null,
8
+ agents: [],
8
9
  };
9
10
 
10
11
  function ensureDir(dirPath) {
@@ -72,9 +73,15 @@ function getEnginePaths(rootDir) {
72
73
 
73
74
  function normalizeConfig(config) {
74
75
  const candidate = config && typeof config === 'object' ? config : {};
76
+ const agent = candidate.agent ? String(candidate.agent).trim().toLowerCase() : null;
77
+ let agents = Array.isArray(candidate.agents) ? candidate.agents : [];
78
+ if (agent && agents.length === 0) {
79
+ agents = [agent];
80
+ }
75
81
  return {
76
- configVersion: Number.isInteger(candidate.configVersion) ? candidate.configVersion : DEFAULT_CONFIG.configVersion,
77
- agent: candidate.agent ? String(candidate.agent).trim().toLowerCase() : null,
82
+ configVersion: 2,
83
+ agent,
84
+ agents: [...new Set(agents)],
78
85
  };
79
86
  }
80
87
 
@@ -13,12 +13,6 @@ const WORKFLOW_DEFINITIONS = {
13
13
  description: 'Refresh project docs after a change in scope, stack, or behavior',
14
14
  repoRelativePath: path.join('docs', 'templates', 'reusable-prompts', '00-project-docs-refresh.md'),
15
15
  },
16
- parity: {
17
- id: 'parity',
18
- commandName: 'parity',
19
- description: 'Audit for documentation drift and ownership mismatches',
20
- repoRelativePath: path.join('docs', 'templates', 'reusable-prompts', '00-project-docs-parity.md'),
21
- },
22
16
  discuss: {
23
17
  id: 'discuss',
24
18
  commandName: 'discuss',
@@ -1,86 +0,0 @@
1
- # Project Docs Parity Reusable Prompt
2
-
3
- Audit the repository for **documentation-system drift**.
4
-
5
- ## Goal
6
-
7
- Find mismatches where project docs, platform instruction surfaces (mirrored rule files), skills, reusable prompts, workflow docs, quick-reference material, or relevant implementation evidence disagree about the same fact.
8
-
9
- ## Scope
10
-
11
- Check at least these areas when present:
12
-
13
- - `docs/project-docs/`
14
- - `docs/project-docs/index.md`
15
- - `docs/project-docs/technical-guidelines/`
16
- - relevant code, tests, configs, or runtime-facing artifacts when a finding depends on current implementation behavior or source-of-truth ownership
17
- - clearly named reference or archive folders such as `docs-legacy/`, `docs-old/`, `archive/`, or `reference/`
18
- - platform instruction surfaces (mirrored rule files)
19
- - `docs/templates/skills/`
20
- - `docs/templates/reusable-prompts/`
21
- - workflow docs and handoff docs
22
-
23
- ### High-Value Drift Categories
24
-
25
- - stack and dependency choices
26
- - test commands and quality gates
27
- - architecture and dependency rules
28
- - optional and conditional regular-doc inventory mismatches
29
- - API / integration ownership
30
- - technical guideline ownership, overlap, and missing guideline index coverage
31
- - semantic legacy-to-owner mapping mismatches where content is relevant but naming differs
32
- - code-vs-doc authority mismatches where current implementation and active docs disagree
33
- - workflow expectations
34
- - roadmap / phase naming
35
- - project identity and naming
36
- - undocumented domain knowledge embedded in the codebase (e.g., decision rationale in comments, architectural constraints in configs, domain rules in validation logic) that should be surfaced into project docs
37
-
38
- ## Required Behavior
39
-
40
- 1. Use project docs as the primary source of truth for documentation ownership and doc-to-doc drift unless the repository explicitly states otherwise.
41
- 2. Use the EHA Project Doc Rules above as the ownership map.
42
- 3. Treat `docs/project-docs/index.md` and `docs/project-docs/technical-guidelines/index.md` as the authoritative inventories for optional regular docs and guideline docs when present.
43
- 4. Treat clearly named reference or archive folders such as `docs-legacy/`, `docs-old/`, `archive/`, or `reference/` as migration input only, not as owner-doc paths.
44
- 5. When evaluating legacy material, classify it by the durable concern it governs rather than by its legacy name or path. Treat names such as `epic`, `milestone`, `roadmap`, `protocol`, `procedure`, `policy`, or `standard` as hints only.
45
- 6. Report likely mappings when content points to an active owner even if naming differs, such as phased-planning content that should map to `foundation/phases.md` or technical-rule content that should map to `technical-guidelines/`.
46
- 7. Distinguish between:
47
- - true contradiction
48
- - stale summary
49
- - historical artifact
50
- - optional module not currently active
51
- 8. When a repo is migrating from another documentation format, use those reference folders to map legacy topics into the correct owner docs under `docs/project-docs/`.
52
- 9. Treat a missing `docs/project-docs/index.md` as drift when optional or conditional regular docs exist beyond the always-required core set.
53
- 10. Treat a missing `technical-guidelines/index.md` as drift when guideline files exist.
54
- 11. Treat registry entries without matching files and files without matching registry entries as drift unless the registry explicitly marks them deprecated or archived.
55
- 12. Treat a missing recommended guideline as drift only when the repo already claims that domain is covered or the repo claims to be fully documented for that domain.
56
- 13. When a finding depends on whether the implementation or the documentation is authoritative, inspect the relevant code, tests, configs, or runtime-facing artifacts before classifying the issue.
57
- 14. If code and documentation conflict and the repository does not explicitly declare which source is authoritative for that fact, do not assume. Report the conflict and ask the user for direction before recommending a fix path.
58
- 15. If a legacy artifact could plausibly map to more than one active owner, or if preserving the legacy label may be intentional, ask the user for direction instead of silently classifying it.
59
- 16. When asking for that direction, prefer a concise question that names the fact in conflict and the likely choices. Example: `I found a conflict between the code and the docs for the active API behavior. Should I treat 1. the code as correct and update the docs, 2. the docs as correct and treat the code as drift, or 3. mark this as an intentional temporary mismatch?`
60
- 17. If strong repository evidence already establishes the authority order for that fact, state that evidence explicitly instead of asking.
61
- 18. Treat missing code evidence the same as missing doc evidence: reduce confidence, state the limitation, and avoid guessing.
62
- 19. Do not fix anything unless explicitly asked.
63
-
64
- ## Output Contract
65
-
66
- For each finding, include:
67
-
68
- - severity
69
- - fact in conflict
70
- - source-of-truth file
71
- - conflicting file
72
- - whether the conflict is doc-vs-doc, code-vs-doc, or registry-vs-file
73
- - why it matters
74
- - recommended owner to update
75
- - whether user direction is required before deciding the fix path
76
-
77
- ## Final Pass
78
-
79
- End with:
80
-
81
- 1. a short list of highest-priority drift items
82
- 2. a short list of acceptable historical artifacts that should not be treated as blockers
83
-
84
- ## Inputs
85
-
86
- Use the current repository docs, platform instruction surfaces, skills, reusable prompts, and any relevant workflow or summary artifacts available below.