vgxness 1.5.1 → 1.5.2

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 (42) hide show
  1. package/README.md +23 -2
  2. package/dist/agents/agent-seed-service.js +10 -0
  3. package/dist/agents/canonical-agent-manifest.js +177 -0
  4. package/dist/agents/canonical-agent-projection.js +146 -0
  5. package/dist/agents/renderers/claude-renderer.js +30 -52
  6. package/dist/cli/bun-bin.js +6 -0
  7. package/dist/cli/cli-help.js +3 -0
  8. package/dist/cli/commands/agent-skill-dispatcher.js +6 -5
  9. package/dist/cli/commands/mcp-dispatcher.js +65 -3
  10. package/dist/cli/index.js +1 -1
  11. package/dist/governance/governance-report-builder.js +45 -26
  12. package/dist/mcp/claude-code-agent-config.js +79 -0
  13. package/dist/mcp/claude-code-config.js +84 -0
  14. package/dist/mcp/client-install-claude-code-contract.js +86 -0
  15. package/dist/mcp/client-install-claude-code.js +85 -0
  16. package/dist/mcp/index.js +5 -0
  17. package/dist/mcp/opencode-default-agent-config.js +7 -113
  18. package/dist/mcp/provider-canonical-agent-manifest.js +39 -0
  19. package/dist/mcp/provider-change-plan.js +57 -1
  20. package/dist/mcp/provider-doctor.js +54 -0
  21. package/dist/mcp/provider-status.js +82 -2
  22. package/dist/mcp/schema.js +2 -2
  23. package/dist/mcp/validation.js +1 -1
  24. package/dist/memory/memory-service.js +4 -0
  25. package/dist/sdd/sdd-workflow-service.js +129 -59
  26. package/dist/setup/providers/claude-setup-adapter.js +7 -4
  27. package/docs/architecture.md +54 -112
  28. package/docs/cli.md +53 -0
  29. package/docs/code-runtime.md +218 -0
  30. package/docs/contributing.md +120 -0
  31. package/docs/glossary.md +211 -0
  32. package/docs/mcp.md +144 -0
  33. package/docs/prd.md +23 -26
  34. package/docs/providers.md +123 -0
  35. package/docs/roadmap.md +88 -0
  36. package/docs/safety.md +147 -0
  37. package/docs/storage.md +93 -0
  38. package/package.json +1 -1
  39. package/docs/funcionamiento-del-sistema.md +0 -865
  40. package/docs/harness-gap-analysis.md +0 -243
  41. package/docs/vgxcode.md +0 -87
  42. package/docs/vgxness-code.md +0 -48
