@vibecompass/vibecompass 0.4.0 → 0.6.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ ## 0.6.0 - 2026-05-25
4
+
5
+ - Bump docs-review to `VibeCompass Docs Review Prompt v2`.
6
+ - Add a staged docs-review workflow: evidence inventory, coverage plan, bounded doc generation, and apply/verify.
7
+ - Add retrieval-oriented metadata expectations so generated architecture docs are useful future context without requiring broad token-heavy loads.
8
+ - Add soft `oversized_architecture_doc` warnings for accepted architecture docs over the 12000-byte budget.
9
+ - Include package-owned workflow registry files in the npm tarball.
10
+
11
+ ## 0.5.0
12
+
13
+ - Previous published release.
package/README.md CHANGED
@@ -20,7 +20,7 @@ Shipped today:
20
20
  - interactive guided init for placement, workflow bootstrap, and first-session setup
21
21
  - lightweight starter architecture/session memory plus example-only decision guidance
22
22
  - generated `context.md` plus opt-in workflow guide files
23
- - opt-in starter `CLAUDE.md` / `AGENTS.md` templates that are created once and never overwritten
23
+ - opt-in starter `CLAUDE.md` / `AGENTS.md` templates that are created only when missing, with VibeCompass-managed regions for future refreshes
24
24
  - `vibecompass start-session` / `vibecompass close-session` for lane-aware local builder workflow
25
25
  - `vibecompass list-sessions` / `vibecompass switch-session` for multiple active session lanes
26
26
  - `vibecompass end-session` as a discoverable alias for `close-session`
@@ -31,6 +31,8 @@ Shipped today:
31
31
  - `vibecompass docs-review --submit-hosted` — submit the review request to the hosted app and poll for proposal/artifact output
32
32
  - `vibecompass docs-review --run-local --provider anthropic` — local provider adapter that saves review output locally
33
33
  - `vibecompass docs-review --apply-output` — apply accepted architecture-doc blocks into canonical `architecture/` docs
34
+ - docs-review prompt v2 with staged evidence inventory, coverage planning, bounded doc generation, retrieval metadata, and soft oversized-doc warnings
35
+ - strict docs-review output validation for architecture-doc fences, duplicate paths, and required frontmatter
34
36
  - `vibecompass docs-review --complete` — mark the review accepted after the docs land
35
37
  - hosted sync commands: `push`, `pull-preview`, `pull-export`, and `apply-export`
36
38
  - canonical file scanning and validation
@@ -68,6 +70,15 @@ command is intentionally unscoped: `vibecompass`.
68
70
  npm install @vibecompass/vibecompass
69
71
  ```
70
72
 
73
+ ## Latest release
74
+
75
+ `0.6.0` upgrades docs-review to `VibeCompass Docs Review Prompt v2`.
76
+ The generated review prompt now guides the LLM through evidence inventory,
77
+ coverage planning, bounded architecture-doc generation, and apply/verify.
78
+ Accepted architecture docs over the 12000-byte soft budget are still applied,
79
+ but surface an `oversized_architecture_doc` warning so users can compact them
80
+ before future LLM sessions load that context.
81
+
71
82
  ## Quickstart
72
83
 
73
84
  Most users should start with the guided bootstrap:
@@ -144,6 +155,11 @@ AGENTS.md # at the tooling root, only if missing and --with-agents is
144
155
 
145
156
  `context.md` is a derived package-owned file. Re-running `init --force --with-workflow`
146
157
  regenerates it; do not treat it as a hand-edited source document.
158
+ Starter `CLAUDE.md` / `AGENTS.md` files include VibeCompass managed markers
159
+ when the package creates them, so later `sync-agents` and session lifecycle
160
+ commands can refresh the generated region without warning. If those files
161
+ already exist without markers, init leaves them untouched unless you explicitly
162
+ adopt them.
147
163
 
148
164
  Check an initialized root without writing files:
149
165
 
@@ -188,9 +204,9 @@ remind you with a non-blocking warning if no completed review exists.
188
204
 
189
205
  What happens:
190
206
 
191
- 1. The CLI asks which LLM you'll use, then prints a versioned prompt template with fixed review criteria.
207
+ 1. The CLI asks which LLM you'll use, then prints a versioned staged review prompt with fixed review criteria.
192
208
  2. You paste that prompt into your AI tool (Claude Code, Codex, Cursor, etc.).
193
- 3. The AI reads your repo and writes architecture docs under
209
+ 3. The AI inventories project memory and source evidence, proposes a coverage plan, then writes only accepted architecture docs under
194
210
  `architecture/<domain>/<feature>/<component>.md`.
195
211
  4. Run `vibecompass docs-review --apply-output` after accepting fenced
196
212
  architecture-doc blocks, or `--complete` if accepted docs were written
@@ -199,8 +215,11 @@ What happens:
199
215
  The guided prompt is deterministic apart from project-specific fields
200
216
  (`project`, `mode`, `root`, provider, and model). It uses the same structure
201
217
  VibeCompass dogfoods: read project memory first, inspect source evidence,
202
- write component docs with review metadata, preserve the starter overview, and
203
- emit accepted docs as `vibecompass-architecture-doc` blocks.
218
+ build a coverage plan, write retrieval-oriented component docs with review
219
+ metadata, preserve the starter overview, and emit accepted docs as
220
+ `vibecompass-architecture-doc` blocks. The prompt includes a soft 12000-byte
221
+ budget per generated architecture doc so future LLM sessions can load targeted
222
+ context without pulling oversized narrative files by default.
204
223
 
205
224
  Plain `--guided` never calls an AI itself. You stay in control of which
206
225
  provider runs the review and what gets saved. Use `--run-local --provider
@@ -283,7 +302,7 @@ Generate agent-instruction files from project memory:
283
302
  npx -y @vibecompass/vibecompass sync-agents --root .compass
284
303
  ```
285
304
 
286
- `sync-agents` writes only VibeCompass managed regions:
305
+ `sync-agents` writes compact VibeCompass bootloader regions:
287
306
 
288
307
  ```md
289
308
  <!-- vibecompass:start - managed by VibeCompass, do not edit -->
@@ -291,13 +310,23 @@ npx -y @vibecompass/vibecompass sync-agents --root .compass
291
310
  <!-- vibecompass:end -->
292
311
  ```
293
312
 
294
- Content outside those markers is preserved. Existing files without markers are
295
- reported as warnings and left untouched unless you explicitly adopt them:
313
+ Content outside those markers is preserved. Package-created starter files
314
+ include managed markers from the beginning. Existing user files without markers
315
+ are reported as warnings and left untouched unless you explicitly adopt them:
296
316
 
297
317
  ```bash
298
318
  npx -y @vibecompass/vibecompass sync-agents --root .compass --adopt-existing
