vgxness 1.5.2 → 1.7.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.
Files changed (40) hide show
  1. package/dist/agents/canonical-agent-projection.js +18 -0
  2. package/dist/agents/renderers/claude-renderer.js +3 -3
  3. package/dist/cli/cli-flags.js +1 -1
  4. package/dist/cli/cli-help.js +7 -7
  5. package/dist/cli/commands/interactive-entrypoint-dispatcher.js +2 -2
  6. package/dist/cli/commands/mcp-dispatcher.js +11 -1
  7. package/dist/cli/commands/setup-dispatcher.js +9 -0
  8. package/dist/cli/tui/main-menu/main-menu-read-model.js +41 -44
  9. package/dist/cli/tui/main-menu/main-menu-render-shape.js +15 -15
  10. package/dist/cli/tui/opentui/main-menu/screen.js +39 -41
  11. package/dist/cli/tui/opentui/main-menu/smoke.js +1 -1
  12. package/dist/cli/tui/opentui/main-menu/view.js +1 -1
  13. package/dist/cli/tui/setup/setup-tui-read-model.js +15 -12
  14. package/dist/mcp/claude-code-agent-config.js +23 -7
  15. package/dist/mcp/claude-code-cli.js +71 -0
  16. package/dist/mcp/claude-code-config.js +1 -1
  17. package/dist/mcp/claude-code-project-memory.js +127 -0
  18. package/dist/mcp/claude-code-scope.js +18 -0
  19. package/dist/mcp/claude-code-user-config.js +55 -0
  20. package/dist/mcp/claude-code-user-memory.js +90 -0
  21. package/dist/mcp/client-install-claude-code-contract.js +91 -12
  22. package/dist/mcp/client-install-claude-code.js +133 -12
  23. package/dist/mcp/control-plane.js +18 -1
  24. package/dist/mcp/index.js +5 -0
  25. package/dist/mcp/provider-change-plan.js +18 -6
  26. package/dist/mcp/provider-doctor.js +71 -5
  27. package/dist/mcp/provider-health-types.js +4 -0
  28. package/dist/mcp/provider-status.js +77 -8
  29. package/dist/mcp/schema.js +4 -3
  30. package/dist/sdd/schema.js +15 -0
  31. package/dist/sdd/sdd-workflow-service.js +59 -29
  32. package/dist/setup/providers/claude-setup-adapter.js +11 -7
  33. package/dist/setup/setup-plan.js +60 -1
  34. package/docs/architecture.md +2 -2
  35. package/docs/cli.md +37 -2
  36. package/docs/glossary.md +2 -2
  37. package/docs/prd.md +2 -2
  38. package/docs/providers.md +33 -6
  39. package/docs/roadmap.md +1 -1
  40. package/package.json +1 -1
@@ -1,5 +1,20 @@
1
1
  import { z } from 'zod';
2
2
  export const sddPhases = ['explore', 'proposal', 'spec', 'design', 'tasks', 'apply-progress', 'verify', 'archive'];
3
+ /**
4
+ * Governance status of an SDD artifact.
5
+ *
6
+ * - `draft` — present in the DB; satisfies downstream readiness when the
7
+ * `VGXNESS_SDD_AUTO_ADVANCE` feature flag is on (or
8
+ * `SddWorkflowService` is constructed with `autoAdvance: true`).
9
+ * Does NOT count toward the change being `complete`.
10
+ * - `accepted` — content has been frozen by an explicit human
11
+ * `vgxness_sdd_accept_artifact` call. Satisfies downstream
12
+ * readiness regardless of the auto-advance flag.
13
+ * - `rejected` — explicit human rejection. Hard-blocker for downstream
14
+ * readiness; can only be cleared by re-opening the artifact.
15
+ * - `superseded`— replaced by a newer artifact under a different topic key.
16
+ * Hard-blocker; cannot be re-saved or accepted.
17
+ */
3
18
  export const sddArtifactStatuses = ['draft', 'accepted', 'rejected', 'superseded'];
4
19
  export const sddArtifactNormalizationWarnings = ['legacy-artifact-defaulted-to-draft', 'invalid-artifact-metadata-defaulted-to-draft'];
5
20
  export const SddArtifactStatusSchema = z.enum(sddArtifactStatuses);
@@ -2,12 +2,32 @@ import { summarizePayloadContent } from '../payload/payload-summary.js';
2
2
  import { isSddPhase, normalizeSddArtifact, sddPhases, sddPrerequisites, sddTopicKey, } from './schema.js';
3
3
  const defaultContext = { actor: 'sdd-workflow-service' };
4
4
  const validChangePattern = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
