@vibecompass/vibecompass 0.4.0 → 0.5.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/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,7 @@ 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
+ - strict docs-review output validation for architecture-doc fences, duplicate paths, and required frontmatter
34
35
  - `vibecompass docs-review --complete` — mark the review accepted after the docs land
35
36
  - hosted sync commands: `push`, `pull-preview`, `pull-export`, and `apply-export`
36
37
  - canonical file scanning and validation
@@ -144,6 +145,11 @@ AGENTS.md # at the tooling root, only if missing and --with-agents is
144
145
 
145
146
  `context.md` is a derived package-owned file. Re-running `init --force --with-workflow`
146
147
  regenerates it; do not treat it as a hand-edited source document.
148
+ Starter `CLAUDE.md` / `AGENTS.md` files include VibeCompass managed markers
149
+ when the package creates them, so later `sync-agents` and session lifecycle
150
+ commands can refresh the generated region without warning. If those files
151
+ already exist without markers, init leaves them untouched unless you explicitly
152
+ adopt them.
147
153
 
148
154
  Check an initialized root without writing files:
149
155
 
@@ -283,7 +289,7 @@ Generate agent-instruction files from project memory:
283
289
  npx -y @vibecompass/vibecompass sync-agents --root .compass
284
290
  ```
285
291
 
286
- `sync-agents` writes only VibeCompass managed regions:
292
+ `sync-agents` writes compact VibeCompass bootloader regions:
287
293
 
288
294
  ```md
289
295
  <!-- vibecompass:start - managed by VibeCompass, do not edit -->
@@ -291,13 +297,23 @@ npx -y @vibecompass/vibecompass sync-agents --root .compass
291
297
  <!-- vibecompass:end -->
292
298
  ```
293
299
 
294
- Content outside those markers is preserved. Existing files without markers are
295
- reported as warnings and left untouched unless you explicitly adopt them:
300
+ Content outside those markers is preserved. Package-created starter files
301
+ include managed markers from the beginning. Existing user files without markers
302
+ are reported as warnings and left untouched unless you explicitly adopt them:
296
303
 
297
304
  ```bash
298
305
  npx -y @vibecompass/vibecompass sync-agents --root .compass --adopt-existing
299
306
  ```
300
307
 
308
+ The managed block intentionally stays short: project-memory root, read order,
309
+ prompt-command routing, and hard safety rules. Detailed workflow lives in
310
+ `context.md` and generated files under `workflows/`, so `CLAUDE.md`, `AGENTS.md`,
311
+ `.cursorrules`, and Copilot instructions do not duplicate long protocol text.
312
+ `CLAUDE.md` starters also keep the mutable `Current session` block above the
313
+ managed region because session lifecycle commands update it. `AGENTS.md`
314
+ starters are intentionally just the managed bootloader; add Codex/team notes
315
+ before or after the marker block if needed, and `sync-agents` will preserve them.
316
+
301
317
  Adoption appends a managed VibeCompass block to the end of existing unmarked
302
318
  agent files, preserves everything outside the markers, and reports possible
303
319
  workflow-overlap lines before you rely on the result. Guided init may offer the
@@ -665,7 +681,18 @@ Accepted review content.
665
681
  ```
666
682
  ````
667
683
 
668
- Only `architecture/*.md` paths are writable through this apply step.
684
+ The fence opening is strict: it must be exactly
685
+ `vibecompass-architecture-doc path=<architecture/*.md>` with one `path`
686
+ attribute and no extra attributes. Malformed architecture-doc fences report a
687
+ targeted error instead of being treated as "no output found".
688
+
689
+ Only `architecture/*.md` paths are writable through this apply step. Component
690
+ docs require non-empty `domain`, `feature`, `component`, and `status`
691
+ frontmatter. The project overview file,
692
+ `architecture/overview/project-shape.md`, may use status-only frontmatter so it
693
+ matches hosted docs-review proposal behavior. If one accepted output contains
694
+ multiple blocks for the same architecture path, local apply fails rather than
695
+ silently overwriting earlier accepted content.
669
696
 
670
697
  `vibecompass docs-review --complete` updates the marker in