@@ -21,7 +21,9 @@ export class SddWorkflowService {
21
21
  if (!validated.ok)
22
22
  return validated;
23
23
  const phases = this.getPhaseStatuses(validated.value.project, validated.value.change);
24
- const readiness = getReadinessFromStatuses(validated.value.change, validated.value.phase, phases);
24
+ if (!phases.ok)
25
+ return phases;
26
+ const readiness = getReadinessFromStatuses(validated.value.change, validated.value.phase, phases.value);
25
27
  return {
26
28
  ok: true,
27
29
  value: {
@@ -36,20 +38,27 @@ export class SddWorkflowService {
36
38
  if (!validated.ok)
37
39
  return validated;
38
40
  const phases = this.getPhaseStatuses(validated.value.project, validated.value.change);
39
- return statusFromPhases(validated.value.change, phases);
41
+ if (!phases.ok)
42
+ return phases;
43
+ return statusFromPhases(validated.value.change, phases.value);
40
44
  }
41
45
  getNext(input) {
42
46
  const validated = validateProjectAndChange(input.project, input.change);
43
47
  if (!validated.ok)
44
48
  return validated;
45
49
  const phases = this.getPhaseStatuses(validated.value.project, validated.value.change);
46
- return ok(nextDecisionFromStatuses(validated.value.change, phases));
50
+ if (!phases.ok)
51
+ return phases;
52
+ return ok(nextDecisionFromStatuses(validated.value.change, phases.value));
47
53
  }
48
54
  getCockpit(input) {
49
55
  const validated = validateProjectAndChange(input.project, input.change);
50
56
  if (!validated.ok)
51
57
  return validated;
52
- const phases = this.getPhaseStatuses(validated.value.project, validated.value.change);
58
+ const snapshot = this.loadPhaseSnapshot(validated.value.project, validated.value.change);
59
+ if (!snapshot.ok)
60
+ return snapshot;
61
+ const phases = snapshot.value.phases;
53
62
  const next = nextDecisionFromStatuses(validated.value.change, phases);
54
63
  const cockpitPhases = phases.map((phaseStatus) => {
55
64
  const readiness = {
@@ -57,9 +66,7 @@ export class SddWorkflowService {
57
66
  phase: phaseStatus.phase,
58
67
  ...getReadinessFromStatuses(validated.value.change, phaseStatus.phase, phases),
59
68
  };
60
- const artifact = phaseStatus.present
61
- ? this.artifactSummaryForPhase(validated.value.project, validated.value.change, phaseStatus.phase, phaseStatus.topicKey)
62
- : undefined;
69
+ const artifact = phaseStatus.present ? cockpitArtifactSummaryFromSnapshotItem(phaseStatus) : undefined;
63
70
  const blockers = cockpitBlockersForPhase(phaseStatus, readiness);
64
71
  return {
65
72
  phase: phaseStatus.phase,
@@ -100,6 +107,39 @@ export class SddWorkflowService {
100
107
  };
101
108
  return ok(cockpit);
102
109
  }
110
+ getGovernanceSnapshot(input) {
111
+ const validated = validateProjectAndChange(input.project, input.change);
112
+ if (!validated.ok)
113
+ return validated;
114
+ const snapshot = this.loadPhaseSnapshot(validated.value.project, validated.value.change);
115
+ if (!snapshot.ok)
116
+ return snapshot;
117
+ const phases = snapshot.value.phases;
118
+ const status = statusFromPhases(validated.value.change, phases);
119
+ if (!status.ok)
120
+ return status;
121
+ const warnings = [];
122
+ const artifacts = phases.flatMap((phase) => {
123
+ if (phase.artifact === undefined)
124
+ return [];
125
+ const envelope = normalizeSddArtifact(phase.artifact);
126
+ warnings.push(...envelope.warnings);
127
+ if ((input.payloadMode ?? 'compact') === 'compact') {
128
+ const compactArtifact = compactGovernanceArtifact(envelope.artifact);
129
+ return [
130
+ {
131
+ phase: phase.phase,
132
+ topicKey: phase.topicKey,
133
+ artifact: compactArtifact,
134
+ envelope: { ...envelope, artifact: compactArtifact },
135
+ },
136
+ ];
137
+ }
138
+ return [{ phase: phase.phase, topicKey: phase.topicKey, artifact: phase.artifact, envelope }];
139
+ });
140
+ const readiness = input.phase === undefined ? undefined : { change: validated.value.change, phase: input.phase, ...getReadinessFromStatuses(validated.value.change, input.phase, phases) };
141
+ return ok({ status: status.value, artifacts, ...(readiness === undefined ? {} : { readiness }), warnings });
142
+ }
103
143
  saveArtifact(input) {
104
144
  const validated = this.validatePhaseInput(input);
105
145
  if (!validated.ok)
@@ -161,12 +201,33 @@ export class SddWorkflowService {
161
201
  if (input.payloadMode !== 'compact')
162
202
  return artifact;
163
203
  const statuses = this.getPhaseStatuses(validated.value.project, validated.value.change);
164
- return ok(compactArtifactProjection(artifact.value, validated.value.change, validated.value.phase, getReadinessFromStatuses(validated.value.change, validated.value.phase, statuses)));
204
+ if (!statuses.ok)
205
+ return statuses;
206
+ return ok(compactArtifactProjection(artifact.value, validated.value.change, validated.value.phase, getReadinessFromStatuses(validated.value.change, validated.value.phase, statuses.value)));
165
207
  }
166
208
  listArtifacts(input) {
167
209
  const validated = validateProjectAndChange(input.project, input.change);
168
210
  if (!validated.ok)
169
211
  return validated;
212
+ if (input.payloadMode === 'compact') {
213
+ const snapshot = this.loadPhaseSnapshot(validated.value.project, validated.value.change);
214
+ if (!snapshot.ok)
215
+ return snapshot;
216
+ return ok({
217
+ project: validated.value.project,
218
+ change: validated.value.change,
219
+ artifacts: snapshot.value.phases.flatMap((phase) => {
220
+ if (phase.artifact === undefined)
221
+ return [];
222
+ return [compactArtifactProjection(phase.artifact, validated.value.change, phase.phase, getReadinessFromStatuses(validated.value.change, phase.phase, snapshot.value.phases))];
223
+ }),
224
+ fullRetrieval: {
225
+ tool: 'vgxness_sdd_list_artifacts',
226
+ payloadMode: 'verbose',
227
+ input: { project: validated.value.project, change: validated.value.change },
228
+ },
229
+ });
230
+ }
170
231
  const listed = this.memory.listArtifactsByTopicPrefix(validated.value.project, `sdd/${validated.value.change}/`, this.context);
171
232
  if (!listed.ok)
172
233
  return listed;
@@ -174,22 +235,7 @@ export class SddWorkflowService {
174
235
  const artifacts = sddPhases
175
236
  .map((phase) => artifactsByTopicKey.get(sddTopicKey(validated.value.change, phase)))
176
237
  .filter((artifact) => artifact !== undefined);
177
- if (input.payloadMode !== 'compact')
178
- return ok({ project: validated.value.project, change: validated.value.change, artifacts });
179
- const statuses = this.getPhaseStatuses(validated.value.project, validated.value.change);
180
- return ok({
181
- project: validated.value.project,
182
- change: validated.value.change,
183
- artifacts: artifacts.map((artifact) => {
184
- const phase = isSddPhase(artifact.phase) ? artifact.phase : phaseFromTopicKey(validated.value.change, artifact.topicKey);
185
- return compactArtifactProjection(artifact, validated.value.change, phase, getReadinessFromStatuses(validated.value.change, phase, statuses));
186
- }),
187
- fullRetrieval: {
188
- tool: 'vgxness_sdd_list_artifacts',
189
- payloadMode: 'verbose',
190
- input: { project: validated.value.project, change: validated.value.change },
191
- },
192
- });
238
+ return ok({ project: validated.value.project, change: validated.value.change, artifacts });
193
239
  }
194
240
  validatePhaseInput(input) {
195
241
  const validated = validateProjectAndChange(input.project, input.change);
@@ -200,31 +246,38 @@ export class SddWorkflowService {
200
246
  return { ok: true, value: { ...validated.value, phase: input.phase } };
201
247
  }
202
248
  getPhaseStatuses(project, change) {
203
- return sddPhases.map((phase) => {
249
+ const snapshot = this.loadPhaseSnapshot(project, change);
250
+ if (!snapshot.ok)
251
+ return snapshot;
252
+ return ok(snapshot.value.phases.map(({ artifact, acceptance, createdAt, updatedAt, warnings, ...status }) => status));
253
+ }
254
+ loadPhaseSnapshot(project, change) {
255
+ const listed = this.memory.listArtifactsByTopicPrefixNoTrace(project, `sdd/${change}/`);
256
+ if (!listed.ok)
257
+ return listed;
258
+ const artifactsByTopicKey = new Map(listed.value.map((artifact) => [artifact.topicKey, artifact]));
259
+ const phases = sddPhases.map((phase) => {
204
260
  const topicKey = sddTopicKey(change, phase);
205
- const artifact = this.memory.getArtifact(project, topicKey, this.context);
206
- if (!artifact.ok)
207
- return { phase, topicKey, present: false, state: 'missing', accepted: false, legacy: false };
208
- return phaseStatusFromArtifact(phase, topicKey, artifact.value);
261
+ const artifact = artifactsByTopicKey.get(topicKey);
262
+ if (artifact === undefined)
263
+ return { phase, topicKey, present: false, state: 'missing', accepted: false, legacy: false, warnings: [] };
264
+ const envelope = normalizeSddArtifact(artifact);
265
+ return {
266
+ phase,
267
+ topicKey,
268
+ present: true,
269
+ state: envelope.metadata.status,
270
+ accepted: envelope.metadata.status === 'accepted',
271
+ legacy: envelope.warnings.includes('legacy-artifact-defaulted-to-draft'),
272
+ artifactId: artifact.id,
273
+ artifact,
274
+ ...(envelope.metadata.acceptance === undefined ? {} : { acceptance: envelope.metadata.acceptance }),
275
+ createdAt: artifact.createdAt,
276
+ updatedAt: artifact.updatedAt,
277
+ warnings: envelope.warnings,
278
+ };
209
279
  });
210
- }
211
- artifactSummaryForPhase(project, change, phase, topicKey) {
212
- const artifact = this.memory.getArtifact(project, topicKey, this.context);
213
- if (!artifact.ok)
214
- return undefined;
215
- const envelope = normalizeSddArtifact(artifact.value);
216
- return {
217
- phase,
218
- topicKey,
219
- present: true,
220
- accepted: envelope.metadata.status === 'accepted',
221
- legacy: envelope.warnings.includes('legacy-artifact-defaulted-to-draft'),
222
- state: envelope.metadata.status,
223
- artifactId: artifact.value.id,
224
- ...(envelope.metadata.acceptance === undefined ? {} : { acceptance: envelope.metadata.acceptance }),
225
- createdAt: artifact.value.createdAt,
226
- updatedAt: artifact.value.updatedAt,
227
- };
280
+ return ok({ project, change, phases });
228
281
  }
229
282
  }
230
283
  export function nextDecisionFromStatuses(change, phases) {
@@ -336,18 +389,6 @@ function getReadinessFromStatuses(change, phase, phases) {
336
389
  blockedPrerequisites,
337
390
  };
338
391
  }
339
- function phaseStatusFromArtifact(phase, topicKey, artifact) {
340
- const envelope = normalizeSddArtifact(artifact);
341
- return {
342
- phase,
343
- topicKey,
344
- present: true,
345
- state: envelope.metadata.status,
346
- accepted: envelope.metadata.status === 'accepted',
347
- legacy: envelope.warnings.includes('legacy-artifact-defaulted-to-draft'),
348
- artifactId: artifact.id,
349
- };
350
- }
351
392
  function compactArtifactProjection(artifact, change, phase, readiness) {
352
393
  const envelope = normalizeSddArtifact(artifact);
353
394
  const summary = summarizePayloadContent(artifact.content);
@@ -370,6 +411,35 @@ function compactArtifactProjection(artifact, change, phase, readiness) {
370
411
  updatedAt: artifact.updatedAt,
371
412
  };
372
413
  }
414
+ function cockpitArtifactSummaryFromSnapshotItem(item) {
415
+ if (item.artifact === undefined || item.artifactId === undefined || item.createdAt === undefined || item.updatedAt === undefined)
416
+ return undefined;
417
+ return {
418
+ phase: item.phase,
419
+ topicKey: item.topicKey,
420
+ present: true,
421
+ accepted: item.accepted === true,
422
+ legacy: item.legacy === true,
423
+ state: item.state ?? 'draft',
424
+ artifactId: item.artifactId,
425
+ ...(item.acceptance === undefined ? {} : { acceptance: item.acceptance }),
426
+ createdAt: item.createdAt,
427
+ updatedAt: item.updatedAt,
428
+ };
429
+ }
430
+ function compactGovernanceArtifact(artifact) {
431
+ return {
432
+ id: artifact.id,
433
+ project: artifact.project,
434
+ topicKey: artifact.topicKey,
435
+ phase: artifact.phase,
436
+ observationId: artifact.observationId,
437
+ createdAt: artifact.createdAt,
438
+ updatedAt: artifact.updatedAt,
439
+ contentLength: artifact.content.length,
440
+ contentOmitted: true,
441
+ };
442
+ }
373
443
  function cockpitBlockersForPhase(status, readiness) {
374
444
  const blockers = [];
375
445
  if (!status.present)
@@ -4,17 +4,20 @@ export const claudeSetupAdapter = {
4
4
  id: 'claude',
5
5
  displayName: 'Claude',
6
6
  supportLevel: 'preview-only',
7
- capabilities: ['mcp-preview', 'manual-guidance'],
8
- targets: [{ kind: 'manual', label: 'Claude MCP config snippet', writableBySetup: false }],
7
+ capabilities: ['mcp-preview', 'mcp-install-plan', 'agent-preview', 'doctor', 'manual-guidance'],
8
+ targets: [
9
+ { kind: 'project-config', label: 'Project .mcp.json', path: '.mcp.json', writableBySetup: false },
10
+ { kind: 'project-config', label: 'Project Claude agents', path: '.claude/agents/*.md', writableBySetup: false },
11
+ ],
9
12
  getStatus(context) {
10
13
  return {
11
14
  providerId: 'claude',
12
15
  status: 'preview-only',
13
- summary: 'Claude setup is preview-only with manual MCP guidance.',
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.',
14
17
  evidence: context.databasePath !== undefined
15
18
  ? ['Claude MCP preview can be generated from the selected database path.']
16
19
  : ['Claude MCP preview uses a placeholder until a database path is selected.'],
17
- guidance: ['Copy snippets manually after reviewing them. The TUI does not install or apply Claude config.'],
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.'],
18
21
  actions: [
19
22
  {
20
23
  id: 'claude-manual-guidance',
@@ -1,10 +1,12 @@
1
1
  # vgxness Architecture
2
2
 
3
+ > **Scope:** this document describes the v1.5.1 architecture as it is actually built. It is the source of truth for how the product works today. Planned work that is not yet shipped lives in [Roadmap](./roadmap.md); historical planning context that no longer reflects reality has been retired. Where this doc disagrees with code, code wins — file a doc-sync task against the relevant module.
4
+
3
5
  `vgxness` is a local-first, provider-agnostic, Gentle-AI-like harness for agentic development. Its core architecture separates the product domain from provider-specific tooling so agents, skills, memory, SDD workflows, runs, and traces can work across OpenCode, Claude Code, and future adapters such as Pi.
4
6
 
5
- The architectural goal is not only to install better prompts or agent configs. `vgxness` should combine an ecosystem configurator with a runtime control plane: configured agents may execute the work, but the product keeps explicit state for phase readiness, artifacts, runs, approvals, checkpoints, and audit evidence.
7
+ The architectural goal is not only to install better prompts or agent configs. `vgxness` combines an ecosystem configurator with a runtime control plane and a native code runtime: configured agents may execute the work, the control plane keeps explicit state for phase readiness, artifacts, runs, approvals, checkpoints, and audit evidence, and the code runtime performs bounded agentic work in the local workspace with explicit permission decisions.
6
8
 
7
- The user-facing shape is deliberately three-surface: **MCP for agents**, **CLI for scriptable operator control**, and **TUI for guided setup and visual local operations**. All three must call the same core services instead of reimplementing workflow rules.
9
+ The user-facing shape is deliberately four-surface: **MCP for agents**, **CLI for scriptable operator control**, **TUI for guided setup and visual local operations**, and **code runtime (`vgxness code`)** for bounded agentic work in the workspace. All four call the same core services instead of reimplementing workflow rules.
8
10
 
9
11
  ## Architecture decision summary
10
12
 
@@ -14,9 +16,9 @@ The user-facing shape is deliberately three-surface: **MCP for agents**, **CLI f
14
16
  | Reference model | Similar product surface to Gentle-AI/`gentle-pi`: agent setup, SDD orchestration, memory wiring, skills, profiles, permissions, verification. |
15
17
  | Differentiator | Verifiable runtime state engine: SDD phases, artifacts, runs, approvals, checkpoints, and audit trails are queryable product state, not prompt-only convention. |
16
18
  | Core workflow | SDD-first canonical state: explore → proposal → spec → design → tasks → apply-progress → verify → archive. |
17
- | Interfaces | MCP server for AI tools, CLI for automation/power users, TUI for guided install/status/profile/SDD workflows. |
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. |
18
20
  | Installation UX | Step-based guided setup with doctor checks, dry-run support, and no manual provider JSON editing on the happy path. |
19
- | Provider strategy | Provider-agnostic domain model with OpenCode and Claude Code first; Pi/`gentle-pi` compatibility is a future adapter/reference target. |
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`. |
20
22
  | Memory | Project memory plus personal/global memory, backed locally. |
21
23
  | Agents | Agents/subagents are registered in a neutral schema, then rendered into provider-specific config. |
22
24
  | Skills | Skills are first-class, versioned, attachable to agents/workflows/adapters, and improved through reviewable proposals. |
@@ -98,7 +100,7 @@ Gentle-AI/`gentle-pi` are strong references for the configurator and agent-behav
98
100
  | Project | Repo-specific memory, SDD artifacts, run history, adapter config, project agents/skills. | `.vgx/` or project-local SQLite store. |
99
101
  | Personal/global | User preferences, reusable skills, cross-project patterns, global agents. | User-level config/data directory. |
100
102
 
101
- The exact path format is still open, but the architectural rule is fixed: **project data and personal data must not be collapsed into one scope**.
103
+ The exact path format is still open, but the architectural rule is fixed: **project data and personal data must not be collapsed into one scope**. See [Storage](./storage.md) for schema, migration layout, and lifecycle.
102
104
 
103
105
  ## SDD workflow engine
104
106
 
@@ -116,18 +118,20 @@ Current phase artifacts use one canonical topic key each:
116
118
  sdd/{change}/{phase}
117
119
  ```
118
120
 
119
- Readiness is based on artifact presence only:
121
+ Readiness is a combination of prerequisite phase artifacts, explicit human acceptance, and aggregate blockers — artifact presence alone is not enough:
120
122
 
121
- | Phase | Required artifacts |
122
- |---|---|
123
- | `explore` | none |
124
- | `proposal` | `explore` |
125
- | `spec` | `proposal` |
126
- | `design` | `proposal`, `spec` |
127
- | `tasks` | `proposal`, `spec`, `design` |
128
- | `apply-progress` | `tasks` |
129
- | `verify` | `apply-progress` |
130
- | `archive` | `verify` |
123
+ | Phase | Required prerequisites | Acceptance required |
124
+ |---|---|---|
125
+ | `explore` | none | no |
126
+ | `proposal` | `explore` | yes (on `explore`) |
127
+ | `spec` | `proposal` | yes (on `proposal`) |
128
+ | `design` | `proposal`, `spec` | yes (on `proposal`, `spec`) |
129
+ | `tasks` | `proposal`, `spec`, `design` | yes (on `proposal`, `spec`, `design`) |
130
+ | `apply-progress` | `tasks` | yes (on `tasks`) |
131
+ | `verify` | `apply-progress` | yes (on `apply-progress`) |
132
+ | `archive` | `verify` | yes (on `verify`) |
133
+
134
+ `SddWorkflowService.getReady(...)` returns a structured `SddReadiness` with `blockedPrerequisites`, while `getCockpit(...)` aggregates `SddCockpitBlocker`s of kind `missing-topic-key`, `unaccepted-phase`, `legacy-artifact`, or `readiness`. Acceptance is recorded only by a human actor (`acceptedBy.type === 'human'`); the runtime rejects agent or anonymous acceptance.
131
135
 
132
136
  Current service API:
133
137
 
@@ -409,7 +413,7 @@ NO silent mutation of active skills. Eso es una línea roja.
409
413
 
410
414
  ## Provider adapter contract
411
415
 
412
- Adapters render registry definitions into provider artifacts without changing the registry model.
416
+ Adapters render registry definitions into provider artifacts without changing the registry model. The full adapter contract, render API, and how to add a new provider live in [Providers](./providers.md); this section is a high-level map.
413
417
 
414
418
  Current contract:
415
419
 
@@ -462,15 +466,15 @@ The checked-in OpenCode default config and `seeds/agents/agent-seed-v1.json` def
462
466
 
463
467
  ## Run lifecycle
464
468
 
465
- A run is the core unit of execution. The current foundation stores local, provider-neutral run records in SQLite; deeper orchestration and approval enforcement are follow-up work.
466
-
467
- Current terminal lifecycle rules:
469
+ A run is the core unit of execution. Run records are stored locally in SQLite and stay provider-neutral. The lifecycle is complete in v1.5.1:
468
470
 
469
471
  ```text
470
- created → completed | failed | blocked | cancelled
472
+ created → planned running needs-human
473
+
474
+ completed | failed | blocked | cancelled
471
475
  ```
472
476
 
473
- The broader planned lifecycle still includes `planned`, `running`, and `needs-human`, but this slice only enforces safe finalization: terminal runs cannot be finalized again, and final outcomes must match the terminal status.
477
+ All eight statuses are first-class on `RunStatus` (`src/runs/schema.ts:1`). The control plane exposes lifecycle operations through `vgxness_run_start`, `vgxness_run_checkpoint`, `vgxness_run_finalize`, and the read-only `vgxness_run_resume_inspect` and `vgxness_run_resume_gate` tools. Finalize is safe by default: terminal runs cannot be finalized again, and the final `outcome` must match the terminal `status` (`success`/`partial`/`failure`/`blocked`/`cancelled`).
474
478
 
475
479
  Current run fields:
476
480
 
@@ -556,14 +560,13 @@ runService.appendCheckpoint({
556
560
  });
557
561
  ```
558
562
 
559
- Follow-up runtime work:
563
+ Open follow-up for run execution lives in [Roadmap](./roadmap.md). The remaining work is:
564
+
565
+ - real provider/tool invocation behind sandboxed executors (the lifecycle and policy recording are stable; the actual executor is still test-only)
566
+ - CLI/MCP orchestration for `resume-after-approval` once a safe executor exists outside tests
567
+ - richer verification evidence summaries that link runs, tasks, and verifications
560
568
 
561
- - active state transitions for `planned`, `running`, and `needs-human`
562
- - real provider/tool invocation behind sandboxed executors
563
- - CLI or adapter orchestration for resume-after-approval once a safe executor exists outside tests
564
- - operator UX for retry admission and retry execution, with clear separation between reservation and actual execution
565
- - sandbox/worktree execution strategies after decision recording is stable
566
- - richer verification evidence summaries
569
+ What is already shipped: 8-state lifecycle, approval records, reserved attempts, retry policy evaluation with `never`/`after-abandoned`/`after-failure`/`after-failure-or-abandoned`, run insights with debug summary, run snapshot export (`RunSnapshotPackageV1`), and a `runs retry-check --approval <id> [--policy <json>]` operator command.
567
570
 
568
571
  ## Trace model
569
572
 
@@ -584,9 +587,7 @@ Minimum trace events:
584
587
 
585
588
  ## Permission model
586
589
 
587
- Permissions must be defined in `vgxness` first, then mapped to adapters.
588
-
589
- Minimum categories:
590
+ Permissions are defined in `vgxness` first, then mapped to adapters through the neutral `permissions` field on agents and subagents. The full safety model, including approval flow, redactors, and runtime gates, is in [Safety model](./safety.md). Categories:
590
591
 
591
592
  | Category | Examples |
592
593
  |---|---|
@@ -600,15 +601,9 @@ Minimum categories:
600
601
  | `provider-tool` | opaque adapter/provider tool calls |
601
602
  | `secrets` | environment variables, credentials, tokens |
602
603
 
603
- Operations can resolve to:
604
-
605
- - `allow`
606
- - `ask`
607
- - `deny`
608
-
609
- Default stance for destructive or external operations: **ask or deny**, never implicit allow.
604
+ Operations resolve to `allow`, `ask`, or `deny`. Destructive or external operations default to **ask or deny**, never implicit allow.
610
605
 
611
- Current foundation API: `evaluatePermission(request)` in `src/permissions/` returns `allow`, `ask`, or `deny` with a reason. Defaults are intentionally conservative:
606
+ Current foundation API: `evaluatePermission(request)` in `src/permissions/policy-evaluator.ts` returns `allow`, `ask`, or `deny` with a reason. Defaults are intentionally conservative:
612
607
 
613
608
  - workspace reads are allowed only when the target path stays inside `workspaceRoot`
614
609
  - edits, shell, git, network, memory writes/searches, and provider-specific tools ask by default
@@ -616,84 +611,31 @@ Current foundation API: `evaluatePermission(request)` in `src/permissions/` retu
616
611
  - destructive, external, privileged, or ambiguous requests require ask even when an agent override would otherwise allow the category
617
612
  - workspace boundary denials cannot be relaxed by agent/subagent overrides
618
613
 
619
- Agent and subagent registry definitions keep neutral `permissions` such as `{ "shell": "ask", "provider-tool": "deny" }`. Provider names and tool details remain opaque metadata; enforcement and sandbox execution are follow-up runtime work.
614
+ The code runtime layers a second, finer-grained decision on top of the policy evaluator: per-tool definitions declare whether a tool is `read`, `confirm`, or `restricted`; `PolicyApprovalBroker`, `StdioApprovalBroker`, and `ConservativePermissionGateway` (in `src/code/runtime/approval-coordinator.ts`) wire approval prompts to the runtime event stream. See [Code runtime](./code-runtime.md) for the workspace-side contract.
620
615
 
621
- ## Future interface surface
616
+ ## Interface surface (current)
622
617
 
623
- Current and near-term CLI surface should build on the plural domain commands documented in `docs/cli.md`. Future shortcuts can be added later, but they should not imply separate singular command families:
618
+ CLI surface groups are documented in [CLI reference](./cli.md). The plural form is canonical singular shortcuts are not added.
624
619
 
625
- ```bash
626
- vgxness init
627
- vgxness memory search|get|save|update
628
- vgxness agents list|register|get|resolve|render
629
- vgxness skills list|register|propose|approve-proposal|apply-proposal
630
- vgxness sdd status|next|ready|save-artifact|accept-artifact|list-artifacts
631
- vgxness runs list|get|timeline|debug|resume-inspect|resume-gate
632
- vgxness mcp doctor|install
633
- vgxness opencode preview
634
- ```
635
-
636
- Representative MCP tools mirror the same core services for agent use. For the current exact tool names, use `SUPPORTED_VGX_MCP_TOOL_NAMES`:
637
-
638
- ```text
639
- vgxness_sdd_status
640
- vgxness_sdd_next
641
- vgxness_sdd_ready
642
- vgxness_sdd_save_artifact
643
- vgxness_sdd_get_artifact
644
- vgxness_sdd_list_artifacts
645
- vgxness_memory_search
646
- vgxness_memory_get
647
- vgxness_memory_save
648
- vgxness_memory_update
649
- vgxness_run_start
650
- vgxness_run_list
651
- vgxness_run_get
652
- vgxness_run_preflight
653
- vgxness_run_checkpoint
654
- vgxness_run_finalize
655
- vgxness_agent_resolve
656
- vgxness_agent_activate
657
- vgxness_manager_profile_get
658
- vgxness_manager_profile_set
659
- vgxness_skill_payload
660
- vgxness_opencode_manager_payload
661
- ```
662
-
663
- The CLI and TUI are human/operator control surfaces. MCP is the agent-facing control surface. Provider integrations are the execution/configuration plane.
620
+ MCP tools mirror the same core services for agent use. The full, current list of 38 tools is in [MCP tools](./mcp.md) and `SUPPORTED_VGX_MCP_TOOL_NAMES` (`src/mcp/schema.ts`); treat that array as the source of truth. The CLI and TUI are human/operator control surfaces. MCP is the agent-facing control surface. Provider integrations and the code runtime sit on the execution plane.
664
621
 
665
622
  ## Evaluation strategy
666
623
 
667
- Minimum eval/test targets:
668
-
669
- - Agent resolution selects the expected agent.
670
- - Skill resolution injects the expected skill.
671
- - Adapter rendering produces valid provider config.
672
- - Permission rules block unsafe operations.
673
- - SDD artifact chains remain complete.
674
- - Memory upserts preserve revisions.
675
- - Run resume restores expected state.
676
- - Skill improvement proposals are versioned and require approval.
677
- - MCP tools call the same core services as CLI/TUI and return actionable blocked states.
678
- - TUI setup screens expose loading, empty, error, success, blocked, and permission states.
624
+ Minimum eval/test targets (asserted through `node:test` files under `test/`, totaling 95 files as of v1.5.1):
625
+
626
+ - Agent resolution selects the expected agent (`test/agents/agent-resolver.test.ts`).
627
+ - Skill resolution injects the expected skill (`test/skills/`).
628
+ - Adapter rendering produces valid provider config (`test/agents/provider-renderer.test.ts`).
629
+ - Permission rules block unsafe operations (`test/permissions/policy-evaluator.test.ts`).
630
+ - SDD artifact chains remain complete and human acceptance is enforced (`test/sdd/sdd-workflow-service.test.ts`).
631
+ - Memory upserts preserve revisions (`test/memory/`).
632
+ - Run resume restores expected run state and respects retry policies (`test/runs/`).
633
+ - Skill improvement proposals are versioned and require approval (`test/skills/`).
634
+ - MCP tools call the same core services as CLI/TUI and return actionable blocked states (`test/mcp/`).
635
+ - Code runtime behavior across inspect, plan, craft-preview, and craft modes (`test/code/`).
636
+ - OpenCode config rendering and drift detection (`test/mcp/opencode-agent-config-drift.test.ts`).
679
637
  - Installation dry-run reports the exact provider config changes before mutation.
680
638
 
681
- ## Immediate implementation recommendation
682
-
683
- The next SDD change should be `harness-runtime-foundation`.
684
-
685
- Scope:
686
-
687
- - define schemas for agents, skills, runs, traces, permissions, and adapters
688
- - add local persistence for these entities where missing
689
- - add adapter validation/render skeleton
690
- - add CLI/MCP/TUI interface boundaries for validation, inspection, and guided setup
691
- - add tests for schema validation, permission decisions, and adapter rendering
692
-
693
- Out of scope:
639
+ ## Future work
694
640
 
695
- - cloud sync
696
- - team collaboration
697
- - web console
698
- - distributed workers
699
- - fully autonomous skill mutation
641
+ Planned work that is not yet shipped lives in [Roadmap](./roadmap.md). This document stays focused on the architecture as built; the roadmap is the place to track what is next and what is explicitly deferred.
package/docs/cli.md CHANGED
@@ -254,6 +254,45 @@ The command prints a deterministic JSON envelope with `flow`, `confidence`, `rea
254
254
 
255
255
  Safety boundary: this is a preview only. It does **not** call providers, edit files, write provider config, create runs, run installers, install global memory, or create `openspec/`. Preview actions are labels/manual commands for review, not executed steps.
256
256
 
257
+ ## Code runtime CLI (`vgxness code`)
258
+
259
+ `vgxness code` is the native workspace runtime for bounded agentic work. It is not a wrapper around OpenCode or any provider; provider adapters translate VGXNESS-native requests only. See [Code runtime](./code-runtime.md) for the full contract; this section lists the CLI surface.
260
+
261
+ Modes (read-only by default unless `--approval-channel` and `--approval-policy` are passed):
262
+
263
+ | Mode | Purpose | Mutations |
264
+ |---|---|---|
265
+ | `inspect` | Read-only investigation of the workspace. | None. |
266
+ | `plan` | Read-only implementation planning. | None. |
267
+ | `craft-preview` | Show the diff that would be applied. | None. |
268
+ | `craft` | Approval-gated, bounded edit-capable work. | Edits, shell, network, git, SDD persistence all routed through explicit policy decisions. |
269
+
270
+ Common flags across modes:
271
+
272
+ ```bash
273
+ vgxness code inspect "<question>" \
274
+ --provider openai-compatible \ # or "fake" for offline testing
275
+ --model <model-id> \
276
+ --stream \ # emit JSONL runtime events as they happen
277
+ --json \ # final response as JSON
278
+ --max-source-bytes <bytes> \ # bound on sources loaded into prompt
279
+ --approval-policy ask|allow|deny \
280
+ --approval-channel stdio|auto \
281
+ --verification none|suggest|run|repair \
282
+ --transcript off|summary|full \
283
+ --memory off|ask|auto
284
+ ```
285
+
286
+ SDD-aware mode is exposed through `vgxness code sdd <change> <phase>`; pass `--save-artifact` only when persistence is intended, and pass `--change-id`/`--phase` to scope work. Read-only phases stay artifact-oriented; `apply-progress` may expose edit and shell tools; `verify` may expose verification shell tools.
287
+
288
+ Useful events-only output for piping into the OpenTUI shell or your own tooling:
289
+
290
+ ```bash
291
+ vgxness code inspect "Summarize the current architecture" --events-jsonl
292
+ ```
293
+
294
+ Safety boundary: `inspect`, `plan`, and `craft-preview` never mutate. `craft` may only mutate through the permission-aware executors and the explicit approval channel; it never writes outside the workspace, never pushes to remote, and never edits `openspec/`. Secret-like values are redacted from prompts, transcripts, checkpoints, and memory saves. See [Safety model](./safety.md).
295
+
257
296
  ## Workflow CLI
258
297
 
259
298
  Use workflow commands when you want an explicit operator-controlled path from intent classification to a recorded run and, optionally, a guarded execution request. Supported workflows are `explore`, `quickfix`, `plan`, `build`, `debug`, and `sdd`:
@@ -872,3 +911,17 @@ Existing project-local stores remain compatible; opt in explicitly when needed:
872
911
  ```bash
873
912
  bun run cli:bun -- memory search --project vgxness --db .vgx/memory.sqlite
874
913
  ```
914
+
915
+ For more on schema, scopes, and lifecycle, see [Storage](./storage.md).
916
+
917
+ ## See also
918
+
919
+ - [Architecture](./architecture.md) — current-state architecture and core domain model.
920
+ - [Code runtime](./code-runtime.md) — `vgxness code` modes, tools, providers, and approval flow.
921
+ - [MCP tools](./mcp.md) — full reference for the 38 MCP tools exposed to agents.
922
+ - [Safety model](./safety.md) — permission categories, approval flow, redactors, and runtime gates.
923
+ - [Storage](./storage.md) — SQLite schema, scopes, and lifecycle.
924
+ - [Providers](./providers.md) — adapter contract and how to add a new provider.
925
+ - [Roadmap](./roadmap.md) — planned work not yet shipped.
926
+ - [Contributing](./contributing.md) — repository layout, verification, and style.
927
+ - [Glossary](./glossary.md) — terminology used across the docs and the codebase.