arkgate 4.6.0 → 4.6.1

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 (75) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +9 -5
  3. package/bin/ark-check-runtime.mjs +98 -7
  4. package/bin/ark-mcp-runtime.mjs +17 -1
  5. package/bin/ark.mjs +5 -3
  6. package/bin/lib/agent-projection.mjs +1 -1
  7. package/bin/lib/analysis-engine.mjs +3 -3
  8. package/bin/lib/ci-and-commands.mjs +11 -11
  9. package/bin/lib/config-contract.mjs +2 -0
  10. package/bin/lib/contract-smells.mjs +5 -5
  11. package/bin/lib/design-smells.mjs +1 -1
  12. package/bin/lib/doctor-advisories.mjs +9 -0
  13. package/bin/lib/doctor-plan.mjs +4 -4
  14. package/bin/lib/field-install.mjs +1 -1
  15. package/bin/lib/html-report-advisories.mjs +20 -0
  16. package/bin/lib/improvement-compass-map.mjs +20 -20
  17. package/bin/lib/pilot-loop.mjs +1 -1
  18. package/bin/lib/post-green-path.mjs +2 -2
  19. package/bin/lib/prepare-change.mjs +9 -0
  20. package/bin/lib/product-copy.mjs +1 -1
  21. package/bin/lib/status-command.mjs +14 -0
  22. package/bin/lib/status-manifest.mjs +17 -0
  23. package/bin/lib/team-parliament-io.mjs +338 -0
  24. package/bin/lib/team-parliament.mjs +383 -0
  25. package/bin/lib/upgrade-whats-new.mjs +16 -0
  26. package/bin/lib/violations.mjs +8 -4
  27. package/dist/{configTypes-CC0FEXoF.d.ts → configTypes-B8uIcLaG.d.ts} +5 -0
  28. package/dist/eslint/index.cjs +2 -2
  29. package/dist/eslint/index.d.ts +1 -1
  30. package/dist/eslint/index.js +2 -2
  31. package/dist/index.cjs +19 -19
  32. package/dist/index.d.ts +61 -2
  33. package/dist/index.js +22 -22
  34. package/docs/README.md +5 -5
  35. package/docs/agent-guide.md +21 -17
  36. package/docs/configuration.md +36 -2
  37. package/docs/develop.md +13 -1
  38. package/docs/enthusiast/README.md +1 -1
  39. package/docs/enthusiast/how-to-agent-gates.md +3 -3
  40. package/docs/enthusiast/how-to-pick-shape.md +2 -2
  41. package/docs/enthusiast/tutorial-first-project.md +4 -3
  42. package/docs/package-surface.md +5 -3
  43. package/docs/product-voice.md +48 -10
  44. package/docs/use.md +6 -1
  45. package/package.json +2 -2
  46. package/schemas/ark.config.schema.json +9 -0
  47. package/schemas/ark.status-manifest.schema.json +51 -0
  48. package/server.json +3 -3
  49. package/templates/agent-skills/README.md +1 -1
  50. package/templates/agent-skills/ark-adopt/SKILL.md +46 -19
  51. package/templates/agent-skills/ark-architect/SKILL.md +24 -145
  52. package/templates/agent-skills/ark-autopilot/SKILL.md +40 -30
  53. package/templates/agent-skills/ark-contract/SKILL.md +21 -105
  54. package/templates/agent-skills/ark-coverage/SKILL.md +3 -0
  55. package/templates/agent-skills/ark-explain/SKILL.md +7 -4
  56. package/templates/agent-skills/ark-explore/SKILL.md +25 -17
  57. package/templates/agent-skills/ark-fix/SKILL.md +34 -157
  58. package/templates/agent-skills/ark-loop/SKILL.md +31 -153
  59. package/templates/agent-skills/ark-place/SKILL.md +25 -13
  60. package/templates/agent-skills/ark-runtime/SKILL.md +3 -3
  61. package/templates/agent-skills/ark-think/SKILL.md +5 -2
  62. package/templates/agent-skills/ark-upgrade/SKILL.md +11 -7
  63. package/templates/skills/ark-adopt.md +46 -19
  64. package/templates/skills/ark-architect.md +24 -145
  65. package/templates/skills/ark-autopilot.md +40 -30
  66. package/templates/skills/ark-contract.md +21 -105
  67. package/templates/skills/ark-coverage.md +3 -0
  68. package/templates/skills/ark-explain.md +7 -4
  69. package/templates/skills/ark-explore.md +25 -17
  70. package/templates/skills/ark-fix.md +34 -157
  71. package/templates/skills/ark-loop.md +31 -153
  72. package/templates/skills/ark-place.md +25 -13
  73. package/templates/skills/ark-runtime.md +3 -3
  74. package/templates/skills/ark-think.md +5 -2
  75. package/templates/skills/ark-upgrade.md +11 -7
package/CHANGELOG.md CHANGED
@@ -5,6 +5,30 @@ in the immutable pre-2.0 archive linked below.
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 4.6.1 — 2026-08-14
9
+
10
+ **Patch** over **4.6.0**. Five-door autonomy (skills write or map in-turn; CLI is sensor +
11
+ gate) plus team parliament (law vs feature: stewards, mixed-PR deny, ratchet vs the merge
12
+ base, cheap `--changed` check). Same 13 skill names. Steward identity is a GitHub handle or
13
+ email, not git `user.name`. **No required config migration.**
14
+
15
+ **Status: prepared** (not yet on npm `latest`; see `docs/releases/4.6.1.md`).
16
+
17
+ ### Added
18
+
19
+ - **Five-door autonomy (SK01–SK05):** `/ark-adopt`, `/ark-place`, `/ark-autopilot`,
20
+ `/ark-explore`, `/ark-upgrade` write or map in the same turn. The other eight names stay
21
+ installed as shortcuts. Invoking a door is the approval; the CLI does not apply the change.
22
+ - **Team parliament (TW01–TW08):** mixed law+product deny; optional `stewards` (GitHub handle
23
+ or email); `--contract-session` / `--contract-diff` / `--changed --base` / `--against` /
24
+ `--persona` / `--author`; `ark status --vs`; doctor `stewardNudge` (ask or show list drift).
25
+ `stewards` is excluded from the policy hash.
26
+
27
+ ### Changed
28
+
29
+ - Doctor, compact router, and public lanes prefer the five doors. Historical changelogs stay
30
+ as shipped.
31
+
8
32
  ## 4.6.0 — 2026-08-12
9
33
 
10
34
  **Minor** over **4.5.7**. Understandable Ark: doctor, HTML, skills, and public docs use common
@@ -13,7 +37,7 @@ software words (import rules, leftover design work, pre-write block) while **Ark
13
37
  “always latest” floor Codex already had. **No required config migration.** JSON field names
14
38
  and `ruleId`s stay stable. No new skill names, sensors, or scores.
15
39
 
16
- **Status: prepared** (not yet on npm `latest`; see `docs/releases/4.6.0.md`).
40
+ **Status: published** (on npm `latest`; see `docs/releases/4.6.0.md`).
17
41
 
18
42
  ### Added
19
43
 
package/README.md CHANGED
@@ -16,8 +16,8 @@ and makes sure a “green” check means something real.
16
16
 
17
17
  </div>
18
18
 
19
- > **ArkGate 4.6.0** is prepared — clearer language + shared agent home skills.
20
- > [4.6.0 notes](docs/releases/4.6.0.md) · [4.5.7](docs/releases/4.5.7.md) (npm `latest`) · [4.5.6](docs/releases/4.5.6.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md)
19
+ > **ArkGate 4.6.0** is on npm `latest` — clearer language + shared agent home skills.
20
+ > [4.6.0 notes](docs/releases/4.6.0.md) · [4.5.7](docs/releases/4.5.7.md) · [4.5.6](docs/releases/4.5.6.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md)
21
21
 
22
22
  ---
23
23
 