299
319
  ```
300
320
 
321
+ The managed block intentionally stays short: project-memory root, read order,
322
+ prompt-command routing, and hard safety rules. Detailed workflow lives in
323
+ `context.md` and generated files under `workflows/`, so `CLAUDE.md`, `AGENTS.md`,
324
+ `.cursorrules`, and Copilot instructions do not duplicate long protocol text.
325
+ `CLAUDE.md` starters also keep the mutable `Current session` block above the
326
+ managed region because session lifecycle commands update it. `AGENTS.md`
327
+ starters are intentionally just the managed bootloader; add Codex/team notes
328
+ before or after the marker block if needed, and `sync-agents` will preserve them.
329
+
301
330
  Adoption appends a managed VibeCompass block to the end of existing unmarked
302
331
  agent files, preserves everything outside the markers, and reports possible
303
332
  workflow-overlap lines before you rely on the result. Guided init may offer the
@@ -665,7 +694,23 @@ Accepted review content.
665
694
  ```
666
695
  ````
667
696
 
668
- Only `architecture/*.md` paths are writable through this apply step.
697
+ The fence opening is strict: it must be exactly
698
+ `vibecompass-architecture-doc path=<architecture/*.md>` with one `path`
699
+ attribute and no extra attributes. Malformed architecture-doc fences report a
700
+ targeted error instead of being treated as "no output found".
701
+
702
+ Only `architecture/*.md` paths are writable through this apply step. Component
703
+ docs require non-empty `domain`, `feature`, `component`, and `status`
704
+ frontmatter. The project overview file,
705
+ `architecture/overview/project-shape.md`, may use status-only frontmatter so it
706
+ matches hosted docs-review proposal behavior. If one accepted output contains
707
+ multiple blocks for the same architecture path, local apply fails rather than
708
+ silently overwriting earlier accepted content.
709
+
710
+ Accepted architecture docs over the soft 12000-byte size budget are applied
711
+ with an `oversized_architecture_doc` warning instead of being rejected. Treat
712
+ that warning as a prompt to compact the doc unless the extra detail is needed
713
+ for future retrieval.
669
714
 
670
715
  `vibecompass docs-review --complete` updates the marker in
671
716
  `state/docs-review.json` to `status: "completed"` once the docs have
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibecompass/vibecompass",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Local-first project-memory core for VibeCompass",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,8 +11,10 @@
11
11
  ".": "./src/index.js"
12
12
  },
13
13
  "files": [
14
+ "CHANGELOG.md",
14
15
  "src/*.js",
15
- "src/generators/**/*.js"
16
+ "src/generators/**/*.js",
17
+ "src/workflows/**/*.js"
16
18
  ],
