@ngockhoale/ukit 2.7.1 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +1 -3
  3. package/manifests/hostCapabilities.yaml +0 -10
  4. package/manifests/instructionRules.yaml +0 -16
  5. package/manifests/platform.full.yaml +2 -16
  6. package/package.json +3 -5
  7. package/scripts/perf/audit-perf.mjs +4 -4
  8. package/scripts/perf/perf-findings.json +420 -0
  9. package/src/cli/adapters.js +10 -13
  10. package/src/cli/commands/doctor.js +15 -7
  11. package/src/cli/index.js +2 -2
  12. package/src/core/opencodeSteer.js +37 -0
  13. package/src/core/projectImportant.js +14 -8
  14. package/src/core/runInstallPipeline.js +10 -0
  15. package/src/core/runtimeConfig.js +36 -4
  16. package/src/core/status.js +6 -4
  17. package/src/manifest/selectItems.js +0 -1
  18. package/templates/.claude/agents/bug-debugger.md +1 -1
  19. package/templates/.claude/agents/feature-implementer.md +1 -1
  20. package/templates/.claude/agents/ukit-small-task-maintainer.md +2 -2
  21. package/templates/.claude/commands/ukit/handoff-create.md +4 -4
  22. package/templates/.claude/commands/ukit/handoff-fullstack.md +4 -4
  23. package/templates/.claude/commands/ukit/handoff-implement.md +2 -2
  24. package/templates/.claude/commands/ukit/handoff-review.md +2 -2
  25. package/templates/.claude/skills/update-status/SKILL.md +1 -1
  26. package/templates/.claude/ukit/index/route-task.mjs +7 -2
  27. package/templates/.codex/README.md +1 -1
  28. package/templates/.codex/settings.json +0 -1
  29. package/templates/.omp/agents/bug-debugger.md +1 -1
  30. package/templates/.omp/agents/feature-implementer.md +1 -1
  31. package/templates/.omp/agents/ukit-small-task-maintainer.md +2 -2
  32. package/templates/AGENTS.md +4 -13
  33. package/templates/CLAUDE.md +1 -3
  34. package/templates/adapter-presets/claude/settings.local.json +0 -1
  35. package/templates/docs/AI_HANDOFF/INDEX.md +1 -1
  36. package/templates/docs/AI_HANDOFF/RULES.md +2 -2
  37. package/templates/docs/PROJECT.md +1 -1
  38. package/templates/docs/UKIT_INTERNALS.md +1 -1
  39. package/templates/instructions/core.md +1 -3
  40. package/templates/instructions/layout.yaml +2 -4
  41. package/templates/instructions/overlays/agents.md +3 -10
  42. package/templates/ukit/storage/config.json +0 -10
  43. package/templates/adapter-presets/opencode/opencode.template.json +0 -1
@@ -19,16 +19,6 @@ export const OPTIONAL_ADAPTERS = [
19
19
  '.codex/agents',
20
20
  ],
21
21
  },