671
698
  `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.5.0",
4
4
  "description": "Local-first project-memory core for VibeCompass",
5
5
  "type": "module",
6
6
  "bin": {
@@ -59,8 +59,10 @@ export async function preflightDocsReview(options = {}, environment = {}) {
59
59
  const localProvider = resolveLocalProvider(options);
60
60
  const runtime = resolveDocsReviewRuntime(project, {
61
61
  env,
62
+ guided: Boolean(options.guided),
62
63
  localProvider,
63
64
  runLocal: shouldRunLocal(options),
65
+ anthropicEnvVar: options.anthropicEnvVar ?? 'ANTHROPIC_API_KEY',
64
66
  });
65
67
  const reviewPrompt = renderReviewPrompt({
66
68
  project,
@@ -180,14 +182,19 @@ async function applyDocsReviewOutput(options) {
180
182
  const blocks = parseArchitectureDocBlocks(source);
181
183
 
182
184
  if (blocks.length === 0) {
185
+ const malformedFenceCount = countMalformedArchitectureDocFences(source);
186
+ if (malformedFenceCount > 0) {
187
+ throw new Error(
188
+ `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.`,
189
+ );
190
+ }
191
+
183
192
  throw new Error(
184
193
  `No accepted architecture doc blocks found in ${outputPath}. Expected fenced blocks like \`\`\`vibecompass-architecture-doc path=architecture/domain/feature/component.md\`.`,
185
194
  );
186
195
  }
187
196
 
188
- for (const block of blocks) {
189
- validateArchitectureDocBlock(block);
190
- }
197
+ validateArchitectureDocBlocks(blocks);
191
198
 
192
199
  const applied = [];
193
200
  for (const block of blocks) {
@@ -357,6 +364,13 @@ function validateDocsReviewMode(options) {
357
364
  }
358
365
 
359
366
  async function promptForReviewConfig(options, environment) {
367
+ if (options.llm && options.model) {
368
+ return normalizeReviewConfig({
369
+ llm: options.llm,
370
+ model: options.model,
371
+ });
372
+ }
373
+
360
374
  const prompter = createPrompter(environment.io, environment.runtime);
361
375
  try {
362
376
  if (!options.llm) {
@@ -485,6 +499,10 @@ function resolveDocsReviewRuntime(project, options) {
485
499
  };
486
500
  }
487
501
 
502
+ if (options.guided) {
503
+ return { provider: 'external' };
504
+ }
505
+
488
506
  throw new Error(
489
507
  `docs-review for local-primary projects requires a hosted sync binding or ${options.anthropicEnvVar}.`,
490
508
  );
@@ -601,6 +619,32 @@ function parseArchitectureDocBlocks(source) {
601
619
  return blocks;
602
620
  }
603
621
 
622
+ function countMalformedArchitectureDocFences(source) {
623
+ const fencePattern = /^```vibecompass-architecture-doc\b.*$/gm;
624
+ const acceptedOpeningPattern = /^```vibecompass-architecture-doc\s+path=[^\s`]+\s*$/;
625
+ let count = 0;
626
+ let match;
627
+
628
+ while ((match = fencePattern.exec(source)) !== null) {
629
+ if (!acceptedOpeningPattern.test(match[0])) {
630
+ count += 1;
631
+ }
632
+ }
633
+
634
+ return count;
635
+ }
636
+
637
+ function validateArchitectureDocBlocks(blocks) {
638
+ const seenPaths = new Set();
639
+ for (const block of blocks) {
640
+ if (seenPaths.has(block.path)) {
641
+ throw new Error(`Accepted docs-review output contains duplicate architecture doc path: ${block.path}`);
642
+ }
643
+ seenPaths.add(block.path);
644
+ validateArchitectureDocBlock(block);
645
+ }
646
+ }
647
+
604
648
  function normalizeBlockPath(value) {
605
649
  return String(value ?? '').trim().replaceAll('\\', '/');
606
650
  }
@@ -625,7 +669,10 @@ function validateArchitectureDocBlock(block) {
625
669
  throw new Error(`Accepted architecture doc ${block.path} must include frontmatter.`);
626
670
  }
627
671
 
628
- for (const field of ['domain', 'feature', 'component', 'status']) {
672
+ const requiredFields = block.path === 'architecture/overview/project-shape.md'
673
+ ? ['status']
674
+ : ['domain', 'feature', 'component', 'status'];
675
+ for (const field of requiredFields) {
629
676
  if (typeof frontmatter.data[field] !== 'string' || frontmatter.data[field].trim() === '') {
630
677
  throw new Error(`Accepted architecture doc ${block.path} requires non-empty frontmatter field "${field}".`);
631
678
  }
@@ -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/)