17
19
  "scripts": {
18
20
  "test": "node --test src/tests/*.test.js",
@@ -5,6 +5,9 @@ import { parseFrontmatter } from './frontmatter.js';
5
5
  import { writeStateManifest } from './manifest.js';
6
6
  import { parseSimpleYaml } from './simple-yaml.js';
7
7
 
8
+ const DOCS_REVIEW_PROMPT_VERSION = 'VibeCompass Docs Review Prompt v2';
9
+ const ARCHITECTURE_DOC_SOFT_SIZE_LIMIT_BYTES = 12000;
10
+
8
11
  export async function preflightDocsReview(options = {}, environment = {}) {
9
12
  validateDocsReviewMode(options);
10
13
  const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd();
@@ -59,8 +62,10 @@ export async function preflightDocsReview(options = {}, environment = {}) {
59
62
  const localProvider = resolveLocalProvider(options);
60
63
  const runtime = resolveDocsReviewRuntime(project, {
61
64
  env,
65
+ guided: Boolean(options.guided),
62
66
  localProvider,
63
67
  runLocal: shouldRunLocal(options),
68
+ anthropicEnvVar: options.anthropicEnvVar ?? 'ANTHROPIC_API_KEY',
64
69
  });
65
70
  const reviewPrompt = renderReviewPrompt({
66
71
  project,
@@ -180,14 +185,20 @@ async function applyDocsReviewOutput(options) {
180
185
  const blocks = parseArchitectureDocBlocks(source);
181
186
 
182
187
  if (blocks.length === 0) {
188
+ const malformedFenceCount = countMalformedArchitectureDocFences(source);
189
+ if (malformedFenceCount > 0) {
190
+ throw new Error(
191
+ `Malformed architecture doc fence found in ${outputPath}. Expected fence openings like \`\`\`vibecompass-architecture-doc path=architecture/domain/feature/component.md\` with exactly one path attribute and no extra attributes.`,
192
+ );
193
+ }
194
+
183
195
  throw new Error(
184
196
  `No accepted architecture doc blocks found in ${outputPath}. Expected fenced blocks like \`\`\`vibecompass-architecture-doc path=architecture/domain/feature/component.md\`.`,
185
197
  );
186
198
  }
187
199
 
188
- for (const block of blocks) {
189
- validateArchitectureDocBlock(block);
190
- }
200
+ validateArchitectureDocBlocks(blocks);
201
+ const warnings = createArchitectureDocSizeWarnings(blocks);
191
202
 
192
203
  const applied = [];
193
204
  for (const block of blocks) {
@@ -208,6 +219,7 @@ async function applyDocsReviewOutput(options) {
208
219
  applied: {
209
220
  output_path: outputPath,
210
221
  architecture_docs: applied,
222
+ ...(warnings.length > 0 ? { warnings } : {}),
211
223
  applied_at: new Date().toISOString(),
212
224
  },
213
225
  completed_at: new Date().toISOString(),
@@ -225,7 +237,7 @@ async function applyDocsReviewOutput(options) {
225
237
  hosted: current.hosted ?? null,
226
238
  applied: marker.applied,
227
239
  reviewPrompt: null,
228
- warnings: [],
240
+ warnings,
229
241
  message: `Applied ${applied.length} accepted architecture doc${applied.length === 1 ? '' : 's'} and completed the docs-review marker.`,
230
242
  };
231
243
  }
@@ -357,6 +369,13 @@ function validateDocsReviewMode(options) {
357
369
  }
358
370
 
359
371
  async function promptForReviewConfig(options, environment) {
372
+ if (options.llm && options.model) {
373
+ return normalizeReviewConfig({
374
+ llm: options.llm,
375
+ model: options.model,
376
+ });
377
+ }
378
+
360
379
  const prompter = createPrompter(environment.io, environment.runtime);
361
380
  try {
362
381
  if (!options.llm) {
@@ -485,6 +504,10 @@ function resolveDocsReviewRuntime(project, options) {
485
504
  };
486
505
  }
487
506
 
507
+ if (options.guided) {
508
+ return { provider: 'external' };
509
+ }
510
+
488
511
  throw new Error(
489
512
  `docs-review for local-primary projects requires a hosted sync binding or ${options.anthropicEnvVar}.`,
490
513
  );
@@ -601,6 +624,32 @@ function parseArchitectureDocBlocks(source) {
601
624
  return blocks;
602
625
  }
603
626
 
627
+ function countMalformedArchitectureDocFences(source) {
628
+ const fencePattern = /^```vibecompass-architecture-doc\b.*$/gm;
629
+ const acceptedOpeningPattern = /^```vibecompass-architecture-doc\s+path=[^\s`]+\s*$/;
630
+ let count = 0;
631
+ let match;
632
+
633
+ while ((match = fencePattern.exec(source)) !== null) {
634
+ if (!acceptedOpeningPattern.test(match[0])) {
635
+ count += 1;
636
+ }
637
+ }
638
+
639
+ return count;
640
+ }
641
+
642
+ function validateArchitectureDocBlocks(blocks) {
643
+ const seenPaths = new Set();
644
+ for (const block of blocks) {
645
+ if (seenPaths.has(block.path)) {
646
+ throw new Error(`Accepted docs-review output contains duplicate architecture doc path: ${block.path}`);
647
+ }
648
+ seenPaths.add(block.path);
649
+ validateArchitectureDocBlock(block);
650
+ }
651
+ }
652
+
604
653
  function normalizeBlockPath(value) {
605
654
  return String(value ?? '').trim().replaceAll('\\', '/');
606
655
  }
@@ -625,13 +674,29 @@ function validateArchitectureDocBlock(block) {
625
674
  throw new Error(`Accepted architecture doc ${block.path} must include frontmatter.`);
626
675
  }
627
676
 
628
- for (const field of ['domain', 'feature', 'component', 'status']) {
677
+ const requiredFields = block.path === 'architecture/overview/project-shape.md'
678
+ ? ['status']
679
+ : ['domain', 'feature', 'component', 'status'];
680
+ for (const field of requiredFields) {
629
681
  if (typeof frontmatter.data[field] !== 'string' || frontmatter.data[field].trim() === '') {
630
682
  throw new Error(`Accepted architecture doc ${block.path} requires non-empty frontmatter field "${field}".`);
631
683
  }
632
684
  }
633
685
  }
634
686
 
687
+ function createArchitectureDocSizeWarnings(blocks) {
688
+ return blocks
689
+ .map((block) => {
690
+ const byteLength = Buffer.byteLength(ensureTrailingNewline(block.content), 'utf8');
691
+ if (byteLength <= ARCHITECTURE_DOC_SOFT_SIZE_LIMIT_BYTES) {
692
+ return null;
693
+ }
694
+
695
+ return `oversized_architecture_doc: ${block.path} is ${byteLength} bytes; soft budget is ${ARCHITECTURE_DOC_SOFT_SIZE_LIMIT_BYTES} bytes. Consider compacting the doc to preserve future LLM context budget.`;
696
+ })
697
+ .filter(Boolean);
698
+ }
699
+
635
700
  async function submitHostedDocsReview(options) {
636
701
  if (options.runtime.provider !== 'hosted') {
637
702
  throw new Error('docs-review --submit-hosted requires a hosted sync binding in project.yaml.');
@@ -1034,9 +1099,9 @@ function renderDocsReviewMessage(options) {
1034
1099
 
1035
1100
  function renderReviewPrompt(options) {
1036
1101
  return [
1037
- '# VibeCompass Docs Review Prompt v1',
1102
+ `# ${DOCS_REVIEW_PROMPT_VERSION}`,
1038
1103
  '',
1039
- 'Run a comprehensive VibeCompass architecture documentation review for the project-memory root below. Follow this prompt exactly; do not invent a different document structure.',
1104
+ 'Run a staged VibeCompass architecture documentation review for the project-memory root below. Follow this prompt exactly; do not invent a different document structure.',
1040
1105
  '',
1041
1106
  '## Review Context',
1042
1107
  `- Project memory root: ${options.rootDir}`,
@@ -1049,13 +1114,35 @@ function renderReviewPrompt(options) {
1049
1114
  '1. Read `project.yaml`.',
1050
1115
  '2. Read `context.md` if present.',
1051
1116
  '3. Read all canonical files under `architecture/`, `decisions/`, and finalized `sessions/`.',
1052
- '4. Inspect the declared repositories and cite concrete source, config, and test files before making implementation claims.',
1117
+ '4. Inspect declared repositories before making implementation claims.',
1118
+ '',
1119
+ '## Staged Review Protocol',
1120
+ 'Stage 1 — Evidence inventory:',
1121
+ '- Build a compact repo inventory from file paths, manifests/config files, route/job/test directories, and existing architecture frontmatter before reading large file bodies.',
1122
+ '- Identify candidate domains, features, components, and ownership boundaries with concrete `repo:path` evidence.',
1123
+ '- Do not fetch or summarize broad source bodies until the coverage plan says a file is needed.',
1124
+ '',
1125
+ 'Stage 2 — Coverage plan:',
1126
+ '- Propose the smallest useful architecture-doc set that will let future agents understand the project and retrieve targeted context.',
1127
+ '- Prioritize entry points, data ownership, external integrations, jobs/async boundaries, auth/security boundaries, and test surfaces.',
1128
+ '- Mark each proposed doc as `comprehensive`, `partial`, or `initial`, with the reason and blindspots.',
1129
+ '- Ask for user acceptance before emitting fenced architecture-doc blocks.',
1130
+ '',
1131
+ 'Stage 3 — Bounded doc generation:',
1132
+ '- Generate only accepted docs, one complete fenced block per architecture path.',
1133
+ '- Keep docs concise and retrieval-oriented: explain contracts, flows, invariants, and ownership; do not rewrite source code or produce file-by-file walkthroughs.',
1134
+ `- Soft size budget: keep each generated architecture doc under ${ARCHITECTURE_DOC_SOFT_SIZE_LIMIT_BYTES} bytes unless the extra detail is necessary and called out in Blindspots or Retrieval guidance.`,
1135
+ '- Include only the most important involved files; prefer representative entry points and owned contracts over exhaustive file lists.',
1136
+ '',
1137
+ 'Stage 4 — Apply and verify:',
1138
+ '- After accepted blocks are written to `state/docs-review-output.md`, run `vibecompass docs-review --apply-output`.',
1139
+ '- Surface any parser warnings, especially oversized docs, so the user can decide whether to compact or accept the output.',
1053
1140
  '',
1054
1141
  '## Architecture Doc Contract',
1055
1142
  'When creating or updating architecture docs, use the existing VibeCompass structure:',
1056
1143
  '- path: `architecture/<domain-slug>/<feature-slug>/<component-slug>.md` for component docs',
1057
1144
  '- frontmatter fields: `domain`, `feature`, `component`, `status`, plus `repo` or `repos` when implementation-scoped',
1058
- '- body sections: `## Description`, `## Review metadata`, `## Details`, `## Next steps`, `## Involved files`',
1145
+ '- body sections: `## Description`, `## Review metadata`, `## Details`, `## Retrieval guidance`, `## Next steps`, `## Involved files`',
1059
1146
  '',
1060
1147
  'Use this exact Review metadata sub-header in every generated architecture doc:',
1061
1148
  '',
@@ -1066,6 +1153,8 @@ function renderReviewPrompt(options) {
1066
1153
  '- Confidence: high | medium | low',
1067
1154
  '- Coverage: comprehensive | partial | initial',
1068
1155
  '- Evidence: repo:path references inspected before making implementation claims',
1156
+ '- Retrieval scope: when future agents should load this doc',
1157
+ `- Token posture: compact unless the doc intentionally exceeds ${ARCHITECTURE_DOC_SOFT_SIZE_LIMIT_BYTES} bytes`,
1069
1158
  '- Blindspots: explicit list, or "None identified" only when evidence is comprehensive',
1070
1159
  '',
1071
1160
  '## Review Rules',
@@ -1077,12 +1166,15 @@ function renderReviewPrompt(options) {
1077
1166
  '6. Put uncertainty in `Blindspots`; do not fill gaps with guesses.',
1078
1167
  '7. Do not append real `D-NNN` decisions without explicit user acceptance. Propose candidate decisions separately.',
1079
1168
  '8. Do not edit `decisions/INDEX.md` directly unless a canonical decision file was explicitly accepted and appended.',
1169
+ '9. Optimize for future retrieval: project-level docs stay compact; component docs carry focused context for a specific area.',
1080
1170
  '',
1081
1171
  '## Output Contract',
1082
1172
  'First provide a concise findings summary with:',
1083
1173
  '- mapped areas',
1084
1174
  '- gaps/blindspots',
1085
- '- proposed architecture docs',
1175
+ '- evidence inventory summary',
1176
+ '- coverage plan and proposed architecture docs',
1177
+ '- token-budget risks or oversized-doc candidates',
1086
1178
  '- proposed decisions, if any',
1087
1179
  '',
1088
1180
  'Then, for each architecture doc the user accepts, output one fenced block exactly like this:',
@@ -8,6 +8,7 @@ import { claudeMdFormat } from './claude-md.js';
8
8
  import { agentsMdFormat } from './agents-md.js';
9
9
  import { cursorRulesFormat } from './cursor-rules.js';
10
10
  import { copilotInstructionsFormat } from './copilot-instructions.js';
11
+ import { getWorkflowConflictScanPatterns } from '../../workflows/registry.js';
11
12
 
12
13
  const FORMATS = [
13
14
  claudeMdFormat,
@@ -17,17 +18,7 @@ const FORMATS = [
17
18
  ];
18
19
 
19
20
  const FORMAT_MAP = new Map(FORMATS.map((format) => [format.name, format]));
20
- const CONFLICT_SCAN_PATTERNS = [
21
- 'session',
22
- 'handoff',
23
- 'decisions',
24
- 'wip.md',
25
- 'review handoff',
26
- 'close-session',
27
- 'address review',
28
- 'builder',
29
- 'reviewer',
30
- ];
21
+ const CONFLICT_SCAN_PATTERNS = getWorkflowConflictScanPatterns();
31
22
 
32
23
  export async function syncAgentInstructionFiles(options = {}) {
33
24
  const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd();
@@ -1,3 +1,5 @@
1
+ import { renderPromptCommandLines } from '../../workflows/registry.js';
2
+
1
3
  export function buildAgentContext(readModel) {
2
4
  return {
3
5
  projectName: readModel.project.name ?? 'Unnamed project',
@@ -16,47 +18,40 @@ export function renderSharedInstructionBody(context, options = {}) {
16
18
  const intro =
17
19
  options.intro ??
18
20
  'Use VibeCompass project memory as the source of truth before making code changes.';
21
+ const contextPath = `${context.rootDir}/context.md`;
19
22
 
20
23
  return [
21
24
  `# ${heading}`,
22
25
  '',
23
26
  intro,
24
27
  '',
25
- `Read \`${context.rootDir}/context.md\` for the full VibeCompass workflow protocol when it exists.`,
28
+ `This managed block is a compact bootloader. Read \`${contextPath}\` for the full VibeCompass workflow protocol; workflow-specific details live under \`${context.rootDir}/workflows/\`.`,
26
29
  '',
27
30
  'Existing project-specific coding, style, framework, and safety instructions outside this managed block remain authoritative. This block owns only VibeCompass project-memory workflow: sessions, handoffs, decisions, docs-review, and close-out.',
28
31
  '',
29
- '## Read First',
32
+ '## Project Snapshot',
30
33
  `- Project memory root: \`${context.rootDir}\``,
31
- '- Read `project.yaml` for project identity, repos, mode, and workflow defaults.',
32
- '- Read the latest finalized session note under `sessions/` before resuming work.',
33
- '- Read `sessions/active/index.yaml` when it exists, then read the selected lane under `sessions/active/<lane-id>/`.',
34
- '- Read the selected lane `wip.md` and `handoff.md` when they exist; they are the active builder/reviewer scratch files.',
35
- '- Read relevant `architecture/` and `decisions/` files before changing implementation.',
34
+ ...renderProjectSnapshot(context),
36
35
  '',
37
- '## Project Shape',
38
- ...renderProjectShape(context),
36
+ '## Read Order',
37
+ `1. Read \`${contextPath}\`.`,
38
+ `2. Read the latest finalized session note under \`${context.rootDir}/sessions/\`.`,
39
+ `3. If present, read \`${context.rootDir}/sessions/active/index.yaml\`, then the selected lane's \`wip.md\` and \`handoff.md\`.`,
40
+ `4. Read relevant \`${context.rootDir}/architecture/\` and \`${context.rootDir}/decisions/\` docs before editing implementation.`,
39
41
  '',
40
- '## Workflow Rules',
41
- '- VibeCompass active builder sessions are named lanes. Use one lane per active feature or workstream; finalized session notes are append-only history under `sessions/YYYY-MM-DD-N-title.md`.',
42
- '- Use `start session` for builder work, `join as reviewer` for review work, and `close session` / `end session` when the builder is ready to close the selected lane.',
43
- '- Use `vibecompass start-session --id <lane-id>` to open a named lane for every active feature or workstream.',
44
- '- Use `vibecompass list-sessions` and `vibecompass switch-session <lane-id>` to inspect or change the current lane.',
45
- '- Treat `sessions/active/index.yaml` as the current lane source of truth; tool-specific Current session blocks are continuity summaries.',
46
- '- Use optional planning mode for risky or ambiguous work: read the same context, propose scope, and record the agreed plan in the selected lane `wip.md` before implementation.',
47
- '- Use `review handoff` to ask a reviewer to inspect the active handoff.',
48
- '- Use `address review` to process reviewer feedback from the selected lane `wip.md` and `handoff.md`.',
49
- '- End the active builder session with the `close session` prompt, which runs close-out and ends with `vibecompass close-session --session <lane-id>`; `end session` and `vibecompass end-session` are accepted aliases.',
50
- '- If stale scratch files block `start-session`, read them first, then close, recover, move, or delete them intentionally before retrying.',
51
- '- Keep decisions append-only in `decisions/`. Session notes may reference decisions, but decisions are the durable source of truth.',
52
- '- Treat generated agent files as views. Update canonical VibeCompass project memory instead of editing managed regions.',
42
+ '## Prompt Commands',
43
+ ...renderPromptCommandLines({ rootRelativePath: context.rootDir }),
44
+ '- The prompt commands above are agent behaviors. The `vibecompass` CLI commands remain the filesystem mechanics behind them.',
53
45
  '',
54
- '## Recent Decisions',
55
- ...renderDecisionLines(context.recentDecisions),
46
+ '## Hard Rules',
47
+ '- Treat `sessions/active/index.yaml` as the current lane source of truth; tool-specific Current session blocks are continuity summaries.',
48
+ '- Keep the selected lane `wip.md` and `handoff.md` current during active builder/reviewer work.',
49
+ '- Keep decisions append-only in `decisions/`; append accepted architectural decisions before implementing them.',
50
+ '- Do not edit this managed block directly. Update canonical VibeCompass memory, then rerun package commands such as `vibecompass sync-agents`.',
56
51
  ].join('\n');
57
52
  }
58
53
 
59
- function renderProjectShape(context) {
54
+ function renderProjectSnapshot(context) {
60
55
  const lines = [];
61
56
 
62
57
  if (context.description) {
@@ -71,18 +66,22 @@ function renderProjectShape(context) {
71
66
  lines.push(`- Repo \`${repo.id}\`: ${repo.remote}`);
72
67
  }
73
68
 
74
- for (const domain of context.domains.slice(0, 8)) {
75
- const features = domain.features.map((feature) => feature.feature).join(', ');
76
- lines.push(`- ${domain.domain}: ${features || 'No features recorded yet.'}`);
69
+ const domainCount = context.domains.length;
70
+ if (domainCount > 0) {
71
+ lines.push(`- Architecture domains recorded: ${domainCount}`);
77
72
  }
78
73
 
79
- return lines.length > 0 ? lines : ['- No architecture domains recorded yet.'];
80
- }
74
+ if (context.recentDecisions.length > 0) {
75
+ lines.push(`- Latest decision: ${renderDecisionLine(context.recentDecisions[0])}`);
76
+ }
81
77
 
82
- function renderDecisionLines(decisions) {
83
- if (!decisions || decisions.length === 0) {
84
- return ['- No decisions recorded yet.'];
78
+ if (context.recentSessions.length > 0) {
79
+ lines.push(`- Latest session: ${context.recentSessions[0].title ?? context.recentSessions[0].path}`);
85
80
  }
86
81
 
87
- return decisions.map((decision) => `- D-${String(decision.decision_id).padStart(3, '0')} — ${decision.title}`);
82
+ return lines.length > 0 ? lines : ['- No project details recorded yet.'];
83
+ }
84
+
85
+ function renderDecisionLine(decision) {
86
+ return `D-${String(decision.decision_id).padStart(3, '0')} — ${decision.title}`;
88
87
  }
@@ -364,7 +364,9 @@ function parseArchitectureDocument(options) {
364
364
  }
365
365
 
366
366
  const data = frontmatter.data;
367
- const requiredFields = ['domain', 'feature', 'component', 'status'];
367
+ const requiredFields = options.relativePath === 'architecture/overview/project-shape.md'
368
+ ? ['status']
369
+ : ['domain', 'feature', 'component', 'status'];
368
370
 
369
371
  for (const field of requiredFields) {
370
372
  if (typeof data[field] !== 'string' || data[field].trim() === '') {
@@ -161,6 +161,9 @@ function isGeneratedWorkflowGuide(kind, content) {
161
161
  if (kind === 'sessions-guide') {
162
162
  return content.includes('Those scratch files are session-scoped working artifacts, not finalized history.');
163
163
  }
164
+ if (kind === 'workflow-docs-review') {
165
+ return content.includes('Generated by VibeCompass. This file is a package-owned workflow guide');
166
+ }
164
167
 
165
168
  return false;
166
169
  }
package/src/scaffold.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import { access, mkdir, readdir, writeFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { resolveWorkflowSettings } from './workflow.js';
4
+ import { getGeneratedWorkflowFiles, renderPromptCommandLines } from './workflows/registry.js';
5
+ import { renderManagedBlock } from './generators/agent-files/markers.js';
6
+ import { renderSharedInstructionBody } from './generators/agent-files/template.js';
4
7
 
5
8
  export async function scaffoldInitFiles(options) {
6
9
  const createdFiles = [];
@@ -59,7 +62,7 @@ export async function scaffoldInitFiles(options) {
59
62
  await writeFile(contextFilePath, workflowScaffold.context.content, 'utf8');
60
63
  createdFiles.push(contextFilePath);
61
64
 
62
- for (const file of workflowScaffold.guides) {
65
+ for (const file of [...workflowScaffold.guides, ...workflowScaffold.workflowFiles]) {
63
66
  const outcome = await writeIfMissing(file.path, file.content);
64
67
  if (outcome.created) {
65
68
  createdFiles.push(file.path);
@@ -124,12 +127,20 @@ export function buildWorkflowScaffoldFiles(options) {
124
127
  content: generateSessionsGuide(options.projectConfig),
125
128
  },
126
129
  ];
130
+ const workflowFiles = getGeneratedWorkflowFiles({
131
+ rootRelativePath: options.rootRelativePath,
132
+ }).map((file) => ({
133
+ kind: file.kind,
134
+ path: path.join(options.rootDir, file.relativePath),
135
+ content: file.content,
136
+ }));
127
137
 
128
138
  return {
129
139
  contextFilePath,
130
140
  context,
131
141
  guides,
132
- files: [context, ...guides],
142
+ workflowFiles,
143
+ files: [context, ...guides, ...workflowFiles],
133
144
  };
134
145
  }
135
146
 
@@ -193,6 +204,7 @@ function generateContextMarkdown(options) {
193
204
  const projectName = options.projectConfig.name;
194
205
  const rootRelativePath = options.rootRelativePath;
195
206
  const workflow = resolveWorkflowSettings(options.projectConfig);
207
+ const promptCommands = renderPromptCommandLines({ rootRelativePath }).join('\n');
196
208
  const repos = options.projectConfig.repos
197
209
  .map((repo) => `- \`${repo.id}\` → ${repo.remote}`)
198
210
  .join('\n');
@@ -233,12 +245,7 @@ ${repos}
233
245
  | "join as reviewer" | Reviewer | No — reviews the builder's work, appends findings, and updates handoff guidance |
234
246
 
235
247
  ## Session prompt commands
236
- - \`start session\` — builder role trigger
237
- - \`join as reviewer\` — reviewer role trigger
238
- - \`planning mode\` — optional prompt-level mode for scoping work before implementation
239
- - \`review handoff\` — reviewer reads the selected lane's \`wip.md\`, \`handoff.md\`, latest finalized note, and relevant diffs before appending findings
240
- - \`address review\` — builder reads reviewer feedback in the selected lane's \`wip.md\` / \`handoff.md\`, responds inline, applies accepted changes, and refreshes the builder handoff
241
- - \`close session\` — builder runs the close-out checklist and ends with \`vibecompass close-session --session <lane-id>\`; \`end session\` is accepted as a synonym
248
+ ${promptCommands}
242
249
 
243
250
  These are prompt commands for agent behavior, not \`vibecompass\` CLI subcommands.
244
251
  Reviewer handback is explicit: the reviewer ends the pass by updating the selected lane's \`wip.md\` + \`handoff.md\` and then stopping. The \`close session\` prompt runs builder close-out and ends with \`vibecompass close-session --session <lane-id>\`, which follows the workflow defaults recorded in \`${rootRelativePath}/project.yaml\`.
@@ -250,7 +257,7 @@ ${renderWorkflowDefaults(workflow)}
250
257
  ## Documentation coverage
251
258
  - The architecture, decision, and session files created by init are an initial scaffold, not a comprehensive codebase review.
252
259
  - Before risky implementation work, inspect the relevant code and update the affected architecture docs.
253
- - Run \`vibecompass docs-review --guided\` when you want a comprehensive documentation review. That command is explicit because it may inspect source files and use AI or hosted scan infrastructure.
260
+ - Use the \`docs review\` prompt command when you want the current AI session to run a comprehensive documentation review. It may run \`vibecompass docs-review --guided\` as package mechanics to record marker state and print the canonical review contract.
254
261
 
255
262
  ## Session startup
256
263
  1. Read \`${rootRelativePath}/project.yaml\`.
@@ -387,7 +394,7 @@ Not yet documented:
387
394
  Before changing any undocumented area, inspect the relevant code and update or add architecture docs.
388
395
 
389
396
  ## Next steps
390
- - Run \`vibecompass docs-review --guided\` for a comprehensive documentation review.
397
+ - Use the \`docs review\` prompt command for a comprehensive documentation review.
391
398
  - Replace this placeholder with domain/feature/component docs as the project map becomes evidence-backed.
392
399
  - Keep architecture docs aligned with implementation changes during each builder session.
393
400
 
@@ -445,7 +452,7 @@ Initialized VibeCompass project memory for ${projectConfig.name}.
445
452
  ${repoLines}
446
453
 
447
454
  ## Next session should start with
448
- 1. Run \`vibecompass docs-review --guided\` if you want a comprehensive documentation review.
455
+ 1. Use the \`docs review\` prompt command if you want a comprehensive documentation review.
449
456
  2. Inspect relevant code before making implementation changes in areas not covered by architecture docs.
450
457
  3. Replace starter placeholders with evidence-backed domain/feature/component docs.
451
458
  `;
@@ -531,33 +538,21 @@ Those scratch files are session-scoped working artifacts, not finalized history.
531
538
  }
532
539
 
533
540
  function generateClaudeTemplate(options) {
534
- const workflow = resolveWorkflowSettings(options.projectConfig);
541
+ return [
542
+ generateClaudeSessionHeader(options),
543
+ renderManagedBlock(renderSharedInstructionBody(buildScaffoldAgentContext(options), {
544
+ heading: `${options.projectConfig.name} Claude Instructions`,
545
+ intro:
546
+ 'Claude should use VibeCompass project memory as the source of truth before planning, editing, or reviewing code.',
547
+ })),
548
+ ].join('\n');
549
+ }
535
550
 
551
+ function generateClaudeSessionHeader(options) {
536
552
  return `# ${options.projectConfig.name} Workspace
537
553
 
538
554
  Read \`${options.contextRelativeToToolingRoot}\` before doing substantive work.
539
555
 
540
- ## Session roles
541
-
542
- | Entry trigger | Role | Owns session lifecycle? |
543
- |---|---|---|
544
- | "start session" | Builder | Yes |
545
- | "join as reviewer" | Reviewer | No |
546
- | "planning mode" | Planner | No — scopes work inside the selected active lane before implementation |
547
-
548
- ## Prompt commands
549
-
550
- - \`start session\` — builder role trigger
551
- - \`join as reviewer\` — reviewer role trigger
552
- - \`planning mode\` — optional prompt-level mode for scoping risky or ambiguous work before implementation
553
- - \`review handoff\` — reviewer reads the selected lane's \`wip.md\`, \`handoff.md\`, latest finalized note, and relevant diffs before appending findings
554
- - \`address review\` — builder reads reviewer feedback in the selected lane's \`wip.md\` / \`handoff.md\`, responds inline, applies accepted changes, and refreshes the builder handoff
555
- - \`close session\` — builder runs the close-out checklist and ends with \`vibecompass close-session --session <lane-id>\`; \`end session\` is accepted as a synonym
556
-
557
- These are prompt commands for agent behavior, not \`vibecompass\` CLI subcommands.
558
- Reviewer handback is explicit: the reviewer ends the pass by updating the selected lane's \`wip.md\` + \`handoff.md\` and then stopping. The \`close session\` prompt runs builder close-out and ends with \`vibecompass close-session --session <lane-id>\`, which follows the workflow defaults recorded in \`${options.rootRelativePath}/project.yaml\`.
559
- \`vibecompass end-session\` is accepted as an alias for \`vibecompass close-session\`; \`close-session\` remains the canonical command name.
560
-
561
556
  ## Current session
562
557
 
563
558
  **Update this block at the start and end of every session.**
@@ -569,64 +564,28 @@ Last thing completed: Project memory bootstrap completed.
569
564
  Blockers: None recorded.
570
565
  Next session should: Read \`${options.contextRelativeToToolingRoot}\`, then open the first builder or reviewer session.
571
566
  \`\`\`
572
-
573
- ## Startup
574
- - Read \`${options.contextRelativeToToolingRoot}\`
575
- - Follow the builder/reviewer protocol defined there
576
- - Use \`vibecompass start-session --id <lane-id>\`, \`vibecompass list-sessions\`, \`vibecompass switch-session <lane-id>\`, and \`vibecompass close-session --session <lane-id>\` to manage active lanes when possible
577
- - Treat \`${options.rootRelativePath}/sessions/active/index.yaml\` as the current lane source of truth; this Current session block is only a continuity summary
578
- - Keep the selected lane's \`${options.rootRelativePath}/sessions/active/<lane-id>/wip.md\` and \`${options.rootRelativePath}/sessions/active/<lane-id>/handoff.md\` current during an active session
579
- - Use planning mode when scope is unclear; record the agreed plan in the selected lane's \`wip.md\` before implementing
580
- - If stale scratch files block \`start-session\`, read them first, then close, recover, move, or delete them intentionally before retrying
581
- - Workflow defaults:
582
- ${renderWorkflowDefaults(workflow)}
583
567
  `;
584
568
  }
585
569
 
586
570
  function generateAgentsTemplate(options) {
587
- const workflow = resolveWorkflowSettings(options.projectConfig);
588
-
589
- return `# ${options.projectConfig.name} Workspace
590
-
591
- This workspace uses VibeCompass project memory rooted at \`${options.rootRelativePath}\`.
592
-
593
- ## Session roles
594
-
595
- | Entry trigger | Role | Owns session lifecycle? |
596
- |---|---|---|
597
- | "start session" | Builder | Yes — opens and closes the session lifecycle |
598
- | "join as reviewer" | Reviewer | No — reviews the builder's work and updates the handoff |
599
- | "planning mode" | Planner | No — scopes work inside the selected active lane before implementation |
600
-
601
- ## Prompt commands
602
-
603
- - \`start session\` — builder role trigger
604
- - \`join as reviewer\` — reviewer role trigger
605
- - \`planning mode\` — optional prompt-level mode for scoping risky or ambiguous work before implementation
606
- - \`review handoff\` — reviewer reads the selected lane's \`wip.md\`, \`handoff.md\`, latest finalized note, and relevant diffs before appending findings
607
- - \`address review\` — builder reads reviewer feedback in the selected lane's \`wip.md\` / \`handoff.md\`, responds inline, applies accepted changes, and refreshes the builder handoff
608
- - \`close session\` — builder runs the close-out checklist and ends with \`vibecompass close-session --session <lane-id>\`; \`end session\` is accepted as a synonym
571
+ return renderManagedBlock(renderSharedInstructionBody(buildScaffoldAgentContext(options), {
572
+ heading: `${options.projectConfig.name} Agent Instructions`,
573
+ intro:
574
+ 'Agents should use VibeCompass project memory as the source of truth before planning, editing, or reviewing code.',
575
+ }));
576
+ }
609
577
 
610
- These are prompt commands for agent behavior, not \`vibecompass\` CLI subcommands.
611
- Reviewer handback is explicit: the reviewer ends the pass by updating the selected lane's \`wip.md\` + \`handoff.md\` and then stopping. The \`close session\` prompt runs builder close-out and ends with \`vibecompass close-session --session <lane-id>\`, which follows the workflow defaults recorded in \`${options.rootRelativePath}/project.yaml\`.
612
- \`vibecompass end-session\` is accepted as an alias for \`vibecompass close-session\`; \`close-session\` remains the canonical command name.
613
-
614
- ## Startup
615
- Before doing substantive work:
616
- 1. Read \`${options.contextRelativeToToolingRoot}\`.
617
- 2. Read the latest finalized session note under \`${options.rootRelativePath}/sessions/\`.
618
- 3. If present, read \`${options.rootRelativePath}/sessions/active/index.yaml\` and choose the selected or current lane.
619
- 4. If present, read \`${options.rootRelativePath}/sessions/active/<lane-id>/wip.md\`.
620
- 5. If present, read \`${options.rootRelativePath}/sessions/active/<lane-id>/handoff.md\`.
621
- 6. Read the relevant docs under \`${options.rootRelativePath}/architecture/\` and \`${options.rootRelativePath}/decisions/\`.
622
-
623
- ## Working rule
624
- Treat \`${options.contextRelativeToToolingRoot}\` as the local workflow source of truth for the builder/reviewer protocol and session scratch-file structure. When the package provides \`start-session\` / \`close-session\`, prefer those commands over hand-editing boilerplate.
625
- Use planning mode when scope is unclear; record the agreed plan in the selected lane's \`wip.md\` before implementing.
626
- If stale scratch files block \`start-session\`, read them first, then close, recover, move, or delete them intentionally before retrying.
627
- - Workflow defaults:
628
- ${renderWorkflowDefaults(workflow)}
629
- `;
578
+ function buildScaffoldAgentContext(options) {
579
+ return {
580
+ projectName: options.projectConfig.name ?? 'Unnamed project',
581
+ description: options.projectConfig.description ?? null,
582
+ mode: options.projectConfig.mode ?? null,
583
+ rootDir: options.rootRelativePath,
584
+ repos: options.projectConfig.repos ?? [],
585
+ domains: [],
586
+ recentDecisions: [],
587
+ recentSessions: [],
588
+ };
630
589
  }
631
590
 
632
591
  function renderWorkflowDefaults(workflow) {
package/src/setup.js CHANGED
@@ -7,6 +7,7 @@ import { promisify } from 'node:util';
7
7
  import { getSupportedAgentFilePaths } from './generators/agent-files/index.js';
8
8
  import { END_MARKER, START_MARKER } from './generators/agent-files/markers.js';
9
9
  import { parseSimpleYaml } from './simple-yaml.js';
10
+ import { getWorkflowConflictScanPatterns } from './workflows/registry.js';
10
11
 
11
12
  const execFileAsync = promisify(execFile);
12
13
 
@@ -859,17 +860,7 @@ function writeAgentAdoptionPreview(prompter, candidates) {
859
860
  }
860
861
 
861
862
  function scanPotentialAgentWorkflowConflicts(content) {
862
- const patterns = [
863
- 'session',
864
- 'handoff',
865
- 'decisions',
866
- 'wip.md',
867
- 'review handoff',
868
- 'close-session',
869
- 'address review',
870
- 'builder',
871
- 'reviewer',
872
- ];
863
+ const patterns = getWorkflowConflictScanPatterns();
873
864
 
874
865
  return content
875
866
  .split(/\r?\n/)
@@ -0,0 +1,138 @@
1
+ export const WORKFLOW_REGISTRY = [
2
+ {
3
+ id: 'session-lifecycle',
4
+ title: 'Session lifecycle',
5
+ detailPath: 'context.md',
6
+ summary: 'Builder/reviewer lane lifecycle, handoffs, planning mode, and close-out.',
7
+ promptCommands: [
8
+ { trigger: 'start session', summary: 'builder role trigger' },
9
+ { trigger: 'join as reviewer', summary: 'reviewer role trigger' },
10
+ { trigger: 'planning mode', summary: 'optional prompt-level mode for scoping work before implementation' },
11
+ { trigger: 'review handoff', summary: 'reviewer reads the selected lane handoff and appends findings' },
12
+ { trigger: 'address review', summary: 'builder processes reviewer feedback from the selected lane scratch files' },
13
+ { trigger: 'close session', summary: 'builder runs the close-out checklist and ends with `vibecompass close-session --session <lane-id>`; `end session` and `vibecompass end-session` are accepted aliases' },
14
+ ],
15
+ },
16
+ {
17
+ id: 'docs-review',
18
+ title: 'Docs review',
19
+ detailPath: 'workflows/docs-review.md',
20
+ summary: 'Generate evidence-backed architecture docs from the user\'s preferred AI session.',
21
+ promptCommands: [
22
+ { trigger: 'docs review', summary: 'agent-led architecture documentation review using the preferred LLM prompt box' },
23
+ ],
24
+ generatedFileKind: 'workflow-docs-review',
25
+ renderFile: renderDocsReviewWorkflow,
26
+ },
27
+ ];
28
+
29
+ export function getPromptCommands() {
30
+ return WORKFLOW_REGISTRY.flatMap((workflow) =>
31
+ workflow.promptCommands.map((command) => ({
32
+ ...command,
33
+ workflowId: workflow.id,
34
+ workflowTitle: workflow.title,
35
+ detailPath: workflow.detailPath,
36
+ })),
37
+ );
38
+ }
39
+
40
+ export function getWorkflowConflictScanPatterns() {
41
+ const patterns = new Set([
42
+ 'session',
43
+ 'handoff',
44
+ 'decisions',
45
+ 'wip.md',
46
+ 'builder',
47
+ 'reviewer',
48
+ ]);
49
+
50
+ for (const command of getPromptCommands()) {
51
+ const normalizedTrigger = command.trigger.toLowerCase();
52
+ patterns.add(normalizedTrigger);
53
+ patterns.add(slugifyPromptTrigger(normalizedTrigger));
54
+ }
55
+
56
+ return Array.from(patterns);
57
+ }
58
+
59
+ export function getGeneratedWorkflowFiles(options = {}) {
60
+ const rootRelativePath = options.rootRelativePath ?? '.';
61
+ return WORKFLOW_REGISTRY
62
+ .filter((workflow) => typeof workflow.renderFile === 'function')
63
+ .map((workflow) => ({
64
+ kind: workflow.generatedFileKind,
65
+ relativePath: workflow.detailPath,
66
+ content: workflow.renderFile({
67
+ rootRelativePath,
68
+ workflow,
69
+ }),
70
+ }));
71
+ }
72
+
73
+ export function renderPromptCommandLines(options = {}) {
74
+ const rootRelativePath = options.rootRelativePath ?? '.';
75
+ return getPromptCommands().map((command) => {
76
+ const detailPath = command.detailPath
77
+ ? ` Read \`${joinRootRelative(rootRelativePath, command.detailPath)}\` for the full workflow.`
78
+ : '';
79
+ return `- \`${command.trigger}\` — ${command.summary}.${detailPath}`;
80
+ });
81
+ }
82
+
83
+ function renderDocsReviewWorkflow(options = {}) {
84
+ const rootRelativePath = options.rootRelativePath ?? '.';
85
+ const projectYamlPath = joinRootRelative(rootRelativePath, 'project.yaml');
86
+ const contextPath = joinRootRelative(rootRelativePath, 'context.md');
87
+ const architecturePath = joinRootRelative(rootRelativePath, 'architecture/');
88
+ const decisionsPath = joinRootRelative(rootRelativePath, 'decisions/');
89
+ const sessionsPath = joinRootRelative(rootRelativePath, 'sessions/');
90
+ const outputPath = joinRootRelative(rootRelativePath, 'state/docs-review-output.md');
91
+
92
+ return `# VibeCompass Workflow — docs review
93
+
94
+ Generated by VibeCompass. This file is a package-owned workflow guide and may be refreshed by \`vibecompass refresh-workflow --apply\`.
95
+
96
+ ## Prompt trigger
97
+
98
+ When the user says \`docs review\`, run this workflow inside the current Claude Code, Codex, Cursor, or Copilot session. The npm package owns state markers and apply mechanics; the AI session owns repository inspection and writing accepted architecture docs.
99
+
100
+ ## Goal
101
+
102
+ Turn starter project memory into evidence-backed architecture docs under \`architecture/<domain>/<feature>/<component>.md\`.
103
+
104
+ ## Steps
105
+
106
+ 1. Read \`${projectYamlPath}\`, \`${contextPath}\`, existing \`${architecturePath}\`, \`${decisionsPath}\`, and finalized \`${sessionsPath}\` notes.
107
+ 2. Inspect the declared source repos in stages:
108
+ - inventory paths, manifests, configs, route/job/test directories, and existing architecture frontmatter first
109
+ - produce a coverage plan before reading broad source bodies
110
+ - read targeted source files only when the coverage plan needs evidence
111
+ 3. Run \`vibecompass docs-review --guided --llm <tool-name> --model <model-name>\` to record the review marker and print the canonical docs-review contract. Use the current AI tool name and model when known.
112
+ 4. Present the evidence inventory, coverage plan, proposed architecture docs, blindspots, and token-budget risks before generating accepted docs.
113
+ 5. Draft only architecture docs the user accepts. Accepted docs must be fenced exactly as \`vibecompass-architecture-doc path=architecture/domain/feature/component.md\` blocks and must include required frontmatter: \`domain\`, \`feature\`, \`component\`, and \`status\`.
114
+ 6. Keep each generated architecture doc focused and retrieval-oriented. Soft budget: under 12000 bytes per doc unless the extra detail is necessary and called out in review metadata or retrieval guidance.
115
+ 7. Write the accepted fenced blocks to \`${outputPath}\`.
116
+ 8. Run \`vibecompass docs-review --apply-output\` to validate and apply the accepted blocks. If accepted docs were written manually outside the output file, run \`vibecompass docs-review --complete\` after confirming the marker should be completed.
117
+ 9. Run \`vibecompass status\` to confirm the docs-review marker is complete. Report the applied architecture paths, any parser warnings such as oversized docs, and any blindspots documented in the accepted docs-review output.
118
+
119
+ ## Rules
120
+
121
+ - Do not duplicate the full canonical review prompt in this file. The package command prints that contract from its current implementation.
122
+ - Follow the canonical review prompt for evidence, blindspot, and decision-recommendation constraints.
123
+ - Treat the package-owned prompt as the source of truth. Tool-specific skills may wrap this workflow, but should not define a divergent docs-review protocol.
124
+ - Do not edit generated agent files directly. Update VibeCompass project memory or rerun package commands instead.
125
+ `;
126
+ }
127
+
128
+ function slugifyPromptTrigger(trigger) {
129
+ return trigger.trim().replace(/\s+/g, '-');
130
+ }
131
+
132
+ function joinRootRelative(rootRelativePath, relativePath) {
133
+ if (!rootRelativePath || rootRelativePath === '.') {
134
+ return relativePath;
135
+ }
136
+
137
+ return `${rootRelativePath.replace(/\/$/, '')}/${relativePath}`;
138
+ }