5
+ function readAutoAdvanceFromEnv() {
6
+ const value = process.env.VGXNESS_SDD_AUTO_ADVANCE;
7
+ return value === 'true' || value === '1';
8
+ }
9
+ function isPrerequisiteSatisfied(status) {
10
+ if (status === undefined)
11
+ return false;
12
+ if (status.legacy === true)
13
+ return false;
14
+ if (status.accepted === true)
15
+ return true;
16
+ if (status.state === 'draft')
17
+ return true;
18
+ return false;
19
+ }
5
20
  export class SddWorkflowService {
6
21
  memory;
7
22
  context;
8
- constructor(memory, context = defaultContext) {
23
+ options;
24
+ constructor(memory, context = defaultContext, options = {}) {
9
25
  this.memory = memory;
10
26
  this.context = context;
27
+ this.options = {
28
+ ...options,
29
+ autoAdvance: options.autoAdvance ?? readAutoAdvanceFromEnv(),
30
+ };
11
31
  }
12
32
  getWorkflow(change) {
13
33
  return sddPhases.map((phase) => ({
@@ -23,7 +43,7 @@ export class SddWorkflowService {
23
43
  const phases = this.getPhaseStatuses(validated.value.project, validated.value.change);
24
44
  if (!phases.ok)
25
45
  return phases;
26
- const readiness = getReadinessFromStatuses(validated.value.change, validated.value.phase, phases.value);
46
+ const readiness = getReadinessFromStatuses(validated.value.change, validated.value.phase, phases.value, this.options);
27
47
  return {
28
48
  ok: true,
29
49
  value: {
@@ -40,7 +60,7 @@ export class SddWorkflowService {
40
60
  const phases = this.getPhaseStatuses(validated.value.project, validated.value.change);
41
61
  if (!phases.ok)
42
62
  return phases;
43
- return statusFromPhases(validated.value.change, phases.value);
63
+ return statusFromPhases(validated.value.change, phases.value, this.options);
44
64
  }
45
65
  getNext(input) {
46
66
  const validated = validateProjectAndChange(input.project, input.change);
@@ -49,7 +69,7 @@ export class SddWorkflowService {
49
69
  const phases = this.getPhaseStatuses(validated.value.project, validated.value.change);
50
70
  if (!phases.ok)
51
71
  return phases;
52
- return ok(nextDecisionFromStatuses(validated.value.change, phases.value));
72
+ return ok(nextDecisionFromStatuses(validated.value.change, phases.value, this.options));
53
73
  }
54
74
  getCockpit(input) {
55
75
  const validated = validateProjectAndChange(input.project, input.change);
@@ -59,12 +79,12 @@ export class SddWorkflowService {
59
79
  if (!snapshot.ok)
60
80
  return snapshot;
61
81
  const phases = snapshot.value.phases;
62
- const next = nextDecisionFromStatuses(validated.value.change, phases);
82
+ const next = nextDecisionFromStatuses(validated.value.change, phases, this.options);
63
83
  const cockpitPhases = phases.map((phaseStatus) => {
64
84
  const readiness = {
65
85
  change: validated.value.change,
66
86
  phase: phaseStatus.phase,
67
- ...getReadinessFromStatuses(validated.value.change, phaseStatus.phase, phases),
87
+ ...getReadinessFromStatuses(validated.value.change, phaseStatus.phase, phases, this.options),
68
88
  };
69
89
  const artifact = phaseStatus.present ? cockpitArtifactSummaryFromSnapshotItem(phaseStatus) : undefined;
70
90
  const blockers = cockpitBlockersForPhase(phaseStatus, readiness);
@@ -115,7 +135,7 @@ export class SddWorkflowService {
115
135
  if (!snapshot.ok)
116
136
  return snapshot;
117
137
  const phases = snapshot.value.phases;
118
- const status = statusFromPhases(validated.value.change, phases);
138
+ const status = statusFromPhases(validated.value.change, phases, this.options);
119
139
  if (!status.ok)
120
140
  return status;
121
141
  const warnings = [];
@@ -137,7 +157,7 @@ export class SddWorkflowService {
137
157
  }
138
158
  return [{ phase: phase.phase, topicKey: phase.topicKey, artifact: phase.artifact, envelope }];
139
159
  });
140
- const readiness = input.phase === undefined ? undefined : { change: validated.value.change, phase: input.phase, ...getReadinessFromStatuses(validated.value.change, input.phase, phases) };
160
+ const readiness = input.phase === undefined ? undefined : { change: validated.value.change, phase: input.phase, ...getReadinessFromStatuses(validated.value.change, input.phase, phases, this.options) };
141
161
  return ok({ status: status.value, artifacts, ...(readiness === undefined ? {} : { readiness }), warnings });
142
162
  }
143
163
  saveArtifact(input) {
@@ -146,13 +166,20 @@ export class SddWorkflowService {
146
166
  return validated;
147
167
  if (input.content.trim().length === 0)
148
168
  return validationFailure('SDD artifact content must not be empty');
149
- return this.memory.saveArtifact({
150
- project: validated.value.project,
151
- topicKey: sddTopicKey(validated.value.change, validated.value.phase),
152
- phase: validated.value.phase,
153
- content: input.content,
154
- metadata: { status: 'draft' },
155
- }, this.context);
169
+ const { project, change, phase } = validated.value;
170
+ const topicKey = sddTopicKey(change, phase);
171
+ const existing = this.memory.getArtifact(project, topicKey, this.context);
172
+ if (existing.ok) {
173
+ const envelope = normalizeSddArtifact(existing.value);
174
+ const status = envelope.metadata.status;
175
+ if (status === 'accepted')
176
+ return validationFailure('Cannot overwrite an accepted SDD artifact; supersede it under a new topic key.');
177
+ if (status === 'rejected')
178
+ return validationFailure('Rejected SDD artifact must be re-opened with an explicit decision before saving.');
179
+ if (status === 'superseded')
180
+ return validationFailure('Cannot overwrite a superseded SDD artifact.');
181
+ }
182
+ return this.memory.saveArtifact({ project, topicKey, phase, content: input.content, metadata: { status: 'draft' } }, this.context);
156
183
  }
157
184
  acceptArtifact(input) {
158
185
  const validated = this.validatePhaseInput(input);
@@ -169,6 +196,11 @@ export class SddWorkflowService {
169
196
  if (!existing.ok)
170
197
  return existing;
171
198
  const existingEnvelope = normalizeSddArtifact(existing.value);
199
+ const existingStatus = existingEnvelope.metadata.status;
200
+ if (existingStatus === 'rejected')
201
+ return validationFailure('Rejected SDD artifact must be re-opened with an explicit decision before accepting.');
202
+ if (existingStatus === 'superseded')
203
+ return validationFailure('Cannot accept a superseded SDD artifact; create a new artifact under a different topic key instead.');
172
204
  const acceptance = {
173
205
  actor: {
174
206
  type: 'human',
@@ -203,7 +235,7 @@ export class SddWorkflowService {
203
235
  const statuses = this.getPhaseStatuses(validated.value.project, validated.value.change);
204
236
  if (!statuses.ok)
205
237
  return statuses;
206
- return ok(compactArtifactProjection(artifact.value, validated.value.change, validated.value.phase, getReadinessFromStatuses(validated.value.change, validated.value.phase, statuses.value)));
238
+ return ok(compactArtifactProjection(artifact.value, validated.value.change, validated.value.phase, getReadinessFromStatuses(validated.value.change, validated.value.phase, statuses.value, this.options)));
207
239
  }
208
240
  listArtifacts(input) {
209
241
  const validated = validateProjectAndChange(input.project, input.change);
@@ -219,7 +251,7 @@ export class SddWorkflowService {
219
251
  artifacts: snapshot.value.phases.flatMap((phase) => {
220
252
  if (phase.artifact === undefined)
221
253
  return [];
222
- return [compactArtifactProjection(phase.artifact, validated.value.change, phase.phase, getReadinessFromStatuses(validated.value.change, phase.phase, snapshot.value.phases))];
254
+ return [compactArtifactProjection(phase.artifact, validated.value.change, phase.phase, getReadinessFromStatuses(validated.value.change, phase.phase, snapshot.value.phases, this.options))];
223
255
  }),
224
256
  fullRetrieval: {
225
257
  tool: 'vgxness_sdd_list_artifacts',
@@ -280,14 +312,14 @@ export class SddWorkflowService {
280
312
  return ok({ project, change, phases });
281
313
  }
282
314
  }
283
- export function nextDecisionFromStatuses(change, phases) {
315
+ export function nextDecisionFromStatuses(change, phases, options = {}) {
284
316
  const blockedPresentPhase = phases.find((status) => {
285
317
  if (!status.present)
286
318
  return false;
287
- return (getReadinessFromStatuses(change, status.phase, phases).blockedPrerequisites ?? []).length > 0;
319
+ return (getReadinessFromStatuses(change, status.phase, phases, options).blockedPrerequisites ?? []).length > 0;
288
320
  });
289
321
  if (blockedPresentPhase !== undefined) {
290
- const readiness = getReadinessFromStatuses(change, blockedPresentPhase.phase, phases);
322
+ const readiness = getReadinessFromStatuses(change, blockedPresentPhase.phase, phases, options);
291
323
  const blockers = readiness.blockedPrerequisites ?? [];
292
324
  return {
293
325
  change,
@@ -329,7 +361,7 @@ export function nextDecisionFromStatuses(change, phases) {
329
361
  recommendedAction: 'No next SDD phase remains for this change.',
330
362
  };
331
363
  }
332
- const readiness = getReadinessFromStatuses(change, nextMissingPhase, phases);
364
+ const readiness = getReadinessFromStatuses(change, nextMissingPhase, phases, options);
333
365
  if (!readiness.ready) {
334
366
  const blockers = readiness.blockedPrerequisites ?? [];
335
367
  return {
@@ -352,24 +384,26 @@ export function nextDecisionFromStatuses(change, phases) {
352
384
  recommendedAction: `Run the ${nextMissingPhase} SDD phase for ${change}.`,
353
385
  };
354
386
  }
355
- function statusFromPhases(change, phases) {
387
+ function statusFromPhases(change, phases, options = {}) {
356
388
  const nextReadyPhase = sddPhases.find((phase) => {
357
389
  if (phases.find((status) => status.phase === phase)?.present)
358
390
  return false;
359
- return getReadinessFromStatuses(change, phase, phases).ready;
391
+ return getReadinessFromStatuses(change, phase, phases, options).ready;
360
392
  });
361
393
  const status = { change, phases };
362
394
  if (nextReadyPhase !== undefined)
363
395
  status.nextReadyPhase = nextReadyPhase;
364
396
  return { ok: true, value: status };
365
397
  }
366
- function getReadinessFromStatuses(change, phase, phases) {
398
+ function getReadinessFromStatuses(change, phase, phases, options = {}) {
367
399
  const satisfiedPrerequisites = [];
368
400
  const missingArtifactTopicKeys = [];
369
401
  const blockedPrerequisites = [];
402
+ const useAutoAdvance = options.autoAdvance === true;
370
403
  for (const prerequisite of sddPrerequisites[phase]) {
371
404
  const status = phases.find((candidate) => candidate.phase === prerequisite);
372
- if (status?.accepted) {
405
+ const satisfied = useAutoAdvance ? isPrerequisiteSatisfied(status) : status?.accepted === true;
406
+ if (satisfied) {
373
407
  satisfiedPrerequisites.push(prerequisite);
374
408
  continue;
375
409
  }
@@ -508,10 +542,6 @@ function blockerReasonForStatus(status) {
508
542
  if (status.legacy === true)
509
543
  return 'legacy';
510
544
  const state = status.state ?? (status.present ? 'draft' : 'missing');
511
- if (state === 'missing')
512
- return 'missing';
513
- if (state === 'accepted')
514
- return 'draft';
515
545
  return state;
516
546
  }
517
547
  function formatBlockers(blockers) {
@@ -3,27 +3,31 @@ import { noWriteActionSafety } from './provider-setup-adapter.js';
3
3
  export const claudeSetupAdapter = {
4
4
  id: 'claude',
5
5
  displayName: 'Claude',
6
- supportLevel: 'preview-only',
7
- capabilities: ['mcp-preview', 'mcp-install-plan', 'agent-preview', 'doctor', 'manual-guidance'],
6
+ supportLevel: 'supported-secondary',
7
+ capabilities: ['mcp-preview', 'mcp-install-plan', 'cli-mcp-plan', 'agent-preview', 'doctor', 'manual-guidance'],
8
8
  targets: [
9
9
  { kind: 'project-config', label: 'Project .mcp.json', path: '.mcp.json', writableBySetup: false },
10
10
  { kind: 'project-config', label: 'Project Claude agents', path: '.claude/agents/*.md', writableBySetup: false },
11
+ { kind: 'project-config', label: 'Project Claude memory', path: 'CLAUDE.md', writableBySetup: false },
12
+ { kind: 'user-config', label: 'User Claude MCP config', path: '~/.claude.json', writableBySetup: false },
13
+ { kind: 'user-config', label: 'User Claude agents', path: '~/.claude/agents/*.md', writableBySetup: false },
14
+ { kind: 'user-config', label: 'User Claude memory', path: '~/.claude/CLAUDE.md', writableBySetup: false },
11
15
  ],
12
16
  getStatus(context) {
13
17
  return {
14
18
  providerId: 'claude',
15
- status: 'preview-only',
16
- summary: 'Claude setup supports project-local read-only planning for .mcp.json and .claude/agents/*.md; confirmed writes are handled by guarded install flows.',
19
+ status: 'supported-secondary',
20
+ summary: 'Claude is supported as a secondary, non-default provider for CLI MCP registration planning/apply, project .mcp.json compatibility, guarded CLAUDE.md memory, user ~/.claude.json MCP merge, and project/user agents; explicit guarded apply is required for writes or CLI execution.',
17
21
  evidence: context.databasePath !== undefined
18
22
  ? ['Claude MCP preview can be generated from the selected database path.']
19
23
  : ['Claude MCP preview uses a placeholder until a database path is selected.'],
20
- guidance: ['Review the Claude plan before any write. VGXNESS never writes ~/.claude.json, CLAUDE.md, or .claude/CLAUDE.md and does not execute/install Claude Code.'],
24
+ guidance: ['Use `vgxness mcp install claude --scope local|project|user --yes --run-id <id>` for explicit guarded apply. Project scope may write .mcp.json, .claude/agents/*.md, and the project-root CLAUDE.md managed block. User/global scope narrowly merges only mcpServers.vgxness in ~/.claude.json, writes ~/.claude/agents/*.md, and manages only the VGXNESS block in ~/.claude/CLAUDE.md. Read-only setup/status surfaces do not execute Claude Code.'],
21
25
  actions: [
22
26
  {
23
27
  id: 'claude-manual-guidance',
24
- label: 'Review Claude MCP snippet',
28
+ label: 'Review guarded Claude install guidance',
25
29
  kind: 'manual-guidance',
26
- description: 'Manual preview guidance only; no install/apply action is available.',
30
+ description: 'Supported secondary guidance only in setup status; writes are available only through the guarded mcp install claude flow with run preflight metadata.',
27
31
  safety: noWriteActionSafety,
28
32
  },
29
33
  ],
@@ -1,4 +1,5 @@
1
1
  import { join, resolve } from 'node:path';
2
+ import { planClaudeCodeMcpInstall } from '../mcp/client-install-claude-code-contract.js';
2
3
  import { planOpenCodeMcpInstall } from '../mcp/client-install-opencode-contract.js';
3
4
  import { resolveMemoryDatabasePath } from '../memory/storage-paths.js';
4
5
  import { vgxnessSetupDefaults } from './setup-defaults.js';
@@ -45,8 +46,66 @@ export function createSetupPlan(input) {
45
46
  },
46
47
  };
47
48
  }
49
+ if (provider === 'claude') {
50
+ const claude = planClaudeCodeMcpInstall({
51
+ cwd: input.workspaceRoot,
52
+ databasePath: database.value.path,
53
+ databasePathSource: database.value.planSource,
54
+ ...(input.overwriteVgxness === undefined ? {} : { overwriteVgxness: input.overwriteVgxness }),
55
+ });
56
+ const targetPath = claude.targetPath;
57
+ if (claude.status === 'refused') {
58
+ return {
59
+ ok: true,
60
+ value: {
61
+ ...common,
62
+ provider: 'claude',
63
+ db: { mode: database.value.mode, path: database.value.path, source: database.value.source },
64
+ status: 'conflict',
65
+ actions: [],
66
+ conflicts: [
67
+ {
68
+ id: claude.reason,
69
+ severity: 'blocking',
70
+ message: claude.message,
71
+ targetPath,
72
+ recovery: claude.reason === 'malformed_claude_project_memory' || claude.reason === 'conflicting_claude_project_memory' ? 'Manually reconcile the VGXNESS markers in project-root CLAUDE.md, then rerun `vgxness setup plan --provider claude`.' : 'Inspect the Claude project config, resolve the conflict, then rerun `vgxness setup plan --provider claude`.',
73
+ },
74
+ ],
75
+ backupsPlanned: [],
76
+ nextCommands: ['vgxness mcp install claude --plan --scope project', 'Resolve the reported Claude project conflict before guarded apply.'],
77
+ },
78
+ };
79
+ }
80
+ return {
81
+ ok: true,
82
+ value: {
83
+ ...common,
84
+ provider: 'claude',
85
+ db: { mode: database.value.mode, path: database.value.path, source: database.value.source },
86
+ status: 'ready',
87
+ actions: [
88
+ {
89
+ id: 'claude-guarded-install',
90
+ description: `Review supported secondary Claude plan for CLI MCP registration, .mcp.json compatibility, ${claude.agentNames.length} .claude/agents/*.md file(s), and guarded project-root CLAUDE.md managed block; apply only with vgxness mcp install claude --scope project --yes --run-id <id>.`,
91
+ mutating: false,
92
+ targetPath,
93
+ backupRequired: claude.backupRequired,
94
+ },
95
+ ],
96
+ conflicts: [],
97
+ backupsPlanned: claude.targets
98
+ .filter((target) => target.kind !== 'cli-mcp-registration' && ((target.kind === 'project-memory' && target.backupRequired) || target.action === 'merge' || target.action === 'update-vgxness'))
99
+ .map((target) => ({
100
+ targetPath: target.path,
101
+ reason: target.kind === 'project-memory' ? 'A future guarded Claude apply would create a managed VGXNESS backup before appending or updating the project-root CLAUDE.md managed block.' : 'A future guarded Claude apply would create a managed VGXNESS backup before merging or updating Claude project configuration.',
102
+ })),
103
+ nextCommands: ['vgxness mcp install claude --plan --scope project', 'vgxness mcp install claude --scope project --yes --run-id <id>', 'OpenCode remains the default/primary provider.'],
104
+ },
105
+ };
106
+ }
48
107
  if (provider !== 'opencode')
49
- return { ok: false, error: { code: 'validation_failed', message: 'Provider must be opencode or none for the setup plan.' } };
108
+ return { ok: false, error: { code: 'validation_failed', message: 'Provider must be opencode, claude, or none for the setup plan.' } };
50
109
  const opencode = planOpenCodeMcpInstall({
51
110
  cwd: input.workspaceRoot,
52
111
  databasePath: database.value.path,
@@ -18,7 +18,7 @@ The user-facing shape is deliberately four-surface: **MCP for agents**, **CLI fo
18
18
  | Core workflow | SDD-first canonical state: explore → proposal → spec → design → tasks → apply-progress → verify → archive. |
19
19
  | Interfaces | MCP server for AI tools, CLI for automation/power users, TUI for guided install/status/profile/SDD workflows, and `vgxness code` runtime for bounded workspace work. |
20
20
  | Installation UX | Step-based guided setup with doctor checks, dry-run support, and no manual provider JSON editing on the happy path. |
21
- | Provider strategy | Provider-agnostic domain model with OpenCode as the primary supported provider; Claude Code is preview/manual only and VGXNESS does not install Claude or write `.claude/` or `CLAUDE.md`. Pi/`gentle-pi` compatibility is a future adapter/reference target. The code runtime speaks to any OpenAI-compatible endpoint through `src/code/providers/openai-compatible-provider-adapter.ts`. |
21
+ | Provider strategy | Provider-agnostic domain model with OpenCode as the primary/default supported provider; Claude Code is supported secondary for CLI MCP registration, project `.mcp.json` compatibility, guarded `CLAUDE.md` managed memory, direct user `~/.claude.json` MCP merge, and project/user agent files. Claude scopes are `local`, `project`, and `user` (`personal`/`global` map to `user`). Read-only status/doctor/change-plan never execute Claude Code; user/global apply mutates only `mcpServers.vgxness`, VGXNESS-owned `~/.claude/agents/*.md`, and the VGXNESS block in `~/.claude/CLAUDE.md` after confirmation/preflight. Pi/`gentle-pi` compatibility is a future adapter/reference target. The code runtime speaks to any OpenAI-compatible endpoint through `src/code/providers/openai-compatible-provider-adapter.ts`. |
22
22
  | Memory | Project memory plus personal/global memory, backed locally. |
23
23
  | Agents | Agents/subagents are registered in a neutral schema, then rendered into provider-specific config. |
24
24
  | Skills | Skills are first-class, versioned, attachable to agents/workflows/adapters, and improved through reviewable proposals. |
@@ -439,7 +439,7 @@ vgxness agents render --provider opencode --project vgxness --name apply-agent
439
439
  Rendering is intentionally read-only: it returns generated content in the CLI response. It does **not** write `.opencode/`, `.claude/`, or any user/global provider config.
440
440
  OpenCode agent keys are sanitized deterministically from registry names, and rendering rejects key collisions instead of overwriting generated config.
441
441
 
442
- Claude Code rendering remains follow-up work after its exact install-safe artifact shape is specified.
442
+ Claude Code install planning/apply is supported through the guarded MCP install path. Rendering remains read-only; confirmed project compatibility writes are limited to `.mcp.json`, `.claude/agents/*.md`, and the project-root `CLAUDE.md` managed block with run preflight metadata. User/global install is a guarded direct path that backs up existing files, merges only `mcpServers.vgxness` in `~/.claude.json`, writes VGXNESS-owned `~/.claude/agents/*.md`, and manages only the VGXNESS block in `~/.claude/CLAUDE.md`.
443
443
 
444
444
  ### OpenCode injection preview
445
445
 
package/docs/cli.md CHANGED
@@ -232,7 +232,7 @@ bun run cli:bun -- sdd status --project vgxness --change my-change
232
232
  Provider support shown in the Installation surface is:
233
233
 
234
234
  - **OpenCode** — supported primary provider with preview/status/doctor and read-only install planning.
235
- - **Claude** — preview-only guidance; no install/apply action is exposed.
235
+ - **Claude** — supported secondary provider for Claude CLI MCP registration, project `.mcp.json` compatibility, guarded `CLAUDE.md` managed memory, user `~/.claude.json` MCP merge, and project/user agents. Scopes are `local|project|user`; `personal`/`global` map to `user`. Explicit guarded apply is outside the guided OpenCode flow and requires `mcp install claude --scope <scope> --yes --run-id <id>`. Read-only status/doctor/change-plan do not execute Claude Code.
236
236
  - **Antigravity** — placeholder/coming-soon guidance only.
237
237
  - **Custom/future** — extension point with safe manual/default unsupported behavior.
238
238
 
@@ -445,7 +445,7 @@ bun run cli:bun -- mcp setup --preview --provider claude --db <path>
445
445
  bun run cli:bun -- mcp doctor --db <path> --project vgxness --change manual-smoke
446
446
  ```
447
447
 
448
- The setup preview JSON includes `installable:false`, `readOnly:true`, `writesProviderConfig:false`, plus a copyable MCP server command. Without `--db`, preview snippets omit `--db` and rely on the global default database; with `--db <path>` or `VGXNESS_DB_PATH`, snippets keep the explicit database argument. If needed, copy the `server.command` and `server.args` from the preview into your client manually; the preview itself never writes that config. For OpenCode config automation, inspect `mcp install opencode --plan` before applying with `--yes`; the default target is `$HOME/.config/opencode/opencode.json`.
448
+ The setup preview JSON includes `installable:false`, `readOnly:true`, `writesProviderConfig:false`, plus a copyable MCP server command. Without `--db`, preview snippets omit `--db` and rely on the global default database; with `--db <path>` or `VGXNESS_DB_PATH`, snippets keep the explicit database argument. If needed, copy the `server.command` and `server.args` from the preview into your client manually; the preview itself never writes that config. For OpenCode config automation, inspect `mcp install opencode --plan` before applying with `--yes`; the default target is `$HOME/.config/opencode/opencode.json`. For Claude config, inspect `mcp install claude --plan --scope local|project|user`; confirmed writes or CLI execution require `mcp install claude --scope <scope> --yes --run-id <id>` so VGXNESS run preflight can authorize each target.
449
449
 
450
450
  The top-level `vgxness doctor` command prints human-readable readiness checks by default and accepts `--json` for scriptable output. Lower-level `mcp doctor` remains useful for MCP-specific checks and manual diagnostics; use `--json` where parseable output is needed. `ready:true` means required checks passed. `ready:false` means at least one required check failed; read the failed check `id`, `detail`, and optional `remediation` to fix the local setup, then run doctor again.
451
451
 
@@ -506,6 +506,41 @@ Manual OpenCode verification checklist:
506
506
  5. In OpenCode, confirm the `vgxness` MCP tools are available.
507
507
  6. Call `vgxness_sdd_status` against a known project/change, then run doctor again if anything fails.
508
508
 
509
+ ## Claude Code MCP install
510
+
511
+ Claude Code is supported as a secondary, non-default provider for VGXNESS MCP/subagent configuration. Planning/status/doctor/change-plan are read-only and do not require Claude Code, network, or credentials. Scopes are `local`, `project`, and `user`; compatibility aliases `personal` and legacy `global` map to Claude `user` with warnings. MCP registration is represented as structured config/argv (`claude mcp add --scope <scope> vgxness -- vgxness mcp start`), never shell strings. User/global apply narrowly merges only `mcpServers.vgxness` in `~/.claude.json` and preserves unknown keys/auth/session data.
512
+
513
+ ```bash
514
+ bun run cli:bun -- mcp install claude --plan --scope project --db <path>
515
+ bun run cli:bun -- mcp install claude --plan --scope user --db <path>
516
+ bun run cli:bun -- mcp install claude --yes --scope project --run-id <id> --db <path>
517
+ ```
518
+
519
+ Allowed project-scope writes after explicit confirmation and run preflight:
520
+
521
+ - `.mcp.json`
522
+ - `.claude/agents/*.md`
523
+ - project-root `CLAUDE.md`, only the VGXNESS managed block; user-authored content outside the block is preserved and existing files are backed up before append/update
524
+
525
+ User agent files target `~/.claude/agents/*.md` only when a future apply path explicitly preflights that external directory. Read-only plans/status/doctor/change-plan never write it.
526
+
527
+ Forbidden writes:
528
+
529
+ - `~/.claude.json` except guarded user/global `mcpServers.vgxness` merge
530
+ - `.claude/CLAUDE.md`; user/global uses `~/.claude/CLAUDE.md` and manages only the VGXNESS block
531
+
532
+ Malformed or conflicting VGXNESS markers in project-root `CLAUDE.md` refuse the full Claude project install before any Claude target is mutated.
533
+
534
+ Manual/opt-in runtime validation checklist (not normal CI):
535
+
536
+ 1. Apply Claude project-local config through the guarded VGXNESS flow.
537
+ 2. Open Claude Code in the project manually.
538
+ 3. Approve the project MCP server if prompted.
539
+ 4. Run `/mcp` and verify `vgxness` is connected.
540
+ 5. Run `/agents` and verify expected project subagents are visible.
541
+ 6. Ask Claude to call a safe read-only VGXNESS MCP tool.
542
+ 7. Confirm forbidden files were not written by VGXNESS.
543
+
509
544
  ## SDD workflow examples
510
545
 
511
546
  Use `sdd` commands to inspect local SDD artifact state and save, read, or list phase artifacts. These commands read and write only the selected `vgxness` local SQLite memory store: `--db <path>` when passed, `VGXNESS_DB_PATH` when set, or the global default database when neither override is present.
package/docs/glossary.md CHANGED
@@ -8,7 +8,7 @@ A human-only action that records explicit approval of a SDD phase artifact. `vgx
8
8
 
9
9
  ## Adapter
10
10
 
11
- A translator between VGXNESS's provider-neutral domain and a specific provider. The control plane uses renderers (OpenCode, JSON, Claude preview). The code runtime uses `CodeProviderAdapter` implementations (`openai-compatible`, `fake`).
11
+ A translator between VGXNESS's provider-neutral domain and a specific provider. The control plane uses renderers/install planners (OpenCode, JSON, Claude project-local support). The code runtime uses `CodeProviderAdapter` implementations (`openai-compatible`, `fake`).
12
12
 
13
13
  ## Agent
14
14
 
@@ -92,7 +92,7 @@ The provider-agnostic front-door classifier for operator text. Maps an intent to
92
92
 
93
93
  ## OpenCode
94
94
 
95
- The primary supported provider for the control plane. The configurator renders OpenCode MCP config and manager/SDD agent definitions. Claude Code is preview/manual only.
95
+ The primary/default supported provider for the control plane. The configurator renders OpenCode MCP config and manager/SDD agent definitions. Claude Code is supported secondary for project-local VGXNESS MCP/subagent configuration through explicit guarded apply.
96
96
 
97
97
  ## Operation attempt
98
98
 
package/docs/prd.md CHANGED
@@ -203,7 +203,7 @@ The same flow must be available through CLI flags for automation and CI-friendly
203
203
  Initial integration targets:
204
204
 
205
205
  - OpenCode — primary supported provider. The configurator plane renders OpenCode MCP config and manager/SDD agent definitions; the code runtime speaks to any OpenAI-compatible endpoint, including OpenCode's local bridge.
206
- - Claude Code — preview/manual only as of v1.5.1. The canonical agent manifest declares Claude support as `preview` with an explicit reason: VGXNESS does not install Claude or write `.claude/` or `CLAUDE.md`. Owners of Claude-only workflows must run setup themselves.
206
+ - Claude Code — supported secondary for project-local VGXNESS MCP/subagent configuration and guarded project-root `CLAUDE.md` managed memory. Confirmed writes are explicit and guarded (`.mcp.json`, `.claude/agents/*.md`, and the `CLAUDE.md` managed block only); VGXNESS does not install/execute Claude Code and never manually writes `~/.claude.json` or `.claude/CLAUDE.md`.
207
207
 
208
208
  Pi/`gentle-pi` is a design reference and future adapter target, not part of the first integration target list unless the MVP scope is explicitly expanded.
209
209
 
@@ -351,7 +351,7 @@ Many of the early PRD questions are resolved in v1.5.1. Tracking them here keeps
351
351
 
352
352
  | Question | Resolved as of v1.5.1 |
353
353
  |---|---|
354
- | First integration adapter | OpenCode primary; Claude is preview/manual. |
354
+ | First integration adapter | OpenCode primary/default; Claude is supported secondary for project-local explicit apply. |
355
355
  | Memory storage scopes | Project memory and personal/global memory live in separate SQLite stores; `--db` flag and `VGXNESS_DB_PATH` env var override. |
356
356
  | Agent config format | Provider-neutral schema in `src/agents/schema.ts`; canonical manifest with validation in `src/agents/canonical-agent-manifest.ts`. |
357
357
  | Skill config format | Versioned skills with source metadata (`path`/`url`/`inline`); active version gating in `src/skills/skill-registry-service.ts`. |
package/docs/providers.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # Providers
2
2
 
3
- VGXNESS is provider-agnostic at the core: the registry stores provider-neutral definitions and adapters translate them into provider-specific config and runtime behavior. This document covers the two adapter layers: the **control-plane adapter** (OpenCode renderer today, with a Claude preview renderer in the tree) and the **code-runtime provider adapter** (OpenAI-compatible + fake).
3
+ VGXNESS is provider-agnostic at the core: the registry stores provider-neutral definitions and adapters translate them into provider-specific config and runtime behavior. This document covers the two adapter layers: the **control-plane adapter** (OpenCode primary plus supported secondary Claude Code support) and the **code-runtime provider adapter** (OpenAI-compatible + fake).
4
4
 
5
- ## Status (v1.5.1)
5
+ ## Status (v1.6.0)
6
6
 
7
7
  | Provider | Control plane | Code runtime | Notes |
8
8
  |---|---|---|---|
9
9
  | OpenCode | `managed` | n/a (target) | Primary supported provider. The configurator renders OpenCode MCP config and manager/SDD agent definitions into the chosen scope. |
10
- | Claude Code | `preview/manual` | n/a | The canonical agent manifest declares Claude support as `preview` with an explicit reason: VGXNESS does not install Claude or write `.claude/` or `CLAUDE.md`. Owners of Claude-only workflows must run setup themselves. |
10
+ | Claude Code | `supported-secondary` | n/a | Supported for Claude CLI MCP registration planning/apply, project `.mcp.json` compatibility, guarded `CLAUDE.md` managed memory, user `~/.claude.json` MCP merge, and project/user agent files. Scopes are `local`, `project`, and `user`; `personal`/`global` map to `user` for compatibility. Confirmed applies are explicit and guarded; read-only surfaces inspect files without executing Claude Code. |
11
11
  | Antigravity | `placeholder` | n/a | Listed in the TUI Installation surface as coming-soon. |
12
12
  | Custom / future | `extension` | extension point | Per the [Architecture](./architecture.md) decision, anything not OpenCode or Claude is a custom extension. |
13
13
  | OpenAI-compatible | n/a | `openai-compatible-provider-adapter.ts` | Real adapter used by `vgxness code`. Speaks to any OpenAI-compatible endpoint. |
@@ -42,9 +42,36 @@ The output is previewable JSON; the renderer does not write to `.opencode/`, `.c
42
42
  vgxness agents render --provider json --project vgxness --name apply-agent
43
43
  ```
44
44
 
45
- ### Claude renderer (preview)
45
+ ### Claude Code support
46
46
 
47
- `src/agents/renderers/claude-renderer.ts` exists in the tree as a preview renderer. The shape of an install-safe Claude artifact is not yet finalized, so the renderer is not enabled for end-to-end install flows.
47
+ Claude Code is supported as a secondary, non-default control-plane target. Read-only status, doctor, setup plan, and change-plan surfaces can inspect or preview Claude targets without Claude Code installed and without writing files.
48
+
49
+ Claude scopes are canonicalized to `local`, `project`, and `user`; VGXNESS compatibility aliases `personal` and legacy `global` map to Claude `user` with warnings. MCP registration is represented as structured config/argv, for example `claude mcp add --scope user vgxness -- vgxness mcp start`; no shell strings are generated. For user/global apply, VGXNESS narrowly merges only `mcpServers.vgxness` in `~/.claude.json`, preserves unknown keys, backs up existing files, and does not manage auth/session data. Status/doctor/change-plan are read-only and do not execute Claude Code.
50
+
51
+ Allowed project-scope writes, only after explicit guarded apply with run preflight metadata (`vgxness mcp install claude --scope project --yes --run-id <id>`):
52
+
53
+ - `.mcp.json`
54
+ - `.claude/agents/*.md`
55
+ - project-root `CLAUDE.md`, only the VGXNESS managed block; user content outside the block is preserved exactly and existing files are backed up before append/update
56
+
57
+ User-scoped agent files target `~/.claude/agents/*.md` only as an explicit external-directory/preflighted operation. They are never written by read-only planning/status/doctor/change-plan.
58
+
59
+ Forbidden writes:
60
+
61
+ - `~/.claude.json` except the guarded user/global merge of `mcpServers.vgxness`
62
+ - `.claude/CLAUDE.md`; user/global memory is `~/.claude/CLAUDE.md` and only the VGXNESS managed block is touched
63
+
64
+ Malformed, duplicate, partial, or conflicting VGXNESS markers in `CLAUDE.md` cause the full Claude project install to be refused before `.mcp.json`, `.claude/agents/*.md`, or `CLAUDE.md` are mutated.
65
+
66
+ Manual/opt-in runtime validation checklist (not normal CI):
67
+
68
+ 1. Apply Claude project-local config through the guarded VGXNESS flow.
69
+ 2. Open Claude Code in the project manually.
70
+ 3. Approve the project MCP server if prompted.
71
+ 4. Run `/mcp` and verify `vgxness` is connected.
72
+ 5. Run `/agents` and verify expected project subagents are visible.
73
+ 6. Ask Claude to call a safe read-only VGXNESS MCP tool.
74
+ 7. Confirm forbidden files were not written by VGXNESS.
48
75
 
49
76
  ### OpenCode injection preview
50
77
 
@@ -113,7 +140,7 @@ Writes happen only through `apply` with explicit consent. Plans, status, doctor,
113
140
 
114
141
  Adapters and renderers must not:
115
142
 
116
- - Write provider config (`.opencode/`, `.claude/`, `opencode.json`, `CLAUDE.md`).
143
+ - Write provider config outside explicit guarded apply. OpenCode install writes only its selected target; Claude project compatibility apply writes only `.mcp.json`, `.claude/agents/*.md`, and the guarded project-root `CLAUDE.md` managed block. Claude user/global apply narrowly merges `mcpServers.vgxness` in `~/.claude.json`, writes VGXNESS-owned `~/.claude/agents/*.md`, and manages only the VGXNESS block in `~/.claude/CLAUDE.md` after confirmation/preflight.
117
144
  - Call providers (`opencode`, `claude`, etc.) during preview or status.
118
145
  - Install global memory.
119
146
  - Create `openspec/`.
package/docs/roadmap.md CHANGED
@@ -63,7 +63,7 @@ The main menu and setup screens are in via OpenTUI. The dashboard directory is e
63
63
 
64
64
  ## Provider coverage
65
65
 
66
- - **Claude Code install path.** Preview/manual only today. The renderer exists; an install-safe Claude artifact shape is the blocker.
66
+ - **Claude Code runtime validation.** Project-local install planning/apply is supported behind explicit run preflight. Remaining work is optional manual runtime smoke guidance or future live smoke tooling; it must stay out of normal CI.
67
67
  - **Antigravity and other custom adapters.** Listed as placeholders; a real adapter would unblock those workflows.
68
68
  - **Provider doctor upgrades.** Doctor checks could surface real config drift, not just existence of expected files.
69
69
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vgxness",
3
- "version": "1.5.2",
3
+ "version": "1.7.0",
4
4
  "description": "CLI and MCP control plane for guided AI-agent workflows, SDD, memory, and OpenCode setup.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {