Browse Source

fix(cli): fix P0 bugs — global flags, .git detection, package root resolution

- Remove duplicate --dry-run/--yolo/--verbose from parent program; Commander.js
  global option stealing caused all safety flags to be silently dropped in every
  subcommand action callback
- Fix isProjectRoot() to use stat() for .git detection; Bun.file().exists()
  returns false for directories, breaking oac init in standard git repos
- Add OAC_PACKAGE_ROOT env var override to getPackageRoot() for dev/monorepo mode;
  registry.json heuristic excluded the repo root causing oac init/add/update to
  throw when run from source
- Fix build script: remove --banner flag that caused double shebang in dist/index.js
- Rewrite bin/oac.js to invoke bun instead of node (dist is bun-only target)
- Refactor installer.ts let accumulators to const using Promise.all + reduce
- Add MVP planning docs (00-MVP-PLAN.md, master synthesis, project breakdown)
darrenhinde 5 months ago
parent
commit
b247492f04

+ 13 - 80
bin/oac.js

@@ -1,90 +1,23 @@
 #!/usr/bin/env node
+'use strict';
 
-/**
- * OpenAgents Control (OAC) CLI
- * 
- * This is the main entry point for the @openagents/control package.
- * It runs the install.sh script to set up the OpenAgents Control system.
- */
-
-const { spawn } = require('child_process');
+const { execFileSync } = require('child_process');
 const path = require('path');
 const fs = require('fs');
 
-// Get the package root directory
-const packageRoot = path.join(__dirname, '..');
-
-// Path to install.sh
-const installScript = path.join(packageRoot, 'install.sh');
+const cliDist = path.join(__dirname, '..', 'packages', 'cli', 'dist', 'index.js');
 
-// Check if install.sh exists
-if (!fs.existsSync(installScript)) {
-  console.error('Error: install.sh not found at', installScript);
+if (!fs.existsSync(cliDist)) {
+  console.error('Error: OAC CLI not built yet. Run: npm run build -w packages/cli');
   process.exit(1);
 }
 
-// Get command line arguments (skip node and script path)
-const args = process.argv.slice(2);
-
-// If no arguments provided, show help
-if (args.length === 0) {
-  console.log(`
-╔═══════════════════════════════════════════════════════════════╗
-║                  OpenAgents Control (OAC)                     ║
-║   AI agent framework for plan-first development workflows     ║
-╚═══════════════════════════════════════════════════════════════╝
-
-Usage:
-  oac [profile]           Install with a specific profile
-  oac --help             Show this help message
-  oac --version          Show version information
-
-Available Profiles:
-  essential              Minimal setup (OpenAgent only)
-  developer              Full development setup (recommended)
-  business               Business-focused agents
-  advanced               Advanced features and specialists
-  full                   Everything included
-
-Examples:
-  oac                    Interactive installation
-  oac developer          Install with developer profile
-  oac --help            Show detailed help
-
-For more information, visit:
-  https://github.com/darrenhinde/OpenAgentsControl
-`);
-  process.exit(0);
-}
-
-// Handle --version flag
-if (args.includes('--version') || args.includes('-v')) {
-  const packageJson = require(path.join(packageRoot, 'package.json'));
-  console.log(`@openagents/control v${packageJson.version}`);
-  process.exit(0);
-}
-
-// Handle --help flag
-if (args.includes('--help') || args.includes('-h')) {
-  // Run install.sh with --help
-  args.push('--help');
-}
-
-// Run the install script with bash
-const child = spawn('bash', [installScript, ...args], {
-  cwd: packageRoot,
-  stdio: 'inherit',
-  env: {
-    ...process.env,
-    OAC_PACKAGE_ROOT: packageRoot
+try {
+  execFileSync('bun', [cliDist, ...process.argv.slice(2)], { stdio: 'inherit' });
+} catch (err) {
+  if (err.code === 'ENOENT') {
+    console.error('Error: Bun is required to run OAC CLI. Install from https://bun.sh');
+    process.exit(1);
   }
-});
-
-child.on('error', (error) => {
-  console.error('Error running install script:', error.message);
-  process.exit(1);
-});
-
-child.on('exit', (code) => {
-  process.exit(code || 0);
-});
+  process.exitCode = err.status ?? 1;
+}

+ 208 - 15
bun.lock

@@ -1,5 +1,6 @@
 {
   "lockfileVersion": 1,
+  "configVersion": 0,
   "workspaces": {
     "": {
       "name": "opencode-agents",
@@ -27,8 +28,66 @@
         "vitest": "^1.6.1",
       },
     },
+    "packages/cli": {
+      "name": "@nextsystems/oac-cli",
+      "version": "1.0.0",
+      "bin": {
+        "oac": "./dist/index.js",
+      },
+      "dependencies": {
+        "@openagents-control/compatibility-layer": "*",
+        "chalk": "^5.3.0",
+        "commander": "^12.0.0",
+        "ora": "^8.0.0",
+        "semver": "^7.6.0",
+        "zod": "^3.23.0",
+      },
+      "devDependencies": {
+        "@types/bun": "latest",
+        "@types/node": "^20.0.0",
+        "@types/semver": "^7.5.0",
+        "typescript": "^5.4.0",
+      },
+    },
+    "packages/compatibility-layer": {
+      "name": "@openagents-control/compatibility-layer",
+      "version": "0.1.0",
+      "bin": {
+        "oac-compat": "dist/cli/index.js",
+      },
+      "dependencies": {
+        "chalk": "^5.3.0",
+        "commander": "^12.1.0",
+        "gray-matter": "^4.0.3",
+        "js-yaml": "^4.1.0",
+        "ora": "^8.0.1",
+        "zod": "^3.23.8",
+      },
+      "devDependencies": {
+        "@types/js-yaml": "^4.0.9",
+        "@types/node": "^20.12.12",
+        "@typescript-eslint/eslint-plugin": "^7.10.0",
+        "@typescript-eslint/parser": "^7.10.0",
+        "@vitest/coverage-v8": "^1.6.0",
+        "eslint": "^8.57.0",
+        "typescript": "^5.4.5",
+        "vitest": "^1.6.0",
+      },
+    },
   },
   "packages": {
+    "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
+
+    "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
+
+    "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
+
+    "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
+
+    "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
+
+    "@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="],
+
     "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
 
     "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
@@ -99,16 +158,28 @@
 
     "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, ""],
 
+    "@istanbuljs/schema": ["@istanbuljs/schema@0.1.3", "", {}, "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA=="],
+
     "@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="],
 
+    "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
+
+    "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
+
     "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
 
+    "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
+
+    "@nextsystems/oac-cli": ["@nextsystems/oac-cli@workspace:packages/cli"],
+
     "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, ""],
 
     "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, ""],
 
     "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, ""],
 
+    "@openagents-control/compatibility-layer": ["@openagents-control/compatibility-layer@workspace:packages/compatibility-layer"],
+
     "@opencode-agents/eval-framework": ["@opencode-agents/eval-framework@workspace:evals/framework"],
 
     "@opencode-ai/sdk": ["@opencode-ai/sdk@1.0.90", "", {}, ""],
@@ -159,10 +230,14 @@
 
     "@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="],
 
+    "@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
+
     "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
 
     "@types/glob": ["@types/glob@8.1.0", "", { "dependencies": { "@types/minimatch": "^5.1.2", "@types/node": "*" } }, ""],
 
+    "@types/js-yaml": ["@types/js-yaml@4.0.9", "", {}, "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="],
+
     "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, ""],
 
     "@types/minimatch": ["@types/minimatch@5.1.2", "", {}, ""],
@@ -171,24 +246,26 @@
 
     "@types/semver": ["@types/semver@7.7.1", "", {}, ""],
 
-    "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@6.21.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.5.1", "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/type-utils": "6.21.0", "@typescript-eslint/utils": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", "natural-compare": "^1.4.0", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", "eslint": "^7.0.0 || ^8.0.0" } }, ""],
+    "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@7.18.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/type-utils": "7.18.0", "@typescript-eslint/utils": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^1.3.0" }, "peerDependencies": { "@typescript-eslint/parser": "^7.0.0", "eslint": "^8.56.0" } }, "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw=="],
 
-    "@typescript-eslint/parser": ["@typescript-eslint/parser@6.21.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", "@typescript-eslint/typescript-estree": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" } }, ""],
+    "@typescript-eslint/parser": ["@typescript-eslint/parser@7.18.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.56.0" } }, "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg=="],
 
-    "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0" } }, ""],
+    "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@7.18.0", "", { "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0" } }, "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA=="],
 
-    "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@6.21.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "6.21.0", "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" } }, ""],
+    "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@7.18.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/utils": "7.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, "peerDependencies": { "eslint": "^8.56.0" } }, "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA=="],
 
-    "@typescript-eslint/types": ["@typescript-eslint/types@6.21.0", "", {}, ""],
+    "@typescript-eslint/types": ["@typescript-eslint/types@7.18.0", "", {}, "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ=="],
 
-    "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" } }, ""],
+    "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@7.18.0", "", { "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^1.3.0" } }, "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA=="],
 
-    "@typescript-eslint/utils": ["@typescript-eslint/utils@6.21.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", "@typescript-eslint/typescript-estree": "6.21.0", "semver": "^7.5.4" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" } }, ""],
+    "@typescript-eslint/utils": ["@typescript-eslint/utils@7.18.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", "@typescript-eslint/typescript-estree": "7.18.0" }, "peerDependencies": { "eslint": "^8.56.0" } }, "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw=="],
 
-    "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" } }, ""],
+    "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@7.18.0", "", { "dependencies": { "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" } }, "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg=="],
 
     "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, ""],
 
+    "@vitest/coverage-v8": ["@vitest/coverage-v8@1.6.1", "", { "dependencies": { "@ampproject/remapping": "^2.2.1", "@bcoe/v8-coverage": "^0.2.3", "debug": "^4.3.4", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-lib-source-maps": "^5.0.4", "istanbul-reports": "^3.1.6", "magic-string": "^0.30.5", "magicast": "^0.3.3", "picocolors": "^1.0.0", "std-env": "^3.5.0", "strip-literal": "^2.0.0", "test-exclude": "^6.0.0" }, "peerDependencies": { "vitest": "1.6.1" } }, "sha512-6YeRZwuO4oTGKxD3bijok756oktHSIm3eczVVzNe3scqzuhLwltIF3S9ZL/vwOVIpURmU6SnZhziXXAfw8/Qlw=="],
+
     "@vitest/expect": ["@vitest/expect@1.6.1", "", { "dependencies": { "@vitest/spy": "1.6.1", "@vitest/utils": "1.6.1", "chai": "^4.3.10" } }, "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog=="],
 
     "@vitest/runner": ["@vitest/runner@1.6.1", "", { "dependencies": { "@vitest/utils": "1.6.1", "p-limit": "^5.0.0", "pathe": "^1.1.1" } }, "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA=="],
@@ -207,7 +284,7 @@
 
     "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, ""],
 
-    "ansi-regex": ["ansi-regex@5.0.1", "", {}, ""],
+    "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
 
     "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, ""],
 
@@ -223,20 +300,28 @@
 
     "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, ""],
 
+    "bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
+
     "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
 
     "callsites": ["callsites@3.1.0", "", {}, ""],
 
     "chai": ["chai@4.5.0", "", { "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", "deep-eql": "^4.1.3", "get-func-name": "^2.0.2", "loupe": "^2.3.6", "pathval": "^1.1.1", "type-detect": "^4.1.0" } }, "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw=="],
 
-    "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, ""],
+    "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
 
     "check-error": ["check-error@1.0.3", "", { "dependencies": { "get-func-name": "^2.0.2" } }, "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg=="],
 
+    "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
+
+    "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="],
+
     "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, ""],
 
     "color-name": ["color-name@1.1.4", "", {}, ""],
 
+    "commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="],
+
     "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
 
     "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
@@ -255,6 +340,8 @@
 
     "doctrine": ["doctrine@3.0.0", "", { "dependencies": { "esutils": "^2.0.2" } }, ""],
 
+    "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
+
     "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": "bin/esbuild" }, ""],
 
     "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, ""],
@@ -267,6 +354,8 @@
 
     "espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } }, ""],
 
+    "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
+
     "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, ""],
 
     "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, ""],
@@ -279,6 +368,8 @@
 
     "execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
 
+    "extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="],
+
     "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
 
     "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, ""],
@@ -303,6 +394,8 @@
 
     "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
 
+    "get-east-asian-width": ["get-east-asian-width@1.5.0", "", {}, "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA=="],
+
     "get-func-name": ["get-func-name@2.0.2", "", {}, "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ=="],
 
     "get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="],
@@ -319,8 +412,12 @@
 
     "graphemer": ["graphemer@1.4.0", "", {}, ""],
 
+    "gray-matter": ["gray-matter@4.0.3", "", { "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q=="],
+
     "has-flag": ["has-flag@4.0.0", "", {}, ""],
 
+    "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="],
+
     "human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
 
     "ignore": ["ignore@5.3.2", "", {}, ""],
@@ -333,18 +430,32 @@
 
     "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
 
+    "is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="],
+
     "is-extglob": ["is-extglob@2.1.1", "", {}, ""],
 
     "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, ""],
 
+    "is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="],
+
     "is-number": ["is-number@7.0.0", "", {}, ""],
 
     "is-path-inside": ["is-path-inside@3.0.3", "", {}, ""],
 
     "is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
 
+    "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
+
     "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
 
+    "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="],
+
+    "istanbul-lib-report": ["istanbul-lib-report@3.0.1", "", { "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" } }, "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw=="],
+
+    "istanbul-lib-source-maps": ["istanbul-lib-source-maps@5.0.6", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0" } }, "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A=="],
+
+    "istanbul-reports": ["istanbul-reports@3.2.0", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA=="],
+
     "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],
 
     "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, ""],
@@ -357,6 +468,8 @@
 
     "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, ""],
 
+    "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="],
+
     "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, ""],
 
     "local-pkg": ["local-pkg@0.5.1", "", { "dependencies": { "mlly": "^1.7.3", "pkg-types": "^1.2.1" } }, "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ=="],
@@ -365,12 +478,18 @@
 
     "lodash.merge": ["lodash.merge@4.6.2", "", {}, ""],
 
+    "log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="],
+
     "loupe": ["loupe@2.3.7", "", { "dependencies": { "get-func-name": "^2.0.1" } }, "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA=="],
 
     "lru-cache": ["lru-cache@11.2.2", "", {}, ""],
 
     "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
 
+    "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="],
+
+    "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="],
+
     "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
 
     "merge2": ["merge2@1.4.1", "", {}, ""],
@@ -379,6 +498,8 @@
 
     "mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
 
+    "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
+
     "minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, ""],
 
     "minipass": ["minipass@7.1.2", "", {}, ""],
@@ -399,6 +520,8 @@
 
     "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, ""],
 
+    "ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="],
+
     "p-limit": ["p-limit@5.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ=="],
 
     "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, ""],
@@ -441,6 +564,8 @@
 
     "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, ""],
 
+    "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
+
     "reusify": ["reusify@1.1.0", "", {}, ""],
 
     "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": "bin.js" }, ""],
@@ -449,6 +574,8 @@
 
     "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, ""],
 
+    "section-matter": ["section-matter@1.0.0", "", { "dependencies": { "extend-shallow": "^2.0.1", "kind-of": "^6.0.0" } }, "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA=="],
+
     "semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, ""],
 
     "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
@@ -463,11 +590,19 @@
 
     "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
 
+    "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="],
+
     "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="],
 
     "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
 
-    "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, ""],
+    "stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="],
+
+    "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
+
+    "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
+
+    "strip-bom-string": ["strip-bom-string@1.0.0", "", {}, "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g=="],
 
     "strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
 
@@ -477,6 +612,8 @@
 
     "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, ""],
 
+    "test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="],
+
     "text-table": ["text-table@0.2.0", "", {}, ""],
 
     "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
@@ -529,12 +666,24 @@
 
     "@humanwhocodes/config-array/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, ""],
 
-    "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.3", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, ""],
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@6.21.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.5.1", "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/type-utils": "6.21.0", "@typescript-eslint/utils": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", "natural-compare": "^1.4.0", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", "eslint": "^7.0.0 || ^8.0.0" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/parser": ["@typescript-eslint/parser@6.21.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", "@typescript-eslint/typescript-estree": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" } }, ""],
+
+    "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+
+    "eslint/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, ""],
 
     "eslint/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, ""],
 
+    "eslint/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, ""],
+
     "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, ""],
 
+    "gray-matter/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="],
+
+    "log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],
+
     "mlly/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
 
     "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
@@ -545,16 +694,38 @@
 
     "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
 
+    "restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
+
     "rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, ""],
 
+    "test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, ""],
+
+    "test-exclude/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, ""],
+
     "vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": "bin/esbuild" }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
 
-    "@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, ""],
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@6.21.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "6.21.0", "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/utils": ["@typescript-eslint/utils@6.21.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", "@typescript-eslint/typescript-estree": "6.21.0", "semver": "^7.5.4" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0" } }, ""],
 
-    "@humanwhocodes/config-array/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, ""],
+    "@opencode-agents/eval-framework/@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@6.21.0", "", {}, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/parser/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/parser/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" } }, ""],
 
     "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, ""],
 
+    "eslint/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, ""],
+
+    "gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
+
     "p-locate/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, ""],
 
     "rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, ""],
@@ -605,6 +776,28 @@
 
     "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="],
 
-    "rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, ""],
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@6.21.0", "", {}, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@6.21.0", "", {}, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@6.21.0", "", {}, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/parser/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.3", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@6.21.0", "", {}, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.3", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.3", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/parser/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, ""],
+
+    "@opencode-agents/eval-framework/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, ""],
   }
 }

+ 9 - 1
docs/planning/00-INDEX.md

@@ -7,7 +7,15 @@
 
 ---
 
-## 📁 Planning Documents
+## 🎯 MVP Plan (START HERE)
+
+**`mvp/00-MVP-PLAN.md`** — The 20% that delivers 80% of the value.
+5 commands, 6 weeks, focused on what users actually care about.
+This is what we build first. Everything else is v1.1+.
+
+---
+
+## 📁 Full Planning Documents (Reference)
 
 ### Core Planning
 

+ 1875 - 0
docs/planning/12-MASTER-SYNTHESIS.md