@@ -48,10 +48,13 @@ dependency inversion — **not a score**). Leftover lenses mean design work may
48
48
  imports are green. Details: [use.md — Improvement compass](docs/use.md#improvement-compass-not-a-score).
49
49
 
50
50
  ```text
51
- start → doctor (+ compass) → day-to-day (place + gate)
52
- optional /ark-autopilot after skill pack
51
+ start → doctor (+ compass) → /ark-adopt (session 0) → day-to-day /ark-place
52
+ /ark-explore then /ark-autopilot when leftover design remains
53
53
  ```
54
54
 
55
+ Teams: keep the constitution out of product PRs. Local gate
56
+ `ark-check --changed --base origin/dev`. Steward law PRs use `--contract-session`.
57
+
55
58
  Aliases `ark` / `ark-check` / `ark-mcp` still work. npm / pnpm / yarn. No install lifecycle scripts.
56
59
 
57
60
  ![Write gate: agent blocked, then self-corrects](docs/assets/ark-write-gate.svg)
@@ -210,7 +213,8 @@ for real systems. Details: [docs/production-hardening.md](docs/production-harden
210
213
  | Config · package surface · TS | [configuration](docs/configuration.md) · [package-surface](docs/package-surface.md) · [typescript-support](docs/typescript-support.md) |
211
214
  | Brownfield | [docs/brownfield-adoption.md](docs/brownfield-adoption.md) |
212
215
  | Security | [SECURITY.md](SECURITY.md) |
213
- | Current release (4.5.7 on npm `latest`) | [docs/releases/4.5.7.md](docs/releases/4.5.7.md) · [CHANGELOG](CHANGELOG.md) |
216
+ | Current release (4.6.0 on npm `latest`) | [docs/releases/4.6.0.md](docs/releases/4.6.0.md) · [CHANGELOG](CHANGELOG.md) |
217
+ | Prior (4.5.7) | [docs/releases/4.5.7.md](docs/releases/4.5.7.md) |
214
218
  | Prior (4.5.0) | [docs/releases/4.5.0.md](docs/releases/4.5.0.md) |
215
219
  | Prior (4.4.0) | [docs/releases/4.4.0.md](docs/releases/4.4.0.md) |
216
220
  | Prior (4.3.0) | [docs/releases/4.3.0.md](docs/releases/4.3.0.md) |
@@ -103,6 +103,13 @@ import { ANALYSIS_COMPLETENESS, analysisIncompleteStatement } from './lib/analys
103
103
  import { reportUnavailableAnalysis } from './lib/unavailable-analysis.mjs';
104
104
  import { validateHardWriteRequest } from './lib/enforcement-profiles.mjs';
105
105
  import { analyzePolicyTransition } from './lib/policy-delta-io.mjs';
106
+ import {
107
+ applyAgainstRatchet,
108
+ bindTeamBaseRefs,
109
+ filterChangedGovernedFiles,
110
+ runTeamPreflight,
111
+ ungovernedDumpMessage,
112
+ } from './lib/team-parliament-io.mjs';
106
113
  import { tryResidentDoctor } from './lib/resident-doctor-client.mjs';
107
114
  import { createDesignDeltaCheck } from './lib/design-delta.mjs';
108
115
  import {
@@ -134,6 +141,14 @@ function parseArgs(argv) {
134
141
  policyBase: undefined,
135
142
  policyBaseRef: undefined,
136
143
  policyAck: undefined, failOnNewSmells: false, baseRef: undefined,
144
+ contractSession: false,
145
+ contractDiff: false,
146
+ changed: false,
147
+ against: undefined,
148
+ base: undefined,
149
+ persona: undefined,
150
+ author: undefined,
151
+ failUngoverned: false,
137
152
  updateBaseline: false,
138
153
  noCache: false,
139
154
  resident: false,
@@ -241,6 +256,13 @@ function parseArgs(argv) {
241
256
  else if (arg === '--policy-base') args.policyBase = requireValue(arg, i++);
242
257
  else if (arg === '--policy-base-ref') args.policyBaseRef = requireValue(arg, i++);
243
258
  else if (arg === '--policy-ack') args.policyAck = requireValue(arg, i++); else if (arg === '--fail-on-new-smells') args.failOnNewSmells = true; else if (arg === '--base-ref') args.baseRef = requireValue(arg, i++);
259
+ else if (arg === '--contract-session') args.contractSession = true;
260
+ else if (arg === '--contract-diff') args.contractDiff = true;
261
+ else if (arg === '--changed') args.changed = true;
262
+ else if (arg === '--against') args.against = requireValue(arg, i++);
263
+ else if (arg === '--base') args.base = requireValue(arg, i++);
264
+ else if (arg === '--persona') args.persona = requireValue(arg, i++);
265
+ else if (arg === '--author') args.author = requireValue(arg, i++);
244
266
  else if (arg === '--root') args.root = path.resolve(requireValue(arg, i++));
245
267
  else if (arg === '--config') args.config = requireValue(arg, i++);
246
268
  else if (arg === '--manifest') args.manifest = requireValue(arg, i++);
@@ -265,7 +287,7 @@ function usage() {
265
287
  return [
266
288
  'Usage: arkgate-check | ark-check (identical bins; product name ArkGate)',
267
289
  ' ark-check --version',
268
- ' ark-check --root <project> --config <ark.config.json> [--manifest <ark.manifest.json>] [--tsconfig <tsconfig.json>] [--strict-merge | --strict | --strict-config] [--policy-base <file> | --policy-base-ref <git-ref>] [--policy-ack <file>] [--fail-on-new-smells --base-ref <git-ref>] [--require-gates] [--require-write-hook <host>] [--json] [--baseline [file]] [--report [file.html]] [--no-cache]',
290
+ ' ark-check --root <project> --config <ark.config.json> [--manifest <ark.manifest.json>] [--tsconfig <tsconfig.json>] [--strict-merge | --strict | --strict-config] [--policy-base <file> | --policy-base-ref <git-ref>] [--policy-ack <file>] [--fail-on-new-smells --base-ref <git-ref>] [--contract-diff] [--contract-session] [--changed] [--against <git-ref>] [--base <git-ref>] [--persona touch|contributor|agent|steward] [--author <id>] [--require-gates] [--require-write-hook <host>] [--json] [--baseline [file]] [--report [file.html]] [--no-cache]',
269
291
  ' ark-check --doctor [--json] [--resident] [--fail-on-new-smells --base-ref <git-ref>] read-only diagnosis; resident JSON falls back cold',
270
292
  ' ark-check --coverage [--json] per-layer file counts + full unclassified list (report only, exit 0)',
271
293
  ' ark-check --plan [--json] classified remediation plan (mechanical-safe / judgment / deferred) + goal; report only',
@@ -291,6 +313,11 @@ function usage() {
291
313
  'violations, commit the baseline file, and gate CI with --baseline: only NEW violations',
292
314
  'fail the check, so the ratchet only moves toward zero.',
293
315
  '',
316
+ 'Team parliament: law files (ark.config / arkrules / .ark-baseline.json) cannot ship in',
317
+ 'the same diff as product source. --changed --base <ref> checks touched files only.',
318
+ '--against <ref> ratchets new keys vs that ref\'s baseline. --contract-session is a',
319
+ 'steward law-only PR. Loosen / baseline-grow need stewards[] + --author when set.',
320
+ '',
294
321
  '--init scans the project for the built-in layer directory conventions (src/domain,',
295
322
  'src/application, src/adapters/persistence, ...) and writes an ark.config.json covering',
296
323
  'only the layers that actually exist, with the default rules filtered to those layers.',
@@ -546,7 +573,7 @@ function runApplyPolicyPack(args) {
546
573
 
547
574
  if (fs.existsSync(configPath) && !args.force) {
548
575
  console.error(
549
- `${configPath} already exists. Re-run with --force to overwrite, or use /ark-contract to evolve it.`
576
+ `${configPath} already exists. Re-run with --force to overwrite, or use /ark-adopt to evolve it.`
550
577
  );
551
578
  process.exitCode = 2;
552
579
  return;
@@ -1030,7 +1057,7 @@ function runInit(args) {
1030
1057
  console.log('A green check ignores this code; it is not "clean", it is unchecked.');
1031
1058
  if (recognized.length > 0) {
1032
1059
  console.log('');
1033
- console.log('Proposed layer for each (from the 11-layer profile + presets — apply via /ark-contract):');
1060
+ console.log('Proposed layer for each (from the 11-layer profile + presets — apply via /ark-adopt):');
1034
1061
  for (const p of recognized) {
1035
1062
  const alt = p.alternatives?.length ? ` (or ${p.alternatives.join(' / ')} — confirm)` : '';
1036
1063
  console.log(` ${p.dir}/ → ${p.layer}${alt}`);
@@ -1281,19 +1308,71 @@ async function main() {
1281
1308
  }
1282
1309
 
1283
1310
  const root = args.root;
1311
+ const bound = bindTeamBaseRefs(args, root);
1312
+ Object.assign(args, bound.args);
1284
1313
  const config = readConfig(root, args.config);
1285
1314
  const policyDelta = analyzePolicyTransition({
1286
1315
  root,
1287
1316
  configPath: args.config,
1288
1317
  candidateConfig: config,
1289
- strictMerge: args.strictMerge,
1318
+ strictMerge: args.strictMerge || args.contractDiff,
1290
1319
  basePath: args.policyBase,
1291
1320
  baseRef: args.policyBaseRef,
1292
1321
  acknowledgementPath: args.policyAck,
1293
1322
  });
1323
+ const preflight = runTeamPreflight({
1324
+ root,
1325
+ args,
1326
+ config,
1327
+ policyDelta,
1328
+ teamBase: bound.teamBase,
1329
+ });
1330
+ const teamParliament = preflight.teamParliament;
1331
+ const changedPaths = preflight.changedPaths;
1332
+ if (preflight.halt) {
1333
+ if (args.json) {
1334
+ console.log(
1335
+ JSON.stringify(
1336
+ {
1337
+ ok: preflight.halt.exitCode === 0,
1338
+ ...(preflight.halt.cheap ? { cheap: true } : {}),
1339
+ teamParliament: preflight.halt.teamParliament,
1340
+ ...(policyDelta ? { policyDelta } : {}),
1341
+ },
1342
+ null,
1343
+ 2
1344
+ )
1345
+ );
1346
+ } else if (preflight.halt.exitCode === 0) {
1347
+ console.log('✔ Ark check passed (no governed source or constitution files in the diff).');
1348
+ } else {
1349
+ console.error(preflight.halt.message);
1350
+ }
1351
+ process.exitCode = preflight.halt.exitCode;
1352
+ return;
1353
+ }
1294
1354
  const manifest = readManifest(root, args.manifest);
1295
1355
  const rules = manifest?.architecture?.rules ?? config.rules;
1296
- const files = collectGovernedFiles(root, config);
1356
+ const allGovernedFiles = collectGovernedFiles(root, config);
1357
+ if (args.failUngoverned && teamParliament?.changeSet?.productPaths?.length) {
1358
+ const governedRel = new Set(
1359
+ allGovernedFiles.map((abs) => normalize(path.relative(root, abs)))
1360
+ );
1361
+ const dumped = teamParliament.changeSet.productPaths.filter((rel) => !governedRel.has(rel));
1362
+ if (dumped.length > 0) {
1363
+ const message = ungovernedDumpMessage(dumped);
1364
+ if (args.json) {
1365
+ console.log(JSON.stringify({ ok: false, teamParliament: { ...teamParliament, ungoverned: dumped }, message }, null, 2));
1366
+ } else {
1367
+ console.error(message);
1368
+ }
1369
+ process.exitCode = 1;
1370
+ return;
1371
+ }
1372
+ }
1373
+ const files = args.changed
1374
+ ? filterChangedGovernedFiles(allGovernedFiles, root, changedPaths, normalize)
1375
+ : allGovernedFiles;
1297
1376
 
1298
1377
  // --coverage is a pure glob/report view (no TypeScript resolver), so serve it BEFORE the
1299
1378
  // TS import: the report must work — and exit 0 — even when typescript isn't installed.
@@ -1381,7 +1460,7 @@ async function main() {
1381
1460
  printViolationBreakdown(summary, { toStderr: true });
1382
1461
  console.error('');
1383
1462
  console.error('Freezing this would bury a likely CONTRACT bug as "debt". Fix the contract');
1384
- console.error('first (/ark-contract), then re-run. To freeze anyway: --update-baseline --force.');
1463
+ console.error('first (/ark-adopt), then re-run. To freeze anyway: --update-baseline --force.');
1385
1464
  process.exitCode = 2;
1386
1465
  return;
1387
1466
  }
@@ -1430,7 +1509,18 @@ async function main() {
1430
1509
  let suppressed = [];
1431
1510
  let activeViolations = violations;
1432
1511
  let staleBaselineKeys = 0;
1433
- if (args.baseline) {
1512
+ if (args.against) {
1513
+ const ratcheted = applyAgainstRatchet({
1514
+ violations,
1515
+ againstRef: args.against,
1516
+ root,
1517
+ changed: args.changed,
1518
+ changedPaths,
1519
+ occurrenceKeys: baselineOccurrenceKeys(violations),
1520
+ });
1521
+ activeViolations = ratcheted.activeViolations;
1522
+ suppressed = ratcheted.suppressed;
1523
+ } else if (args.baseline) {
1434
1524
  const baseline = readBaseline(root, args.baseline);
1435
1525
  if (baseline.exists) {
1436
1526
  const occurrenceKeys = baselineOccurrenceKeys(violations);
@@ -1755,6 +1845,7 @@ async function main() {
1755
1845
  }
1756
1846
  : {}),
1757
1847
  ...(codexRepoSkillGap ? { codexRepoSkillGap } : {}), ...(policyDelta ? { policyDelta } : {}), ...(designDelta ? { edgeValid: edgeOk, designDelta } : {}),
1848
+ ...(teamParliament ? { teamParliament } : {}),
1758
1849
  }, null, 2));
1759
1850
  } else {
1760
1851
  for (const warning of warnings) {
@@ -73,6 +73,8 @@ import {
73
73
  } from './lib/prepare-change.mjs';
74
74
  import { detectWritePathCapabilities } from './lib/write-path-detect.mjs';
75
75
  import { collectGovernedFiles, isGovernableSourceFile } from './lib/scan-files.mjs';
76
+ import { classifyChangeSet, evaluateTeamGate } from './lib/team-parliament.mjs';
77
+ import { contractSessionFrom } from './lib/team-parliament-io.mjs';
76
78
  import {
77
79
  canonicalizeCandidateChanges,
78
80
  resolvedCompilerInputPaths,
@@ -657,6 +659,20 @@ function runHookPayload(payload, gate, config, args, ts, attemptContext, output
657
659
  return;
658
660
  }
659
661
  const patchWrites = parsedPatch.writes;
662
+ const patchChangeSet = classifyChangeSet(patchWrites.map((change) => String(change.path)));
663
+ const patchLawGate = evaluateTeamGate({
664
+ changeSet: patchChangeSet,
665
+ contractSession: contractSessionFrom({}),
666
+ });
667
+ if (patchLawGate.deny && patchChangeSet.mixed) {
668
+ const message = patchLawGate.message;
669
+ output.stderr(`Ark architecture gate: ${message}\n`);
670
+ if (grokStyle) {
671
+ output.stdout(`${JSON.stringify({ decision: 'deny', reason: message })}\n`);
672
+ }
673
+ output.status(2);
674
+ return;
675
+ }
660
676
  const sourceWrites = patchWrites.filter((change) =>
661
677
  isGovernableSourceFile(path.basename(String(change.path)))
662
678
  );
@@ -1387,7 +1403,7 @@ function printSessionContext(config, profile, forbiddenGlobals, args, configPath
1387
1403
  const governedPercent = coverage?.coverage?.governed?.percent ?? coverage?.governed?.percent;
1388
1404
  if (shouldShowNewHereNudge(args.root, configPath, governedPercent, false)) {
1389
1405
  lines.push('');
1390
- lines.push('New to Ark? Run /ark-architect or: ark-check --recommend');
1406
+ lines.push('New to Ark? Run /ark-adopt (or /ark-architect) or: ark-check --recommend');
1391
1407
  }
1392
1408
 
1393
1409
  process.stdout.write(`${lines.join('\n')}\n`);
package/bin/ark.mjs CHANGED
@@ -138,6 +138,7 @@ function parseArgs(argv) {
138
138
  }
139
139
  else if (arg === '--expected-root') args.expectedRoot = path.resolve(requireValue(arg, i++));
140
140
  else if (arg === '--expected-project-id') args.expectedProjectId = requireValue(arg, i++);
141
+ else if (arg === '--vs') args.vs = requireValue(arg, i++);
141
142
  else if (arg === '--write') args.write = true;
142
143
  else if (arg === '--check') args.check = true;
143
144
  else if (arg === '--stdout') args.stdout = true;
@@ -157,7 +158,7 @@ function usage() {
157
158
  [--archetype <playbook-id>] [--tools <list>] [--require-write-hook <host>] [--yes] [--force] [--no-strict]
158
159
  ark upgrade [--root <project>] [--tools <list>] [--apply] [--plan-digest <sha256>] [--accept-conflicts] [--refresh-skills] [--json] [--no-install] [--no-strict]
159
160
  ark preflight --changes <change-set.json> [--change-map <map.json>] [--root <project>] [--config ark.config.json] [--manifest <manifest.json>] [--tsconfig <tsconfig.json>] [--json]
160
- ark status [--root <project>] [--config ark.config.json] [--json]
161
+ ark status [--root <project>] [--config ark.config.json] [--json] [--vs <git-ref>]
161
162
  [--expected-root <abs>] [--expected-project-id sha256:…] [--tools <host>]
162
163
  ark agents-md [--root <project>] [--config ark.config.json] [--write] [--check] [--stdout] [--json]
163
164
  [--tools <host>]
@@ -796,7 +797,7 @@ async function start(args) {
796
797
  console.log('');
797
798
  console.log('Next (the only flow you need):');
798
799
  if (falseGreenGap) {
799
- console.log(' 1. In your agent: /ark-adopt (or /ark-contract) — fix the contract first');
800
+ console.log(' 1. In your agent: /ark-adopt — fix the architecture config first');
800
801
  console.log(' → reclassify I/O dirs out of Application; then /ark-autopilot for residual debt.');
801
802
  } else {
802
803
  console.log(' 1. In your agent: /ark-autopilot');
@@ -811,7 +812,7 @@ async function start(args) {
811
812
  }
812
813
  console.log('');
813
814
  console.log('Optional later: ark-check --report ark-report.html (captures a day-zero/evolution report).');
814
- console.log('Optional later: --plan · --coverage · /ark-explore · /ark-fix · /ark-place · ark upgrade');
815
+ console.log('Optional later: --plan · --coverage · /ark-explore · /ark-autopilot · /ark-place · ark upgrade');
815
816
  return 0;
816
817
  } finally {
817
818
  rl?.close();
@@ -941,6 +942,7 @@ async function main() {
941
942
  expectedProjectId: args.expectedProjectId,
942
943
  host: args.tools,
943
944
  arkgateVersion: cliVersion(),
945
+ vs: args.vs,
944
946
  });
945
947
  }
946
948
 
@@ -151,7 +151,7 @@ export function buildAgentProjectionBody(facts) {
151
151
  lines.push('### Primary path', '', '1. Run doctor (`ark-check --doctor`) — status light + primary next action.', '2. Read the improvement compass (not a score). Name leftover work in plain language; never “done” on green imports alone while leftover design work remains.', '3. Call `ark_identity` with `project.expectedRoot` at the exact project root; reuse root + `projectId` on Ark MCP calls.', '4. Read architecture config with `ark_manifest` (same expectation). `ark://manifest` is compatibility-only / unverified.', '5. Place files inside configured layers; validate; run the check command above on violations — fix architecture, do not weaken the gate.', '6. Single door: import-rule debt → fix; leftover design work / residual shape lenses → map then guided apply with user OK.', '', '### Contract layers (summary)', '', formatAgentProjectionLayers(layers), '');
152
152
  }
153
153
  else {
154
- lines.push('### Contract layers', '', formatAgentProjectionLayers(layers), '', 'When creating a **new** kind of code that no layer covers, update `ark.config.json` first (`/ark-contract`), then place the file.', '', '### Diagnostic codes (short list)', '', formatAgentProjectionCatalogShortList(catalog, docsPath), '', '### Session truth', '', '- Machine snapshot: `ark status --json` (or MCP `ark_status`) — identity, activation honesty, last check, residual counts. **Not a score.**', '- Authoritative contract: `ark_manifest` after a matched `ark_identity` handshake.', '');
154
+ lines.push('### Contract layers', '', formatAgentProjectionLayers(layers), '', 'When creating a **new** kind of code that no layer covers, update `ark.config.json` first (`/ark-adopt`), then place the file.', '', '### Diagnostic codes (short list)', '', formatAgentProjectionCatalogShortList(catalog, docsPath), '', '### Session truth', '', '- Machine snapshot: `ark status --json` (or MCP `ark_status`) — identity, activation honesty, last check, residual counts. **Not a score.**', '- Authoritative contract: `ark_manifest` after a matched `ark_identity` handshake.', '');
155
155
  }
156
156
  lines.push('### Enforcement surfaces (authoritative)', '', AGENT_PROJECTION_ENFORCEMENT_SURFACES.map((surface) => `- \`${surface}\``).join('\n'), '');
157
157
  return lines.join('\n').replace(/\n{3,}/g, '\n\n').trimEnd() + '\n';