22
- {
23
- key: 'opencode',
24
- label: 'OpenCode',
25
- itemIds: [
26
- 'multi-opencode-config',
27
- ],
28
- managedPaths: [
29
- 'opencode.json',
30
- ],
31
- },
32
22
  {
33
23
  key: 'omp',
34
24
  label: 'Oh My Pi (omp)',
@@ -75,13 +65,11 @@ export const TOOL_ALIASES = new Map([
75
65
  ['claude-code', 'claude'],
76
66
  ['codex', 'codex'],
77
67
  ['openai-codex', 'codex'],
78
- ['opencode', 'opencode'],
79
- ['open-code', 'opencode'],
80
68
  ['omp', 'omp'],
81
69
  ['oh-my-pi', 'omp'],
82
70
  ]);
83
71
 
84
- export const TOOLS_FLAG_HELP = 'all|none|claude,codex,opencode,omp';
72
+ export const TOOLS_FLAG_HELP = 'all|none|claude,codex,omp';
85
73
 
86
74
  export function parseToolsArg(argv = []) {
87
75
  let toolsArg = null;
@@ -137,6 +125,15 @@ export function resolveOptionalToolKeys(toolsArg) {
137
125
  );
138
126
  }
139
127
 
128
+ // legacy: 'opencode'/'open-code' were adapters until the OpenCode lane was removed.
129
+ // Warn + ignore so `--tools=opencode` still exits 0 instead of hard-failing.
130
+ if (normalizedToken === 'opencode' || normalizedToken === 'open-code') {
131
+ console.warn(
132
+ `[UKit] '${token}' was removed as a UKit adapter — ignoring. Allowed: ${TOOLS_FLAG_HELP}`,
133
+ );
134
+ continue;
135
+ }
136
+
140
137
  const normalizedTool = TOOL_ALIASES.get(normalizedToken) ?? null;
141
138
  if (!normalizedTool) {
142
139
  throw new Error(`Unknown tool '${token}'. Allowed: ${TOOLS_FLAG_HELP}`);
@@ -24,6 +24,7 @@ import {
24
24
  } from '../../core/projectImportant.js';
25
25
  import { runDocContractChecks } from '../../core/docContracts.js';
26
26
  import { inspectUnattendedMode } from '../../core/unattendedDoctor.js';
27
+ import { findOpencodeArtifacts, opencodeSteerMessage } from '../../core/opencodeSteer.js';
27
28
 
28
29
  export const DOCTOR_HELP_FLAGS = new Set(['--help', '-h']);
29
30
  const KNOWN_FLAGS = new Set([...DOCTOR_HELP_FLAGS, '--skills', '--gateway', '--docs']);
@@ -203,13 +204,16 @@ export async function runDoctor({ packageRoot, projectRoot, argv = [], homeDir =
203
204
  remedy: INSTALL_REPAIR,
204
205
  });
205
206
  }
206
- if (piWiring.opencode.installed) {
207
+ // SPEC FR-007 — a leftover opencode.json is a WARN row: advisory only, never a
208
+ // FAIL, never auto-fixed. Removal is the user's manual action.
209
+ const opencodeArtifacts = findOpencodeArtifacts(projectRoot);
210
+ if (opencodeArtifacts.length > 0) {
207
211
  projectChecks.push({
208
- label: 'OpenCode fallback present (AGENTS.md owner-instructions section)',
209
- passed: piWiring.opencode.wired,
210
- failed: !piWiring.opencode.wired,
211
- remediationClass: 'install-repairable',
212
- remedy: INSTALL_REPAIR,
212
+ label: opencodeSteerMessage(opencodeArtifacts),
213
+ passed: true,
214
+ severity: 'warning',
215
+ remediationClass: 'advisory',
216
+ remedy: 'Remove it manually: rm opencode.json',
213
217
  });
214
218
  }
215
219
 
@@ -252,7 +256,11 @@ export async function runDoctor({ packageRoot, projectRoot, argv = [], homeDir =
252
256
  console.log('[UKit] Project rules checks:');
253
257
  for (const check of projectChecks) {
254
258
  if (check.applicable === false) continue;
255
- console.log(`[UKit] ${ok(check.passed)} ${check.label}`);
259
+ const severity = check.severity === 'warning' ? ' (warning)' : '';
260
+ console.log(`[UKit] ${ok(check.passed)} ${check.label}${severity}`);
261
+ if (check.remedy && check.severity === 'warning') {
262
+ console.log(`[UKit] remedy: ${check.remedy}`);
263
+ }
256
264
  }
257
265
 
258
266
  // TASK-011 / SPEC §8 (FR-007): unattended-mode checks — same remediation-class
package/src/cli/index.js CHANGED
@@ -117,8 +117,8 @@ export async function runCli({ argv, packageRoot, projectRoot, packageVersion })
117
117
  console.log('');
118
118
  console.log('Options (install / diff):');
119
119
  console.log(' --tools=<list> Comma-separated adapters to enable (default: all)');
120
- console.log(' Values: claude, codex, opencode, omp');
121
- console.log(' Example: ukit install --tools=claude,codex,opencode,omp');
120
+ console.log(' Values: claude, codex, omp');
121
+ console.log(' Example: ukit install --tools=claude,codex,omp');
122
122
  console.log(' Use --tools=none to disable all optional adapters');
123
123
  console.log(' --with-codegraph Enable CodeGraph MCP integration in CLAUDE.md');
124
124
  console.log(' Adds routing rules that prefer codegraph_* tools for');
@@ -0,0 +1,37 @@
1
+ // SPEC FR-004 — OpenCode support was removed. Any leftover artifact is a user
2
+ // file: UKit never installs, repairs, merges, or deletes it (only `ukit
3
+ // uninstall` may). This helper is the single source of truth for detection and
4
+ // the canonical steer message shared by projectImportant, status, and doctor.
5
+
6
+ import { existsSync } from 'node:fs';
7
+ import path from 'node:path';
8
+
9
+ // Extensible list — detection is one existsSync per known filename, no parsing.
10
+ const OPENCODE_ARTIFACT_NAMES = ['opencode.json'];
11
+
12
+ /**
13
+ * @param {string} projectRoot
14
+ * @returns {string[]} absolute paths of detected OpenCode artifacts
15
+ */
16
+ export function findOpencodeArtifacts(projectRoot) {
17
+ return OPENCODE_ARTIFACT_NAMES
18
+ .map((name) => path.join(projectRoot, name))
19
+ .filter((candidate) => existsSync(candidate));
20
+ }
21
+
22
+ /**
23
+ * Canonical steer copy. Callers must print this verbatim so every surface
24
+ * (status line, doctor WARN row, stderr warning) reads identically.
25
+ *
26
+ * @param {string[]} paths detected artifact paths from findOpencodeArtifacts
27
+ * @returns {string}
28
+ */
29
+ export function opencodeSteerMessage(paths = []) {
30
+ const names = (Array.isArray(paths) ? paths : [])
31
+ .map((entry) => path.basename(String(entry)))
32
+ .filter(Boolean);
33
+ const fileList = names.length > 0 ? names.join(' ') : 'opencode.json';
34
+ return `[ukit] ${fileList} detected — OpenCode is no longer supported. `
35
+ + `ukit will not install, repair, or merge this file. `
36
+ + `Remove it manually: rm ${fileList}`;
37
+ }
@@ -25,6 +25,7 @@ import {
25
25
  isSensitiveDataGateEnabled,
26
26
  loadSensitiveAllowlist,
27
27
  } from './sensitiveValueScanner.js';
28
+ import { findOpencodeArtifacts, opencodeSteerMessage } from './opencodeSteer.js';
28
29
 
29
30
  export const PROJECT_IMPORTANT_FILENAME = 'PROJECT_IMPORTANT.md';
30
31
  export const PROJECT_IMPORTANT_CODEPOINT_LIMIT = 6000;
@@ -338,12 +339,14 @@ export async function renderProjectImportantForProject(projectRoot, options = {}
338
339
  * TASK-044 — adapter wiring facts for status/doctor (spec §13/§14).
339
340
  *
340
341
  * Returns install + wiring facts only — never file bodies. Claude wiring is
341
- * always expected; omp/Codex/OpenCode are checked only when installed, and an
342
- * absent adapter is `installed:false`, never a failure.
342
+ * always expected; omp/Codex are checked only when installed, and an
343
+ * absent adapter is `installed:false`, never a failure. A leftover
344
+ * `opencode.json` is no longer an adapter signal — it is detected and
345
+ * reported via `opencodeArtifacts` + a steer warning, never wired.
343
346
  *
344
347
  * @param {string} projectRoot
345
348
  * @param {{ trackedPaths?: string[] }} [options] install.json file list, if known
346
- * @returns {Promise<{claude: object, omp: object, codex: object, opencode: object, agentsFallback: boolean}>}
349
+ * @returns {Promise<{claude: object, omp: object, codex: object, opencodeArtifacts: string[], agentsFallback: boolean}>}
347
350
  */
348
351
  export async function inspectProjectImportantWiring(projectRoot, options = {}) {
349
352
  const trackedPaths = Array.isArray(options.trackedPaths) ? options.trackedPaths : [];
@@ -397,7 +400,7 @@ export async function inspectProjectImportantWiring(projectRoot, options = {}) {
397
400
  wired: runtimeModule && hookInstalled && hookExecutable && settingsWired,
398
401
  };
399
402
 
400
- // --- AGENTS.md owner-instructions pointer (shared Codex/OpenCode fallback) ---
403
+ // --- AGENTS.md owner-instructions pointer (shared Codex fallback) ---
401
404
  let agentsFallback = false;
402
405
  try {
403
406
  const agents = await readFile(agentsPath, 'utf8');
@@ -425,9 +428,12 @@ export async function inspectProjectImportantWiring(projectRoot, options = {}) {
425
428
  const codexInstalled = tracked('.codex/') || await exists(path.join(projectRoot, '.codex', 'settings.json'));
426
429
  const codex = { installed: codexInstalled, wired: codexInstalled && agentsFallback };
427
430
 
428
- // --- OpenCode fallback (only when opencode.json tracked/installed) ---
429
- const opencodeInstalled = tracked('opencode.json') || await exists(path.join(projectRoot, 'opencode.json'));
430
- const opencode = { installed: opencodeInstalled, wired: opencodeInstalled && agentsFallback };
431
+ // --- OpenCode steer (SPEC FR-005) — a leftover opencode.json is a user file:
432
+ // never wired, never installed/repaired. Detect it and steer toward removal.
433
+ const opencodeArtifacts = findOpencodeArtifacts(projectRoot);
434
+ if (opencodeArtifacts.length > 0) {
435
+ console.warn(opencodeSteerMessage(opencodeArtifacts));
436
+ }
431
437
 
432
- return { claude, omp, codex, opencode, agentsFallback };
438
+ return { claude, omp, codex, opencodeArtifacts, agentsFallback };
433
439
  }
@@ -15,6 +15,7 @@ import { ensureGitignore } from './ensureGitignore.js';
15
15
  import { repairBrokenHooks } from './repairBrokenHooks.js';
16
16
  import { applyGatewayResilienceEnv } from './gatewayResilienceEnv.js';
17
17
  import { cleanupEmptyParents, readJsonIfExists, removeFileOrLinkOnly, resolveProjectRelativePath } from './fileOps.js';
18
+ import { findOpencodeArtifacts, opencodeSteerMessage } from './opencodeSteer.js';
18
19
 
19
20
  const AUTO_PRUNE_OBSOLETE_PREFIXES = [
20
21
  '.claude/skills/',
@@ -261,6 +262,15 @@ export async function runInstallPipeline({
261
262
  const installMetaData = await readJsonIfExists(pathConfig.installMetaPath);
262
263
  const isReinstall = Boolean(installMetaData?.tool === 'ukit');
263
264
 
265
+ // SPEC FR-004/§security — a leftover opencode.json is a user file: detect and
266
+ // steer toward manual removal. Install never writes, merges, repairs, or
267
+ // deletes it (obsolete-path pruning excludes it; only `ukit uninstall` may
268
+ // remove it).
269
+ const opencodeArtifacts = findOpencodeArtifacts(pathConfig.projectRoot);
270
+ if (opencodeArtifacts.length > 0) {
271
+ console.warn(opencodeSteerMessage(opencodeArtifacts));
272
+ }
273
+
264
274
  if (isReinstall && !dryRun) {
265
275
  await migrateLegacyRuntimeRoot(pathConfig.projectRoot);
266
276
  }
@@ -9,8 +9,10 @@ const require = createRequire(import.meta.url);
9
9
  const { version: PACKAGE_VERSION } = require('../../package.json');
10
10
 
11
11
  // legacy: 'antigravity' stays valid — Antigravity adapter removed in v2.2.0, but an existing
12
- // config.json naming it must not become invalid.
13
- const VALID_AGENTS = new Set(['claude-code', 'codex', 'antigravity', 'opencode', 'omp']);
12
+ // config.json naming it must not become invalid. 'opencode' is NOT kept valid here: the
13
+ // OpenCode lane was removed this cycle, so stale 'opencode' values are normalized away
14
+ // (strip + console.warn) in normalizeLegacyOpencodeEntries instead of hard-failing.
15
+ const VALID_AGENTS = new Set(['claude-code', 'codex', 'antigravity', 'omp']);
14
16
 
15
17
  // Reserved permission modes for orchestration.permissionMode (single source of truth).
16
18
  // 'unattended' is the only mode implemented this cycle; interactive/safe-auto are reserved.
@@ -90,7 +92,6 @@ export function buildDefaultRuntimeConfig(overrides = {}) {
90
92
  mustNotBlockMainTask: true,
91
93
  targets: {
92
94
  claude: { autoCompact: true, mode: 'precompact-reinject', preserveExistingHooks: true },
93
- opencode: { autoCompact: true, mode: 'native-auto-prune', preserveExistingCompaction: true },
94
95
  // 'precompact-reinject' like claude, NOT codex's 'soft-handoff': omp exposes real
95
96
  // pre-compaction hook events, so there is nothing to work around with a state file.
96
97
  omp: { autoCompact: true, mode: 'precompact-reinject', preserveExistingHooks: true },
@@ -653,6 +654,37 @@ export function validateRuntimeConfig(config) {
653
654
  };
654
655
  }
655
656
 
657
+ // OpenCode was removed as an adapter this cycle. Stale 'opencode' values inside
658
+ // validated agent lists/keys are stripped with a steer warning — never a hard-fail —
659
+ // so an old config.json still loads instead of falling back to defaults.
660
+ function normalizeLegacyOpencodeEntries(config) {
661
+ const warned = { value: false };
662
+ const warnOnce = () => {
663
+ if (!warned.value) {
664
+ console.warn(`[UKit] Removed stale 'opencode' agent entries from UKit runtime config — OpenCode is no longer supported.`);
665
+ warned.value = true;
666
+ }
667
+ };
668
+
669
+ if (isPlainObject(config) && config.agent === 'opencode') {
670
+ warnOnce();
671
+ config.agent = 'claude-code';
672
+ }
673
+
674
+ if (isPlainObject(config) && Array.isArray(config.agents) && config.agents.includes('opencode')) {
675
+ warnOnce();
676
+ config.agents = config.agents.filter((agent) => agent !== 'opencode');
677
+ }
678
+
679
+ const targets = config?.compact?.agentContext?.targets;
680
+ if (isPlainObject(targets) && 'opencode' in targets) {
681
+ warnOnce();
682
+ delete targets.opencode;
683
+ }
684
+
685
+ return config;
686
+ }
687
+
656
688
  export async function inspectRuntimeConfig(projectRoot) {
657
689
  const runtimePaths = buildRuntimePaths(projectRoot);
658
690
  let exists = false;
@@ -670,7 +702,7 @@ export async function inspectRuntimeConfig(projectRoot) {
670
702
  }
671
703
  }
672
704
 
673
- const config = buildDefaultRuntimeConfig(rawConfig ?? {});
705
+ const config = normalizeLegacyOpencodeEntries(buildDefaultRuntimeConfig(rawConfig ?? {}));
674
706
  const validation = validateRuntimeConfig(config);
675
707
  const errors = [
676
708
  ...(parseError ? [`config.json parse error: ${parseError}`] : []),
@@ -8,13 +8,13 @@ import { countMemoryItems } from './memory/store.js';
8
8
  import { buildCompactPressureState } from './compact/threshold.js';
9
9
  import { detectProjectContext } from '../context/detectProjectContext.js';
10
10
  import { inspectProjectImportant, inspectProjectImportantWiring } from './projectImportant.js';
11
+ import { opencodeSteerMessage } from './opencodeSteer.js';
11
12
 
12
13
  function formatPrimaryAgent(agentKey) {
13
14
  if (agentKey === 'claude-code') return 'Claude Code';
14
15
  if (agentKey === 'codex') return 'OpenAI Codex';
15
16
  // legacy: Antigravity adapter removed in this release; existing config.json may still name it
16
17
  if (agentKey === 'antigravity') return 'Antigravity';
17
- if (agentKey === 'opencode') return 'OpenCode';
18
18
  if (agentKey === 'omp') return 'Oh My Pi (omp)';
19
19
  return agentKey || 'Unknown';
20
20
  }
@@ -24,7 +24,6 @@ async function detectAdapterLabels(projectRoot, primaryAgent) {
24
24
 
25
25
  const checks = [
26
26
  { label: 'OpenAI Codex', path: '.codex/settings.json' },
27
- { label: 'OpenCode', path: 'opencode.json' },
28
27
  { label: 'Oh My Pi (omp)', path: '.omp/config.yml' },
29
28
  ];
30
29
 
@@ -171,8 +170,11 @@ export async function buildStatusReport(projectRoot) {
171
170
  claude: piWiring.claude.wired,
172
171
  omp: piWiring.omp.installed ? piWiring.omp.wired : undefined,
173
172
  codex: piWiring.codex.installed ? piWiring.codex.wired : undefined,
174
- opencode: piWiring.opencode.installed ? piWiring.opencode.wired : undefined,
175
173
  },
174
+ // SPEC FR-006 — leftover opencode.json is a user file: steer, never wire.
175
+ opencodeSteer: piWiring.opencodeArtifacts.length > 0
176
+ ? opencodeSteerMessage(piWiring.opencodeArtifacts)
177
+ : null,
176
178
  };
177
179
 
178
180
  return {
@@ -226,7 +228,6 @@ function formatProjectImportantWiring(pi) {
226
228
  const parts = [`Claude runtime ${mark(pi.wiring.claude)}`];
227
229
  if (pi.wiring.omp !== undefined) parts.push(`omp runtime ${mark(pi.wiring.omp)}`);
228
230
  if (pi.wiring.codex !== undefined) parts.push(`Codex fallback ${mark(pi.wiring.codex)}`);
229
- if (pi.wiring.opencode !== undefined) parts.push(`OpenCode fallback ${mark(pi.wiring.opencode)}`);
230
231
  return parts.join(' / ');
231
232
  }
232
233
 
@@ -237,6 +238,7 @@ export function formatStatusReport(report) {
237
238
  `${padLabel('Project')} ${report.projectName}`,
238
239
  `${padLabel('Project rules')} ${formatProjectImportantRules(report.projectImportant)}`,
239
240
  `${padLabel('Rule wiring')} ${formatProjectImportantWiring(report.projectImportant)}`,
241
+ ...(report.projectImportant.opencodeSteer ? [report.projectImportant.opencodeSteer] : []),
240
242
  `${padLabel('Adapters')} ${report.adapters.join(', ')}`,
241
243
  `${padLabel('Memory items')} ${report.memoryCounts.projectCount} project / ${report.memoryCounts.sessionCount} session / ${report.memoryCounts.userCount} user`,
242
244
  `${padLabel('Last compact')} ${report.lastCompact}`,
@@ -5,7 +5,6 @@ export const OPTIONAL_ADAPTER_ITEM_IDS = new Set([
5
5
  'multi-codex-settings-json',
6
6
  'multi-codex-settings-local',
7
7
  'multi-codex-agents-link',
8
- 'multi-opencode-config',
9
8
  'multi-omp-agents-md',
10
9
  'multi-omp-rules',
11
10
  'multi-omp-config',
@@ -50,7 +50,7 @@ Systematic debugging — understand before fixing.
50
50
 
51
51
  ```
52
52
  STATUS: DONE | BLOCKED | PARTIAL
53
- EXECUTOR_TOOL: [claude-code | kilo-code | codex | opencode | other]
53
+ EXECUTOR_TOOL: [claude-code | kilo-code | codex | other]
54
54
  EXECUTOR_MODEL: [exact model name you are running as. "unknown" if you cannot tell.]
55
55
  EXECUTOR_SUBAGENT: [subagent name within your host, if any, else "-"]
56
56
  SUMMARY: [1-2 sentences — root cause and fix]
@@ -72,7 +72,7 @@ and even then, report it, don't ask about it.
72
72
 
73
73
  ```
74
74
  STATUS: DONE | BLOCKED | PARTIAL
75
- EXECUTOR_TOOL: [claude-code | kilo-code | codex | opencode | other]
75
+ EXECUTOR_TOOL: [claude-code | kilo-code | codex | other]
76
76
  EXECUTOR_MODEL: [exact model name you are running as — e.g. unic-code, claude-sonnet-4-5, gpt-5-mini. If you truly cannot tell, write "unknown" — reviewer treats unknown as suspicious and asks the human to confirm.]
77
77
  EXECUTOR_SUBAGENT: [name of the subagent you are, if your host has multiple — e.g. "Kilo:code", "Claude:feature-implementer". Otherwise "-".]
78
78
  SUMMARY: [1-2 sentences of what was implemented]
@@ -24,7 +24,7 @@ You are UKit's internal small-task maintainer. You run as a sidecar/parallel/non
24
24
  - Summarizing `docs/STATUS.md`, `docs/TASKS.md`, `docs/WORKLOG.md`, or memory snippets into compact handoff notes.
25
25
  - Deciding fast vs slow lane, safe vs risky lane, whether a skill should be activated, and whether the current prompt has enough steps planned.
26
26
  - Choosing compact-now vs compact-later and summarize-vs-keep-detail for UKit context hygiene.
27
- - Keeping agent context compact without removing existing lanes: Claude PreCompact/reinject stays active, OpenCode native auto/prune compaction stays active, and Codex Desktop soft handoffs use `compact.codexContext.compactTarget` (default 150 lines; preferred 120-150; hard max 170) while preserving critical state.
27
+ - Keeping agent context compact without removing existing lanes: Claude PreCompact/reinject stays active and Codex Desktop soft handoffs use `compact.codexContext.compactTarget` (default 150 lines; preferred 120-150; hard max 170) while preserving critical state.
28
28
  - Small, reversible UKit runtime maintenance decisions.
29
29
 
30
30
  ## Never Use For
@@ -45,7 +45,7 @@ You are UKit's internal small-task maintainer. You run as a sidecar/parallel/non
45
45
  5. If safe, make the smallest cleanup/summary/classification/routing decision.
46
46
  6. Follow the CoDev priority order: output quality first, then safety, then speed, then token discipline. Spend tokens/steps when they protect correctness.
47
47
  7. Use small step budgets: trivial = 1 step, simple = up to 2 steps, non-trivial = up to 4 planned steps before the main model reassesses.
48
- 8. For long sessions, preserve existing Claude/OpenCode auto-compact behavior; for Codex Desktop, target a compact handoff of about 120-150 lines, never above 170 lines for this lane, not a full transcript replay.
48
+ 8. For long sessions, preserve existing Claude auto-compact behavior; for Codex Desktop, target a compact handoff of about 120-150 lines, never above 170 lines for this lane, not a full transcript replay.
49
49
  9. Preserve user-owned content; do not delete unclear tasks.
50
50
  10. Report exactly what changed or what decision was made.
51
51
 
@@ -1,7 +1,7 @@
1
1
  # /ukit:handoff-create — Phase 1 + 2: Plan
2
2
 
3
3
  **Role: PLANNER**
4
- **Tool: any** (Claude Code / Codex / omp / Kilo / OpenCode — your choice)
4
+ **Tool: any** (Claude Code / Codex / omp / Kilo — your choice)
5
5
  **Model split:**
6
6
  - Read/understand → lite model (haiku · unic-lite · cheapest available)
7
7
  - Write plan + tasks → strong model (Opus · unic-smart · strongest available)
@@ -49,7 +49,7 @@ After the batched call, run Steps 1–2.5 to completion without further question
49
49
  4. Read `docs/AI_HANDOFF/tasks/_TEMPLATE.md` → task file structure
50
50
  5. Return a compact summary. Do NOT write anything yet.
51
51
 
52
- > **For the human operator, on a tool with no agent support (Codex, OpenCode) — not an instruction to the model:** manually switch to the lite model, run the steps above yourself, keep the summary in context.
52
+ > **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the lite model, run the steps above yourself, keep the summary in context.
53
53
 
54
54
  ---
55
55
 
@@ -122,7 +122,7 @@ The planner agent does the following (use Step 1 summary — do NOT re-read file
122
122
 
123
123
  8. Report: task IDs, dependency graph, any `needs_breakdown` + reason
124
124
 
125
- > **For the human operator, on a tool with no agent support (Codex, OpenCode) — not an instruction to the model:** manually switch to the strong model, execute steps 1–7 above yourself.
125
+ > **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the strong model, execute steps 1–7 above yourself.
126
126
 
127
127
  ---
128
128
 
@@ -143,7 +143,7 @@ intact. What it no longer does is hand a stalled plan back and wait.
143
143
  2. `Issues Found` → route back to Step 2: planner revises `PLAN.md` and the affected `TASK-xxx.md` files to address every finding, then re-submit for another Step 2.5 review (this becomes the next round). Do NOT commit or hand off to executor on `Issues Found`.
144
144
  3. `Approved` → append `PLAN_REVIEW: Approved by <reviewer model>` to PLAN.md's `## Planner Report` footer, then proceed.
145
145
 
146
- > **For the human operator, on a tool with no agent support (Codex, OpenCode) — not an instruction to the model:** manually switch to the strong model in a **separate** chat/session from Step 2, paste PLAN.md, review using the Spec/Plan Review checklist in `.claude/agents/code-reviewer.md`.
146
+ > **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the strong model in a **separate** chat/session from Step 2, paste PLAN.md, review using the Spec/Plan Review checklist in `.claude/agents/code-reviewer.md`.
147
147
 
148
148
  ---
149
149
 
@@ -1,7 +1,7 @@
1
1
  # /ukit:handoff-fullstack — Full Pipeline: Plan → Implement → Review
2
2
 
3
3
  **Role: ORCHESTRATOR**
4
- **Tool: any** (Claude Code / Codex / omp / Kilo / OpenCode — your choice)
4
+ **Tool: any** (Claude Code / Codex / omp / Kilo — your choice)
5
5
 
6
6
  ## Model Split
7
7
 
@@ -186,7 +186,7 @@ counter and starts a new cycle automatically.
186
186
 
187
187
  Return a compact summary. Do NOT write any files yet.
188
188
 
189
- > **For the human operator, on a tool with no agent support (Codex, OpenCode) — not an instruction to the model:** manually switch to the lite model and run P1 yourself.
189
+ > **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the lite model and run P1 yourself.
190
190
 
191
191
  ### P2 — Write PLAN.md + task files (strong model)
192
192
 
@@ -270,7 +270,7 @@ is written. What it no longer does is hand a stalled plan back to a human who is
270
270
  2. `Issues Found` → route back to P2: `handoff-planner` revises `PLAN.md` and the affected `TASK-xxx.md` files to address every finding, then re-submit for one more P2.5 review round — subject to the loop cap above.
271
271
  3. `Approved` → append `PLAN_REVIEW: Approved by <reviewer model>` to PLAN.md's `## Planner Report` footer, then proceed to P3.
272
272
 
273
- > **For the human operator, on a tool with no agent support (Codex, OpenCode) — not an instruction to the model:** manually switch to the strong model in a **separate** chat/session from P2, paste PLAN.md, review using the Spec/Plan Review checklist in `.claude/agents/code-reviewer.md`.
273
+ > **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the strong model in a **separate** chat/session from P2, paste PLAN.md, review using the Spec/Plan Review checklist in `.claude/agents/code-reviewer.md`.
274
274
 
275
275
  ### P3 — Commit the plan (lite model)
276
276
 
@@ -281,7 +281,7 @@ git add docs/AI_HANDOFF/ && git commit -m "handoff: plan — <goal>"
281
281
 
282
282
  Replace `<goal>` with the one-sentence goal from ACTIVE.md. This locks the plan in git before any implementation begins.
283
283
 
284
- > **For the human operator, on a tool with no agent support (Codex, OpenCode) — not an instruction to the model:** manually switch to the lite model for P2/P3.
284
+ > **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the lite model for P2/P3.
285
285
 
286
286
  ---
287
287
 
@@ -1,7 +1,7 @@
1
1
  # /ukit:handoff-implement — Phase 3: Execute
2
2
 
3
3
  **Role: EXECUTOR (orchestrated)**
4
- **Tool: any** (Claude Code / Codex / omp / Kilo / OpenCode — your choice)
4
+ **Tool: any** (Claude Code / Codex / omp / Kilo — your choice)
5
5
  **Model: code model** (Sonnet · unic-code · cheap-smart)
6
6
 
7
7
  > **omp model tiers:** the tiers above map to `.omp/config.yml`'s `modelRoles`, referenced from agent frontmatter as `@smol` / `@default` / `@slow`.
@@ -170,7 +170,7 @@ disk in the task file, which is where the reviewer reads them from. Pasting them
170
170
  second time is what blows up the orchestrator's context window and kills the run mid-wave.
171
171
  ```
172
172
 
173
- > **For the human operator, on a tool with no agent support (Codex, OpenCode) — not an instruction to the model:** open each task in a separate session with the code model.
173
+ > **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** open each task in a separate session with the code model.
174
174
 
175
175
  ### 3c — Orchestrator: copy changes to main + IMMEDIATELY delete worktree
176
176
 
@@ -1,7 +1,7 @@
1
1
  # /ukit:handoff-review — Phase 4: Review
2
2
 
3
3
  **Role: REVIEWER**
4
- **Tool: any** (Claude Code / Codex / omp / Kilo / OpenCode — your choice)
4
+ **Tool: any** (Claude Code / Codex / omp / Kilo — your choice)
5
5
  **Model: strong model, MUST differ from executor** (Opus · unic-smart · strongest available)
6
6
 
7
7
  > **omp model tiers:** the tiers above map to `.omp/config.yml`'s `modelRoles`, referenced from agent frontmatter as `@smol` / `@default` / `@slow`.
@@ -191,4 +191,4 @@ This is the only place this command may ask for a compaction. All state lives in
191
191
  `INDEX.md` and `RUN.md`, so a compacted or fresh session resumes with nothing lost.
192
192
 
193
193
  > Orchestrator (this session) handles Step 1, 2e, and 3 directly — those are not delegated.
194
- > **For the human operator, on a tool with no agent support (Codex, OpenCode) — not an instruction to the model:** manually switch to the strong model, run 2a–2d per task (one session at a time).
194
+ > **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the strong model, run 2a–2d per task (one session at a time).
@@ -48,7 +48,7 @@ When updating meaningful state, update the header:
48
48
  ## Freshness
49
49
 
50
50
  - Last meaningful update: YYYY-MM-DD HH:mm
51
- - Updated by: Claude / Codex / OpenCode / human
51
+ - Updated by: Claude / Codex / human
52
52
  - Status confidence: high / medium / low
53
53
  - Stale after: 72h
54
54
  ```
@@ -816,7 +816,12 @@ async function main() {
816
816
  const lastPrompt = readFlagValue(args, '--last-prompt')
817
817
  ?? previousState?.routingContext?.lastExplicitUserPromptText
818
818
  ?? '';
819
- const adapter = readFlagValue(args, '--adapter') ?? inferAdapterFromInvocation(process.argv[1] || '');
819
+ const KNOWN_ADAPTERS = new Set(['claude', 'codex', 'antigravity']);
820
+ const rawAdapter = readFlagValue(args, '--adapter') ?? inferAdapterFromInvocation(process.argv[1] || '');
821
+ const adapter = KNOWN_ADAPTERS.has(rawAdapter) ? rawAdapter : 'claude';
822
+ if (rawAdapter !== adapter) {
823
+ console.error(`route-task: unknown --adapter "${rawAdapter}" — falling back to claude`);
824
+ }
820
825
  const commandNamespace = adapter === 'codex'
821
826
  ? '.codex'
822
827
  : (adapter === 'antigravity' ? '.antigravity' : '.claude');
@@ -826,7 +831,7 @@ async function main() {
826
831
  .trim();
827
832
 
828
833
  if (!promptText && !commandText && !targetFile) {
829
- console.error('Usage: node .codex/ukit/index/route-task.mjs "<prompt>" [--tool-command <cmd>] [--target <file>] [--type trivial|simple|non-trivial] [--session-id <id>] [--adapter codex|claude|antigravity|opencode]');
834
+ console.error('Usage: node .codex/ukit/index/route-task.mjs "<prompt>" [--tool-command <cmd>] [--target <file>] [--type trivial|simple|non-trivial] [--session-id <id>] [--adapter codex|claude|antigravity]');
830
835
  process.exitCode = 1;
831
836
  return;
832
837
  }
@@ -8,7 +8,7 @@ Auto-generated by UKit for OpenAI Codex.
8
8
  ## Core UKit Rule
9
9
 
10
10
  - Human-facing workflow should optimize for one remembered command: `ukit install`.
11
- - After install, normal work should feel natural inside **Claude/Codex/OpenCode/omp**.
11
+ - After install, normal work should feel natural inside **Claude/Codex/omp**.
12
12
  - **Quality first, then speed, then token discipline**: do not waste reads, logs, or repeated helper output.
13
13
  - **Never stop after read-only steps.** For implement/apply/fix requests, continue to actual Edit/Write and verification in the same turn.
14
14
 
@@ -233,7 +233,6 @@
233
233
  },
234
234
  "agentContext": {
235
235
  "preserveClaudePreCompact": true,
236
- "preserveOpenCodeCompaction": true,
237
236
  "codexSoftHandoff": {
238
237
  "autoCompact": true,
239
238
  "budgetTokens": 100000,
@@ -49,7 +49,7 @@ Systematic debugging — understand before fixing.
49
49
 
50
50
  ```
51
51
  STATUS: DONE | BLOCKED | PARTIAL
52
- EXECUTOR_TOOL: [claude-code | kilo-code | codex | opencode | other]
52
+ EXECUTOR_TOOL: [claude-code | kilo-code | codex | other]
53
53
  EXECUTOR_MODEL: [exact model name you are running as. "unknown" if you cannot tell.]
54
54
  EXECUTOR_SUBAGENT: [subagent name within your host, if any, else "-"]
55
55
  SUMMARY: [1-2 sentences — root cause and fix]
@@ -71,7 +71,7 @@ and even then, report it, don't ask about it.
71
71
 
72
72
  ```
73
73
  STATUS: DONE | BLOCKED | PARTIAL
74
- EXECUTOR_TOOL: [claude-code | kilo-code | codex | opencode | other]
74
+ EXECUTOR_TOOL: [claude-code | kilo-code | codex | other]
75
75
  EXECUTOR_MODEL: [exact model name you are running as — e.g. unic-code, claude-sonnet-4-5, gpt-5-mini. If you truly cannot tell, write "unknown" — reviewer treats unknown as suspicious and asks the human to confirm.]
76
76
  EXECUTOR_SUBAGENT: [name of the subagent you are, if your host has multiple — e.g. "Kilo:code", "Claude:feature-implementer". Otherwise "-".]
77
77
  SUMMARY: [1-2 sentences of what was implemented]
@@ -24,7 +24,7 @@ You are UKit's internal small-task maintainer. You run as a sidecar/parallel/non
24
24
  - Summarizing `docs/STATUS.md`, `docs/TASKS.md`, `docs/WORKLOG.md`, or memory snippets into compact handoff notes.
25
25
  - Deciding fast vs slow lane, safe vs risky lane, whether a skill should be activated, and whether the current prompt has enough steps planned.
26
26
  - Choosing compact-now vs compact-later and summarize-vs-keep-detail for UKit context hygiene.
27
- - Keeping agent context compact without removing existing lanes: Claude PreCompact/reinject stays active, OpenCode native auto/prune compaction stays active, and Codex Desktop soft handoffs use `compact.codexContext.compactTarget` (default 150 lines; preferred 120-150; hard max 170) while preserving critical state.
27
+ - Keeping agent context compact without removing existing lanes: Claude PreCompact/reinject stays active and Codex Desktop soft handoffs use `compact.codexContext.compactTarget` (default 150 lines; preferred 120-150; hard max 170) while preserving critical state.
28
28
  - Small, reversible UKit runtime maintenance decisions.
29
29
 
30
30
  ## Never Use For
@@ -45,7 +45,7 @@ You are UKit's internal small-task maintainer. You run as a sidecar/parallel/non
45
45
  5. If safe, make the smallest cleanup/summary/classification/routing decision.
46
46
  6. Follow the CoDev priority order: output quality first, then safety, then speed, then token discipline. Spend tokens/steps when they protect correctness.
47
47
  7. Use small step budgets: trivial = 1 step, simple = up to 2 steps, non-trivial = up to 4 planned steps before the main model reassesses.
48
- 8. For long sessions, preserve existing Claude/OpenCode auto-compact behavior; for Codex Desktop, target a compact handoff of about 120-150 lines, never above 170 lines for this lane, not a full transcript replay.
48
+ 8. For long sessions, preserve existing Claude auto-compact behavior; for Codex Desktop, target a compact handoff of about 120-150 lines, never above 170 lines for this lane, not a full transcript replay.
49
49
  9. Preserve user-owned content; do not delete unclear tasks.
50
50
  10. Report exactly what changed or what decision was made.
51
51
 
@@ -4,7 +4,7 @@
4
4
  ## Core Rule
5
5
  <!-- RULES: CORE-01 CORE-02 -->
6
6
  - Human-facing UKit workflow collapses to one remembered command: `ukit install`.
7
- - After install, default to natural-language work inside **Claude Code / Codex / OpenCode / omp**.
7
+ - After install, default to natural-language work inside **Claude Code / Codex / omp**.
8
8
  - **Quality first, then speed, then token discipline.**
9
9
  - **Never stop after read-only steps** — implement/apply/fix requests continue to Edit/Write + verification in the same turn.
10
10
 
@@ -140,25 +140,16 @@ CHỈ kích hoạt khi task đi qua `docs/AI_HANDOFF/` (user nói "execute task
140
140
  - Contract map: `tiny-fix` → lite · `local-fix`, `local-build`, `shared-edit`, `find-cause`, `map-impact` → code · `review-release` → smart. Escalation: same file/symbol failing `debugLoopThreshold` (default 2) times routes the next attempt one tier higher, capped at `smart`.
141
141
  - `unic-vision` is a capability lane, not a cost tier — unverified vision must never guess image contents; route images to `ukit-vision-analyst`. Harness table: `docs/UKIT_INTERNALS.md`.
142
142
 
143
- ## Session Start — OpenCode
143
+ ## Project Owner Instructions — Codex
144
144
 
145
- <!-- RULE: HOST-OC-01 -->
146
- At the start of every OpenCode session, before working on the first task:
147
- 1. Reuse matching route hints from `.claude/ukit/skill-router-state.json`; scan `.claude/skills/` (listing only) and read a SKILL.md only when a task triggers it.
148
- 2. For every non-trivial task, run `/ukit-route <task summary>` for skill + context hints **before** writing code; if it names a skill, read that SKILL.md — do not skip. When `router.enabled: true` in `.ukit/storage/config.json`, prefer router output over guessing; treat it as internal continuation — continue to edit/verify, don't stop.
149
-
150
- ## Project Owner Instructions — Codex and OpenCode
151
-
152
- When running in Codex or OpenCode, read and follow the root
145
+ When running in Codex, read and follow the root
153
146
  `PROJECT_IMPORTANT.md` before doing project work. It is the canonical
154
147
  project-owner instruction source. Do not copy its contents into this file.
155
148
  If it is missing or unreadable, state that limitation and continue with the
156
149
  remaining project instructions.
157
- <!-- RULES: OWN-01 HOST-OWN-01 -->
150
+ <!-- RULE: OWN-01 -->
158
151
  ## Skills
159
152
  - Canonical skills live in `.claude/skills/`; adapter mirrors may exist (`.codex/skills/` → symlink). **omp** reads `.claude/skills/` via its `claude` discovery provider.
160
- - **OpenCode**: reads `AGENTS.md` at session start only — it does NOT auto-load skills; the model must explicitly read the triggered SKILL.md.
161
- - `ukit-*` commands in `opencode.json` are internal helper entrypoints — never ask end users to run them.
162
153
 
163
154
  ## Project Snapshot
164
155
  - Project: {{project.name}} | Root: {{project.root}}