@@ -0,0 +1,1875 @@
+# OAC Package Refactor — Master Planning Document
+
+**Document**: 12-MASTER-SYNTHESIS.md  
+**GitHub Issue**: #206  
+**Status**: Authoritative Implementation Plan  
+**Date**: 2026-02-19  
+**Synthesized from**: 6 specialist research agents (Context, Agent Behaviour, Task Breakdown, Plugin System, ExternalScout, CLI & Multi-IDE)
+
+---
+
+## Table of Contents
+
+1. [Executive Summary](#1-executive-summary)
+2. [Architecture Overview](#2-architecture-overview)
+3. [The 5 Core Subsystems](#3-the-5-core-subsystems)
+4. [Implementation Phases (9 Weeks)](#4-implementation-phases-9-weeks)
+5. [Key Technical Decisions](#5-key-technical-decisions)
+6. [Critical Gaps to Address](#6-critical-gaps-to-address)
+7. [Configuration Schema](#7-configuration-schema)
+8. [Auto-Update Strategy](#8-auto-update-strategy)
+9. [CLI Command Reference](#9-cli-command-reference)
+10. [Success Metrics](#10-success-metrics)
+
+---
+
+## 1. Executive Summary
+
+### What We Are Building
+
+OAC (`@nextsystems/oac`) is transitioning from a 52KB bash-script installer (`install.sh`) into a proper npm CLI package with a rich plugin system, registry-backed component management, and first-class multi-IDE support.
+
+The refactored OAC manages four types of AI configuration artifacts across four IDEs:
+
+| Artifact | Description | Primary Location |
+|----------|-------------|------------------|
+| **Agents** | `.md` files with YAML frontmatter defining AI personas and permissions | `.opencode/agent/` |
+| **Context files** | Markdown guides that shape AI behaviour in a session | `.opencode/context/` |
+| **Skills** | Loadable modules (`SKILL.md` + `router.sh` + `scripts/`) | `.opencode/skills/` |
+| **Plugins** | IDE integration hooks (TypeScript events, file-based, shell scripts) | IDE-specific |
+
+| IDE | Priority | Integration Method |
+|-----|----------|--------------------|
+| OpenCode | PRIMARY | TypeScript npm plugin (`"plugin": ["@nextsystems/oac"]`) |
+| Claude Code | Secondary | File-based plugin (`.claude-plugin/`) |
+| Cursor | Tertiary | Router pattern in `.cursorrules` |
+| Windsurf | Partial | Partial compatibility adapter |
+
+### Key Architectural Decisions (Summary)
+
+1. **OpenCode is the primary target** — richest plugin API (25+ events, custom tools, TypeScript SDK). All other IDEs are adaptation layers.
+2. **Bundle context into npm, do not fetch at runtime** — eliminates network dependency during AI sessions, enables offline use, provides version-locked reproducibility.
+3. **`agent.json` + `prompt.md` as source of truth** — clean separation of metadata/configuration from prose content; generate IDE-specific formats from this canonical form.
+4. **shadcn-inspired registry** — adapt the shadcn component registry pattern for agents, skills, and context files. Already have `registry.json` in the repo.
+5. **`oac.lock` lockfile** — reproducible installs across machines and CI, analogous to `package-lock.json`.
+6. **Two-layer update system** — `update-notifier` for the CLI binary itself; hash-based registry polling for content files.
+7. **Monorepo with tsup** — `packages/cli` (new) + `packages/compatibility-layer` (existing) + `packages/plugin-abilities` (existing).
+
+### Success Criteria
+
+- `npx @nextsystems/oac init` completes full project setup in under 2 minutes
+- All bundled content survives `npm update` without overwriting user customizations
+- OpenCode auto-updates agent/context files on every session start via `session.created` event
+- `oac doctor` catches 100% of common misconfiguration issues
+- Registry supports community-published agents/skills with SHA256 verification
+- Zero bash script dependency for any core functionality (install.sh becomes legacy/deprecated)
+
+---
+
+## 2. Architecture Overview
+
+### Package Structure (Monorepo)
+
+```
+@nextsystems/oac/                    # Root package (npm: @nextsystems/oac)
+├── bin/
+│   └── oac.js                       # CLI entry point (compiled)
+├── packages/
+│   ├── cli/                         # NEW: Full commander.js CLI
+│   │   ├── src/
+│   │   │   ├── commands/            # One file per command group
+│   │   │   ├── registry/            # Registry client
+│   │   │   ├── resolvers/           # 6-layer context resolver
+│   │   │   ├── adapters/            # IDE format adapters
+│   │   │   └── index.ts             # Entry point
+│   │   ├── tsconfig.json
+│   │   └── package.json
+│   ├── compatibility-layer/         # EXISTING: Multi-IDE adapters
+│   │   ├── src/
+│   │   │   ├── adapters/
+│   │   │   │   ├── claude.ts        # COMPLETE
+│   │   │   │   ├── cursor.ts        # COMPLETE
+│   │   │   │   └── windsurf.ts      # COMPLETE
+│   │   │   └── index.ts
+│   │   └── package.json
+│   └── plugin-abilities/            # EXISTING: OpenCode plugin
+│       ├── src/
+│       │   ├── events/              # 25+ OpenCode event handlers
+│       │   └── index.ts
+│       └── package.json
+├── .opencode/                       # Bundled OAC configuration
+│   ├── agent/                       # Agent .md files (YAML frontmatter)
+│   ├── context/                     # Bundled context files
+│   ├── skills/                      # Skill packages
+│   ├── plugin/                      # OpenCode plugin hooks
+│   └── opencode.json                # OpenCode config
+├── registry.json                    # Component registry (shadcn-style)
+├── manifest.json                    # Bundle manifest with checksums
+├── oac.lock                         # Lockfile template (copied to project)
+└── package.json
+```
+
+### The 5 Core Subsystems and Their Relationships
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│                     OAC CLI (Subsystem 1)                        │
+│  oac init / add / update / remove / context / skill / plugin    │
+│  oac doctor / rollback / publish / browse / search              │
+└──────────┬────────────┬───────────────┬────────────┬────────────┘
+           │            │               │            │
+           ▼            ▼               ▼            ▼
+┌──────────────┐ ┌────────────┐ ┌──────────────┐ ┌─────────────┐
+│   Context    │ │  Agent &   │ │   Plugin     │ │  Registry & │
+│   System     │ │   Skill    │ │   System     │ │  Community  │
+│ (Subsystem 2)│ │ Management │ │ (Subsystem 4)│ │(Subsystem 5)│
+│              │ │(Subsystem 3│ │              │ │             │
+│ 6-layer      │ │            │ │ OpenCode     │ │ shadcn      │
+│ resolution   │ │ agent.json │ │ Claude Code  │ │ registry    │
+│ Bundle/      │ │ + prompt.md│ │ Cursor       │ │ oac.lock    │
+│ manifest     │ │ Presets    │ │ Windsurf     │ │ SHA256 hash │
+│ Auto-update  │ │ Skills pkg │ │ session.     │ │ verify      │
+└──────────────┘ └────────────┘ │ created hook │ └─────────────┘
+                                └──────────────┘
+```
+
+### Data Flow: From Registry to IDE
+
+```
+npm registry / community registry
+         │
+         │  oac add agent/openagent
+         ▼
+   Registry Client
+         │ fetches files + verifies SHA256
+         ▼
+   oac.lock updated
+         │
+         ├──► .opencode/agent/openagent/
+         │      ├── agent.json       (metadata, permissions, config)
+         │      └── prompt.md        (prose content)
+         │
+         │  oac compat apply --ide=cursor
+         ▼
+   Compatibility Adapter
+         │
+         ├──► .cursorrules           (Cursor router pattern)
+         ├──► CLAUDE.md             (Claude Code format)
+         └──► .windsurfrules        (Windsurf format)
+```
+
+### Data Flow: Auto-Update via OpenCode Plugin
+
+```
+OpenCode session starts
+         │
+         │  fires session.created event
+         ▼
+   plugin-abilities/src/events/session.ts
+         │
+         │  reads oac.lock
+         │  checks registry for newer versions
+         │  compares SHA256 of installed files
+         ▼
+   No user modifications detected → auto-update silently
+   User modifications detected    → prompt user (or skip in --yolo mode)
+         │
+         ▼
+   Files updated in .opencode/
+   IDE picks up changes on next tool invocation
+```
+
+---
+
+## 3. The 5 Core Subsystems
+
+---
+
+### Subsystem 1: CLI & Package Distribution
+
+#### Current State
+
+The current `bin/oac.js` is 91 lines of Node.js that spawns `install.sh` (52KB bash script). It has no command parsing, no help text, no interactive prompts, and no multi-IDE awareness. The npm package `files` array in `package.json` already bundles `.opencode/` content correctly.
+
+#### Target State
+
+A full `commander.js`-based CLI with 20+ commands, interactive prompts via `@inquirer/prompts`, progress indication via `ora`, and coloured output via `chalk`. Built with `tsup` into `dist/cli.js`, entry point remains `bin/oac.js` which simply requires the compiled output.
+
+#### Package Structure
+
+```json
+// packages/cli/package.json
+{
+  "name": "@nextsystems/oac-cli",
+  "private": true,
+  "main": "dist/index.js",
+  "scripts": {
+    "build": "tsup src/index.ts --format cjs --dts",
+    "test": "vitest run",
+    "dev": "tsup src/index.ts --watch"
+  },
+  "dependencies": {
+    "commander": "^12.0.0",
+    "@inquirer/prompts": "^5.0.0",
+    "ora": "^8.0.0",
+    "chalk": "^5.0.0",
+    "conf": "^13.0.0",
+    "fs-extra": "^11.0.0",
+    "semver": "^7.6.0",
+    "zod": "^3.23.0",
+    "update-notifier": "^7.0.0"
+  }
+}
+```
+
+#### Commander.js Structure
+
+```typescript
+// packages/cli/src/index.ts
+import { Command } from "commander";
+import { initCommand } from "./commands/init";
+import { addCommand } from "./commands/add";
+import { contextCommand } from "./commands/context";
+import { skillCommand } from "./commands/skill";
+import { pluginCommand } from "./commands/plugin";
+import { doctorCommand } from "./commands/doctor";
+
+const program = new Command()
+  .name("oac")
+  .description("AI agent configuration manager")
+  .version(packageJson.version)
+  .option("--yolo", "skip all confirmations")
+  .option("--no-color", "disable color output");
+
+program.addCommand(initCommand);
+program.addCommand(addCommand);
+program.addCommand(contextCommand);
+program.addCommand(skillCommand);
+program.addCommand(pluginCommand);
+program.addCommand(doctorCommand);
+// ... additional commands
+
+program.parse();
+```
+
+#### Key Design Decisions
+
+- **tsup over tsc**: tsup bundles dependencies into a single file, eliminating runtime `node_modules` resolution issues when installed globally via `npm install -g`
+- **`--yolo` flag**: Skips all `inquirer` prompts and confirmation gates. Required for CI/automation use cases
+- **`conf` for global config**: Uses OS-appropriate config directory (`~/.config/oac/` on Linux/Mac, `%APPDATA%/oac/` on Windows). Survives npm updates
+- **`update-notifier`**: Background process checks npm registry for CLI updates; shows non-blocking notification at session end
+
+#### Critical Gaps
+
+- The entire `packages/cli/` package does not exist yet — needs to be created from scratch
+- `bin/oac.js` needs to be rewritten to simply `require('../packages/cli/dist/index.js')`
+- `install.sh` remains as legacy fallback during transition but should be deprecated in v1.0
+
+---
+
+### Subsystem 2: Context System
+
+#### Current State
+
+Context files exist in `.opencode/context/` with a rich function-based and concern-based organizational pattern. `CONTEXT_SYSTEM_GUIDE.md` (16KB) documents the system thoroughly. However there is no programmatic management — files are installed/copied by `install.sh` and never updated automatically.
+
+#### Target State
+
+A 6-layer resolution system where the CLI and plugin can deterministically locate, version, and update context files. All OAC-maintained context files are bundled into the npm package with SHA256 checksums tracked in `manifest.json`.
+
+#### The 6-Layer Priority Resolution
+
+```
+Priority (highest to lowest):
+┌─────────────────────────────────────────────────────┐
+│ 1. .oac/context/          project override          │ ← USER OWNED
+│ 2. .opencode/context/     IDE config dir            │ ← OAC MANAGED (with user edits)
+│ 3. IDE-specific dir       e.g. .cursor/context/     │ ← IDE MANAGED
+│ 4. docs/                  project documentation     │ ← PROJECT OWNED
+│ 5. ~/.config/oac/context/ user global overrides     │ ← USER OWNED
+│ 6. npm package bundled    @nextsystems/oac/context/  │ ← OAC DEFAULT
+└─────────────────────────────────────────────────────┘
+```
+
+Resolution algorithm:
+1. Walk layers 1-6 in order
+2. First file found at a given logical name wins
+3. User-owned layers (1, 4, 5) are never overwritten by `oac update`
+4. OAC-managed layer (2) is updated only when no user modifications detected (SHA256 match)
+
+#### Bundle/Manifest Approach
+
+```json
+// manifest.json (in npm package root, copied to .oac/manifest.json on init)
+{
+  "version": "0.7.1",
+  "generatedAt": "2026-02-19T00:00:00Z",
+  "context": {
+    "typescript-patterns.md": {
+      "sha256": "a1b2c3d4...",
+      "size": 4821,
+      "category": "language",
+      "description": "TypeScript coding patterns and conventions"
+    },
+    "git-workflow.md": {
+      "sha256": "e5f6a7b8...",
+      "size": 2341,
+      "category": "workflow"
+    }
+  },
+  "agents": {
+    "openagent": {
+      "sha256": "c9d0e1f2...",
+      "files": ["agent.json", "prompt.md"]
+    }
+  },
+  "skills": {
+    "task-management": {
+      "sha256": "f3a4b5c6...",
+      "files": ["SKILL.md", "router.sh", "scripts/task-cli.js"]
+    }
+  }
+}
+```
+
+#### Auto-Update Mechanism
+
+```
+oac update context (or: triggered by session.created event)
+         │
+         ├── Read .oac/manifest.json (installed versions + hashes)
+         ├── Fetch registry for latest manifest
+         ├── For each context file:
+         │    ├── SHA256(installed file) == manifest.sha256?
+         │    │    YES → file is stock OAC → safe to update
+         │    │    NO  → file has user modifications
+         │    │         ├── update mode == "auto-all"  → overwrite + backup
+         │    │         ├── update mode == "auto-safe" → skip + notify
+         │    │         └── update mode == "manual"    → skip silently
+         │    └── New version available? → download + install + update manifest
+         └── Print summary of updated / skipped / conflict files
+```
+
+#### CLI Commands
+
+```bash
+oac context install [name]     # Install a specific context file
+oac context update [name]      # Update installed context files
+oac context validate           # Validate all context files are syntactically correct
+oac context resolve <name>     # Show which layer a context file resolves from
+oac context list               # List all context files with source layer
+oac context diff <name>        # Show diff between installed and stock version
+```
+
+#### Key Design Decisions
+
+- **Bundle into npm, not fetch at runtime**: Context files are needed the moment an AI session starts. Network dependency at that point is unacceptable. Bundling ensures offline functionality and version-locked reproducibility.
+- **ContextScout navigation**: The existing ContextScout agent that discovers relevant context via navigation is preserved. The CLI manages the underlying files; ContextScout operates on them.
+- **`manifest.json` is the authoritative truth**: Neither `package.json` version nor git history determines what's installed — only `manifest.json` + SHA256 comparison.
+
+---
+
+### Subsystem 3: Agent & Skill Management
+
+#### Current State
+
+Agents are `.md` files with YAML frontmatter in `.opencode/agent/`. No programmatic management exists. Skills live in `.opencode/skills/` as `SKILL.md` + `router.sh` + `scripts/` bundles. `task-cli.ts` is a TypeScript file requiring `ts-node` to run — this is a critical gap.
+
+#### Target State
+
+A canonical `agent.json` + `prompt.md` two-file representation per agent, with IDE-specific formats generated on demand. Skills are proper packages with compiled JS. A preset system allows user customizations to survive updates.
+
+#### Agent Architecture: `agent.json` + `prompt.md`
+
+```
+.opencode/agent/openagent/
+├── agent.json        # Metadata, permissions, config, OAC-specific data
+└── prompt.md         # The actual agent prompt content (prose)
+```
+
+```json
+// agent.json — canonical agent definition
+{
+  "name": "openagent",
+  "displayName": "Open Agent",
+  "version": "2.1.0",
+  "description": "Primary orchestration agent for plan-first development",
+  "model": "claude-sonnet-4-5",
+  "maxTokens": 8192,
+  "permission": [
+    { "deny": "bash(**)" },
+    { "allow": "bash(git status, git diff, git log)" },
+    { "allow": "bash(npm run*)" }
+  ],
+  "tools": ["read", "write", "edit", "bash", "glob", "grep"],
+  "tags": ["orchestration", "planning", "primary"],
+  "oac": {
+    "bundledSha256": "a1b2c3d4e5f6...",
+    "installedAt": "2026-02-19T00:00:00Z",
+    "source": "registry",
+    "presetApplied": "team-lead-preset"
+  }
+}
+```
+
+```markdown
+---
+name: openagent
+model: claude-sonnet-4-5
+maxTokens: 8192
+---
+
+# Open Agent
+
+You are OpenAgent, the primary orchestration agent...
+[prose content continues]
+```
+
+**Design principle**: `prompt.md` YAML frontmatter contains only fields that the IDE (OpenCode) reads natively. All OAC-specific metadata goes in `agent.json`. This avoids frontmatter bloat and keeps IDE compatibility clean.
+
+#### Permission System
+
+The `permission:` field uses **last-match-wins** evaluation (same as OpenCode's native system):
+
+```json
+"permission": [
+  { "deny": "bash(**)" },          // default deny all bash
+  { "allow": "bash(git status)" }, // allow specific git commands
+  { "allow": "bash(npm run*)" }    // allow npm run commands
+]
+```
+
+Rules are evaluated in order; the LAST matching rule wins. This matches OpenCode's permission semantics exactly, ensuring IDE-native compatibility.
+
+#### Preset System
+
+User customizations are stored separately from stock agent files:
+
+```
+~/.config/oac/presets/
+├── team-lead-preset.json       # User's customizations
+└── solo-dev-preset.json
+
+// team-lead-preset.json
+{
+  "name": "team-lead-preset",
+  "appliesTo": ["openagent", "task-manager"],
+  "overrides": {
+    "model": "claude-opus-4-5",
+    "maxTokens": 16384,
+    "permission": [
+      { "allow": "bash(docker*)" }
+    ]
+  },
+  "promptAppend": "\n\n## Team Context\nAlways consider team conventions..."
+}
+```
+
+When `oac update` runs:
+1. Stock `agent.json` + `prompt.md` are updated from registry
+2. Preset is re-applied on top of updated stock
+3. Final merged files written to `.opencode/agent/`
+4. User never loses customizations
+
+#### Essential Agents
+
+| Agent | Purpose | Critical |
+|-------|---------|---------|
+| `openagent` | Primary orchestration, plan-first development | Yes |
+| `opencoder` | Code implementation | Yes |
+| `contextscout` | Context discovery and navigation | Yes |
+| `externalscout` | External documentation fetching | Yes |
+| `task-manager` | Task breakdown and tracking | Yes |
+| `coder-agent` | Focused coding tasks | Yes |
+
+#### Skill Packaging
+
+```
+.opencode/skills/task-management/
+├── SKILL.md          # Skill definition (YAML frontmatter + prose)
+├── router.sh         # Dispatch script (must be fully implemented, not stub)
+└── scripts/
+    ├── task-cli.js   # COMPILED from task-cli.ts (NOT ts-node)
+    └── helpers.js
+```
+
+```yaml
+# SKILL.md frontmatter
+---
+name: task-management
+version: 1.2.0
+description: Task breakdown, tracking, and validation
+entrypoint: router.sh
+scripts:
+  - scripts/task-cli.js
+permissions:
+  - read: ".tmp/sessions/**"
+  - write: ".tmp/sessions/**"
+---
+```
+
+#### Four Core Skills
+
+| Skill | Status | Critical Gap |
+|-------|--------|-------------|
+| `task-management` | Mostly complete | `task-cli.ts` must be compiled to JS |
+| `context-manager` | router.sh is STUB | Needs full implementation (highest priority) |
+| `context7` | Complete | None |
+| `smart-router-skill` | Complete | None |
+
+#### CLI Commands
+
+```bash
+oac add agent <name>           # Install agent from registry
+oac remove agent <name>        # Remove agent
+oac list agents                # List installed agents
+oac customize agent <name>     # Open editor for agent customization
+oac presets list               # List available presets
+oac presets apply <preset>     # Apply preset to agents
+oac validate agents            # Validate all agent files
+oac create agent               # Interactive agent creation wizard
+
+oac skill install <name>       # Install skill from registry
+oac skill list                 # List installed skills
+oac skill update [name]        # Update skill(s)
+oac skill remove <name>        # Remove skill
+oac skill validate             # Validate all skills
+
+oac task status                # Show current task session status
+oac task next                  # Get next task
+oac task complete <id>         # Mark task as complete
+```
+
+---
+
+### Subsystem 4: Plugin System
+
+#### Current State
+
+**Two existing plugin systems**:
+1. **Claude Code** (`.claude-plugin/`): File-based plugin using `session-start.sh` bash script. Functional but bash-only.
+2. **OpenCode** (`packages/plugin-abilities/`): TypeScript event system. Compatibility layer (Phases 1-3) is ~59% complete. CLI integration is missing.
+
+Adapters for Claude, Cursor, and Windsurf exist in `packages/compatibility-layer/` and are functionally complete but have no CLI wiring.
+
+#### Target State
+
+OAC becomes a first-class OpenCode npm plugin registered in `opencode.json`:
+
+```json
+// .opencode/opencode.json
+{
+  "plugin": ["@nextsystems/oac"],
+  "model": "claude-sonnet-4-5",
+  "theme": "opencode"
+}
+```
+
+This single line activates the full OAC plugin system including auto-updates on session start.
+
+#### OpenCode Plugin (PRIMARY)
+
+OpenCode offers the richest integration API:
+- 25+ lifecycle events (session.created, file.changed, tool.before, tool.after, etc.)
+- Custom tool registration
+- TypeScript SDK with full type safety
+- npm-based distribution (no file copying required)
+
+```typescript
+// packages/plugin-abilities/src/index.ts
+import type { Plugin } from "@opencode/sdk";
+import { handleSessionCreated } from "./events/session";
+import { handleToolBefore } from "./events/tools";
+
+export default {
+  name: "@nextsystems/oac",
+  version: "0.7.1",
+
+  events: {
+    "session.created": handleSessionCreated,
+    "tool.before": handleToolBefore,
+  },
+
+  tools: [
+    // Custom OAC tools exposed to the AI
+  ],
+} satisfies Plugin;
+```
+
+```typescript
+// packages/plugin-abilities/src/events/session.ts
+export async function handleSessionCreated(ctx: SessionContext) {
+  // 1. Check for OAC updates
+  const updates = await checkForUpdates();
+
+  // 2. Apply safe updates (no user modifications)
+  await applySafeUpdates(updates);
+
+  // 3. Notify about skipped updates (user-modified files)
+  if (updates.conflicts.length > 0) {
+    ctx.notify(`OAC: ${updates.conflicts.length} files have local modifications — run 'oac update' to manage`);
+  }
+
+  // 4. Validate active context
+  await validateActiveContext(ctx);
+}
+```
+
+#### Claude Code Plugin (Secondary)
+
+The `.claude-plugin/session-start.sh` needs to be rewritten in TypeScript and compiled:
+
+```
+.claude-plugin/
+├── plugin.json          # Plugin manifest
+├── session-start.js     # Compiled from session-start.ts
+└── src/
+    └── session-start.ts # TypeScript source
+```
+
+```json
+// .claude-plugin/plugin.json
+{
+  "name": "@nextsystems/oac",
+  "version": "0.7.1",
+  "hooks": {
+    "session-start": "node session-start.js"
+  }
+}
+```
+
+#### Cursor Integration
+
+Cursor uses a single `.cursorrules` file (100KB limit). OAC generates this file from installed agents/context:
+
+```bash
+oac compat apply --ide=cursor
+# Generates .cursorrules with router pattern:
+# - Lists available agent personas
+# - Includes abbreviated context
+# - Stays under 100KB limit
+```
+
+#### Windsurf Integration
+
+Windsurf uses `.windsurfrules`. Adapter is functionally complete; needs CLI wiring only.
+
+#### Compatibility Layer CLI (Missing — High Priority)
+
+The compatibility adapters exist but have NO CLI. This must be added:
+
+```bash
+oac compat apply --ide=cursor        # Generate cursor-specific files
+oac compat apply --ide=claude        # Generate CLAUDE.md etc.
+oac compat apply --ide=windsurf      # Generate .windsurfrules
+oac compat apply --all               # Apply all compatible IDEs
+oac compat status                    # Show compatibility status per IDE
+oac compat validate --ide=cursor     # Validate generated files
+```
+
+#### Plugin CLI Commands
+
+```bash
+oac plugin install <name>            # Install plugin from registry
+oac plugin update [name]             # Update plugin(s)
+oac plugin remove <name>             # Remove plugin
+oac plugin list                      # List installed plugins
+oac plugin configure <name>          # Configure plugin settings
+oac plugin create                    # Scaffold new plugin
+```
+
+---
+
+### Subsystem 5: Registry & Community
+
+#### Current State
+
+`registry.json` exists at the repo root (106KB). It appears to be a flat JSON file. The exact format and whether it follows a published schema is unclear. No community contribution workflow exists. No lockfile system exists.
+
+#### Target State
+
+A shadcn-inspired registry with:
+- Typed component entries with SHA256 verification
+- `oac.lock` lockfile for reproducible installs
+- Community contribution via PR workflow
+- Security scanning on all community contributions
+
+#### Registry Item Format
+
+```json
+// registry.json
+{
+  "version": "1",
+  "registryUrl": "https://registry.nextsystems.dev/oac",
+  "items": [
+    {
+      "name": "openagent",
+      "type": "oac:agent",
+      "version": "2.1.0",
+      "description": "Primary orchestration agent for plan-first development",
+      "tags": ["orchestration", "planning", "primary"],
+      "author": "nextsystems",
+      "license": "MIT",
+      "files": [
+        {
+          "path": "agent.json",
+          "target": ".opencode/agent/openagent/agent.json",
+          "url": "https://registry.nextsystems.dev/oac/agents/openagent/2.1.0/agent.json",
+          "sha256": "a1b2c3d4..."
+        },
+        {
+          "path": "prompt.md",
+          "target": ".opencode/agent/openagent/prompt.md",
+          "url": "https://registry.nextsystems.dev/oac/agents/openagent/2.1.0/prompt.md",
+          "sha256": "e5f6a7b8..."
+        }
+      ],
+      "dependencies": [],
+      "peerDependencies": ["context7"]
+    },
+    {
+      "name": "task-management",
+      "type": "oac:skill",
+      "version": "1.2.0",
+      "files": [
+        {
+          "path": "SKILL.md",
+          "target": ".opencode/skills/task-management/SKILL.md",
+          "url": "...",
+          "sha256": "..."
+        },
+        {
+          "path": "router.sh",
+          "target": ".opencode/skills/task-management/router.sh",
+          "url": "...",
+          "sha256": "..."
+        },
+        {
+          "path": "scripts/task-cli.js",
+          "target": ".opencode/skills/task-management/scripts/task-cli.js",
+          "url": "...",
+          "sha256": "..."
+        }
+      ]
+    }
+  ]
+}
+```
+
+#### `oac.lock` Format
+
+```json
+// oac.lock (committed to git — enables reproducible installs)
+{
+  "version": "1",
+  "generatedAt": "2026-02-19T00:00:00Z",
+  "oacVersion": "0.7.1",
+  "installed": {
+    "agents": {
+      "openagent": {
+        "version": "2.1.0",
+        "source": "registry",
+        "sha256": {
+          "agent.json": "a1b2c3d4...",
+          "prompt.md": "e5f6a7b8..."
+        },
+        "installedAt": "2026-02-19T00:00:00Z",
+        "userModified": {
+          "agent.json": false,
+          "prompt.md": true
+        }
+      }
+    },
+    "skills": {
+      "task-management": {
+        "version": "1.2.0",
+        "source": "registry",
+        "sha256": { ... },
+        "installedAt": "..."
+      }
+    },
+    "context": {
+      "typescript-patterns.md": {
+        "version": "1.0.3",
+        "source": "bundled",
+        "sha256": "...",
+        "installedAt": "..."
+      }
+    }
+  }
+}
+```
+
+#### Directory Ownership (oh-my-zsh Pattern)
+
+```
+.opencode/agent/
+├── openagent/          # OAC-managed (tracked in oac.lock)
+├── task-manager/       # OAC-managed
+└── custom/             # USER-OWNED (never touched by oac update)
+    └── my-custom-agent/
+```
+
+OAC **never** modifies files in `.opencode/agent/custom/` or `.opencode/context/custom/`. This is the clean separation between OAC-managed and user-owned content.
+
+#### CLI Commands
+
+```bash
+oac browse                           # TUI browser of registry
+oac search <query>                   # Search registry
+oac publish <path>                   # Publish to community registry
+oac registry add <url>               # Add custom registry source
+oac registry list                    # List configured registries
+```
+
+---
+
+## 4. Implementation Phases (9 Weeks)
+
+### Phase Overview
+
+```
+Week 1-2: Foundation & Package Structure
+Week 3:   Context System
+Week 4:   Agent & Skill Management
+Week 5:   Plugin System (OpenCode primary)
+Week 6:   Compatibility Layer CLI
+Week 7:   Registry & Lockfile
+Week 8:   Auto-Update & Community
+Week 9:   Polish, Doctor, Testing
+```
+
+---
+
+### Phase 1: Foundation (Week 1-2)
+
+**Goal**: Working CLI binary with package structure. `oac --help` works and shows all commands.
+
+**What Gets Built**:
+
+1. Create `packages/cli/` package
+   - `tsconfig.json`, `package.json` with all dependencies
+   - `tsup.config.ts` for build
+   - `src/index.ts` with commander.js skeleton
+   - All command files as stubs (return "not yet implemented")
+
+2. Rewrite `bin/oac.js`
+   ```javascript
+   #!/usr/bin/env node
+   require('../packages/cli/dist/index.js');
+   ```
+
+3. Add `packages/cli` to root `workspaces` in `package.json`
+
+4. Configure `tsup` to compile `task-cli.ts` → `task-cli.js`
+   - Remove `ts-node` dependency from skills
+   - Update `router.sh` references to use compiled `task-cli.js`
+
+5. Set up `vitest` for testing across all packages
+
+6. Create `~/.config/oac/config.json` initialization in `oac init`
+
+**Dependencies**: None (this is the foundation everything else builds on)
+
+**Validation Criteria**:
+- `oac --help` lists all planned commands with descriptions
+- `oac --version` outputs correct version
+- `npx @nextsystems/oac init` runs without error
+- All packages build with zero TypeScript errors
+- `task-cli.js` executes correctly without `ts-node`
+
+---
+
+### Phase 2: Init & Doctor (Week 2)
+
+**Goal**: `oac init` sets up a project correctly. `oac doctor` diagnoses problems.
+
+**What Gets Built**:
+
+1. `oac init` command (interactive wizard)
+   ```
+   ? Which IDE are you using? (OpenCode / Claude Code / Cursor / Windsurf / Multiple)
+   ? Install standard agent pack? (Yes / No / Select)
+   ? Enable auto-updates? (Auto-safe / Auto-all / Manual)
+   ? Create .oac/config.json? (Yes)
+   ```
+   - Creates `.oac/config.json` (project config)
+   - Creates `oac.lock` (empty initially)
+   - Copies bundled content to `.opencode/`
+   - Creates `manifest.json` copy in project
+   - Adds entries to `.gitignore` (sessions, tmp)
+
+2. `oac doctor` command
+   - Checks: OAC version vs latest
+   - Checks: oac.lock exists and is valid
+   - Checks: all agents in oac.lock are present on disk
+   - Checks: all SHA256s match (detects corruption)
+   - Checks: IDE-specific config is correct
+   - Checks: `task-cli.js` is compiled (not `.ts`)
+   - Checks: context-manager `router.sh` is not a stub
+   - Reports: pass/warn/fail per check
+
+**Validation Criteria**:
+- `oac init` completes in < 30 seconds on first run
+- `oac doctor` correctly identifies a deliberately broken install
+- `oac doctor --fix` auto-repairs fixable issues
+
+---
+
+### Phase 3: Context System (Week 3)
+
+**Goal**: Full context system with 6-layer resolution and CLI management.
+
+**What Gets Built**:
+
+1. `ContextResolver` class implementing 6-layer resolution
+2. `oac context list` — shows all context with source layer
+3. `oac context resolve <name>` — shows which layer wins
+4. `oac context install <name>` — installs specific context file
+5. `oac context update` — updates all OAC-managed context
+6. `oac context validate` — validates syntax
+7. `oac context diff <name>` — diff vs stock version
+
+**Context Resolver Implementation**:
+
+```typescript
+// packages/cli/src/resolvers/context.ts
+const RESOLUTION_LAYERS = [
+  { name: "project-override",  path: ".oac/context",                    userOwned: true },
+  { name: "opencode-config",   path: ".opencode/context",               userOwned: false },
+  { name: "ide-specific",      path: ".cursor/context",                  userOwned: false },
+  { name: "project-docs",      path: "docs",                            userOwned: true },
+  { name: "user-global",       path: "~/.config/oac/context",           userOwned: true },
+  { name: "npm-bundled",       path: "__dirname/../../.opencode/context", userOwned: false },
+];
+
+export async function resolveContext(name: string): Promise<ResolvedContext> {
+  for (const layer of RESOLUTION_LAYERS) {
+    const filePath = join(layer.path, name);
+    if (await exists(filePath)) {
+      return { filePath, layer, userOwned: layer.userOwned };
+    }
+  }
+  throw new Error(`Context file not found: ${name}`);
+}
+```
+
+**Validation Criteria**:
+- `oac context list` shows correct source layer for each file
+- Updating a user-modified file is blocked/warned
+- `oac context resolve` output matches manual file system inspection
+
+---
+
+### Phase 4: Agent & Skill Management (Week 4)
+
+**Goal**: Full agent and skill lifecycle management. Preset system working.
+
+**What Gets Built**:
+
+1. `agent.json` schema with Zod validation
+2. `oac add agent <name>` — install from registry
+3. `oac remove agent <name>` — remove with confirmation
+4. `oac list agents` — tabular view with versions
+5. `oac customize agent <name>` — opens editor, saves to preset
+6. `oac presets list/apply` — preset management
+7. `oac validate agents` — schema validation
+8. **Fix context-manager router.sh stub** — implement full dispatch logic
+9. `oac skill install/list/update/remove/validate`
+
+**Agent Schema (Zod)**:
+
+```typescript
+// packages/cli/src/schemas/agent.ts
+const AgentSchema = z.object({
+  name: z.string().regex(/^[a-z][a-z0-9-]*$/),
+  displayName: z.string(),
+  version: z.string(),
+  description: z.string(),
+  model: z.string().optional(),
+  maxTokens: z.number().optional(),
+  permission: z.array(z.union([
+    z.object({ allow: z.string() }),
+    z.object({ deny: z.string() }),
+  ])).optional(),
+  tools: z.array(z.string()).optional(),
+  tags: z.array(z.string()).default([]),
+  oac: z.object({
+    bundledSha256: z.string(),
+    installedAt: z.string(),
+    source: z.enum(["registry", "bundled", "local"]),
+    presetApplied: z.string().optional(),
+  }).optional(),
+});
+```
+
+**context-manager router.sh** (critical gap fix):
+
+```bash
+#!/usr/bin/env bash
+# router.sh — context-manager skill dispatcher
+set -euo pipefail
+
+COMMAND="${1:-help}"
+SCRIPTS_DIR="$(dirname "$0")/scripts"
+
+case "$COMMAND" in
+  discover)    node "$SCRIPTS_DIR/discover.js" "${@:2}" ;;
+  fetch)       node "$SCRIPTS_DIR/fetch.js" "${@:2}" ;;
+  harvest)     node "$SCRIPTS_DIR/harvest.js" "${@:2}" ;;
+  extract)     node "$SCRIPTS_DIR/extract.js" "${@:2}" ;;
+  compress)    node "$SCRIPTS_DIR/compress.js" "${@:2}" ;;
+  organize)    node "$SCRIPTS_DIR/organize.js" "${@:2}" ;;
+  cleanup)     node "$SCRIPTS_DIR/cleanup.js" "${@:2}" ;;
+  workflow)    node "$SCRIPTS_DIR/workflow.js" "${@:2}" ;;
+  *)           echo "Usage: router.sh <discover|fetch|harvest|extract|compress|organize|cleanup|workflow>"; exit 1 ;;
+esac
+```
+
+**Validation Criteria**:
+- `oac add agent openagent` installs correctly and updates `oac.lock`
+- `oac customize agent openagent` opens editor and saves preset
+- After `oac update`, customizations survive
+- `oac validate agents` catches malformed `agent.json`
+- context-manager `router.sh` dispatches all 8 commands correctly
+
+---
+
+### Phase 5: OpenCode Plugin (Week 5)
+
+**Goal**: OAC registers as an OpenCode npm plugin. Auto-update works on session start.
+
+**What Gets Built**:
+
+1. Complete `packages/plugin-abilities/src/index.ts` as a proper OpenCode plugin
+2. `session.created` event handler with update check logic
+3. Register in `.opencode/opencode.json` as `"plugin": ["@nextsystems/oac"]`
+4. Session management CLI: `oac session list/clean`
+
+**OpenCode Plugin Registration**:
+
+```json
+// .opencode/opencode.json (updated)
+{
+  "plugin": ["@nextsystems/oac"],
+  "model": "claude-sonnet-4-5",
+  "theme": "opencode"
+}
+```
+
+**Session Created Handler**:
+
+```typescript
+// packages/plugin-abilities/src/events/session.ts
+import { checkForUpdates, applySafeUpdates } from "../updater";
+import { readLockfile } from "../lockfile";
+
+export async function handleSessionCreated(ctx: SessionContext) {
+  try {
+    const lockfile = await readLockfile();
+    const updates = await checkForUpdates(lockfile);
+
+    if (updates.safe.length > 0) {
+      await applySafeUpdates(updates.safe);
+      // Silent — don't interrupt the user's session
+    }
+
+    if (updates.conflicts.length > 0 && !lockfile.config.suppressConflictWarnings) {
+      ctx.log.warn(
+        `OAC: ${updates.conflicts.length} components have updates but local modifications. ` +
+        `Run 'oac update --interactive' to manage.`
+      );
+    }
+  } catch (err) {
+    // Never crash the user's session due to OAC errors
+    ctx.log.debug(`OAC update check failed: ${err.message}`);
+  }
+}
+```
+
+**Validation Criteria**:
+- OpenCode loads `@nextsystems/oac` plugin without error
+- `session.created` fires and completes without affecting session start time > 500ms
+- Auto-update correctly identifies modified files and skips them
+- Plugin unloads cleanly when removed from `opencode.json`
+
+---
+
+### Phase 6: Compatibility Layer CLI (Week 6)
+
+**Goal**: All existing compatibility adapters (Claude, Cursor, Windsurf) wired to CLI commands.
+
+**What Gets Built**:
+
+1. `oac compat apply --ide=<ide>` command wiring to existing adapters
+2. `oac compat status` — show what's generated for each IDE
+3. `oac compat validate --ide=<ide>` — validate generated files
+4. Claude Code plugin: rewrite `session-start.sh` → `session-start.ts` → compile to `session-start.js`
+5. Cursor: enforce 100KB limit in generator, warn if exceeded
+
+**Compat Apply Implementation**:
+
+```typescript
+// packages/cli/src/commands/compat.ts
+import { ClaudeAdapter } from "@nextsystems/oac-compatibility-layer";
+import { CursorAdapter } from "@nextsystems/oac-compatibility-layer";
+import { WindsurfAdapter } from "@nextsystems/oac-compatibility-layer";
+
+export const compatApplyCommand = new Command("apply")
+  .option("--ide <ide>", "target IDE (claude|cursor|windsurf|all)")
+  .option("--dry-run", "show what would be generated without writing")
+  .action(async (options) => {
+    const agents = await loadInstalledAgents();
+    const context = await loadInstalledContext();
+
+    const adapters = resolveAdapters(options.ide);
+    for (const adapter of adapters) {
+      const output = await adapter.generate({ agents, context });
+      if (!options.dryRun) {
+        await adapter.write(output);
+      }
+      console.log(`Generated ${adapter.name} files`);
+    }
+  });
+```
+
+**Validation Criteria**:
+- `oac compat apply --all` runs without error with a fresh install
+- Cursor output stays under 100KB
+- Claude Code `session-start.js` runs without `ts-node`
+- `oac compat status` correctly shows missing/present/outdated state
+
+---
+
+### Phase 7: Registry & Lockfile (Week 7)
+
+**Goal**: Full registry client with lockfile. `oac add` fetches from registry and records in lock.
+
+**What Gets Built**:
+
+1. Registry client with SHA256 verification
+2. `oac.lock` read/write with atomic updates
+3. `oac add` fetches from registry, verifies hash, writes to disk, updates lock
+4. `oac remove` removes files and updates lock
+5. `oac browse` TUI browser of registry items
+6. `oac search <query>` search registry
+
+**Registry Client**:
+
+```typescript
+// packages/cli/src/registry/client.ts
+export class RegistryClient {
+  async fetch(name: string, type: OACItemType): Promise<RegistryItem> {
+    const url = `${this.baseUrl}/${type}s/${name}`;
+    const item = await fetch(url).then(r => r.json());
+    return RegistryItemSchema.parse(item);
+  }
+
+  async download(item: RegistryItem): Promise<DownloadedFiles> {
+    const files = await Promise.all(
+      item.files.map(async (f) => {
+        const content = await fetch(f.url).then(r => r.text());
+        const sha256 = await computeSHA256(content);
+        if (sha256 !== f.sha256) {
+          throw new Error(`SHA256 mismatch for ${f.path}: expected ${f.sha256}, got ${sha256}`);
+        }
+        return { ...f, content };
+      })
+    );
+    return files;
+  }
+}
+```
+
+**Atomic Lockfile Updates**:
+
+```typescript
+// packages/cli/src/registry/lockfile.ts
+export async function updateLockfile(
+  lockfilePath: string,
+  updates: LockfileUpdate[]
+): Promise<void> {
+  const tmpPath = lockfilePath + ".tmp";
+  const lock = await readLockfile(lockfilePath);
+  for (const update of updates) {
+    applyUpdate(lock, update);
+  }
+  await writeFile(tmpPath, JSON.stringify(lock, null, 2));
+  await rename(tmpPath, lockfilePath); // Atomic rename
+}
+```
+
+**Validation Criteria**:
+- `oac add agent openagent` downloads, verifies SHA256, installs, updates `oac.lock`
+- Corrupted download (wrong SHA256) is rejected with clear error
+- `oac.lock` is valid JSON after every operation
+- `oac remove agent openagent` removes files and updates `oac.lock`
+
+---
+
+### Phase 8: Auto-Update & Community (Week 8)
+
+**Goal**: Background update checking, conflict resolution, community publish workflow.
+
+**What Gets Built**:
+
+1. `update-notifier` integration for CLI binary updates
+2. Registry polling with configurable interval
+3. `oac update` with `--interactive` conflict resolution
+4. `oac rollback <component>` to previous version
+5. `oac publish` workflow for community contributions
+6. Update modes: `manual` / `auto-safe` / `auto-all` / `locked`
+
+**Update Modes**:
+
+```typescript
+type UpdateMode = 
+  | "manual"      // Never auto-update, always prompt
+  | "auto-safe"   // Auto-update files with no local modifications
+  | "auto-all"    // Auto-update everything, backup modifications
+  | "locked"      // Never update, lock.json is authoritative
+```
+
+**Rollback**:
+
+```typescript
+// oac rollback openagent
+// Reads previous version from lock history
+// Fetches from registry at pinned version
+// Restores files + updates lock
+```
+
+**Validation Criteria**:
+- `update-notifier` shows update message when newer CLI version available
+- `oac update --interactive` correctly shows diffs and prompts for each conflict
+- `oac rollback openagent` restores previous version
+- Update mode `auto-safe` correctly skips user-modified files
+- Update mode `auto-all` creates backup before overwriting
+
+---
+
+### Phase 9: Polish & Testing (Week 9)
+
+**Goal**: Production-ready package with comprehensive test coverage and documentation.
+
+**What Gets Built**:
+
+1. Unit tests for all core functionality (vitest)
+2. Integration tests for CLI commands
+3. End-to-end test: fresh install → configure → update cycle
+4. `oac doctor` covers all known failure modes
+5. Performance: measure and optimize `session.created` handler
+6. README and getting-started guide updates
+7. Deprecation of `install.sh` with migration notice
+
+**Test Coverage Targets**:
+- Unit tests: ≥ 80% coverage on `packages/cli/src/`
+- Integration tests: all 20+ commands
+- E2E test: full install/update/rollback cycle
+
+**Validation Criteria**:
+- All tests pass on macOS, Linux, Windows (via GitHub Actions)
+- `oac init` completes in < 2 minutes on fresh machine
+- `session.created` handler adds < 500ms to session start
+- `oac doctor` passes on a correct install
+
+---
+
+## 5. Key Technical Decisions
+
+### Decision 1: OpenCode as Primary Target
+
+**Rationale**: OpenCode offers a TypeScript plugin SDK with 25+ lifecycle events, custom tool registration, and npm-based distribution. This is the richest integration model available among the four IDEs. By targeting OpenCode first, we get:
+- Auto-update on every session start (via `session.created`)
+- Type-safe plugin development
+- Zero file-copying for plugin distribution (npm handles it)
+- Future access to new OpenCode capabilities as they're released
+
+Claude Code, Cursor, and Windsurf are adaptation layers — we write once for OpenCode and adapt for others.
+
+### Decision 2: Bundle Context into npm (Not Fetch at Runtime)
+
+**Rationale**: Context files are needed the moment an AI session starts. A network fetch at that moment creates:
+- Latency (adds delay to every session)
+- Network dependency (fails offline, in CI, on slow connections)
+- Version drift (server updates mid-session)
+
+By bundling context into the npm package, we get zero-latency access, offline functionality, and version-locked reproducibility. The `manifest.json` + SHA256 system handles update detection separately from file delivery.
+
+### Decision 3: `agent.json` + `prompt.md` Separation
+
+**Rationale**: Separating metadata from prose has three benefits:
+1. **Diffability**: `agent.json` changes (model, permissions) are clearly separated from prompt content changes — easier to review in PRs
+2. **IDE compatibility**: `prompt.md` frontmatter contains only fields OpenCode reads natively. OAC metadata in `agent.json` doesn't pollute the frontmatter
+3. **Preset application**: Presets can override specific `agent.json` fields without touching `prompt.md`, and vice versa
+
+### Decision 4: shadcn Registry Pattern
+
+**Rationale**: shadcn demonstrated that a file-copy registry model is superior to package-per-component for configuration files. Benefits:
+- Users own their copies — they can modify them freely
+- No npm install needed to add an agent/skill/context file
+- SHA256 verification provides security without requiring a signing infrastructure
+- Community can contribute by PR to `registry.json`
+
+The `oac.lock` lockfile extends this pattern with version pinning and reproducibility.
+
+### Decision 5: Backward Compatibility Strategy
+
+During the 9-week transition:
+- `install.sh` continues to work but shows a deprecation notice
+- `bin/oac.js` is backward compatible — no arguments → runs equivalent of old behavior
+- All files installed by old `install.sh` remain valid; `oac doctor` can adopt them into `oac.lock`
+- `oac init --import` scans existing `.opencode/` and creates `oac.lock` from discovered files
+
+---
+
+## 6. Critical Gaps to Address
+
+These are gaps that will break functionality if not addressed before launch. Ordered by priority.
+
+### Gap 1: context-manager router.sh is a STUB (P0)
+
+**Current state**: `router.sh` in `.opencode/skills/context-manager/` exists but dispatches nothing.  
+**Impact**: The context-manager skill is completely non-functional.  
+**Fix**: Implement full dispatch logic to 8 subcommands (see Phase 4 above).  
+**Owner**: Phase 4, Week 4.
+
+### Gap 2: task-cli.ts requires ts-node (P0)
+
+**Current state**: `task-cli.ts` is invoked directly via `ts-node` in `router.sh`.  
+**Impact**: Breaks in any environment without `ts-node` (most production setups).  
+**Fix**: Compile `task-cli.ts` → `task-cli.js` via `tsup` in the build pipeline. Update `router.sh` to call `node task-cli.js`.  
+**Owner**: Phase 1, Week 1.
+
+### Gap 3: Compatibility Layer has no CLI (P1)
+
+**Current state**: `packages/compatibility-layer/` adapters are functionally complete but have zero CLI exposure.  
+**Impact**: Multi-IDE users cannot generate Claude/Cursor/Windsurf files via `oac` commands.  
+**Fix**: Wire adapters to `oac compat apply` command (Phase 6, Week 6).  
+**Owner**: Phase 6, Week 6.
+
+### Gap 4: OpenCode plugin does not exist as a proper plugin (P1)
+
+**Current state**: `packages/plugin-abilities/` has event handler stubs but is not registered in `opencode.json` as a proper plugin.  
+**Impact**: Auto-update via `session.created` does not fire.  
+**Fix**: Complete plugin-abilities implementation and add to `opencode.json` plugin array.  
+**Owner**: Phase 5, Week 5.
+
+### Gap 5: No lockfile system (P1)
+
+**Current state**: Installed components are not tracked. No reproducibility.  
+**Impact**: Teams cannot share exact installs. Updates cannot detect user modifications.  
+**Fix**: Implement `oac.lock` with atomic read/write (Phase 7, Week 7).  
+**Owner**: Phase 7, Week 7.
+
+### Gap 6: Full CLI does not exist (P0 — foundation)
+
+**Current state**: `bin/oac.js` is 91 lines that spawns `install.sh`.  
+**Impact**: Everything depends on this being fixed.  
+**Fix**: Create `packages/cli/` and rewrite `bin/oac.js` (Phase 1, Week 1-2).  
+**Owner**: Phase 1, Week 1.
+
+### Gap 7: No test infrastructure (P2)
+
+**Current state**: No tests exist anywhere in the codebase.  
+**Impact**: Regressions will go undetected. Cannot validate fixes.  
+**Fix**: Set up vitest in Phase 1, write tests progressively through Phases 2-9.  
+**Owner**: Phase 1 (setup) + ongoing.
+
+---
+
+## 7. Configuration Schema
+
+### Global Config: `~/.config/oac/config.json`
+
+```json
+{
+  "$schema": "https://registry.nextsystems.dev/oac/schemas/global-config.json",
+  "version": "1",
+  "defaults": {
+    "ide": "opencode",
+    "updateMode": "auto-safe",
+    "registry": "https://registry.nextsystems.dev/oac",
+    "telemetry": false
+  },
+  "presets": {
+    "default": "~/.config/oac/presets/default.json"
+  },
+  "auth": {
+    "registryToken": null
+  }
+}
+```
+
+**`updateMode` values**:
+- `"manual"` — Never auto-update. Run `oac update` explicitly.
+- `"auto-safe"` — Auto-update only files matching stock SHA256 (default).
+- `"auto-all"` — Auto-update everything. Creates `.oac/backups/` before overwriting.
+- `"locked"` — Never update. `oac.lock` is authoritative.
+
+### Project Config: `.oac/config.json`
+
+```json
+{
+  "$schema": "https://registry.nextsystems.dev/oac/schemas/project-config.json",
+  "version": "1",
+  "project": {
+    "name": "my-project",
+    "ide": "opencode",
+    "updateMode": "auto-safe"
+  },
+  "agents": {
+    "enabled": ["openagent", "task-manager", "contextscout"],
+    "disabled": []
+  },
+  "context": {
+    "enabled": ["typescript-patterns", "git-workflow"],
+    "disabled": []
+  },
+  "skills": {
+    "enabled": ["task-management", "context-manager", "context7"],
+    "disabled": []
+  },
+  "compatibility": {
+    "cursor": { "enabled": true, "autoRegenerate": true },
+    "claude": { "enabled": true, "autoRegenerate": false },
+    "windsurf": { "enabled": false }
+  }
+}
+```
+
+### `oac.lock` Format
+
+```json
+{
+  "$schema": "https://registry.nextsystems.dev/oac/schemas/lockfile.json",
+  "version": "1",
+  "generatedAt": "2026-02-19T00:00:00Z",
+  "oacVersion": "0.7.1",
+  "installed": {
+    "agents": {
+      "<name>": {
+        "version": "<semver>",
+        "source": "registry | bundled | local",
+        "registryUrl": "<url>",
+        "sha256": {
+          "<filename>": "<sha256>"
+        },
+        "installedAt": "<iso8601>",
+        "updatedAt": "<iso8601>",
+        "userModified": {
+          "<filename>": true | false
+        },
+        "presetApplied": "<preset-name> | null"
+      }
+    },
+    "skills": { "<same shape>" },
+    "context": { "<same shape>" },
+    "plugins": { "<same shape>" }
+  },
+  "history": [
+    {
+      "action": "add | update | remove | rollback",
+      "component": "<type>/<name>",
+      "fromVersion": "<semver> | null",
+      "toVersion": "<semver>",
+      "timestamp": "<iso8601>"
+    }
+  ]
+}
+```
+
+### OAC Component Manifest: `manifest.json`
+
+```json
+{
+  "$schema": "https://registry.nextsystems.dev/oac/schemas/manifest.json",
+  "version": "1",
+  "packageVersion": "0.7.1",
+  "generatedAt": "2026-02-19T00:00:00Z",
+  "agents": {
+    "<name>": {
+      "version": "<semver>",
+      "description": "<string>",
+      "files": {
+        "<filename>": {
+          "sha256": "<sha256>",
+          "size": 4821
+        }
+      }
+    }
+  },
+  "skills": { "<same shape>" },
+  "context": {
+    "<filename>": {
+      "version": "<semver>",
+      "sha256": "<sha256>",
+      "size": 2341,
+      "category": "language | workflow | tooling | project"
+    }
+  }
+}
+```
+
+---
+
+## 8. Auto-Update Strategy
+
+### Two-Layer Update System
+
+**Layer 1: CLI Binary Updates** (via `update-notifier`)
+
+```typescript
+// packages/cli/src/index.ts
+import updateNotifier from "update-notifier";
+import packageJson from "../../package.json";
+
+const notifier = updateNotifier({
+  pkg: packageJson,
+  updateCheckInterval: 1000 * 60 * 60 * 24, // Check daily
+});
+
+// Non-blocking: shows notification at end of command
+notifier.notify();
+```
+
+**Layer 2: Content File Updates** (hash-based registry polling)
+
+```
+Content update check flow:
+
+1. Read oac.lock (installed versions + sha256)
+2. Fetch registry manifest (latest versions + sha256)
+3. For each installed component:
+   a. Compare installed version vs registry version (semver)
+   b. If newer version available:
+      i.  Compute SHA256 of file on disk
+      ii. Compare to oac.lock sha256 for that file
+          MATCH  → file is stock OAC → SAFE TO UPDATE
+          DIFFER → file has user modifications → RESPECT updateMode
+4. Apply updates according to updateMode
+5. Update oac.lock
+```
+
+### Hash-Based Conflict Detection
+
+The SHA256 stored in `oac.lock` is the hash of the file **as installed from the registry**, not the current file on disk. This allows detection of user modifications:
+
+```typescript
+async function detectModification(
+  installedPath: string,
+  lockEntry: LockfileEntry
+): Promise<boolean> {
+  const currentContent = await readFile(installedPath);
+  const currentSha256 = await sha256(currentContent);
+  const installedSha256 = lockEntry.sha256[basename(installedPath)];
+  return currentSha256 !== installedSha256;
+}
+```
+
+### User-Owned vs OAC-Managed Files
+
+```
+OAC-MANAGED (tracked in oac.lock, updated by oac update):
+  .opencode/agent/<name>/          (standard agents)
+  .opencode/context/<name>.md     (standard context)
+  .opencode/skills/<name>/         (standard skills)
+
+USER-OWNED (never touched by oac update):
+  .opencode/agent/custom/          (user's custom agents)
+  .opencode/context/custom/        (user's custom context)
+  .oac/context/                    (project overrides, highest priority)
+  docs/                            (project documentation)
+  ~/.config/oac/presets/           (user presets)
+```
+
+### Update Modes in Detail
+
+| Mode | Behavior | Best For |
+|------|----------|---------|
+| `manual` | Never updates automatically. Must run `oac update` | Teams with strict change control |
+| `auto-safe` | Updates only files with SHA256 matching oac.lock (default) | Solo developers, most teams |
+| `auto-all` | Updates everything; backs up modified files to `.oac/backups/` | Users who want always-latest |
+| `locked` | Ignores registry. oac.lock is authoritative. | CI/CD, reproducible builds |
+
+### Update in OpenCode Plugin
+
+```typescript
+// Runs on every session.created — must be fast
+export async function handleSessionCreated(ctx: SessionContext) {
+  const updateMode = await getUpdateMode();
+  if (updateMode === "locked") return; // Fast exit for locked mode
+
+  const check = await checkUpdatesWithTimeout(5000); // 5s timeout
+  if (!check) return; // Network unavailable — skip silently
+
+  if (check.safeUpdates.length > 0 && updateMode !== "manual") {
+    await applySafeUpdates(check.safeUpdates); // Unmodified files
+  }
+
+  if (check.conflicts.length > 0) {
+    ctx.log.info(`OAC: ${check.conflicts.length} updates available (run 'oac update')`);
+  }
+}
+```
+
+---
+
+## 9. CLI Command Reference
+
+### Core Commands
+
+```bash
+oac init [--ide <ide>] [--no-agents] [--no-context] [--yolo]
+  Initialize OAC in the current project. Interactive wizard by default.
+  Creates: .oac/config.json, oac.lock, copies bundled content
+
+oac add <type> <name> [--version <semver>] [--yolo]
+  Install a component from the registry.
+  Types: agent, skill, context, plugin
+  Example: oac add agent openagent
+
+oac remove <type> <name> [--yolo]
+  Remove an installed component.
+  Example: oac remove agent openagent
+
+oac update [type] [name] [--interactive] [--dry-run] [--yolo]
+  Update installed components. Without args, updates all safe components.
+  --interactive: prompts for each conflict
+  --dry-run: shows what would be updated without making changes
+
+oac list [type] [--format table|json]
+  List installed components with versions and modification status.
+  Example: oac list agents
+
+oac doctor [--fix]
+  Diagnose installation issues. --fix auto-repairs fixable issues.
+
+oac rollback <type> <name> [--version <semver>]
+  Rollback a component to a previous version.
+  Example: oac rollback agent openagent --version 2.0.0
+```
+
+### Context Commands
+
+```bash
+oac context install <name>
+  Install a specific context file from the registry.
+
+oac context update [name]
+  Update context file(s). Without name, updates all safe context.
+
+oac context list [--format table|json]
+  List installed context files with source layer.
+
+oac context resolve <name>
+  Show which resolution layer provides a context file.
+
+oac context validate [name]
+  Validate context file syntax and frontmatter.
+
+oac context diff <name>
+  Show diff between installed file and stock (registry) version.
+```
+
+### Agent Commands
+
+```bash
+oac add agent <name>              # Install from registry
+oac remove agent <name>           # Remove agent
+oac list agents                   # List with versions and status
+oac customize agent <name>        # Open editor, save as preset
+oac validate agents [name]        # Validate agent.json schema
+oac create agent                  # Interactive creation wizard
+oac show agent <name>             # Show agent configuration
+
+oac presets list                  # List available presets
+oac presets apply <preset> [agents...]   # Apply preset to agents
+oac presets create <name>         # Create preset from current customizations
+oac presets remove <name>         # Delete preset
+```
+
+### Skill Commands
+
+```bash
+oac skill install <name>          # Install skill from registry
+oac skill update [name]           # Update skill(s)
+oac skill remove <name>           # Remove skill
+oac skill list                    # List installed skills
+oac skill validate [name]         # Validate SKILL.md and router.sh
+oac skill run <name> <command>    # Run skill command directly
+
+oac task status                   # Show current task session
+oac task next                     # Get next task from session
+oac task complete <id>            # Mark task as complete
+oac task session list             # List task sessions
+oac task session clean [--older-than <days>]  # Clean old sessions
+```
+
+### Plugin Commands
+
+```bash
+oac plugin install <name>         # Install plugin from registry
+oac plugin update [name]          # Update plugin(s)
+oac plugin remove <name>          # Remove plugin
+oac plugin list                   # List installed plugins
+oac plugin configure <name>       # Configure plugin settings
+oac plugin create                 # Scaffold new plugin
+```
+
+### Compatibility Commands
+
+```bash
+oac compat apply [--ide <ide>] [--all] [--dry-run]
+  Generate IDE-specific files from installed agents/context.
+  IDEs: cursor, claude, windsurf
+  Example: oac compat apply --ide cursor
+
+oac compat status
+  Show compatibility file status for each supported IDE.
+
+oac compat validate [--ide <ide>]
+  Validate generated compatibility files.
+
+oac compat clean [--ide <ide>]
+  Remove generated compatibility files.
+```
+
+### Registry Commands
+
+```bash
+oac browse [type]                 # TUI browser of registry
+oac search <query> [--type <type>]  # Search registry
+oac publish <path>                # Publish component to community registry
+oac registry add <url>            # Add custom registry source
+oac registry remove <url>         # Remove custom registry
+oac registry list                 # List configured registries
+oac registry status               # Check registry connectivity
+```
+
+### Configuration Commands
+
+```bash
+oac configure                     # Interactive config editor
+oac configure get <key>           # Get config value
+oac configure set <key> <value>   # Set config value
+oac configure reset               # Reset to defaults
+
+oac show [type] [name]            # Show details of installed component
+oac edit [type] [name]            # Open component in $EDITOR
+```
+
+### Global Flags
+
+```bash
+--yolo                  # Skip all confirmations
+--no-color              # Disable color output
+--quiet                 # Minimal output
+--verbose               # Verbose output
+--debug                 # Debug output with stack traces
+--json                  # Output as JSON (machine-readable)
+--config <path>         # Use alternate config file
+--registry <url>        # Use alternate registry URL
+```
+
+---
+
+## 10. Success Metrics
+
+### Technical Metrics
+
+| Metric | Target | Measurement Method |
+|--------|--------|-------------------|
+| Test coverage | ≥ 80% on `packages/cli/src/` | vitest coverage |
+| Build time | < 30 seconds for full build | `time npm run build` |
+| CLI startup time | < 200ms for `oac --version` | `time oac --version` |
+| `oac init` time | < 2 minutes on fresh machine | Manual timing |
+| `session.created` overhead | < 500ms | OpenCode plugin timing |
+| Bundle size | < 5MB total npm package | `npm pack --dry-run` |
+| TypeScript errors | 0 errors on `tsc --noEmit` | CI check |
+| Zero bash dependencies | `oac` commands work without bash | Test on fresh Windows VM |
+
+### User Experience Metrics
+
+| Metric | Target | Measurement Method |
+|--------|--------|-------------------|
+| Setup time (solo dev) | < 2 minutes from `npx @nextsystems/oac init` to working | User testing |
+| Update friction | Zero prompts in `auto-safe` mode | Automated test |
+| Customization survival rate | 100% presets survive `oac update` | Integration test |
+| `oac doctor` detection rate | 100% of documented failure modes | Test against each failure mode |
+| Rollback reliability | `oac rollback` succeeds 100% if oac.lock is present | Integration test |
+
+### Community Adoption Metrics (6-month targets)
+
+| Metric | Target |
+|--------|--------|
+| npm weekly downloads | > 1,000 |
+| Community registry contributions | > 10 agents/skills submitted |
+| GitHub issues: "broken install" | < 5% of total issues |
+| `oac doctor --fix` auto-repair success rate | > 90% |
+| Multi-IDE users | > 20% of users run `oac compat apply` |
+
+### Migration Metrics
+
+| Metric | Target |
+|--------|--------|
+| `install.sh` usage | < 20% of installs by Week 9 |
+| Users successfully migrated via `oac init --import` | > 80% |
+| Regressions reported after migration | 0 P0/P1 bugs |
+
+---
+
+## Appendix A: File Naming Conventions
+
+```
+Agents:   .opencode/agent/<name>/agent.json + prompt.md
+Skills:   .opencode/skills/<name>/SKILL.md + router.sh + scripts/*.js
+Context:  .opencode/context/<name>.md
+Plugins:  packages/plugin-abilities/ (OpenCode) | .claude-plugin/ (Claude Code)
+Config:   .oac/config.json (project) | ~/.config/oac/config.json (global)
+Lock:     oac.lock (project root, commit to git)
+Manifest: manifest.json (project root, commit to git)
+Backups:  .oac/backups/<timestamp>/<component>/ (git-ignored)
+Sessions: .tmp/sessions/ (git-ignored)
+Presets:  ~/.config/oac/presets/<name>.json (survives npm updates)
+```
+
+## Appendix B: Dependency Rationale
+
+| Package | Purpose | Why Not Alternative |
+|---------|---------|---------------------|
+| `commander` | CLI framework | Battle-tested, good TypeScript support. Yargs has more complex API. |
+| `@inquirer/prompts` | Interactive prompts | Official Inquirer v9 rewrite, modular. Better than `enquirer` |
+| `ora` | Spinners | Standard, well-maintained |
+| `chalk` | Colors | Standard, ESM-compatible v5 |
+| `conf` | Global config persistence | OS-correct paths, handles JSON schema |
+| `fs-extra` | File operations | Adds `copy`, `ensureDir`, `readJSON` etc. Better than raw `fs` |
+| `semver` | Version comparison | npm's own semver library, authoritative |
+| `zod` | Schema validation | Best TypeScript DX, composable schemas |
+| `update-notifier` | CLI update notifications | Non-blocking background check |
+| `tsup` | Build tool | Bundles deps, fast, simple config |
+| `vitest` | Testing | Fast, native ESM, compatible with tsup |
+
+## Appendix C: Migration Path from install.sh
+
+```bash
+# Old workflow:
+curl -fsSL https://install.nextsystems.dev/oac | bash
+
+# New workflow (v1.0):
+npx @nextsystems/oac init
+
+# For existing users:
+oac init --import          # Scans .opencode/ and creates oac.lock
+oac doctor                 # Validates the import
+oac compat apply --all     # Regenerates IDE-specific files
+
+# install.sh shows deprecation notice but continues to work:
+echo "DEPRECATED: install.sh will be removed in v2.0. Run: npx @nextsystems/oac init"
+```
+
+---
+
+*Document status: Authoritative master plan. All implementation decisions should reference this document. Update this document when architectural decisions change.*
+
+*Next action: Begin Phase 1 — create `packages/cli/` package structure and rewrite `bin/oac.js`.*

+ 1330 - 0
docs/planning/13-PROJECT-BREAKDOWN.md

@@ -0,0 +1,1330 @@
+# OAC Package Refactor — Project Breakdown
+
+**Document**: 13-PROJECT-BREAKDOWN.md  
+**GitHub Issue**: #206  
+**Status**: Approved for Implementation  
+**Date**: 2026-02-19  
+**Based on**: 12-MASTER-SYNTHESIS.md + Architecture Review (CodeReviewer)
+
+> **Architecture Review Key Finding**: The synthesis plan is 75% solid. The critical gap is a missing **provider/adapter pattern** for non-IDE subsystems (context, task management, registry). This must be built in Project 1 before anything else. It enables users to swap out any subsystem — including the context system and task management — with their own implementations.
+
+---
+
+## Overview: 6 Discrete Projects
+
+| # | Project | What It Builds | Depends On |
+|---|---------|---------------|------------|
+| **P1** | `@nextsystems/oac-core` | Shared interfaces, schemas, provider contracts | Nothing |
+| **P2** | `@nextsystems/oac-cli` | Full CLI (commander.js, all commands, config, lockfile) | P1 |
+| **P3** | Context System | 6-layer resolver, bundle/manifest, auto-update | P1, P2 |
+| **P4** | Agent & Skill Management | agent.json+prompt.md, presets, skills packaging | P1, P2 |
+| **P5** | Plugin System | OpenCode TS plugin, Claude Code rewrite, Cursor/Windsurf | P1, P2, P4 |
+| **P6** | Registry & Community | shadcn registry, oac.lock, community publishing | P1, P2 |
+
+Projects P3–P6 can be worked in parallel once P1 and P2 are complete.
+
+---
+
+## Project 1: `@nextsystems/oac-core` — Shared Interfaces & Provider Contracts
+
+**Purpose**: Zero-dependency package containing all TypeScript interfaces, Zod schemas, and provider contracts. Every other package depends on this. Users implement these interfaces to swap subsystems.
+
+**Why first**: Without this, schemas diverge between packages (already happening: `AgentFrontmatterSchema` in compatibility-layer vs planned `AgentSchema` in CLI). Fixes the dual-source-of-truth problem identified in the review.
+
+### What to Build
+
+#### 1.1 Provider Interfaces (The Extensibility Layer)
+
+These are the interfaces users implement to replace OAC's default subsystems:
+
+```typescript
+// src/providers/context.ts
+export interface IContextProvider {
+  readonly id: string;
+  readonly displayName: string;
+  resolve(name: string): Promise<ContextFile | null>;
+  list(query?: ContextQuery): Promise<ContextFile[]>;
+  install(name: string, source: string | Buffer): Promise<void>;
+  update(name: string, newContent: string, expectedSha256: string): Promise<'updated' | 'skipped' | 'conflict'>;
+  isModified(name: string, installedSha256: string): Promise<boolean>;
+  validate(name: string): Promise<ValidationResult>;
+}
+
+// src/providers/task-management.ts
+export interface ITaskManagementProvider {
+  readonly id: string;
+  readonly displayName: string;
+  createSession(tasks: Omit<Task, 'id'>[]): Promise<TaskSession>;
+  getCurrentSession(): Promise<TaskSession | null>;
+  getNextTask(sessionId: string): Promise<Task | null>;
+  completeTask(sessionId: string, taskId: string): Promise<void>;
+  listSessions(): Promise<TaskSession[]>;
+  cleanSessions(olderThanDays: number): Promise<number>;
+}
+
+// src/providers/registry.ts
+export interface IRegistryProvider {
+  readonly id: string;
+  readonly displayName: string;
+  readonly baseUrl: string;
+  fetch(name: string, type: ComponentType): Promise<RegistryItem>;
+  search(query: string, options?: RegistrySearchOptions): Promise<RegistryItem[]>;
+  download(item: RegistryItem): Promise<Array<{ file: RegistryFile; content: string }>>;
+  ping(): Promise<boolean>;
+  getLatestVersion(name: string, type: ComponentType): Promise<string>;
+}
+
+// src/providers/ide-adapter.ts
+export interface IIDEAdapter {
+  readonly id: string;
+  readonly displayName: string;
+  fromOAC(agent: OACAgent, context: OACContext[]): Promise<IDEAdapterResult>;
+  toOAC(source: string): Promise<OACAgent>;
+  getOutputPath(): string;
+  getCapabilities(): IDECapabilities;
+  validate(output: IDEAdapterResult): ValidationResult;
+}
+
+// src/providers/agent-profile.ts
+export interface IAgentProfileProvider {
+  readonly id: string;
+  readonly displayName: string;
+  list(): Promise<AgentProfile[]>;
+  get(name: string): Promise<AgentProfile | null>;
+  has(name: string): Promise<boolean>;
+}
+```
+
+#### 1.2 Canonical Zod Schemas
+
+One schema per concept, used by all packages:
+
+```typescript
+// src/schemas/agent.ts — The canonical agent schema
+export const AgentConfigSchema = z.object({
+  name: z.string().regex(/^[a-z][a-z0-9-]*$/),
+  displayName: z.string(),
+  version: z.string(),
+  description: z.string(),
+  model: z.string().optional(),
+  temperature: z.number().min(0).max(1).optional(),
+  maxSteps: z.number().optional(),
+  mode: z.enum(['primary', 'subagent', 'all']).optional(),
+  permission: z.array(PermissionRuleSchema).optional(),
+  tools: z.array(z.string()).optional(),
+  skills: z.array(z.string()).optional(),
+  oac: z.object({
+    bundledSha256: z.string().optional(),
+    installedAt: z.string().optional(),
+    source: z.enum(['registry', 'bundled', 'local']),
+    presetApplied: z.string().optional(),
+    tags: z.array(z.string()).default([]),
+    category: z.string().optional(),
+  }).optional(),
+});
+
+// src/schemas/config.ts — Global + project config
+// src/schemas/lockfile.ts — oac.lock format
+// src/schemas/registry.ts — registry.json + registry item format
+// src/schemas/skill.ts — SKILL.md frontmatter
+// src/schemas/context.ts — Context file frontmatter
+// src/schemas/manifest.ts — manifest.json (npm bundle inventory)
+```
+
+#### 1.3 Provider Registry (Wiring Layer)
+
+```typescript
+// src/provider-registry.ts
+export class ProviderRegistry {
+  private contextProvider: IContextProvider;
+  private taskProvider: ITaskManagementProvider;
+  private registryProviders: Map<string, IRegistryProvider>;
+  private ideAdapters: Map<string, IIDEAdapter>;
+  private agentProfileProviders: Map<string, IAgentProfileProvider>;
+
+  constructor(config: OACConfig) { /* initialize defaults */ }
+  
+  async loadFromConfig(config: OACConfig): Promise<void> {
+    // Dynamically import custom providers from config.providers.*
+    // Supports: npm package name, local path, or URL (for registry)
+  }
+
+  getContextProvider(): IContextProvider { ... }
+  getTaskProvider(): ITaskManagementProvider { ... }
+  getRegistry(name?: string): IRegistryProvider { ... }
+  getAllRegistries(): IRegistryProvider[] { ... }
+  getIDEAdapter(id: string): IIDEAdapter | undefined { ... }
+}
+```
+
+#### 1.4 Shared Types
+
+```typescript
+// src/types/index.ts
+export type ComponentType = 'agent' | 'skill' | 'context' | 'plugin';
+export type UpdateMode = 'manual' | 'auto-safe' | 'auto-all' | 'locked';
+export type ConflictStrategy = 'ask' | 'skip' | 'overwrite' | 'backup' | 'yolo';
+export type InstallLocation = 'local' | 'global';
+
+export interface ValidationResult {
+  valid: boolean;
+  errors: string[];
+  warnings: string[];
+}
+
+export interface ContextFile {
+  name: string;
+  content: string;
+  path: string;
+  layer: string;
+  userOwned: boolean;
+  sha256: string;
+}
+
+export interface OACAgent {
+  config: AgentConfig;
+  promptMd: string;
+  systemMd?: string;
+}
+// ... all shared types
+```
+
+### Package Structure
+
+```
+packages/core/
+├── src/
+│   ├── providers/
+│   │   ├── context.ts          # IContextProvider interface
+│   │   ├── task-management.ts  # ITaskManagementProvider interface
+│   │   ├── registry.ts         # IRegistryProvider interface
+│   │   ├── ide-adapter.ts      # IIDEAdapter interface
+│   │   └── agent-profile.ts    # IAgentProfileProvider interface
+│   ├── schemas/
+│   │   ├── agent.ts            # AgentConfigSchema (Zod)
+│   │   ├── config.ts           # OACConfigSchema (Zod)
+│   │   ├── lockfile.ts         # LockfileSchema (Zod)
+│   │   ├── registry.ts         # RegistrySchema + RegistryItemSchema (Zod)
+│   │   ├── skill.ts            # SkillFrontmatterSchema (Zod)
+│   │   ├── context.ts          # ContextFrontmatterSchema (Zod)
+│   │   └── manifest.ts         # ManifestSchema (Zod)
+│   ├── provider-registry.ts    # ProviderRegistry class
+│   └── types/
+│       └── index.ts            # All shared TypeScript types
+├── package.json                # Zero runtime deps (only zod as peer)
+└── tsconfig.json
+```
+
+### Key Constraints
+
+- **Zero runtime dependencies** (except `zod` as a peer dep)
+- All interfaces must be stable — breaking changes require major version bump
+- Export everything from `index.ts` for clean imports: `import { IContextProvider } from '@nextsystems/oac-core'`
+- Must be usable by third-party plugin authors to implement custom providers
+
+### Context Files Needed
+
+- `.opencode/context/core/standards/code-quality.md`
+- `.opencode/context/core/standards/test-coverage.md`
+
+### Validation Criteria
+
+- [ ] All 5 provider interfaces defined and exported
+- [ ] All Zod schemas match existing codebase field names (no divergence from compatibility-layer)
+- [ ] `ProviderRegistry` loads custom providers from `config.providers.*` via dynamic import
+- [ ] Zero runtime dependencies (only zod peer dep)
+- [ ] 100% TypeScript strict mode
+- [ ] All types exported from single `index.ts`
+
+---
+
+## Project 2: `@nextsystems/oac-cli` — Full CLI Package
+
+**Purpose**: The main `oac` command. Commander.js-based CLI with all commands, config system, lockfile, approval/YOLO system, and wiring to all providers.
+
+**Depends on**: Project 1 (`@nextsystems/oac-core`)
+
+### What to Build
+
+#### 2.1 CLI Entry Point & Command Structure
+
+```typescript
+// src/index.ts — lazy-loaded commands (keeps oac --version < 50ms)
+program
+  .command('init')
+  .action(async (...args) => {
+    const { initCommand } = await import('./commands/init.js');
+    return initCommand(...args);
+  });
+// All commands use dynamic import — never eager-load
+```
+
+**Complete command surface**:
+
+| Command | Description |
+|---------|-------------|
+| `oac init [profile]` | First-run wizard, project setup |
+| `oac install <ide> [profile]` | Install for specific IDE |
+| `oac add <component>` | Add individual component (agent/skill/context) |
+| `oac update [component]` | Update installed components |
+| `oac remove <component>` | Remove a component |
+| `oac list [type]` | List installed/available components |
+| `oac browse [type]` | Interactive TUI browser |
+| `oac search <query>` | Search registry |
+| `oac configure [subcommand]` | Manage configuration |
+| `oac context <subcommand>` | Context system management |
+| `oac skill <subcommand>` | Skill management |
+| `oac plugin <subcommand>` | Plugin management |
+| `oac doctor` | Diagnose installation health |
+| `oac rollback [component]` | Undo last operation |
+| `oac publish <path>` | Publish to community registry |
+| `oac compat <subcommand>` | IDE compatibility tools |
+| `oac show <component>` | Show component details |
+| `oac presets <subcommand>` | Manage personal presets |
+| `oac registry <subcommand>` | Manage registry sources |
+
+**Global flags** (all commands):
+```
+--yolo          Skip all confirmations, auto-resolve conflicts
+--dry-run       Preview changes without executing
+--local         Force local install (.opencode/ in CWD)
+--global        Force global install (~/.config/oac/)
+--verbose       Detailed output
+--quiet         Suppress output except errors
+```
+
+#### 2.2 Config System
+
+```typescript
+// src/config/manager.ts
+export class ConfigManager {
+  // Merges: defaults → global (~/.config/oac/config.json) → project (.oac/config.json)
+  async load(): Promise<OACConfig>;
+  async set(keyPath: string, value: unknown, scope: 'global' | 'local'): Promise<void>;
+  async get(keyPath: string): Promise<unknown>;
+  async validate(config: unknown): Promise<OACConfig>;  // Uses OACConfigSchema from core
+}
+```
+
+**Config file locations**:
+- Global: `~/.config/oac/config.json`
+- Project: `.oac/config.json` (committed to git)
+- Env overrides: `OAC_YOLO=true`, `OAC_REGISTRY_URL=...`, `OAC_BRANCH=...`
+
+**Config schema** (key sections):
+```json
+{
+  "version": "1.0.0",
+  "preferences": {
+    "defaultIDE": "opencode",
+    "installLocation": "local",
+    "yoloMode": false,
+    "conflictStrategy": "ask",
+    "autoBackup": true,
+    "updateMode": "manual"
+  },
+  "providers": {
+    "context": null,
+    "taskManagement": null,
+    "registry": null,
+    "ideAdapters": []
+  },
+  "registries": [
+    { "name": "official", "url": "https://registry.nextsystems.dev/oac", "priority": 1 }
+  ],
+  "ides": {
+    "opencode": { "enabled": true, "path": ".opencode", "profile": "developer" },
+    "cursor": { "enabled": false, "path": ".cursor", "profile": "developer" },
+    "claude": { "enabled": false, "path": ".claude", "profile": "developer" }
+  }
+}
+```
+
+#### 2.3 Approval / YOLO System
+
+```typescript
+// src/approval/manager.ts
+export class ApprovalManager {
+  constructor(private opts: { yolo: boolean; strategy: ConflictStrategy }) {}
+
+  // Returns: 'proceed' | 'skip' | 'backup-and-proceed' | 'abort'
+  async resolveConflict(file: ConflictFile): Promise<ConflictResolution>;
+  
+  // Batch approval for multiple files
+  async resolveAll(files: ConflictFile[]): Promise<Map<string, ConflictResolution>>;
+  
+  // Show diff between existing and new file
+  async showDiff(existing: string, incoming: string): Promise<void>;
+}
+```
+
+**Conflict resolution flow**:
+1. File doesn't exist → install silently
+2. File exists, SHA256 matches installed version → update silently (not user-modified)
+3. File exists, SHA256 differs from installed → user-modified → prompt (or YOLO: backup+overwrite)
+4. `--yolo` → backup all conflicts, overwrite all, report at end
+
+#### 2.4 Lockfile System
+
+```typescript
+// src/lockfile/manager.ts
+export class LockfileManager {
+  // oac.lock format (committed to git)
+  async read(): Promise<OACLock>;
+  async write(lock: OACLock): Promise<void>;
+  async addComponent(component: InstalledComponent): Promise<void>;
+  async removeComponent(name: string, type: ComponentType): Promise<void>;
+  async getComponent(name: string, type: ComponentType): Promise<InstalledComponent | null>;
+  async isModified(name: string, type: ComponentType): Promise<boolean>;
+  async pruneHistory(maxEntries?: number): Promise<void>;  // Prevents unbounded growth
+}
+```
+
+**oac.lock format**:
+```json
+{
+  "version": "1",
+  "oacVersion": "1.0.0",
+  "generated": "2026-02-19T00:00:00Z",
+  "installed": {
+    "opencode": {
+      "profile": "developer",
+      "location": "local",
+      "path": ".opencode",
+      "components": {
+        "agent:openagent": {
+          "version": "1.0.0",
+          "sha256": "abc123",
+          "installedAt": "2026-02-19T10:00:00Z",
+          "source": "https://registry.nextsystems.dev/oac",
+          "userModified": false
+        }
+      }
+    }
+  },
+  "historyPolicy": { "maxEntries": 50 },
+  "history": [
+    { "timestamp": "...", "action": "install", "component": "agent:openagent", "version": "1.0.0" }
+  ]
+}
+```
+
+#### 2.5 Backup System
+
+```typescript
+// src/backup/manager.ts
+export class BackupManager {
+  // Backups stored in .oac/backups/ (git-ignored)
+  async backup(filePath: string): Promise<string>;  // Returns backup path
+  async restore(backupPath: string): Promise<void>;
+  async listBackups(component?: string): Promise<Backup[]>;
+  async pruneBackups(maxPerComponent?: number): Promise<void>;
+}
+```
+
+#### 2.6 `oac doctor` Command
+
+Checks (in order):
+1. Node.js version ≥ 18
+2. Config files valid JSON + schema
+3. Registry reachable (network check)
+4. All installed component files exist on disk
+5. SHA256 integrity of installed files vs lockfile
+6. Dependency graph complete (no missing deps)
+7. IDE-specific paths exist and readable
+8. `oac.lock` in sync with installed files
+9. `task-cli.js` compiled (not just `.ts`)
+10. `context-manager/router.sh` is not a stub
+11. Git integration (uncommitted changes warning)
+12. Custom providers loadable (if configured)
+
+#### 2.7 Developer Tooling Scripts
+
+```
+scripts/
+├── generate-manifest.ts    # Auto-generate manifest.json from .opencode/context/ files
+├── generate-navigation.ts  # Auto-generate navigation.md files per category
+├── validate-registry.ts    # Validate registry.json integrity (already exists, keep)
+├── validate-content.ts     # Validate all context/agent/skill files
+└── add-content.ts          # Scaffold new content with correct metadata
+```
+
+**Adding a new context file** (the simplified workflow):
+```bash
+# Before: manual SHA256, manual manifest.json, manual registry.json
+# After:
+npm run add-content -- --type context --name typescript-patterns --category development
+# → Creates .opencode/context/development/typescript-patterns.md with frontmatter
+# → Auto-updates manifest.json with SHA256
+# → Auto-updates registry.json
+# → Auto-updates navigation.md for that category
+```
+
+### Package Structure
+
+```
+packages/cli/
+├── src/
+│   ├── commands/
+│   │   ├── init.ts
+│   │   ├── install.ts
+│   │   ├── add.ts
+│   │   ├── update.ts
+│   │   ├── remove.ts
+│   │   ├── list.ts
+│   │   ├── browse.ts
+│   │   ├── search.ts
+│   │   ├── configure.ts
+│   │   ├── context.ts
+│   │   ├── skill.ts
+│   │   ├── plugin.ts
+│   │   ├── doctor.ts
+│   │   ├── rollback.ts
+│   │   ├── publish.ts
+│   │   ├── compat.ts
+│   │   ├── show.ts
+│   │   ├── presets.ts
+│   │   └── registry.ts
+│   ├── config/
+│   │   ├── manager.ts
+│   │   └── defaults.ts
+│   ├── approval/
+│   │   ├── manager.ts
+│   │   └── strategies.ts
+│   ├── lockfile/
+│   │   └── manager.ts
+│   ├── backup/
+│   │   └── manager.ts
+│   ├── ui/
+│   │   ├── prompts.ts      # @inquirer/prompts wrappers
+│   │   ├── progress.ts     # ora + cli-progress wrappers
+│   │   └── logger.ts       # chalk + log levels
+│   └── index.ts            # Commander setup, lazy command loading
+├── scripts/
+│   ├── generate-manifest.ts
+│   ├── generate-navigation.ts
+│   ├── validate-content.ts
+│   └── add-content.ts
+├── package.json
+└── tsconfig.json
+```
+
+### Key Dependencies
+
+```json
+{
+  "dependencies": {
+    "@nextsystems/oac-core": "workspace:*",
+    "commander": "^12.0.0",
+    "@inquirer/prompts": "^5.0.0",
+    "chalk": "^5.3.0",
+    "ora": "^8.0.1",
+    "cli-progress": "^3.12.0",
+    "update-notifier": "^7.3.1",
+    "conf": "^13.0.0",
+    "fs-extra": "^11.2.0",
+    "glob": "^10.3.0",
+    "gray-matter": "^4.0.3",
+    "semver": "^7.6.0",
+    "diff": "^5.2.0"
+  }
+}
+```
+
+### Validation Criteria
+
+- [ ] `oac --version` completes in < 50ms (lazy loading)
+- [ ] `oac init developer --yolo` completes in < 2 minutes
+- [ ] All commands have `--dry-run` support
+- [ ] `--yolo` flag skips all interactive prompts
+- [ ] Config merges correctly: defaults → global → project → env vars
+- [ ] `oac.lock` written after every install/update/remove
+- [ ] `oac.lock` history capped at 50 entries
+- [ ] `oac doctor` catches all 12 defined failure modes
+- [ ] Backups created before any overwrite
+- [ ] Custom providers load from `config.providers.*`
+- [ ] 80%+ test coverage on core modules
+
+---
+
+## Project 3: Context System
+
+**Purpose**: 6-layer context resolution, bundle/manifest management, auto-update, and the `oac context *` commands. Implements `IContextProvider` from Project 1.
+
+**Depends on**: P1 (core interfaces), P2 (CLI commands, config)
+
+### What to Build
+
+#### 3.1 Default Context Provider (6-Layer Resolver)
+
+```typescript
+// src/providers/default-context-provider.ts
+export class DefaultContextProvider implements IContextProvider {
+  readonly id = 'oac-default';
+  readonly displayName = 'OAC 6-Layer Context Resolver';
+
+  private layers: string[];
+  private cache: Map<string, ContextFile>;  // (filename, mtime) → ContextFile
+
+  constructor(config: OACConfig) {
+    this.layers = this.buildLayers(config);
+  }
+
+  private buildLayers(config: OACConfig): string[] {
+    const projectRoot = process.cwd();
+    const home = os.homedir();
+    const pkgPath = dirname(require.resolve('@nextsystems/oac/package.json'));
+    return [
+      join(projectRoot, '.oac/context'),           // L1: project override (highest)
+      join(projectRoot, '.opencode/context'),       // L2: project context
+      join(projectRoot, '.claude/context'),          // L3: IDE-specific (claude)
+      join(projectRoot, '.cursor/context'),          // L3: IDE-specific (cursor)
+      join(projectRoot, 'docs/context'),             // L4: project docs
+      join(home, '.config/oac/context'),             // L5: user global
+      join(pkgPath, 'context'),                      // L6: OAC bundled (lowest)
+    ];
+  }
+
+  async resolve(name: string): Promise<ContextFile | null> {
+    // Check cache first (invalidate on mtime change)
+    for (const [index, basePath] of this.layers.entries()) {
+      const fullPath = join(basePath, name);
+      if (await pathExists(fullPath)) {
+        return this.buildContextFile(fullPath, LAYER_NAMES[index]);
+      }
+    }
+    return null;
+  }
+}
+```
+
+#### 3.2 Manifest System
+
+```typescript
+// src/manifest/manager.ts
+export class ManifestManager {
+  // manifest.json = npm package inventory (never modified by users)
+  async readBundled(): Promise<BundledManifest>;  // Reads from npm package
+  
+  // .opencode/.oac-manifest.json = project install state
+  async readInstalled(projectRoot: string): Promise<InstalledManifest>;
+  async writeInstalled(projectRoot: string, manifest: InstalledManifest): Promise<void>;
+  
+  // Compare to find what needs updating
+  async computeDrift(projectRoot: string): Promise<DriftReport>;
+}
+```
+
+**Manifest contract** (clarified from review):
+- `manifest.json` (in npm package) = **what ships in the package** — never modified by users, auto-generated by `scripts/generate-manifest.ts`
+- `.opencode/.oac-manifest.json` (in project) = **what's installed** — written by `oac context install`, read by `oac context update`
+- `oac.lock` = **full install state** including non-context components
+
+#### 3.3 Auto-Generated Manifest
+
+```typescript
+// scripts/generate-manifest.ts (runs at npm publish time)
+// Scans .opencode/context/ → computes SHA256 for each file → writes manifest.json
+// NEVER hand-maintain SHA256s
+```
+
+#### 3.4 Auto-Generated Navigation Files
+
+```typescript
+// scripts/generate-navigation.ts (runs at npm publish time)
+// Reads manifest.json → generates navigation.md per category directory
+// NEVER hand-maintain navigation.md files
+```
+
+#### 3.5 Context Resolution Map (for AI Sessions)
+
+```typescript
+// Written by OpenCode plugin at session.created
+// Tells ContextScout which layer each file came from
+// .oac/context-resolution-map.json (git-ignored)
+{
+  "generatedAt": "2026-02-19T10:00:00Z",
+  "resolved": {
+    "core/standards/code-quality.md": {
+      "layer": 2,
+      "layerName": "project-context",
+      "path": ".opencode/context/core/standards/code-quality.md",
+      "userModified": false
+    }
+  }
+}
+```
+
+#### 3.6 CLI Commands
+
+```bash
+oac context install                     # Install from npm bundle (interactive)
+oac context install --profile standard  # Select profile
+oac context install --global            # Install to ~/.config/oac/context/
+oac context install --ide claude        # Install to .claude/context/
+oac context install --dry-run           # Preview
+
+oac context update                      # Update from npm bundle (interactive)
+oac context update --check              # Show what would change
+oac context update --yolo               # Auto-apply all updates
+
+oac context validate                    # Full validation report
+oac context validate --ci               # Exit 1 on failure (for CI)
+oac context validate --fix              # Auto-fix recoverable issues
+
+oac context list                        # List all context files
+oac context list --tree                 # As directory tree
+oac context resolve <ref>               # Show which layer wins
+oac context sources                     # Show all context source directories
+oac context override <ref>              # Copy to .oac/context/ for customization
+oac context add <source>                # Add external context (GitHub/local)
+oac context diff <ref>                  # Diff installed vs bundled version
+```
+
+#### 3.7 Context Profiles
+
+```json
+// In manifest.json
+{
+  "profiles": {
+    "essential": {
+      "files": ["core/standards/code-quality", "core/standards/documentation", "core/standards/test-coverage"]
+    },
+    "standard": {
+      "extends": "essential",
+      "files": ["core/workflows/task-delegation-basics", "core/workflows/code-review", "core/standards/security-patterns"]
+    },
+    "developer": {
+      "extends": "standard",
+      "files": ["development/principles/clean-code", "development/principles/api-design"]
+    }
+  }
+}
+```
+
+### Key Design Decisions
+
+- **Bundle into npm, not fetch at runtime** — deterministic, offline-capable
+- **Auto-generate manifest.json and navigation.md** — never hand-maintain SHA256s
+- **Resolution map written at session start** — ContextScout knows which layer each file came from
+- **Layer 1 (`.oac/context/`) is the escape hatch** — always wins, user-owned
+- **Layer 6 (npm bundle) is always present** — no install required for fallback
+
+### Validation Criteria
+
+- [ ] `oac context resolve core/standards/code-quality.md` shows correct layer
+- [ ] Layer 1 override wins over all other layers
+- [ ] `scripts/generate-manifest.ts` produces correct SHA256s
+- [ ] `scripts/generate-navigation.ts` produces valid navigation.md files
+- [ ] `oac context validate --ci` exits 1 on broken references
+- [ ] Resolution cache invalidates on file mtime change
+- [ ] Custom context provider loads from `config.providers.context`
+- [ ] Context resolution map written at session start
+
+---
+
+## Project 4: Agent & Skill Management
+
+**Purpose**: `agent.json` + `prompt.md` architecture, preset/customization system, skill packaging, multi-IDE format conversion, and `oac add/customize/presets/skill` commands.
+
+**Depends on**: P1 (core interfaces), P2 (CLI, config, lockfile)
+
+### What to Build
+
+#### 4.1 Agent Architecture
+
+**Source of truth**: `agent.json` (config) + `prompt.md` (prose) per agent directory.
+
+```
+.opencode/agents/
+├── core/
+│   ├── openagent/
+│   │   ├── agent.json      # Config, permissions, metadata
+│   │   └── prompt.md       # Prose content (what the AI reads)
+│   └── opencoder/
+│       ├── agent.json
+│       └── prompt.md
+└── subagents/
+    ├── contextscout/
+    │   ├── agent.json
+    │   └── prompt.md
+    └── ...
+```
+
+**`agent.json` schema** (from `@nextsystems/oac-core`):
+```json
+{
+  "name": "openagent",
+  "displayName": "OpenAgent",
+  "version": "1.0.0",
+  "description": "Universal orchestrator for complex tasks",
+  "mode": "primary",
+  "temperature": 0.1,
+  "permission": [
+    { "bash": { "*": "deny", "git status*": "allow" } },
+    { "edit": { "**/*.env*": "deny" } }
+  ],
+  "skills": ["task-management", "context-manager"],
+  "oac": {
+    "source": "bundled",
+    "tags": ["universal", "orchestration"],
+    "category": "core"
+  }
+}
+```
+
+**IDE format generation** (from `agent.json` + `prompt.md`):
+- OpenCode: generates YAML frontmatter + prompt body → `.opencode/agent/core/openagent.md`
+- Claude Code: generates Claude-compatible frontmatter → `.claude/agents/openagent.md`
+- Cursor: merges all agents into `.cursorrules` (router pattern)
+- Windsurf: generates `.windsurf/agents/openagent.json`
+
+#### 4.2 Preset / Customization System
+
+```
+~/.config/oac/presets/          # User's personal presets (global)
+├── agents/
+│   ├── my-openagent.md         # Preset file with CUSTOMIZATION markers
+│   └── strict-reviewer.md
+└── .presets.json               # Index of presets
+
+.oac/presets/                   # Team presets (committed to git)
+├── team-lead.json
+└── solo-dev.json
+```
+
+**Preset file format** (merge-safe):
+```markdown
+---
+preset:
+  name: my-openagent
+  base: agent:openagent
+  baseVersion: 1.0.0
+  updateStrategy: manual
+---
+
+<!-- CUSTOMIZATION: Approval Gates -->
+Auto-approve read operations (glob, read, grep)
+<!-- END CUSTOMIZATION -->
+
+[Rest of base agent prompt unchanged]
+```
+
+**Preset commands**:
+```bash
+oac customize agent:openagent           # Create preset (wizard)
+oac use preset:my-openagent             # Activate for project
+oac use preset:my-openagent --global    # Activate globally
+oac presets list                        # List all presets
+oac presets list --active               # Show active presets
+oac import preset ./team-preset.md      # Import team preset
+oac export preset:my-openagent          # Export for sharing
+```
+
+#### 4.3 Skill Packaging
+
+**Skill structure** (standardized):
+```
+.opencode/skills/{skill-name}/
+├── SKILL.md          # REQUIRED: frontmatter + instructions
+├── router.sh         # OPTIONAL: CLI entry point
+├── scripts/
+│   └── *.js          # COMPILED (not .ts) — eliminates ts-node dependency
+└── config/
+    └── *.json
+```
+
+**Critical**: All TypeScript scripts compiled to JS as part of package build. `task-cli.ts` → `task-cli.js`. No ts-node at runtime.
+
+**Skill commands**:
+```bash
+oac skill install task-management       # Install from OAC registry
+oac skill install task-management@1.0.0 # Specific version
+oac skill install --all                 # Install all bundled skills
+oac skill list                          # List installed skills
+oac skill update                        # Update all skills
+oac skill remove task-management        # Remove skill
+oac skill validate                      # Validate all skills
+oac skill doctor                        # Health check (router.sh, scripts exist, etc.)
+```
+
+#### 4.4 context-manager Skill Implementation
+
+**Critical gap**: `context-manager/router.sh` is currently a stub. Must implement:
+
+```
+.opencode/skills/context-manager/
+├── SKILL.md
+├── router.sh           # Routes to scripts below
+└── scripts/
+    ├── discover.js     # Glob-based context file discovery
+    ├── fetch.js        # Calls ExternalScout / Context7 API
+    ├── harvest.js      # Parses source doc, creates permanent context
+    ├── extract.js      # Targeted extraction from context files
+    ├── compress.js     # Summary/truncation of large files
+    ├── organize.js     # File reorganization by concern
+    ├── cleanup.js      # Removes stale .tmp/ files
+    └── process.js      # Orchestrates multi-step guided workflows
+```
+
+#### 4.5 Task CLI Compilation
+
+```bash
+# Build step: compile task-cli.ts → task-cli.js
+# Included in npm package files
+# oac doctor checks for task-cli.js presence
+```
+
+**`oac task` commands** (wrapping compiled task-cli.js):
+```bash
+oac task status [feature]               # Show task status
+oac task next [feature]                 # Show next eligible tasks
+oac task complete <feature> <seq> "msg" # Mark complete
+oac task validate [feature]             # Validate JSON files
+oac task plan [feature] --visualize     # Show execution plan
+```
+
+**`oac session` commands**:
+```bash
+oac session list                        # List active sessions
+oac session resume {session-id}         # Resume a session
+oac session cleanup {session-id}        # Remove session files
+oac session archive {session-id}        # Archive to .tmp/archive/
+```
+
+### Validation Criteria
+
+- [ ] `agent.json` + `prompt.md` generates valid OpenCode frontmatter
+- [ ] `agent.json` + `prompt.md` generates valid Claude Code format
+- [ ] `agent.json` + `prompt.md` generates valid `.cursorrules` router
+- [ ] Preset `<!-- CUSTOMIZATION: -->` markers survive agent updates
+- [ ] `task-cli.js` compiled and included in npm package
+- [ ] `context-manager/router.sh` routes to real implementations (not stub)
+- [ ] All skill scripts are `.js` (no `.ts` at runtime)
+- [ ] Custom task management provider loads from `config.providers.taskManagement`
+- [ ] Team presets in `.oac/presets/` override global presets
+
+---
+
+## Project 5: Plugin System
+
+**Purpose**: OpenCode TypeScript plugin (primary), Claude Code plugin rewrite, Cursor/Windsurf adapters, and `oac plugin *` commands.
+
+**Depends on**: P1 (core interfaces), P2 (CLI), P4 (agent/skill management)
+
+### What to Build
+
+#### 5.1 OpenCode TypeScript Plugin (Primary — New)
+
+```typescript
+// .opencode/plugin/oac.ts (installed by oac plugin install opencode)
+import type { Plugin } from "@opencode-ai/plugin";
+
+export const OACPlugin: Plugin = async ({ project, client, $, directory }) => {
+  const config = await loadOACConfig(directory);
+  const manifest = await loadInstalledManifest(directory);
+  const skillMap = await buildSkillMap(directory);
+
+  return {
+    // Register OAC agents
+    config: async (currentConfig) => ({
+      ...currentConfig,
+      agents: [...(currentConfig.agents || []), ...await loadOACAgents(directory)]
+    }),
+
+    // Skills as tools + tool.execute.before hooks
+    tool: createSkillTools(skillMap),
+
+    // Session start: inject workflow + check updates
+    "session.created": async ({ event }) => {
+      // 1. Write context resolution map
+      await writeContextResolutionMap(directory);
+      
+      // 2. Inject using-oac workflow (non-blocking)
+      const workflow = skillMap.get('using-oac')?.content;
+      if (workflow) {
+        await client.session.prompt({
+          path: { id: event.id },
+          body: { noReply: true, parts: [{ type: "text", text: workflow }] }
+        });
+      }
+      
+      // 3. Check for updates (throttled: once per 24h, non-blocking)
+      checkForUpdates(directory, client, event.id, config).catch(() => {});
+    },
+
+    // Skill invocation via tool hooks
+    "tool.execute.before": async (input, output) => {
+      if (input.tool.startsWith("oac_skill_")) {
+        const skill = skillMap.get(input.tool);
+        if (skill) {
+          await client.session.prompt({
+            path: { id: input.sessionID },
+            body: { noReply: true, parts: [{ type: "text", text: skill.content }] }
+          });
+        }
+      }
+    },
+
+    // Background cleanup on session idle
+    "session.idle": async ({ event }) => {
+      if (config.cleanup?.autoPrompt) {
+        await cleanupOldTempFiles(directory, config.cleanup);
+      }
+    },
+  };
+};
+```
+
+**Auto-update via `session.created`**:
+- Throttled: check once per 24 hours max
+- Non-blocking: never delays session start
+- Notification via `client.tui.showToast()`
+- If `autoUpdate: "safe"`: silently update non-modified files
+- If `autoUpdate: false` (default): show toast with `oac update` hint
+
+#### 5.2 Claude Code Plugin Rewrite
+
+**Current**: `session-start.sh` (bash, fragile JSON escaping)  
+**Target**: `session-start.js` (compiled TypeScript, proper JSON.stringify)
+
+```typescript
+// plugins/claude-code/hooks/session-start.ts → compiled to session-start.js
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+const skillPath = join(__dirname, '../skills/using-oac/SKILL.md');
+const skillContent = readFileSync(skillPath, 'utf-8');
+
+const output = {
+  additionalContext: skillContent,
+  hookSpecificOutput: {
+    type: 'session-start',
+    message: '🤖 OAC Active — 6-stage workflow enabled'
+  }
+};
+
+process.stdout.write(JSON.stringify(output));
+```
+
+#### 5.3 Cursor Adapter (Router Pattern)
+
+```typescript
+// Generates .cursorrules from all installed agents
+// Router pattern: single file, all agents merged with section headers
+// 100KB limit enforced with warnings
+export class CursorPluginAdapter {
+  async generate(agents: OACAgent[], contexts: ContextFile[]): Promise<string> {
+    // Sort: core agents first, then specialists
+    // Embed essential context inline
+    // Warn if > 80KB
+    // Error if > 100KB
+  }
+}
+```
+
+#### 5.4 Plugin Commands
+
+```bash
+oac plugin install opencode             # Install OpenCode TypeScript plugin
+oac plugin install claude               # Install Claude Code plugin
+oac plugin install cursor               # Generate .cursorrules
+oac plugin install windsurf             # Install Windsurf config
+oac plugin install --all                # Install for all configured IDEs
+
+oac plugin update opencode              # Update plugin
+oac plugin update --all                 # Update all plugins
+oac plugin update --check               # Check only
+
+oac plugin remove opencode              # Remove plugin
+oac plugin list                         # List installed plugins
+oac plugin status                       # Health check
+oac plugin configure opencode           # Configure plugin settings
+
+oac plugin create <name>                # Scaffold new plugin
+oac plugin test <name>                  # Test plugin
+oac plugin publish <path>               # Publish to community
+```
+
+#### 5.5 Third-Party Plugin Support
+
+```typescript
+// oac.json — plugin manifest for community plugins
+{
+  "name": "oac-plugin-security-agents",
+  "version": "1.0.0",
+  "type": "plugin",
+  "provides": ["agents", "skills", "context"],
+  "ides": ["opencode", "claude"],
+  "registry": "./registry.json"
+}
+```
+
+```bash
+# Install community plugin
+oac plugin add oac-plugin-security-agents
+oac plugin add https://github.com/user/my-oac-plugin
+```
+
+### Validation Criteria
+
+- [ ] OpenCode plugin installs to `.opencode/plugin/oac.ts`
+- [ ] `session.created` fires and injects workflow within 5 seconds
+- [ ] Update check throttled to once per 24 hours
+- [ ] `session.created` never crashes (silent failure on errors)
+- [ ] Claude Code `session-start.js` uses `JSON.stringify` (not manual escaping)
+- [ ] Cursor `.cursorrules` warns at 80KB, errors at 100KB
+- [ ] Custom IDE adapters load from `config.providers.ideAdapters`
+- [ ] `oac plugin status` shows health for all installed plugins
+
+---
+
+## Project 6: Registry & Community
+
+**Purpose**: shadcn-inspired registry, `oac.lock` lockfile, community publishing, security scanning, and `oac publish/browse/search/registry` commands.
+
+**Depends on**: P1 (core interfaces), P2 (CLI, lockfile)
+
+### What to Build
+
+#### 6.1 Registry Client
+
+```typescript
+// src/registry/client.ts
+export class RegistryClient {
+  constructor(private providers: IRegistryProvider[]) {}
+
+  // Multi-registry resolution: highest priority wins
+  async fetch(name: string, type: ComponentType): Promise<RegistryItem> {
+    for (const provider of this.providers) {
+      try {
+        return await provider.fetch(name, type);
+      } catch { continue; }
+    }
+    throw new Error(`Component not found: ${type}:${name}`);
+  }
+
+  async search(query: string, options?: RegistrySearchOptions): Promise<RegistryItem[]> {
+    // Search all registries, deduplicate by name+type, sort by priority
+    const results = await Promise.allSettled(
+      this.providers.map(p => p.search(query, options))
+    );
+    return deduplicateAndSort(results);
+  }
+}
+```
+
+#### 6.2 Registry Format (shadcn-inspired)
+
+**Registry index** (`registry.json`):
+```json
+{
+  "$schema": "https://registry.nextsystems.dev/oac/schema/registry.json",
+  "version": "3.0.0",
+  "items": [
+    {
+      "name": "openagent",
+      "type": "oac:agent",
+      "title": "OpenAgent",
+      "description": "Universal orchestrator",
+      "version": "1.0.0",
+      "ides": ["opencode", "claude", "cursor", "windsurf"],
+      "registryDependencies": ["contextscout", "task-manager"],
+      "files": [
+        {
+          "path": "agents/core/openagent/agent.json",
+          "type": "oac:agent-config",
+          "target": ".opencode/agents/core/openagent/agent.json"
+        },
+        {
+          "path": "agents/core/openagent/prompt.md",
+          "type": "oac:agent-prompt",
+          "target": ".opencode/agents/core/openagent/prompt.md"
+        }
+      ]
+    }
+  ]
+}
+```
+
+#### 6.3 Multi-Registry Support
+
+```json
+// config.json
+{
+  "registries": [
+    { "name": "private", "url": "https://registry.company.com/oac", "priority": 1, "authToken": "${OAC_PRIVATE_TOKEN}" },
+    { "name": "official", "url": "https://registry.nextsystems.dev/oac", "priority": 2 }
+  ]
+}
+```
+
+Resolution: highest priority registry wins. `oac add agent:openagent --registry official` to override.
+
+#### 6.4 Community Publishing
+
+```bash
+oac publish ./my-agent/                 # Publish to community registry
+# Flow:
+# 1. Validate oac.json schema
+# 2. Run security scan (secrets detection, malware check)
+# 3. Compute SHA256 for all files
+# 4. Submit PR to community registry repo
+# 5. CI runs security scan
+# 6. Maintainer reviews and merges
+
+oac publish ./my-agent/ --private       # Publish to private registry
+```
+
+#### 6.5 Security Scanning
+
+```typescript
+// src/security/scanner.ts
+export class SecurityScanner {
+  async scan(files: string[]): Promise<ScanResult> {
+    return {
+      secrets: await this.detectSecrets(files),    // gitleaks patterns
+      malware: await this.scanMalware(files),       // basic pattern matching
+      permissions: await this.analyzePermissions(files),  // permission audit
+      externalCalls: await this.findExternalCalls(files), // network calls
+    };
+  }
+}
+```
+
+#### 6.6 Browse TUI
+
+```typescript
+// src/commands/browse.ts — interactive TUI using @inquirer/prompts
+// Categories → Components → Preview → Install
+// Arrow keys to navigate, Space to select, Enter to preview, 'i' to install
+```
+
+#### 6.7 Registry Commands
+
+```bash
+oac browse [type]                       # Interactive TUI browser
+oac search <query>                      # Search all registries
+oac show agent:openagent                # Show component details
+oac verify agent:openagent              # Verify SHA256 + signature
+
+oac registry list                       # List configured registries
+oac registry add <url> [--name <name>]  # Add registry
+oac registry remove <name>              # Remove registry
+oac registry ping                       # Check all registries reachable
+oac registry sync                       # Sync local cache
+
+oac publish <path>                      # Publish to community
+oac publish <path> --registry private   # Publish to private registry
+```
+
+### Validation Criteria
+
+- [ ] Multi-registry resolution: private registry wins over official
+- [ ] `oac search` works across all configured registries
+- [ ] SHA256 verification on every download
+- [ ] Security scan runs before `oac publish`
+- [ ] `oac browse` TUI navigable with arrow keys
+- [ ] Private registry supports auth token via env var
+- [ ] Custom registry provider loads from `config.providers.registry`
+- [ ] `oac.lock` updated after every registry operation
+
+---
+
+## Cross-Project: How Users Swap Subsystems
+
+This is the key extensibility story. Users configure custom providers in `.oac/config.json`:
+
+```json
+{
+  "providers": {
+    "context": "@my-company/oac-notion-context",
+    "taskManagement": "@my-company/oac-linear-provider",
+    "registry": "https://registry.internal.company.com/oac",
+    "ideAdapters": ["@my-company/oac-jetbrains-adapter"]
+  }
+}
+```
+
+**Custom context provider** (replaces ContextScout + 6-layer resolution):
+```typescript
+// @my-company/oac-notion-context
+import type { IContextProvider } from '@nextsystems/oac-core';
+
+export default class NotionContextProvider implements IContextProvider {
+  readonly id = 'notion';
+  readonly displayName = 'Notion Context Provider';
+  // Fetches context from Notion database instead of filesystem
+}
+```
+
+**Custom task management provider** (replaces TaskManager/BatchExecutor):
+```typescript
+// @my-company/oac-linear-provider
+import type { ITaskManagementProvider } from '@nextsystems/oac-core';
+
+export default class LinearTaskProvider implements ITaskManagementProvider {
+  readonly id = 'linear';
+  readonly displayName = 'Linear Issue Tracker';
+  // Creates/reads tasks from Linear API instead of .tmp/tasks/ JSON files
+}
+```
+
+**Custom IDE adapter** (adds JetBrains support):
+```typescript
+// @my-company/oac-jetbrains-adapter
+import type { IIDEAdapter } from '@nextsystems/oac-core';
+
+export default class JetBrainsAdapter implements IIDEAdapter {
+  readonly id = 'jetbrains';
+  readonly displayName = 'JetBrains AI Assistant';
+  // Converts OAC agents to JetBrains AI Assistant format
+}
+```
+
+---
+
+## Implementation Order & Dependencies
+
+```
+Week 1-2:   P1 (core interfaces) — MUST BE FIRST
+Week 3-4:   P2 (CLI foundation) — MUST BE SECOND
+Week 5-6:   P3 + P4 in parallel (context system + agent/skill management)
+Week 7:     P5 (plugin system) — needs P4 complete
+Week 8-9:   P6 (registry + community) — can start after P2
+```
+
+```
+P1 ──► P2 ──► P3 (parallel)
+              P4 (parallel) ──► P5
+              P6 (parallel)
+```
+
+---
+
+## What Each Project Needs From the Existing Codebase
+
+| Project | Reuse | Rewrite | New |
+|---------|-------|---------|-----|
+| P1 (core) | Types from compatibility-layer | Unify schemas | Provider interfaces |
+| P2 (CLI) | `bin/oac.js` entry point | Full CLI (91 lines → full commander) | Config, lockfile, approval, backup |
+| P3 (context) | `.opencode/context/` files | Context resolution (currently ContextScout only) | Manifest auto-gen, navigation auto-gen |
+| P4 (agents/skills) | All `.opencode/agent/` files, skills | task-cli.ts → .js, context-manager stub | agent.json+prompt.md split, preset system |
+| P5 (plugins) | Claude Code plugin structure | session-start.sh → .js | OpenCode TS plugin (new) |
+| P6 (registry) | `registry.json` structure, validate-registry.ts | Registry format (v2→v3) | Multi-registry, community publishing, TUI |
+
+---
+
+## Success Criteria (All Projects)
+
+- [ ] `npx @nextsystems/oac init developer` completes in < 2 minutes
+- [ ] `oac --version` responds in < 50ms
+- [ ] Custom context provider replaces ContextScout with zero CLI changes
+- [ ] Custom task management provider replaces TaskManager with zero CLI changes
+- [ ] Private registry works with auth token
+- [ ] `oac doctor` catches all known failure modes
+- [ ] All content files survive `npm update` without overwriting user customizations
+- [ ] OpenCode auto-updates on session start (non-blocking)
+- [ ] Zero bash script dependency for any core functionality
+- [ ] 80%+ test coverage on all packages
+- [ ] `oac.lock` enables reproducible installs across machines

+ 1335 - 0
docs/planning/14-PROVIDER-PATTERN-FINAL.md

@@ -0,0 +1,1335 @@
+# OAC Provider/Adapter Pattern — Final Recommendation
+
+**Document**: 14-PROVIDER-PATTERN-FINAL.md
+**Status**: FINAL — authoritative before implementation starts
+**Date**: 2026-02-19
+**Author**: Architecture Review
+**Drives**: Projects P1–P6 (all 6 projects)
+
+> This document is the final word on provider/adapter architecture. No deviation from these
+> patterns without a formal ADR. Implementation begins with these interfaces locked.
+
+---
+
+## 1. The Chosen Pattern
+
+**Decision: Option C — Hybrid. Separate typed interfaces per subsystem sharing a common `OACPlugin` composition type.**
+
+### Evaluation Matrix
+
+| Criterion | Option A (Vite Monolith) | Option B (Separate Interfaces) | Option C (Hybrid) |
+|-----------|--------------------------|-------------------------------|-------------------|
+| Simplicity for community authors | Medium — one big object, most hooks irrelevant | High — implement only your subsystem | **High** — each interface is small and focused |
+| TypeScript inference | Poor — optional methods on monolith collapse to `undefined` everywhere | **Excellent** — each interface fully typed | **Excellent** — each interface fully typed |
+| OpenCode compatibility | Neutral | Neutral | **Best** — `OACPlugin` maps cleanly to OpenCode's plugin type |
+| Composability | Poor — can't mix providers | Medium — wire manually | **Best** — `defineConfig()` composes cleanly |
+| Testability | Poor — mock entire monolith | **Excellent** — mock one interface | **Excellent** — mock one interface |
+| Fit with existing BaseAdapter | Poor — BaseAdapter is a class, not a hook object | Good — direct mapping | **Best** — IIDEAdapter extends the same contract |
+| Plugin author DX | Poor — "which hook do I implement?" | Good | **Best** — `implements IContextProvider` is unambiguous |
+
+### Rationale
+
+Option A (Vite monolith) is rejected because OAC's subsystems have fundamentally **different dispatch semantics**:
+- Context resolution is **first-match-wins** (one provider answers)
+- IDE adapters are **fan-out** (all adapters write in parallel)
+- Registry lookup is **priority-ordered fallthrough**
+
+These cannot coexist correctly in a single optional-hook object without obscuring the semantics behind comments. A `NotionContextProvider` author does not need to know about IDE adapter hooks, and giving them an object with 25 optional methods is hostile.
+
+Option B (pure separation) is good but loses the composition story. Users need one place to hand OAC their full configuration without assembling a `ProviderRegistry` manually.
+
+Option C gives the best of both:
+- Each interface is **small, focused, and semantically unambiguous**
+- `OACPlugin` is the **user-facing composition type** — what goes in `oac.config.ts`
+- `defineConfig()` provides the helper that validates and assembles everything
+- The `ProviderRegistry` (internal to the CLI) wires dispatch semantics
+
+**The Vite-style hooks apply at the `ProviderRegistry` dispatch level, not at the interface level.** The registry implements `callFirst()` and `callAll()` dispatch internally. Plugin authors just implement `IContextProvider`, not "hooks".
+
+---
+
+## 2. Final TypeScript Interfaces
+
+These are authoritative. They go verbatim into `packages/core/src/`.
+
+### 2.1 Supporting Types (`packages/core/src/types/index.ts`)
+
+```typescript
+// ============================================================================
+// Primitive Types
+// ============================================================================
+
+export type ComponentType = 'agent' | 'skill' | 'context' | 'plugin';
+export type UpdateMode = 'manual' | 'auto-safe' | 'auto-all' | 'locked';
+export type ConflictStrategy = 'ask' | 'skip' | 'overwrite' | 'backup' | 'yolo';
+export type InstallLocation = 'local' | 'global';
+export type ContextLayerName =
+  | 'project-override'    // L1: .oac/context/
+  | 'project-context'     // L2: .opencode/context/
+  | 'ide-specific'        // L3: .claude/context/, .cursor/context/
+  | 'project-docs'        // L4: docs/context/
+  | 'user-global'         // L5: ~/.config/oac/context/
+  | 'oac-bundled';        // L6: npm package (lowest priority)
+
+// ============================================================================
+// Shared Result Types
+// ============================================================================
+
+export interface ValidationResult {
+  valid: boolean;
+  errors: string[];
+  warnings: string[];
+}
+
+export interface OACOperationResult<T = void> {
+  success: boolean;
+  data?: T;
+  errors: string[];
+  warnings: string[];
+}
+
+// ============================================================================
+// Context Types
+// ============================================================================
+
+export interface ContextFile {
+  /** Relative name used to resolve the file, e.g. "core/standards/code-quality.md" */
+  name: string;
+  content: string;
+  /** Absolute path on disk */
+  path: string;
+  layer: ContextLayerName;
+  /** True if the installed SHA256 differs from the bundled SHA256 */
+  userOwned: boolean;
+  sha256: string;
+}
+
+export interface ContextQuery {
+  category?: string;
+  layer?: ContextLayerName;
+  userOwned?: boolean;
+  tags?: string[];
+}
+
+// ============================================================================
+// Task Management Types
+// ============================================================================
+
+export type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'blocked' | 'skipped';
+export type TaskPriority = 'critical' | 'high' | 'medium' | 'low';
+
+export interface Task {
+  id: string;
+  title: string;
+  description?: string;
+  status: TaskStatus;
+  priority: TaskPriority;
+  dependencies: string[]; // task IDs
+  assignee?: string;
+  metadata?: Record<string, unknown>;
+}
+
+export interface TaskSession {
+  id: string;
+  feature: string;
+  createdAt: string; // ISO 8601
+  updatedAt: string;
+  tasks: Task[];
+  completedCount: number;
+  totalCount: number;
+}
+
+// ============================================================================
+// Registry Types
+// ============================================================================
+
+export interface RegistryFile {
+  /** Path within the registry item's source */
+  path: string;
+  type: string; // e.g. "oac:agent-config", "oac:agent-prompt", "oac:skill"
+  /** Install target relative to project root */
+  target: string;
+}
+
+export interface RegistryItem {
+  name: string;
+  type: ComponentType;
+  title: string;
+  description: string;
+  version: string;
+  ides: string[];
+  registryDependencies: string[];
+  files: RegistryFile[];
+  sha256?: string;
+  publishedAt?: string;
+  author?: string;
+  tags?: string[];
+}
+
+export interface RegistrySearchOptions {
+  type?: ComponentType;
+  ide?: string;
+  tags?: string[];
+  limit?: number;
+  offset?: number;
+}
+
+// ============================================================================
+// IDE Adapter Types
+// ============================================================================
+
+export interface IDECapabilities {
+  /** IDE identifier, e.g. "opencode", "cursor", "claude", "windsurf" */
+  id: string;
+  displayName: string;
+  supportsMultipleAgents: boolean;
+  supportsSkills: boolean;
+  supportsHooks: boolean;
+  supportsGranularPermissions: boolean;
+  supportsContexts: boolean;
+  supportsCustomModels: boolean;
+  supportsTemperature: boolean;
+  supportsMaxSteps: boolean;
+  configFormat: 'markdown' | 'yaml' | 'json' | 'plain';
+  outputStructure: 'single-file' | 'multi-file' | 'directory';
+  notes?: string[];
+}
+
+export interface IDEOutputFile {
+  /** Absolute path to write */
+  path: string;
+  content: string;
+  encoding?: 'utf-8' | 'base64';
+}
+
+export interface IDEAdapterResult {
+  success: boolean;
+  files: IDEOutputFile[];
+  warnings: string[];
+  errors: string[];
+}
+
+// ============================================================================
+// Agent Profile Types
+// ============================================================================
+
+export interface AgentProfile {
+  name: string;
+  displayName: string;
+  description: string;
+  /** Agent IDs included in this profile */
+  agents: string[];
+  /** Skill IDs included in this profile */
+  skills: string[];
+  /** Context profile name (from manifest.json profiles) */
+  contextProfile?: string;
+}
+
+// ============================================================================
+// OAC Agent (canonical internal representation)
+// ============================================================================
+
+/**
+ * OACAgent is the canonical internal representation of an agent.
+ * It is the type that flows between subsystems. Adapters convert
+ * to/from this type. It is NOT the same as OpenAgent (the legacy
+ * compatibility-layer type).
+ */
+export interface OACAgent {
+  /** From agent.json */
+  config: import('../schemas/agent.js').AgentConfig;
+  /** From prompt.md — the prose content */
+  promptMd: string;
+  /** From system.md — optional system prompt override */
+  systemMd?: string;
+  /** Resolved source path */
+  sourcePath: string;
+}
+
+// ============================================================================
+// OAC Context (resolved context file for IDE adapter consumption)
+// ============================================================================
+
+export type OACContext = ContextFile;
+```
+
+### 2.2 Provider Interfaces (`packages/core/src/providers/`)
+
+#### `context.ts`
+
+```typescript
+import type { ContextFile, ContextQuery, ValidationResult } from '../types/index.js';
+
+/**
+ * Provides context files to OAC's resolution pipeline.
+ *
+ * The default implementation is the 6-layer filesystem resolver.
+ * Replace with a Notion/Confluence/custom implementation by pointing
+ * config.providers.context at your package.
+ *
+ * Dispatch: callFirst() — first provider that returns non-null wins.
+ */
+export interface IContextProvider {
+  /** Unique stable identifier, e.g. "oac-default", "notion", "confluence" */
+  readonly id: string;
+  readonly displayName: string;
+
+  /**
+   * Resolve a single context file by name.
+   * Return null if this provider does not have the file.
+   */
+  resolve(name: string): Promise<ContextFile | null>;
+
+  /** List all context files this provider can serve. */
+  list(query?: ContextQuery): Promise<ContextFile[]>;
+
+  /**
+   * Install a context file.
+   * Called by `oac context install`.
+   */
+  install(name: string, source: string | Buffer): Promise<void>;
+
+  /**
+   * Update an existing context file if the installed version matches
+   * expectedSha256. Returns 'skipped' if user-modified, 'conflict' if
+   * the new content differs from expected.
+   */
+  update(
+    name: string,
+    newContent: string,
+    expectedSha256: string
+  ): Promise<'updated' | 'skipped' | 'conflict'>;
+
+  /**
+   * Return true if the installed file at `name` has been modified
+   * relative to `installedSha256`.
+   */
+  isModified(name: string, installedSha256: string): Promise<boolean>;
+
+  /** Full validation of a named context file. */
+  validate(name: string): Promise<ValidationResult>;
+}
+```
+
+#### `task-management.ts`
+
+```typescript
+import type { Task, TaskSession } from '../types/index.js';
+
+/**
+ * Manages task sessions for OAC's agent workflow system.
+ *
+ * The default implementation stores sessions as JSON in .tmp/tasks/.
+ * Replace with a Linear/Jira/GitHub Issues implementation.
+ *
+ * Dispatch: single provider — no fan-out.
+ */
+export interface ITaskManagementProvider {
+  readonly id: string;
+  readonly displayName: string;
+
+  /** Create a new task session with the given tasks. */
+  createSession(tasks: Omit<Task, 'id'>[], feature: string): Promise<TaskSession>;
+
+  /** Get the current active session, or null if none. */
+  getCurrentSession(): Promise<TaskSession | null>;
+
+  /**
+   * Get the next eligible task (no unmet dependencies, status=pending).
+   * Returns null when all tasks are complete.
+   */
+  getNextTask(sessionId: string): Promise<Task | null>;
+
+  /** Mark a task as completed. */
+  completeTask(sessionId: string, taskId: string): Promise<void>;
+
+  /** List all sessions (active and archived). */
+  listSessions(): Promise<TaskSession[]>;
+
+  /** Delete sessions older than the given number of days. Returns count deleted. */
+  cleanSessions(olderThanDays: number): Promise<number>;
+}
+```
+
+#### `registry.ts`
+
+```typescript
+import type { RegistryItem, RegistryFile, RegistrySearchOptions, ComponentType } from '../types/index.js';
+
+/**
+ * Provides access to a component registry.
+ *
+ * The default implementation talks to registry.nextsystems.dev.
+ * Replace with a private enterprise registry.
+ *
+ * Dispatch: callFirst() in priority order — highest-priority registry that
+ * has the component wins. All registries participate in search (merged).
+ */
+export interface IRegistryProvider {
+  readonly id: string;
+  readonly displayName: string;
+  /** Base URL of this registry, used for display and auth. */
+  readonly baseUrl: string;
+  /** Higher number = higher priority in multi-registry resolution. */
+  readonly priority: number;
+
+  /** Fetch metadata for a specific component. Throws if not found. */
+  fetch(name: string, type: ComponentType): Promise<RegistryItem>;
+
+  /** Search the registry. Returns empty array (not throws) if no results. */
+  search(query: string, options?: RegistrySearchOptions): Promise<RegistryItem[]>;
+
+  /**
+   * Download all files for a registry item.
+   * Returns array of { file, content } pairs ready to write to disk.
+   */
+  download(item: RegistryItem): Promise<Array<{ file: RegistryFile; content: string }>>;
+
+  /** Health check. Returns true if registry is reachable. */
+  ping(): Promise<boolean>;
+
+  /** Get the latest published version string for a component. */
+  getLatestVersion(name: string, type: ComponentType): Promise<string>;
+}
+```
+
+#### `ide-adapter.ts`
+
+```typescript
+import type { OACAgent, OACContext, IDEAdapterResult, IDECapabilities, ValidationResult } from '../types/index.js';
+
+/**
+ * Converts OAC agents to IDE-specific configuration formats.
+ *
+ * Built-in implementations: OpenCode, Claude Code, Cursor, Windsurf.
+ * Community extensions: JetBrains, Zed, etc.
+ *
+ * Dispatch: callAll() — ALL registered IDE adapters run in parallel.
+ * Each adapter writes its own output files.
+ */
+export interface IIDEAdapter {
+  /** Unique stable identifier, e.g. "opencode", "cursor", "claude", "windsurf" */
+  readonly id: string;
+  readonly displayName: string;
+
+  /**
+   * Convert OAC agents + context to this IDE's format.
+   * Returns file paths and content to write, plus warnings.
+   * MUST NOT write to disk — the caller writes the files.
+   */
+  fromOAC(agents: OACAgent[], context: OACContext[]): Promise<IDEAdapterResult>;
+
+  /**
+   * Parse this IDE's config format back to OAC agents.
+   * Used by `oac compat import`.
+   * `source` is the raw file content.
+   */
+  toOAC(source: string): Promise<OACAgent[]>;
+
+  /**
+   * Return the output directory/file path for this IDE.
+   * Relative to project root, e.g. ".opencode", ".cursorrules".
+   */
+  getOutputPath(): string;
+
+  /** Describe what this IDE supports. */
+  getCapabilities(): IDECapabilities;
+
+  /**
+   * Validate the result before writing. Called after fromOAC().
+   * Returns warnings about feature loss, size limits, etc.
+   */
+  validate(result: IDEAdapterResult): ValidationResult;
+}
+```
+
+#### `agent-profile.ts`
+
+```typescript
+import type { AgentProfile } from '../types/index.js';
+
+/**
+ * Provides agent profiles (developer, minimal, enterprise, etc.).
+ *
+ * The default implementation reads from the OAC npm package manifest.
+ * Enterprise users can point this at an internal profile registry.
+ *
+ * Dispatch: callFirst() — first provider that has the profile wins.
+ */
+export interface IAgentProfileProvider {
+  readonly id: string;
+  readonly displayName: string;
+
+  /** List all available profiles. */
+  list(): Promise<AgentProfile[]>;
+
+  /** Get a profile by name. Returns null if not found. */
+  get(name: string): Promise<AgentProfile | null>;
+
+  /** Check if a profile exists. */
+  has(name: string): Promise<boolean>;
+}
+```
+
+### 2.3 `OACPlugin` — User-Facing Composition Type (`packages/core/src/plugin.ts`)
+
+```typescript
+import type { IContextProvider } from './providers/context.js';
+import type { ITaskManagementProvider } from './providers/task-management.js';
+import type { IRegistryProvider } from './providers/registry.js';
+import type { IIDEAdapter } from './providers/ide-adapter.js';
+import type { IAgentProfileProvider } from './providers/agent-profile.js';
+
+/**
+ * OACPlugin is what a user (or enterprise author) exports from oac.config.ts.
+ *
+ * All fields are optional. OAC uses defaults for any field not provided.
+ *
+ * @example
+ * ```ts
+ * // oac.config.ts
+ * import { defineConfig } from '@nextsystems/oac-core';
+ * import { NotionContextProvider } from '@my-company/oac-notion-context';
+ * import { LinearTaskProvider } from '@my-company/oac-linear';
+ *
+ * export default defineConfig({
+ *   context: new NotionContextProvider({ token: process.env.NOTION_TOKEN! }),
+ *   taskManagement: new LinearTaskProvider({ apiKey: process.env.LINEAR_KEY! }),
+ *   ideAdapters: [process.env.CI && new CIOnlyAdapter()].filter(Boolean),
+ * });
+ * ```
+ */
+export interface OACPlugin {
+  /**
+   * Replace the default 6-layer filesystem context resolver.
+   * Provide ONE context provider. If multiple are needed, compose them
+   * inside a wrapper that implements IContextProvider.
+   */
+  context?: IContextProvider;
+
+  /**
+   * Replace the default JSON-file task management system.
+   */
+  taskManagement?: ITaskManagementProvider;
+
+  /**
+   * Additional registry providers, prepended before the official registry.
+   * The first registry in this array that finds a component wins.
+   * The official registry is always appended as the final fallback.
+   */
+  registries?: IRegistryProvider[];
+
+  /**
+   * Additional IDE adapters. These are run IN ADDITION TO built-in adapters
+   * unless you also set `replaceBuiltInAdapters: true`.
+   *
+   * Falsy values are filtered (enables: `process.env.CI && new CIAdapter()`).
+   */
+  ideAdapters?: Array<IIDEAdapter | false | null | undefined>;
+
+  /**
+   * If true, built-in IDE adapters (OpenCode, Claude, Cursor, Windsurf) are
+   * NOT registered. Your `ideAdapters` array is the complete set.
+   * Default: false.
+   */
+  replaceBuiltInAdapters?: boolean;
+
+  /**
+   * Additional agent profile providers, tried before the built-in manifest profiles.
+   */
+  profileProviders?: IAgentProfileProvider[];
+}
+```
+
+### 2.4 `defineConfig()` Helper (`packages/core/src/define-config.ts`)
+
+```typescript
+import type { OACPlugin } from './plugin.js';
+
+/**
+ * Type-safe configuration helper. Validates the shape of your plugin
+ * configuration at TypeScript compile time and provides IDE autocomplete.
+ *
+ * This is a pure identity function at runtime — it exists solely for
+ * TypeScript's benefit and to signal intent to readers.
+ *
+ * @example
+ * ```ts
+ * // oac.config.ts
+ * import { defineConfig } from '@nextsystems/oac-core';
+ *
+ * export default defineConfig({
+ *   context: new NotionContextProvider(),
+ * });
+ * ```
+ */
+export function defineConfig(plugin: OACPlugin): OACPlugin {
+  return plugin;
+}
+```
+
+### 2.5 `ProviderRegistry` — Internal Wiring (`packages/core/src/provider-registry.ts`)
+
+```typescript
+import type { IContextProvider } from './providers/context.js';
+import type { ITaskManagementProvider } from './providers/task-management.js';
+import type { IRegistryProvider } from './providers/registry.js';
+import type { IIDEAdapter } from './providers/ide-adapter.js';
+import type { IAgentProfileProvider } from './providers/agent-profile.js';
+import type { OACPlugin } from './plugin.js';
+
+export class ProviderRegistryError extends Error {
+  constructor(message: string) {
+    super(message);
+    this.name = 'ProviderRegistryError';
+  }
+}
+
+/**
+ * ProviderRegistry is the internal wiring layer used by the CLI.
+ * It is NOT a singleton. Each CLI invocation creates one via
+ * `createProviderRegistry(config, plugin)`.
+ *
+ * Dispatch semantics:
+ * - Context: callFirst() — first provider returning non-null wins
+ * - Task management: single provider
+ * - Registry: callFirst() in priority order, all participate in search
+ * - IDE adapters: callAll() — all run in parallel
+ * - Profile providers: callFirst() — first provider returning non-null wins
+ */
+export class ProviderRegistry {
+  private _context: IContextProvider;
+  private _taskManagement: ITaskManagementProvider;
+  private _registries: IRegistryProvider[];
+  private _ideAdapters: Map<string, IIDEAdapter>;
+  private _profileProviders: IAgentProfileProvider[];
+
+  // Use createProviderRegistry() — not this constructor directly
+  constructor(
+    context: IContextProvider,
+    taskManagement: ITaskManagementProvider,
+    registries: IRegistryProvider[],
+    ideAdapters: IIDEAdapter[],
+    profileProviders: IAgentProfileProvider[]
+  ) {
+    this._context = context;
+    this._taskManagement = taskManagement;
+    // Sort registries by priority descending
+    this._registries = [...registries].sort((a, b) => b.priority - a.priority);
+    this._ideAdapters = new Map(ideAdapters.map(a => [a.id, a]));
+    this._profileProviders = profileProviders;
+  }
+
+  // ── Context ──────────────────────────────────────────────────────────────
+
+  get context(): IContextProvider {
+    return this._context;
+  }
+
+  // ── Task Management ──────────────────────────────────────────────────────
+
+  get taskManagement(): ITaskManagementProvider {
+    return this._taskManagement;
+  }
+
+  // ── Registry ─────────────────────────────────────────────────────────────
+
+  get registries(): IRegistryProvider[] {
+    return this._registries;
+  }
+
+  getRegistry(id: string): IRegistryProvider | undefined {
+    return this._registries.find(r => r.id === id);
+  }
+
+  /**
+   * callFirst() for registry fetch/version lookup.
+   * Tries each registry in priority order, returns first success.
+   */
+  async resolveFromRegistry<T>(
+    fn: (registry: IRegistryProvider) => Promise<T>
+  ): Promise<T> {
+    const errors: Error[] = [];
+    for (const registry of this._registries) {
+      try {
+        return await fn(registry);
+      } catch (err) {
+        errors.push(err instanceof Error ? err : new Error(String(err)));
+      }
+    }
+    throw new ProviderRegistryError(
+      `No registry satisfied the request. Errors:\n${errors.map(e => `  - ${e.message}`).join('\n')}`
+    );
+  }
+
+  // ── IDE Adapters ─────────────────────────────────────────────────────────
+
+  getIDEAdapter(id: string): IIDEAdapter | undefined {
+    return this._ideAdapters.get(id);
+  }
+
+  get ideAdapters(): IIDEAdapter[] {
+    return Array.from(this._ideAdapters.values());
+  }
+
+  /**
+   * callAll() for IDE adapter output generation.
+   * Runs all adapters in parallel. Partial failures are collected,
+   * not thrown — the caller decides what to do with failed adapters.
+   */
+  async runAllAdapters(
+    fn: (adapter: IIDEAdapter) => Promise<void>
+  ): Promise<Map<string, Error | null>> {
+    const results = new Map<string, Error | null>();
+    await Promise.all(
+      Array.from(this._ideAdapters.entries()).map(async ([id, adapter]) => {
+        try {
+          await fn(adapter);
+          results.set(id, null);
+        } catch (err) {
+          results.set(id, err instanceof Error ? err : new Error(String(err)));
+        }
+      })
+    );
+    return results;
+  }
+
+  // ── Profile Providers ────────────────────────────────────────────────────
+
+  get profileProviders(): IAgentProfileProvider[] {
+    return this._profileProviders;
+  }
+
+  /**
+   * callFirst() for profile resolution.
+   */
+  async resolveProfile(name: string): Promise<import('./types/index.js').AgentProfile | null> {
+    for (const provider of this._profileProviders) {
+      const profile = await provider.get(name);
+      if (profile !== null) return profile;
+    }
+    return null;
+  }
+}
+
+/**
+ * Factory function — the ONLY way to create a ProviderRegistry.
+ * Never export `new ProviderRegistry()` or a module-level instance.
+ *
+ * The CLI calls this once per invocation after loading oac.config.ts.
+ * Tests call this with mock providers for isolation.
+ */
+export async function createProviderRegistry(
+  plugin: OACPlugin,
+  defaults: {
+    context: IContextProvider;
+    taskManagement: ITaskManagementProvider;
+    officialRegistry: IRegistryProvider;
+    builtInAdapters: IIDEAdapter[];
+    builtInProfileProvider: IAgentProfileProvider;
+  }
+): Promise<ProviderRegistry> {
+  const context = plugin.context ?? defaults.context;
+  const taskManagement = plugin.taskManagement ?? defaults.taskManagement;
+
+  const registries: IRegistryProvider[] = [
+    ...(plugin.registries ?? []),
+    defaults.officialRegistry,
+  ];
+
+  const ideAdapters: IIDEAdapter[] = plugin.replaceBuiltInAdapters
+    ? (plugin.ideAdapters?.filter(Boolean) as IIDEAdapter[] ?? [])
+    : [
+        ...defaults.builtInAdapters,
+        ...(plugin.ideAdapters?.filter(Boolean) as IIDEAdapter[] ?? []),
+      ];
+
+  const profileProviders: IAgentProfileProvider[] = [
+    ...(plugin.profileProviders ?? []),
+    defaults.builtInProfileProvider,
+  ];
+
+  return new ProviderRegistry(
+    context,
+    taskManagement,
+    registries,
+    ideAdapters,
+    profileProviders
+  );
+}
+```
+
+---
+
+## 3. How Existing Code Maps In
+
+### 3.1 AdapterRegistry → ProviderRegistry
+
+`AdapterRegistry` is kept in `packages/compatibility-layer/` for backward compatibility with the 236 existing tests. It is **not** moved — its role is narrower (IDE adapter storage). `ProviderRegistry` is the new top-level wiring for all subsystems.
+
+```
+AdapterRegistry (existing)         ProviderRegistry (new)
+──────────────────────────         ───────────────────────
+register(adapter, aliases)    →    constructor(ideAdapters: IIDEAdapter[])
+get(nameOrAlias)              →    getIDEAdapter(id)
+getAll()                      →    ideAdapters getter
+findByFeature(feature)        →    (move to IDE-specific query utilities)
+registerBuiltInAdapters()     →    defaults.builtInAdapters in createProviderRegistry()
+export const registry = ...   →    DELETED (see §3.3)
+```
+
+`AdapterRegistry.registerBuiltInAdapters()` becomes a function in `packages/cli/src/defaults.ts`:
+
+```typescript
+// packages/cli/src/defaults.ts
+export async function loadBuiltInAdapters(): Promise<IIDEAdapter[]> {
+  const adapters: IIDEAdapter[] = [];
+  const modules = [
+    ['opencode', () => import('./adapters/opencode.js')],
+    ['claude',   () => import('./adapters/claude.js')],
+    ['cursor',   () => import('./adapters/cursor.js')],
+    ['windsurf', () => import('./adapters/windsurf.js')],
+  ] as const;
+
+  for (const [id, loader] of modules) {
+    try {
+      const mod = await loader();
+      adapters.push(mod.default);
+    } catch {
+      // Adapter not available in this build — skip silently
+    }
+  }
+  return adapters;
+}
+```
+
+### 3.2 BaseAdapter → IIDEAdapter
+
+`BaseAdapter` maps to `IIDEAdapter` as follows:
+
+| BaseAdapter | IIDEAdapter | Notes |
+|-------------|-------------|-------|
+| `abstract name: string` | `readonly id: string` | Renamed for clarity |
+| `abstract displayName: string` | `readonly displayName: string` | Same |
+| `abstract toOAC(source: string): Promise<OpenAgent>` | `toOAC(source: string): Promise<OACAgent[]>` | Now returns array (multi-agent IDEs) |
+| `abstract fromOAC(agent: OpenAgent): Promise<ConversionResult>` | `fromOAC(agents: OACAgent[], context: OACContext[]): Promise<IDEAdapterResult>` | Takes all agents + context |
+| `abstract getConfigPath(agent?)` | `getOutputPath(): string` | Simplified — path is static per IDE |
+| `abstract getCapabilities(): ToolCapabilities` | `getCapabilities(): IDECapabilities` | `ToolCapabilities` renamed `IDECapabilities` |
+| `abstract validateConversion(agent)` | `validate(result: IDEAdapterResult): ValidationResult` | Validates output, not input |
+
+**Migration approach**: existing `ClaudeAdapter`, `CursorAdapter`, `WindsurfAdapter` stay in `packages/compatibility-layer/` and continue extending `BaseAdapter`. In Project 5, new adapter implementations in `packages/cli/src/adapters/` implement `IIDEAdapter` directly. Both patterns coexist during the transition.
+
+### 3.3 Singleton Fix (Critical — Blocks Test Isolation)
+
+**Before** (`packages/compatibility-layer/src/core/AdapterRegistry.ts:358`):
+```typescript
+// BUG: Module-level singleton — shared state bleeds between tests
+export const registry = new AdapterRegistry();
+```
+
+**After**:
+```typescript
+// DELETED — do not export a module-level instance
+
+// Keep the class and export it:
+export { AdapterRegistry } from './AdapterRegistry.js';
+
+// The CLI creates its own instance:
+// const reg = new AdapterRegistry();
+// await reg.registerBuiltInAdapters();
+```
+
+**For the CLI** (`packages/cli/src/index.ts`):
+```typescript
+// One instance per CLI invocation — created in the command handler, not at module load
+async function runCommand(args: string[]): Promise<void> {
+  const config = await loadOACConfig();
+  const plugin = await loadUserPlugin(config);
+  const registry = await createProviderRegistry(plugin, await loadDefaults(config));
+  // pass `registry` into command handlers
+}
+```
+
+**For the compatibility-layer tests** (backward-compatible fix, no test changes):
+
+In test setup files, replace:
+```typescript
+import { registry } from '../core/AdapterRegistry.js';
+// registry is the same singleton for all tests — BAD
+```
+with:
+```typescript
+import { AdapterRegistry } from '../core/AdapterRegistry.js';
+const registry = new AdapterRegistry(); // fresh instance per test
+```
+
+If the tests import from the old path, add a `beforeEach` reset:
+```typescript
+import { registry } from '../core/AdapterRegistry.js';
+beforeEach(() => registry.clear()); // temporary mitigation
+```
+
+This is the minimal fix that doesn't break the 236 tests while the full migration proceeds.
+
+### 3.4 AgentLoader Module Globals Fix
+
+**Before** (`packages/compatibility-layer/src/core/AgentLoader.ts:169`):
+```typescript
+// BUG: Module globals — bleed between tests, never invalidated
+let cachedMetadata: Record<string, Partial<OpenAgent["metadata"]>> = {};
+let metadataLoaded = false;
+```
+
+**After** — move cache into the class instance:
+```typescript
+export class AgentLoader {
+  private projectRoot?: string;
+  // Cache lives on the instance, not the module
+  private cachedMetadata: Record<string, Partial<OpenAgent["metadata"]>> | null = null;
+
+  constructor(projectRoot?: string) {
+    this.projectRoot = projectRoot;
+  }
+
+  private loadMetadataFile(): Record<string, Partial<OpenAgent["metadata"]>> {
+    if (this.cachedMetadata !== null) {
+      return this.cachedMetadata;
+    }
+    // ... same file loading logic ...
+    this.cachedMetadata = parsed.agents || {};
+    return this.cachedMetadata;
+  }
+}
+```
+
+Tests that need a fresh metadata load: `new AgentLoader(testRoot)` — the fresh instance has no cache. No test changes required.
+
+### 3.5 Types From `types.ts`: Keep / Fix / Replace
+
+| Type | Action | Reason |
+|------|--------|--------|
+| `ToolAccessSchema` | **Keep** — move to core | Still valid |
+| `PermissionRuleSchema` | **Keep** — move to core | Still valid |
+| `GranularPermissionSchema` | **Keep** — move to core | Still valid |
+| `ContextPrioritySchema` | **Keep** — move to core | Still valid |
+| `ModelIdentifierSchema` | **Fix** — `z.union([z.string(), z.string()])` → `z.string()` | Union of identical types is a bug |
+| `TemperatureSchema` | **Fix** — add `.min(0).max(2)` | Unconstrained allows nonsense values |
+| `AgentMetadataSchema` | **Fix** — make consistent with `OpenAgentSchema.metadata` (all optional or all required — pick one) | Strict vs loose mismatch causes validation failures |
+| `OpenAgentSchema.metadata` | **Fix** — align with `AgentMetadataSchema` | One or the other must be the canonical shape |
+| `ToolCapabilities` | **Rename** → `IDECapabilities` in core | More precise name, same fields |
+| `ConversionResult` | **Replace** → `IDEAdapterResult` in core | Richer type (files vs configs, better error model) |
+| `ToolConfig` | **Keep in compat-layer** — used by existing adapters | Not needed in core |
+| `AgentFrontmatterSchema` | **Keep** — move to core | Canonical schema |
+| `OpenAgentSchema` | **Keep** — move to core, fix metadata inconsistency | Canonical |
+
+**Schema fix — ModelIdentifierSchema**:
+```typescript
+// Before (bug):
+export const ModelIdentifierSchema = z.union([z.string(), z.string()]);
+
+// After:
+export const ModelIdentifierSchema = z.string()
+  .min(1)
+  .describe('Model identifier, e.g. "claude-opus-4-5", "gpt-4o", "gemini-2.0-flash"');
+```
+
+**Schema fix — TemperatureSchema**:
+```typescript
+// Before (unconstrained):
+export const TemperatureSchema = z.number();
+
+// After:
+export const TemperatureSchema = z.number()
+  .min(0)
+  .max(2)
+  .describe('Model temperature (0.0–2.0). Most IDEs cap at 1.0.');
+```
+
+**Schema fix — AgentMetadata strict/OpenAgent metadata loose**:
+```typescript
+// Root cause: AgentMetadataSchema requires category/type/author
+// but OpenAgentSchema.metadata makes them all optional.
+// Decision: OpenAgentSchema.metadata IS AgentMetadataSchema (all required except tags/deps)
+
+export const OpenAgentSchema = z.object({
+  frontmatter: AgentFrontmatterSchema,
+  metadata: AgentMetadataSchema,   // Use the strict schema — it's the canonical shape
+  systemPrompt: z.string(),
+  contexts: z.array(ContextReferenceSchema).default([]),
+  sections: z.object({ ... }).optional(),
+});
+```
+
+---
+
+## 4. Configuration Design
+
+### 4.1 Format Decision: `oac.config.ts` (TypeScript)
+
+**Decision: `oac.config.ts`, not `oac.config.json`.**
+
+Rationale:
+1. Providers are class instances — they cannot be expressed in JSON
+2. Environment variable interpolation is native in TypeScript (`process.env.NOTION_TOKEN!`)
+3. Conditional providers work naturally: `process.env.CI && ciAdapter()`
+4. TypeScript gives compile-time validation of the config shape
+5. `defineConfig()` provides full IDE autocomplete
+
+JSON config is used for **data** (preferences, registries list, IDE paths). TypeScript is used for **behavior** (provider wiring).
+
+The two files coexist:
+- `.oac/config.json` — committed to git, data-only, no secrets
+- `oac.config.ts` — committed to git, provider wiring, imports from npm packages
+- `~/.config/oac/config.json` — user-global preferences (not committed)
+
+### 4.2 Config Loading Pipeline
+
+```typescript
+// packages/cli/src/config/loader.ts
+
+export async function loadFullConfig(cwd: string): Promise<{
+  data: OACConfig;
+  plugin: OACPlugin;
+}> {
+  // Step 1: Load data config (JSON, three-way merge)
+  const defaults = getConfigDefaults();
+  const globalData = await loadConfigJson('~/.config/oac/config.json');
+  const projectData = await loadConfigJson(join(cwd, '.oac/config.json'));
+  const envOverrides = readEnvOverrides();
+
+  const data = OACConfigSchema.parse(
+    deepMerge(defaults, globalData, projectData, envOverrides)
+  );
+
+  // Step 2: Load TypeScript plugin (optional)
+  const pluginPath = join(cwd, 'oac.config.ts');
+  let plugin: OACPlugin = {};
+
+  if (await pathExists(pluginPath)) {
+    // Use jiti for zero-config TS execution (no ts-node required)
+    const { createJiti } = await import('jiti');
+    const jiti = createJiti(import.meta.url);
+    const mod = await jiti.import(pluginPath);
+    plugin = mod.default ?? mod;
+  }
+
+  return { data, plugin };
+}
+```
+
+### 4.3 Environment Variable Mapping
+
+| Env Var | Maps To | Type |
+|---------|---------|------|
+| `OAC_YOLO=true` | `data.preferences.yoloMode` | boolean |
+| `OAC_REGISTRY_URL=https://...` | Prepends to `data.registries` with priority 0 | string |
+| `OAC_BRANCH=main` | `data.preferences.branch` | string |
+| `OAC_INSTALL_LOCATION=global` | `data.preferences.installLocation` | `'local' \| 'global'` |
+| `OAC_CONFLICT_STRATEGY=yolo` | `data.preferences.conflictStrategy` | ConflictStrategy |
+| `OAC_PRIVATE_TOKEN=...` | Used by registry providers that opt in | string |
+| `OAC_VERBOSE=true` | CLI verbosity | boolean |
+| `OAC_QUIET=true` | CLI quiet mode | boolean |
+
+Environment variables override JSON config but **cannot** wire providers (use `oac.config.ts` for that).
+
+### 4.4 `defineConfig()` Signature (Final)
+
+```typescript
+// packages/core/src/define-config.ts
+
+/**
+ * @param plugin - Your OAC provider configuration
+ * @returns The same object, typed as OACPlugin
+ *
+ * @example Minimal — override context only
+ * ```ts
+ * export default defineConfig({
+ *   context: new NotionContextProvider({ token: process.env.NOTION_TOKEN! }),
+ * });
+ * ```
+ *
+ * @example Enterprise — full stack replacement
+ * ```ts
+ * export default defineConfig({
+ *   context: new ConfluenceContextProvider({ baseUrl: '...', token: '...' }),
+ *   taskManagement: new JiraTaskProvider({ projectKey: 'ENG', token: '...' }),
+ *   registries: [new PrivateRegistryProvider({ url: '...', token: '...' })],
+ *   ideAdapters: [new JetBrainsAdapter()],
+ * });
+ * ```
+ *
+ * @example Conditional — CI-only adapter
+ * ```ts
+ * export default defineConfig({
+ *   ideAdapters: [
+ *     process.env.CI && new CIMetricsAdapter(),
+ *   ],
+ * });
+ * ```
+ */
+export function defineConfig(plugin: OACPlugin): OACPlugin {
+  return plugin;
+}
+```
+
+### 4.5 OACConfig Schema (Data Shape)
+
+```typescript
+// packages/core/src/schemas/config.ts
+
+export const OACConfigSchema = z.object({
+  version: z.string().default('1.0.0'),
+  preferences: z.object({
+    defaultIDE: z.string().default('opencode'),
+    installLocation: z.enum(['local', 'global']).default('local'),
+    yoloMode: z.boolean().default(false),
+    conflictStrategy: z.enum(['ask', 'skip', 'overwrite', 'backup', 'yolo']).default('ask'),
+    autoBackup: z.boolean().default(true),
+    updateMode: z.enum(['manual', 'auto-safe', 'auto-all', 'locked']).default('manual'),
+    branch: z.string().default('main'),
+  }).default({}),
+  registries: z.array(z.object({
+    name: z.string(),
+    url: z.string().url(),
+    priority: z.number().int().min(0).default(1),
+    authTokenEnvVar: z.string().optional(), // e.g. "OAC_PRIVATE_TOKEN"
+  })).default([{ name: 'official', url: 'https://registry.nextsystems.dev/oac', priority: 1 }]),
+  ides: z.record(z.string(), z.object({
+    enabled: z.boolean().default(false),
+    path: z.string().optional(),
+    profile: z.string().default('developer'),
+  })).default({
+    opencode: { enabled: true, path: '.opencode', profile: 'developer' },
+  }),
+});
+
+export type OACConfig = z.infer<typeof OACConfigSchema>;
+```
+
+---
+
+## 5. `packages/core` Final Structure
+
+```
+packages/core/
+├── src/
+│   ├── providers/
+│   │   ├── context.ts             # IContextProvider interface
+│   │   ├── task-management.ts     # ITaskManagementProvider interface
+│   │   ├── registry.ts            # IRegistryProvider interface
+│   │   ├── ide-adapter.ts         # IIDEAdapter interface
+│   │   └── agent-profile.ts       # IAgentProfileProvider interface
+│   ├── schemas/
+│   │   ├── agent.ts               # AgentConfigSchema + AgentFrontmatterSchema (canonical)
+│   │   ├── config.ts              # OACConfigSchema
+│   │   ├── lockfile.ts            # OACLockSchema + InstalledComponentSchema
+│   │   ├── registry.ts            # RegistryItemSchema + RegistrySchema
+│   │   ├── skill.ts               # SkillFrontmatterSchema
+│   │   ├── context.ts             # ContextFrontmatterSchema + ContextFileSchema
+│   │   └── manifest.ts            # BundledManifestSchema + InstalledManifestSchema
+│   ├── types/
+│   │   └── index.ts               # All shared TypeScript types (§2.1 above)
+│   ├── plugin.ts                  # OACPlugin interface
+│   ├── define-config.ts           # defineConfig() helper
+│   ├── provider-registry.ts       # ProviderRegistry class + createProviderRegistry()
+│   └── index.ts                   # Re-exports everything (single import surface)
+├── package.json
+└── tsconfig.json
+```
+
+**`src/index.ts`** (complete barrel — everything available from `'@nextsystems/oac-core'`):
+```typescript
+// Providers
+export type { IContextProvider } from './providers/context.js';
+export type { ITaskManagementProvider } from './providers/task-management.js';
+export type { IRegistryProvider } from './providers/registry.js';
+export type { IIDEAdapter } from './providers/ide-adapter.js';
+export type { IAgentProfileProvider } from './providers/agent-profile.js';
+
+// Schemas (Zod objects, for runtime validation)
+export { AgentFrontmatterSchema, AgentConfigSchema } from './schemas/agent.js';
+export { OACConfigSchema } from './schemas/config.js';
+export { OACLockSchema } from './schemas/lockfile.js';
+export { RegistryItemSchema, RegistrySchema } from './schemas/registry.js';
+export { SkillFrontmatterSchema } from './schemas/skill.js';
+export { ContextFrontmatterSchema } from './schemas/context.js';
+export { BundledManifestSchema, InstalledManifestSchema } from './schemas/manifest.js';
+
+// Types (TypeScript-only)
+export type {
+  ComponentType, UpdateMode, ConflictStrategy, InstallLocation,
+  ContextLayerName, ContextFile, ContextQuery,
+  Task, TaskStatus, TaskPriority, TaskSession,
+  RegistryFile, RegistryItem, RegistrySearchOptions,
+  IDECapabilities, IDEOutputFile, IDEAdapterResult,
+  AgentProfile, OACAgent, OACContext,
+  ValidationResult, OACOperationResult,
+  // Inferred from schemas
+  AgentFrontmatter, AgentConfig, OACConfig, OACLock,
+} from './types/index.js';
+
+// Plugin system
+export type { OACPlugin } from './plugin.js';
+export { defineConfig } from './define-config.js';
+
+// Provider registry (internal wiring — CLI uses this, not plugin authors)
+export { ProviderRegistry, createProviderRegistry, ProviderRegistryError } from './provider-registry.js';
+```
+
+**`package.json`**:
+```json
+{
+  "name": "@nextsystems/oac-core",
+  "version": "1.0.0",
+  "description": "Shared interfaces, schemas, and provider contracts for OAC",
+  "type": "module",
+  "exports": {
+    ".": {
+      "import": "./dist/index.js",
+      "types": "./dist/index.d.ts"
+    }
+  },
+  "files": ["dist"],
+  "scripts": {
+    "build": "tsc --project tsconfig.json",
+    "typecheck": "tsc --noEmit",
+    "test": "vitest run"
+  },
+  "peerDependencies": {
+    "zod": "^3.22.0"
+  },
+  "devDependencies": {
+    "typescript": "^5.4.0",
+    "vitest": "^1.5.0",
+    "zod": "^3.22.0"
+  }
+}
+```
+
+**Zero runtime dependencies.** `zod` is a peer dependency — the CLI and plugin authors both have it. This means `@nextsystems/oac-core` ships ~0 bytes of dependencies.
+
+---
+
+## 6. Migration Path (No Breaking Changes to 236 Tests)
+
+The migration is designed so that every step leaves the test suite green. Each step is a separate PR.
+
+### Step 1: Fix Module-Level Bugs (No New Code)
+
+**PR: "fix: eliminate module-level singletons that break test isolation"**
+
+1. In `AdapterRegistry.ts:358`: Remove `export const registry = new AdapterRegistry()`. Add `export function createAdapterRegistry(): AdapterRegistry { return new AdapterRegistry(); }`.
+2. In test files that import `registry`: Add `beforeEach(() => registry.clear())` as a bridge (or switch to `createAdapterRegistry()`).
+3. In `AgentLoader.ts:169`: Move `cachedMetadata` and `metadataLoaded` to instance fields.
+4. In `plugin.ts`: Remove `const pluginInstance = new AbilitiesPlugin()`. Make `AbilitiesPlugin` instantiated in the consumer.
+
+**Test impact**: Tests that relied on shared singleton state may need `beforeEach(() => registry.clear())`. All 236 tests must pass after this step.
+
+### Step 2: Fix Schema Bugs
+
+**PR: "fix: correct schema bugs in types.ts"**
+
+1. Fix `ModelIdentifierSchema`: `z.union([z.string(), z.string()])` → `z.string()`
+2. Fix `TemperatureSchema`: add `.min(0).max(2)`
+3. Fix `AgentMetadataSchema` vs `OpenAgentSchema.metadata` inconsistency: use `AgentMetadataSchema` inside `OpenAgentSchema`
+
+**Test impact**: Tests that previously passed invalid temperature/model values will now fail Zod validation — fix the test data, not the schema.
+
+### Step 3: Create `packages/core` Package
+
+**PR: "feat(core): create @nextsystems/oac-core with provider interfaces"**
+
+1. Create `packages/core/` with the directory structure from §5
+2. Copy types from `compatibility-layer/src/types.ts` into `core/src/schemas/` (with schema fixes applied)
+3. Write the 5 provider interfaces, `OACPlugin`, `defineConfig()`, `ProviderRegistry`
+4. Add `"@nextsystems/oac-core": "workspace:*"` to root `package.json`
+5. Fix root `package.json` workspaces: `["packages/*", "evals/framework"]`
+
+**Test impact**: Zero — no existing code changed, only new files added.
+
+### Step 4: Wire Compatibility-Layer to Core Types
+
+**PR: "refactor(compat): import shared types from @nextsystems/oac-core"**
+
+1. In `compatibility-layer/src/types.ts`: Change schema definitions to re-export from `@nextsystems/oac-core` (keep backward-compatible exports)
+2. In `compatibility-layer/src/adapters/BaseAdapter.ts`: Import `OACAgent`, `IDEAdapterResult` from `@nextsystems/oac-core`
+
+**Test impact**: Zero if re-exports are clean. Run `tsc --noEmit` to confirm.
+
+### Step 5: Migrate Adapters to IIDEAdapter
+
+**PR: "refactor(compat): ClaudeAdapter, CursorAdapter, WindsurfAdapter implement IIDEAdapter"**
+
+1. Add `implements IIDEAdapter` to each adapter class
+2. Rename `name` → `id` on each adapter
+3. Update `fromOAC` signature to accept `agents[]` + `context[]`
+4. Add `validate()` method to each adapter
+
+**Test impact**: Adapter tests that call `adapter.name` need updating to `adapter.id`. This is the one place where test changes are expected — they are mechanical renames.
+
+### Step 6: CLI Wiring
+
+**PR: "feat(cli): wire ProviderRegistry into CLI commands"**
+
+1. Create `packages/cli/` with `createProviderRegistry()` call in CLI entry point
+2. Load `oac.config.ts` via jiti if present
+3. Pass `ProviderRegistry` into command handlers
+
+**Test impact**: CLI tests get fresh registry per test via `createProviderRegistry()` with mock providers.
+
+---
+
+## 7. Impact on Each of the 6 Projects
+
+### P1: `@nextsystems/oac-core`
+
+This document **is** the specification for P1. The team builds exactly the interfaces, types, schemas, `OACPlugin`, `defineConfig()`, and `ProviderRegistry` defined in §2. The package has zero runtime dependencies (zod is peer). The 5 provider interfaces are the extensibility contract that must remain stable — no breaking changes without a major version bump. Primary deliverable: a clean `index.ts` barrel from which every other package imports. Time estimate: 1–2 weeks. The schema fixes in §3.5 are part of P1, not P4.
+
+### P2: `@nextsystems/oac-cli`
+
+P2 depends on P1 and builds around `createProviderRegistry()`. Every CLI command receives a `ProviderRegistry` instance, never a singleton. The `ConfigManager` loads `.oac/config.json` (data) and `oac.config.ts` (plugin wiring) separately via the pipeline in §4.2. The `jiti` dependency handles TypeScript config execution without requiring ts-node. CLI commands must never import providers directly — they receive them through the registry. The YOLO flag maps to `OACConfig.preferences.conflictStrategy = 'yolo'`, not a separate code path.
+
+### P3: Context System
+
+P3 implements `IContextProvider` twice: `DefaultContextProvider` (6-layer filesystem resolver) and tests can mock it. The `DefaultContextProvider` is the only built-in implementation; it is passed as `defaults.context` to `createProviderRegistry()`. The 6-layer resolution logic lives entirely inside this class — nothing else in the codebase does path resolution. `oac context install` calls `provider.install()`, `oac context update` calls `provider.update()`. The dispatch semantics (callFirst) mean that if an enterprise user provides a `NotionContextProvider`, the 6-layer resolver is completely bypassed — no partial execution, no fallthrough.
+
+### P4: Agent & Skill Management
+
+P4 introduces the `agent.json` + `prompt.md` split. The `OACAgent` type defined in §2.1 is exactly what flows between P4's loader and the IDE adapters. P4 implements `IAgentProfileProvider` (built-in, reading from `manifest.json` profiles). The `AgentLoader` refactor (instance-scoped cache, §3.4) is a P4 prerequisite and should be done in P1's bug-fix step. The `task-cli.ts → task-cli.js` compilation happens in P4's build pipeline; the resulting `.js` file implements the default `ITaskManagementProvider` behavior for local JSON sessions.
+
+### P5: Plugin System
+
+P5 implements the IDE adapters as `IIDEAdapter` (not extending `BaseAdapter`). The OpenCode TS plugin is an OpenCode plugin (a different abstraction — `Plugin` from `@opencode-ai/plugin`) that internally calls `createProviderRegistry()` to get the configured context and task providers. The Claude Code adapter implements `IIDEAdapter.fromOAC()` to generate `session-start.js`. Cursor and Windsurf adapters are straightforward `IIDEAdapter` implementations. The `callAll()` dispatch in `ProviderRegistry.runAllAdapters()` is what P5 calls when `oac install --all` runs — all IDE adapters execute in parallel.
+
+### P6: Registry & Community
+
+P6 implements `IRegistryProvider` as `OfficialRegistryProvider` (nextsystems.dev) and provides the wiring for user-configured private registries. The `RegistryClient` in §P6 of the breakdown maps to `ProviderRegistry.resolveFromRegistry()` — the priority-ordered callFirst dispatch. Multi-registry search is implemented by calling `search()` on all registries, deduplicating by `name+type`, and returning sorted results. Auth tokens for private registries are read from `config.registries[n].authTokenEnvVar` — the env var name is stored in config, the value is never stored.
+
+---
+
+## 8. Red Lines
+
+The following are explicitly forbidden. Each has a one-line rationale.
+
+| Do Not | Why |
+|--------|-----|
+| Export a module-level singleton (`export const registry = new X()`) | Singletons bleed state between tests and make isolation impossible |
+| Add runtime dependencies to `packages/core` | Zero-dep is a load-time guarantee; adding deps violates the contract with plugin authors |
+| Use `ts-node` at runtime | Eliminates a fragile dev dependency from production paths; use jiti or pre-compile |
+| Merge `IContextProvider` and `ITaskManagementProvider` into one interface | Different dispatch semantics (callFirst vs single) cannot be unified without obscuring behavior |
+| Make `OACPlugin` fields required | Plugin authors implement one subsystem; required fields force them to stub everything else |
+| Use TSyringe, Inversify, or any DI container | Decorator-based DI requires `emitDecoratorMetadata`, is incompatible with ESM tree-shaking, and creates plugin author friction |
+| Use Effect-TS | Its error model and type complexity is appropriate for library authors, not community plugin authors writing `implements IContextProvider` |
+| Store auth tokens in `.oac/config.json` | Secrets in config files get committed to git; use env vars and store only the env var name |
+| Implement `callAll()` dispatch outside `ProviderRegistry` | Dispatch semantics must be centralized; scattered fan-out logic produces inconsistent error handling |
+| Give IDE adapters filesystem write access directly | Adapters return file content; the CLI writes files; this enables dry-run support and prevents adapters from bypassing conflict resolution |
+| Use `z.union([z.string(), z.string()])` anywhere | Duplicate union members collapse to the first — this is always a bug |
+| Share `AgentLoader` instance between parallel requests | `AgentLoader` has instance-scoped cache; a shared instance across concurrent loads will return stale data |
+| Make `BaseAdapter` implement `IIDEAdapter` via inheritance | Inheritance creates a coupling between the compatibility-layer and core; the adapters in P5 implement `IIDEAdapter` directly |
+| Hand-maintain SHA256 hashes in manifest.json | Manual SHA256s drift; `scripts/generate-manifest.ts` must be the only source |
+| Put business logic in `defineConfig()` | It is an identity function for type safety; logic in it is invisible to callers |
+| Make `ProviderRegistry` accept partial providers without defaults | A registry with no context provider crashes at runtime; defaults must be passed to `createProviderRegistry()` |
+
+---
+
+*This document supersedes all prior provider/adapter discussions. Implementation of P1 begins with the interfaces in §2 locked.*

+ 606 - 0
docs/planning/mvp/00-MVP-PLAN.md

@@ -0,0 +1,606 @@
+# OAC MVP — The 20% That Delivers 80% of the Value
+
+**Date**: 2026-02-19
+**Status**: ACTIVE — This is what we build first
+**Branch**: `feature/oac-package-refactor`
+**Issue**: #206
+
+---
+
+## The Aim
+
+**One sentence**: Make it dead simple to install, manage, and keep updated a set of excellent AI agents and context files across any IDE — and get out of the user's way.
+
+**What users actually want**:
+1. "Set me up fast so I can code with AI" → `oac init`
+2. "Keep my stuff updated without breaking my changes" → `oac update`
+3. "Work with whatever IDE I'm in" → `oac apply`
+4. "Let me grab the context/agents I need" → `oac add`
+5. "Tell me if something's wrong" → `oac doctor`
+
+**What users do NOT want**: Provider interfaces, 6-layer resolution theory, preset merge strategies, TUI browsers, community registries, plugin architectures. Those are our problems, not theirs.
+
+---
+
+## The Focus
+
+### The Product is the CONTENT, Not the CLI
+
+The agents, context files, and skills we ship are the product. The CLI is a delivery truck. If the agents are mediocre, the fanciest CLI won't save us. If the agents are excellent, even a basic CLI wins.
+
+**Priority order**:
+1. Excellent bundled content (agents + context)
+2. Reliable install/update that respects user changes
+3. Multi-IDE output generation
+4. Everything else
+
+### Context System is the Core Value
+
+Context files are what make AI agents actually useful in a project. Without project-specific context (coding standards, architecture patterns, domain knowledge), agents give generic answers. With good context, they give great answers.
+
+**The context system must**:
+- Let users install curated context files easily
+- Let users add/remove individual context files
+- Let users override any context file with their own version
+- Keep bundled context updated without touching user overrides
+- Work offline (bundled in npm, no network fetch at runtime)
+
+---
+
+## 5 Commands. That's the MVP.
+
+```
+oac init          Set up agents + context in my project
+oac update        Update everything, skip what I changed
+oac apply         Generate files for Cursor/Claude/Windsurf
+oac add <thing>   Add a specific agent, context file, or skill
+oac doctor        Tell me what's broken and how to fix it
+```
+
+Plus these flags that work on any command:
+```
+--yolo            Skip all confirmations (auto-enabled when CI=true)
+--dry-run         Show what would happen without doing it
+--verbose         Show detailed output
+```
+
+And one bonus for discoverability:
+```
+oac list          Show what's installed
+oac status        One-screen summary of everything
+```
+
+That's 7 commands total. Nothing else ships in v1.0.
+
+---
+
+## What "Done" Looks Like — The Passing State
+
+### Gate 1: `oac init` Works (Week 2)
+
+**User runs**: `npx @nextsystems/oac init`
+
+**What happens**:
+1. Detects current directory (must be a project root — has `package.json` or `.git`)
+2. Auto-detects IDEs present (`.opencode/`, `.cursor/`, `.claude/`)
+3. Asks ONE question: "Install standard agent pack? (Y/n)"
+4. Copies bundled agents + context to `.opencode/`
+5. Writes `.oac/manifest.json` (tracks what was installed + SHA256 of each file)
+6. Writes `.oac/config.json` (minimal defaults)
+7. Prints: "Done! X agents and Y context files installed. Run `oac doctor` to verify."
+
+**Passing criteria**:
+- [ ] Completes in < 30 seconds on a cold run
+- [ ] `npx @nextsystems/oac init` works (no global install required)
+- [ ] Idempotent — running twice doesn't duplicate or break anything
+- [ ] Skips files that already exist (prints "skipped: already exists")
+- [ ] Works on macOS, Linux, Windows
+- [ ] Zero interactive prompts with `--yolo` flag
+- [ ] `CI=true` environment auto-enables `--yolo`
+- [ ] Exit code 0 on success, non-zero on failure
+
+**What it installs by default**:
+```
+.opencode/
+├── agent/
+│   ├── core/
+│   │   ├── openagent.md              # Primary orchestrator
+│   │   └── opencoder.md              # Code implementation
+│   ├── development/
+│   │   ├── TestEngineer.md
+│   │   ├── CodeReviewer.md
+│   │   ├── CoderAgent.md
+│   │   └── BuildAgent.md
+│   └── discovery/
+│       ├── ContextScout.md
+│       └── ExternalScout.md
+├── context/
+│   ├── core/
+│   │   └── standards/
+│   │       ├── code-quality.md
+│   │       ├── test-coverage.md
+│   │       └── security-patterns.md
+│   ├── development/
+│   │   └── principles/
+│   │       ├── clean-code.md
+│   │       └── api-design.md
+│   └── [project-intelligence templates]
+├── skills/
+│   ├── task-management/
+│   └── context-manager/
+├── config.json
+└── opencode.json
+
+.oac/
+├── manifest.json                     # What OAC installed + SHA256 hashes
+└── config.json                       # User preferences
+```
+
+---
+
+### Gate 2: `oac update` Works (Week 3)
+
+**User runs**: `oac update`
+
+**What happens**:
+1. Reads `.oac/manifest.json` (what's installed + original SHA256)
+2. Compares each installed file's current SHA256 against the manifest
+3. For each file:
+   - SHA256 matches manifest → file is untouched → safe to update → update silently
+   - SHA256 differs from manifest → user modified it → SKIP and report
+4. Copies new versions of safe-to-update files from npm bundle
+5. Updates `.oac/manifest.json` with new SHA256s
+6. Prints summary: "Updated X files. Skipped Y files (user-modified)."
+
+**Passing criteria**:
+- [ ] Updates files the user hasn't touched
+- [ ] NEVER overwrites a file the user modified (unless `--yolo`)
+- [ ] `--yolo` creates `.oac/backups/{filename}.{timestamp}` before overwriting
+- [ ] `oac update --check` shows what WOULD change without changing anything
+- [ ] `oac update --dry-run` same as `--check` (alias)
+- [ ] Works when npm package has been updated (`npm update @nextsystems/oac`)
+- [ ] Handles new files (files in new version that didn't exist before → install them)
+- [ ] Handles removed files (files removed from new version → leave user's copy, warn)
+- [ ] Prints clear list: "Updated: file1, file2. Skipped (modified): file3. New: file4."
+
+**The manifest format** (simple, not a full lockfile):
+```json
+{
+  "version": "1",
+  "oacVersion": "0.7.1",
+  "installedAt": "2026-02-19T10:00:00Z",
+  "updatedAt": "2026-02-19T10:00:00Z",
+  "files": {
+    ".opencode/agent/core/openagent.md": {
+      "sha256": "a1b2c3d4...",
+      "source": "bundled",
+      "installedAt": "2026-02-19T10:00:00Z"
+    },
+    ".opencode/context/core/standards/code-quality.md": {
+      "sha256": "e5f6a7b8...",
+      "source": "bundled",
+      "installedAt": "2026-02-19T10:00:00Z"
+    }
+  }
+}
+```
+
+---
+
+### Gate 3: `oac add` Works for Context (Week 4)
+
+**User runs**: `oac add context:react-patterns`
+
+**What happens**:
+1. Looks up `react-patterns` in the bundled registry (`registry.json`)
+2. Finds the file path in the npm package
+3. Copies it to `.opencode/context/development/react-patterns.md`
+4. Updates `.oac/manifest.json`
+5. Prints: "Added react-patterns to .opencode/context/development/"
+
+**Also supports**:
+```bash
+oac add agent:rust-specialist       # Add a specific agent
+oac add skill:context-manager       # Add a specific skill
+oac add context:typescript-patterns # Add a specific context file
+oac remove context:react-patterns   # Remove something
+```
+
+**Passing criteria**:
+- [ ] `oac add` with no args shows available components grouped by type
+- [ ] `oac add context:X` installs the context file to the right location
+- [ ] `oac add agent:X` installs the agent file to the right location
+- [ ] Warns if component already exists: "Already installed. Use --force to reinstall."
+- [ ] `oac remove X` removes the file and updates manifest
+- [ ] `oac list` shows all installed components with type and path
+- [ ] `oac list --context` filters to context files only
+- [ ] `oac list --agents` filters to agents only
+
+**Why context is the priority for `add`**:
+Context files are the most granular, most frequently added/removed, and most project-specific. A Rust project needs different context than a React project. Users will `oac add context:rust-patterns` far more often than `oac add agent:X`.
+
+---
+
+### Gate 4: `oac apply` Works (Week 5)
+
+**User runs**: `oac apply cursor`
+
+**What happens**:
+1. Reads all installed agents from `.opencode/agent/`
+2. Uses the compatibility layer adapters (already built!) to convert
+3. Generates `.cursorrules` with a router pattern
+4. Prints: "Generated .cursorrules (45KB) with 6 agents."
+
+**Also supports**:
+```bash
+oac apply claude          # Generate CLAUDE.md
+oac apply windsurf        # Generate .windsurfrules
+oac apply --all           # Generate for all detected IDEs
+```
+
+**Passing criteria**:
+- [ ] `oac apply cursor` generates valid `.cursorrules`
+- [ ] `oac apply claude` generates valid `CLAUDE.md`
+- [ ] `oac apply windsurf` generates valid `.windsurfrules`
+- [ ] `oac apply --all` detects which IDEs are present and generates for each
+- [ ] Warns about feature limitations: "Cursor: skills not supported, skipping 3 skills"
+- [ ] Warns about size: "Cursor: .cursorrules is 92KB (limit: 100KB) — consider removing agents"
+- [ ] `--dry-run` shows what would be generated without writing
+- [ ] Existing IDE files are backed up before overwriting (`.cursorrules.bak`)
+
+**Key insight**: The compatibility layer adapters (`packages/compatibility-layer/`) already exist and work. This command is mostly wiring them to the CLI. Don't rewrite them.
+
+---
+
+### Gate 5: `oac doctor` Works (Week 5)
+
+**User runs**: `oac doctor`
+
+**What happens**:
+```
+OAC Doctor — Checking your setup...
+
+  ✓ OAC version: 1.0.0 (latest)
+  ✓ Node.js: v20.11.0 (>= 18 required)
+  ✓ Config: .oac/config.json valid
+  ✓ Manifest: .oac/manifest.json valid
+  ✓ Agents: 8 installed, all files present
+  ✓ Context: 15 files installed, all files present
+  ✓ Skills: 3 installed, all files present
+  ⚠ Modified: 2 files modified since install
+    - .opencode/agent/core/openagent.md (modified 2 days ago)
+    - .opencode/context/core/standards/code-quality.md (modified 5 hours ago)
+  ✓ IDE: OpenCode detected (.opencode/)
+  ⚠ IDE: Cursor detected (.cursor/) — run 'oac apply cursor' to sync
+
+  Result: HEALTHY (2 warnings)
+```
+
+**Passing criteria**:
+- [ ] Checks OAC version against npm registry (non-blocking, skip if offline)
+- [ ] Checks Node.js version >= 18
+- [ ] Validates `.oac/config.json` and `.oac/manifest.json` exist and are valid JSON
+- [ ] Verifies every file in manifest exists on disk
+- [ ] Reports which files have been modified (SHA256 mismatch)
+- [ ] Detects installed IDEs and suggests `oac apply` if out of sync
+- [ ] Exit code 0 if healthy, 1 if errors found
+- [ ] `oac doctor --json` outputs machine-readable JSON (for CI)
+
+---
+
+### Gate 6: `oac status` Works (Week 5)
+
+**User runs**: `oac status`
+
+**What happens**:
+```
+OAC v1.0.0 — ~/my-project
+
+  Agents:   8 installed (2 core, 6 subagents)
+  Context:  15 files (12 bundled, 3 custom)
+  Skills:   3 installed
+  Modified: 2 files have local changes
+  Updates:  Available (run 'oac update --check')
+  IDE:      OpenCode (active), Cursor (needs sync)
+
+  Run 'oac doctor' for full health check
+```
+
+---
+
+## What We Build — Technical Breakdown
+
+### Package: `packages/cli/`
+
+New package. Commander.js CLI. This is the only new package for MVP.
+
+```
+packages/cli/
+├── src/
+│   ├── commands/
+│   │   ├── init.ts           # oac init
+│   │   ├── update.ts         # oac update
+│   │   ├── add.ts            # oac add / oac remove
+│   │   ├── apply.ts          # oac apply
+│   │   ├── doctor.ts         # oac doctor
+│   │   ├── list.ts           # oac list
+│   │   └── status.ts         # oac status
+│   ├── lib/
+│   │   ├── manifest.ts       # Read/write .oac/manifest.json
+│   │   ├── config.ts         # Read/write .oac/config.json
+│   │   ├── bundled.ts        # Locate bundled files in npm package
+│   │   ├── sha256.ts         # Compute file hashes
+│   │   ├── installer.ts      # Copy files with conflict detection
+│   │   ├── registry.ts       # Read registry.json, resolve components
+│   │   └── ide-detect.ts     # Detect installed IDEs
+│   ├── ui/
+│   │   ├── logger.ts         # Colored output (chalk)
+│   │   └── spinner.ts        # Progress indication (ora)
+│   └── index.ts              # Commander.js entry point
+├── package.json
+├── tsconfig.json
+└── tsup.config.ts
+```
+
+### Dependencies (minimal)
+
+```json
+{
+  "dependencies": {
+    "commander": "^12.0.0",
+    "chalk": "^5.3.0",
+    "ora": "^8.0.0",
+    "fs-extra": "^11.2.0",
+    "semver": "^7.6.0",
+    "zod": "^3.23.0"
+  },
+  "devDependencies": {
+    "tsup": "^8.0.0",
+    "typescript": "^5.4.0",
+    "vitest": "^1.5.0"
+  }
+}
+```
+
+No `@inquirer/prompts` (no interactive wizards in MVP).
+No `conf` (we write JSON directly).
+No `update-notifier` (doctor checks version manually).
+No `cli-progress` (ora spinner is enough).
+No `diff` (we don't show diffs in MVP, just skip modified files).
+No `gray-matter` (we don't parse frontmatter in the CLI).
+
+### What We Reuse (Don't Rewrite)
+
+| Existing Code | How We Use It |
+|---------------|---------------|
+| `packages/compatibility-layer/` | `oac apply` calls these adapters directly |
+| `registry.json` | `oac add` reads this to find components |
+| `.opencode/` bundled content | `oac init` copies from here |
+| `install.sh` | Keep as legacy fallback, deprecation notice |
+| `bin/oac.js` | Rewrite to: `require('../packages/cli/dist/index.js')` |
+
+### What We Do NOT Build in MVP
+
+| Feature | Why Not |
+|---------|---------|
+| `@nextsystems/oac-core` package | Provider interfaces are for v1.1 extensibility |
+| `oac.config.ts` | TypeScript config is a power-user feature |
+| `agent.json` + `prompt.md` split | Current `.md` format works fine, migrate later |
+| `oac.lock` lockfile | Manifest is enough for single-user, lockfile is for teams |
+| Preset system | Users can edit files directly for now |
+| TUI browser | `oac list` is enough for discovery |
+| Community publishing | No community yet |
+| Security scanning | No community components to scan yet |
+| OpenCode plugin (session.created) | Auto-update is nice-to-have, `oac update` is enough |
+| `oac browse` / `oac search` | `oac list` covers this |
+| `oac rollback` | `.oac/backups/` + git is enough |
+| `oac customize` / `oac presets` | Edit files directly |
+| `oac compat import` (toOAC) | One-way conversion is enough |
+| Multi-registry support | One registry is enough |
+| `oac publish` | No community yet |
+| `oac session` / `oac task` | Task management stays as-is |
+
+---
+
+## The Manifest — Our Source of Truth
+
+The manifest is the simplest possible tracking system. Not a lockfile (no dependency resolution, no version ranges, no history). Just: "what did OAC install, and what was the hash?"
+
+### `.oac/manifest.json`
+
+```json
+{
+  "version": "1",
+  "oacVersion": "1.0.0",
+  "installedAt": "2026-02-19T10:00:00Z",
+  "updatedAt": "2026-02-19T10:00:00Z",
+  "files": {
+    ".opencode/agent/core/openagent.md": {
+      "sha256": "a1b2c3d4e5f6...",
+      "type": "agent",
+      "source": "bundled",
+      "installedAt": "2026-02-19T10:00:00Z"
+    },
+    ".opencode/context/core/standards/code-quality.md": {
+      "sha256": "f7e8d9c0b1a2...",
+      "type": "context",
+      "source": "bundled",
+      "installedAt": "2026-02-19T10:00:00Z"
+    }
+  }
+}
+```
+
+### `.oac/config.json`
+
+```json
+{
+  "version": "1",
+  "preferences": {
+    "yoloMode": false,
+    "autoBackup": true
+  }
+}
+```
+
+That's it. No IDE config, no provider config, no registry config. Just user preferences.
+
+---
+
+## The Update Algorithm — The Core of the Whole System
+
+This is the most important code in the entire project. Get this right and everything else follows.
+
+```
+FOR each file in NEW npm bundle:
+  IF file exists in manifest:
+    currentHash = SHA256(file on disk)
+    manifestHash = manifest.files[file].sha256
+    
+    IF currentHash == manifestHash:
+      → File is UNTOUCHED by user
+      → SAFE to update
+      → Copy new version, update manifest hash
+    ELSE:
+      → File was MODIFIED by user
+      → SKIP (unless --yolo)
+      → If --yolo: backup to .oac/backups/, then overwrite, update manifest
+  ELSE:
+    → File is NEW in this version
+    → Install it, add to manifest
+
+FOR each file in manifest NOT in new bundle:
+  → File was REMOVED from OAC
+  → Leave user's copy alone
+  → Remove from manifest
+  → Warn: "file.md is no longer maintained by OAC"
+```
+
+This algorithm is simple, predictable, and safe. Users can always understand what happened by reading the output.
+
+---
+
+## Timeline
+
+| Week | What Ships | Gate |
+|------|-----------|------|
+| **Week 1** | `packages/cli/` skeleton, `bin/oac.js` rewrite, build pipeline, `oac --version` works | — |
+| **Week 2** | `oac init` fully working, manifest system, bundled content copying | Gate 1 |
+| **Week 3** | `oac update` fully working, SHA256 comparison, skip-if-modified | Gate 2 |
+| **Week 4** | `oac add/remove`, `oac list`, registry.json reading | Gate 3 |
+| **Week 5** | `oac apply` (wire compatibility layer), `oac doctor`, `oac status` | Gate 4, 5, 6 |
+| **Week 6** | Testing, error messages, edge cases, documentation, npm publish prep | All gates pass |
+
+**Total: 6 weeks to a shippable v1.0**
+
+---
+
+## What Comes After MVP (v1.1 Roadmap)
+
+Once MVP ships and we have real users giving feedback:
+
+| Feature | Trigger to Build |
+|---------|-----------------|
+| `oac.lock` lockfile | When teams ask for reproducible installs |
+| `agent.json` + `prompt.md` split | When we need programmatic agent management |
+| Provider interfaces (`oac-core`) | When someone wants to swap a subsystem |
+| `oac.config.ts` | When enterprise users need custom providers |
+| Preset system | When users complain about losing customizations on update |
+| TUI browser (`oac browse`) | When we have 50+ components and `oac list` isn't enough |
+| Community registry | When we have 1,000+ users and people want to share |
+| Security scanning | When community components exist |
+| OpenCode plugin (auto-update) | When users forget to run `oac update` |
+| `oac rollback` | When users ask for it (git covers most cases) |
+| GUI wrapper | When content creators are a real user segment |
+
+**Rule: Don't build it until someone asks for it.**
+
+---
+
+## Non-Negotiable Quality Standards
+
+### Every command must:
+- Print what it's about to do BEFORE doing it
+- Print what it did AFTER doing it
+- Support `--dry-run` to preview without executing
+- Support `--yolo` to skip confirmations
+- Return exit code 0 on success, non-zero on failure
+- Never silently fail — always print errors in plain English
+- Never modify a user-edited file without explicit consent
+
+### Error messages must:
+- Say what went wrong
+- Say why it went wrong (if known)
+- Say how to fix it
+- Example: "Error: .oac/manifest.json not found. Run 'oac init' to set up your project."
+
+### The CLI must:
+- Start in < 100ms (`oac --version` must be instant)
+- Use lazy imports (don't load commander commands until needed)
+- Work offline (all bundled content, no network required for core operations)
+- Work without global install (`npx @nextsystems/oac` must work)
+
+---
+
+## How to Validate the MVP is Right
+
+### User Test 1: Fresh Project Setup
+```bash
+mkdir my-project && cd my-project && git init
+npx @nextsystems/oac init
+# Expected: agents + context installed in < 30 seconds
+# Expected: user can immediately start coding with AI
+```
+
+### User Test 2: Update After Customization
+```bash
+# User edits an agent file
+vim .opencode/agent/core/openagent.md
+# OAC updates
+oac update
+# Expected: edited file is SKIPPED, everything else updates
+# Expected: clear message about what was skipped and why
+```
+
+### User Test 3: Add Context for a Specific Stack
+```bash
+oac add context:react-patterns
+oac add context:typescript-patterns
+oac list --context
+# Expected: both files installed, listed correctly
+```
+
+### User Test 4: Multi-IDE Setup
+```bash
+oac apply cursor
+oac apply claude
+# Expected: .cursorrules and CLAUDE.md generated
+# Expected: warnings about unsupported features
+```
+
+### User Test 5: Something Goes Wrong
+```bash
+rm .oac/manifest.json
+oac doctor
+# Expected: "manifest.json missing — run 'oac init' to repair"
+oac init
+# Expected: re-initializes without duplicating files
+```
+
+---
+
+## Summary
+
+**Build 5 commands. Ship in 6 weeks. Make the content excellent.**
+
+The CLI is a delivery truck for great AI agents and context files. The update system that respects user changes is the killer feature. Everything else can wait until users tell us what they need.
+
+```
+oac init     → Get set up
+oac update   → Stay current
+oac add      → Get what you need
+oac apply    → Work in any IDE
+oac doctor   → Fix problems
+```
+
+That's the MVP. That's the 20% that delivers 80% of the value.

File diff suppressed because it is too large
+ 641 - 247
package-lock.json


+ 6 - 3
package.json

@@ -3,7 +3,9 @@
   "version": "0.7.1",
   "description": "AI agent framework for plan-first development workflows with approval-based execution. Multi-language support for TypeScript, Python, Go, Rust and more.",
   "workspaces": [
-    "evals/framework"
+    "evals/framework",
+    "packages/cli",
+    "packages/compatibility-layer"
   ],
   "bin": {
     "oac": "./bin/oac.js"
@@ -31,10 +33,11 @@
     "LICENSE",
     "README.md",
     "CHANGELOG.md",
-    "CONTEXT_SYSTEM_GUIDE.md"
+    "CONTEXT_SYSTEM_GUIDE.md",
+    "packages/cli/dist/"
   ],
   "engines": {
-    "node": ">=14.0.0"
+    "node": ">=18.0.0"
   },
   "scripts": {
     "test": "npm run test:all",

+ 1 - 1
packages/cli/package.json

@@ -10,7 +10,7 @@
   "types": "./dist/index.d.ts",
   "files": ["dist"],
   "scripts": {
-    "build": "bun build src/index.ts --outdir dist --target bun --splitting --banner '#!/usr/bin/env bun'",
+    "build": "rm -rf dist && bun build src/index.ts --outdir dist --target bun --splitting",
     "build:watch": "bun build src/index.ts --outdir dist --target bun --splitting --watch",
     "dev": "bun run src/index.ts",
     "test": "bun test",

+ 0 - 3
packages/cli/src/index.ts

@@ -9,9 +9,6 @@ program
   .name('oac')
   .description('OpenAgents Control — install, manage, and update AI agents and context files')
   .version(readCliVersion(), '-v, --version', 'Print version and exit')
-  .option('--yolo', 'Skip all confirmations (auto-enabled when CI=true)', false)
-  .option('--dry-run', 'Show what would happen without doing it', false)
-  .option('--verbose', 'Show detailed output', false)
 
 // Lazy-load command modules in parallel — keeps startup < 100ms
 async function main(): Promise<void> {

+ 9 - 1
packages/cli/src/lib/bundled.ts

@@ -26,6 +26,13 @@ const BUNDLED_SUBDIRS = [
  * import.meta.dir is Bun's native equivalent of __dirname.
  */
 export function getPackageRoot(): string {
+  // Allow dev/monorepo override via environment variable.
+  // In production (npm install), OAC_PACKAGE_ROOT is not set so the walk runs as before.
+  // In dev, set OAC_PACKAGE_ROOT=/path/to/repo to bypass the walk entirely.
+  const envOverride = process.env['OAC_PACKAGE_ROOT'];
+  if (envOverride) {
+    return envOverride;
+  }
   // import.meta.dir is Bun's native equivalent of __dirname — points to packages/cli/dist/ at runtime
   return findPackageRoot(import.meta.dir);
 }
@@ -64,7 +71,8 @@ export function findPackageRoot(dir: string): string {
       throw new Error(
         `getPackageRoot: could not find a directory with ".opencode/" and "package.json" ` +
           `(without a "registry.json" at the same level) walking up from "${dir}". ` +
-          `Is @nextsystems/oac installed correctly?`,
+          `Is @nextsystems/oac installed correctly? ` +
+          `In dev/monorepo mode, set OAC_PACKAGE_ROOT env var to the repo root.`,
       );
     }
     current = parent;

+ 102 - 74
packages/cli/src/lib/installer.ts

@@ -1,4 +1,5 @@
 import path from "node:path";
+import { stat } from "node:fs/promises";
 import { computeFileHash, hashesMatch } from "./sha256.js";
 import {
   type ManifestFile,
@@ -191,22 +192,20 @@ async function processOneFile(
   const { relativePath, sourcePath, destPath, manifest, options, timestamp } =
     args;
 
-  // TODO: §4.1 — complex restructure needed (catch returns different shape than FileDecision)
-  let decision: FileDecision;
-  try {
-    decision = await decideFileAction(
-      relativePath,
-      manifest,
-      destPath,
-      options,
-    );
-  } catch (err) {
-    const msg = err instanceof Error ? err.message : String(err);
+  const decisionResult = await (async () => {
+    try {
+      return { ok: true as const, value: await decideFileAction(relativePath, manifest, destPath, options) };
+    } catch (err) {
+      return { ok: false as const, msg: err instanceof Error ? err.message : String(err) };
+    }
+  })();
+  if (!decisionResult.ok) {
     return {
-      patch: { errors: [`${relativePath}: decision failed — ${msg}`] },
+      patch: { errors: [`${relativePath}: decision failed — ${decisionResult.msg}`] },
       entry: null,
     };
   }
+  const decision = decisionResult.value;
 
   const now = new Date().toISOString();
   const fileType = classifyBundledFile(relativePath);
@@ -280,34 +279,50 @@ export async function installFiles(
   options: InstallOptions,
 ): Promise<{ result: InstallResult; updatedManifest: ManifestFile }> {
   const now = new Date().toISOString();
-  let manifest = createEmptyManifest("0.0.0"); // TODO: §4.1 — complex restructure needed (loop accumulator)
-  let result = { ...EMPTY_RESULT }; // TODO: §4.1 — complex restructure needed (loop accumulator)
 
-  for (const relativePath of files) {
-    const sourcePath = getBundledFilePath(options.packageRoot, relativePath);
-    const destPath = path.join(options.projectRoot, relativePath);
+  type FileOutcome =
+    | { ok: true; relativePath: string; entry: FileEntry }
+    | { ok: false; relativePath: string; msg: string };
 
-    log(options, `install: ${relativePath}`);
-    try {
-      await installFile(sourcePath, destPath, options);
-      const sha256 = options.dryRun ? "" : await computeFileHash(destPath);
-      const entry: FileEntry = {
-        sha256,
-        type: classifyBundledFile(relativePath),
-        source: "bundled",
-        installedAt: now,
+  const outcomes = await Promise.all(
+    files.map(async (relativePath): Promise<FileOutcome> => {
+      const sourcePath = getBundledFilePath(options.packageRoot, relativePath);
+      const destPath = path.join(options.projectRoot, relativePath);
+      log(options, `install: ${relativePath}`);
+      try {
+        await installFile(sourcePath, destPath, options);
+        const sha256 = options.dryRun ? "" : await computeFileHash(destPath);
+        const entry: FileEntry = {
+          sha256,
+          type: classifyBundledFile(relativePath),
+          source: "bundled",
+          installedAt: now,
+        };
+        return { ok: true, relativePath, entry };
+      } catch (err) {
+        const msg = err instanceof Error ? err.message : String(err);
+        return { ok: false, relativePath, msg };
+      }
+    }),
+  );
+
+  const { result, updatedManifest } = outcomes.reduce(
+    (acc, outcome) => {
+      if (outcome.ok) {
+        return {
+          result: mergeResult(acc.result, { installed: [outcome.relativePath] }),
+          updatedManifest: addFileToManifest(acc.updatedManifest, outcome.relativePath, outcome.entry),
+        };
+      }
+      return {
+        result: mergeResult(acc.result, { errors: [`${outcome.relativePath}: ${outcome.msg}`] }),
+        updatedManifest: acc.updatedManifest,
       };
-      manifest = addFileToManifest(manifest, relativePath, entry);
-      result = mergeResult(result, { installed: [relativePath] });
-    } catch (err) {
-      const msg = err instanceof Error ? err.message : String(err);
-      result = mergeResult(result, {
-        errors: [`${relativePath}: ${msg}`],
-      });
-    }
-  }
+    },
+    { result: { ...EMPTY_RESULT }, updatedManifest: createEmptyManifest("0.0.0") },
+  );
 
-  return { result, updatedManifest: manifest };
+  return { result, updatedManifest };
 }
 
 /**
@@ -330,47 +345,58 @@ export async function updateFiles(
   const bundledFiles = await listBundledFiles(options.packageRoot);
   const timestamp = buildTimestamp();
 
-  let workingManifest: ManifestFile =
-    manifest ?? createEmptyManifest("0.0.0"); // TODO: §4.1 — complex restructure needed (loop accumulator)
-  let result = { ...EMPTY_RESULT }; // TODO: §4.1 — complex restructure needed (loop accumulator)
-
-  // Phase 1: process each file in the new bundle
-  for (const relativePath of bundledFiles) {
-    const sourcePath = getBundledFilePath(options.packageRoot, relativePath);
-    const destPath = path.join(options.projectRoot, relativePath);
-
-    const { patch, entry } = await processOneFile({
-      relativePath,
-      sourcePath,
-      destPath,
-      manifest,
-      options,
-      timestamp,
-    });
-
-    result = mergeResult(result, patch);
-
-    // Update the working manifest if we have a new/updated entry
-    if (entry !== null) {
-      workingManifest = addFileToManifest(workingManifest, relativePath, entry);
-    }
-  }
+  // Phase 1: process each file in the new bundle (parallel)
+  const phase1Results = await Promise.all(
+    bundledFiles.map(async (relativePath) => {
+      const sourcePath = getBundledFilePath(options.packageRoot, relativePath);
+      const destPath = path.join(options.projectRoot, relativePath);
+      const { patch, entry } = await processOneFile({
+        relativePath,
+        sourcePath,
+        destPath,
+        manifest,
+        options,
+        timestamp,
+      });
+      return { relativePath, patch, entry };
+    }),
+  );
+
+  const phase1 = phase1Results.reduce(
+    (acc, { relativePath, patch, entry }) => ({
+      result: mergeResult(acc.result, patch),
+      workingManifest:
+        entry !== null
+          ? addFileToManifest(acc.workingManifest, relativePath, entry)
+          : acc.workingManifest,
+    }),
+    {
+      result: { ...EMPTY_RESULT } as InstallResult,
+      workingManifest: manifest ?? createEmptyManifest("0.0.0"),
+    },
+  );
 
   // Phase 2: handle files in manifest that are no longer in the bundle
   const bundledSet = new Set(bundledFiles);
-  const manifestPaths = Object.keys(workingManifest.files);
-
-  for (const trackedPath of manifestPaths) {
-    if (!bundledSet.has(trackedPath)) {
-      process.stdout.write(
-        `[oac] warn: "${trackedPath}" is no longer maintained by OAC — your copy is untouched\n`,
-      );
-      workingManifest = removeFileFromManifest(workingManifest, trackedPath);
-      result = mergeResult(result, { removed_from_manifest: [trackedPath] });
-    }
-  }
+  const manifestPaths = Object.keys(phase1.workingManifest.files);
+
+  const { result, updatedManifest } = manifestPaths.reduce(
+    (acc, trackedPath) => {
+      if (!bundledSet.has(trackedPath)) {
+        process.stdout.write(
+          `[oac] warn: "${trackedPath}" is no longer maintained by OAC — your copy is untouched\n`,
+        );
+        return {
+          result: mergeResult(acc.result, { removed_from_manifest: [trackedPath] }),
+          updatedManifest: removeFileFromManifest(acc.updatedManifest, trackedPath),
+        };
+      }
+      return acc;
+    },
+    { result: phase1.result, updatedManifest: phase1.workingManifest },
+  );
 
-  return { result, updatedManifest: workingManifest };
+  return { result, updatedManifest };
 }
 
 /**
@@ -380,7 +406,9 @@ export async function updateFiles(
 export async function isProjectRoot(dir: string): Promise<boolean> {
   const [hasPackageJson, hasGit] = await Promise.all([
     Bun.file(path.join(dir, "package.json")).exists(),
-    Bun.file(path.join(dir, ".git")).exists(),
+    // stat() works for both files (.git in worktrees) and directories (.git in normal repos)
+    // Bun.file().exists() returns false for directories, so we must use stat() here
+    stat(path.join(dir, ".git")).then(() => true).catch(() => false),
   ]);
   return hasPackageJson || hasGit;
 }

Some files were not shown because too many files changed in this diff