oh-my-opencode 5.0.0-beta.79 → 5.0.0-beta.80

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 (96) hide show
  1. package/.agents/command/remove-deadcode.md +1 -1
  2. package/.agents/skills/hyperplan/SKILL.md +5 -5
  3. package/.agents/skills/remove-deadcode/SKILL.md +1 -1
  4. package/.agents/skills/security-research/SKILL.md +4 -4
  5. package/dist/cli/index.js +499 -336
  6. package/dist/cli-node/index.js +499 -336
  7. package/dist/config-migration/category-deep-split.d.ts +3 -0
  8. package/dist/config-migration/migration-plans.d.ts +1 -0
  9. package/dist/features/builtin-commands/templates/hyperplan.d.ts +1 -1
  10. package/dist/features/builtin-commands/templates/refactor-sections/team-mode-addendum.d.ts +1 -1
  11. package/dist/features/builtin-commands/templates/remove-ai-slops.d.ts +1 -1
  12. package/dist/index.js +282 -123
  13. package/dist/plugin-config/omo-config-chain.d.ts +1 -0
  14. package/dist/skills/debugging/references/methodology/02-investigate.md +5 -5
  15. package/dist/skills/refactor/SKILL.md +2 -2
  16. package/dist/skills/remove-ai-slops/SKILL.md +4 -4
  17. package/dist/skills/ulw-execute/SKILL.md +3 -2
  18. package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
  19. package/dist/skills/ulw-research/SKILL.md +2 -2
  20. package/dist/tools/delegate-task/openai-categories.d.ts +6 -4
  21. package/dist/tui.js +146 -71
  22. package/package.json +14 -14
  23. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  24. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +77 -8
  25. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  26. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  27. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  28. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  30. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  31. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  32. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  33. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  34. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  35. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  36. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  37. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  38. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  39. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  40. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +63 -17
  41. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +63 -17
  42. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  43. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  44. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  45. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  46. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
  47. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  48. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  49. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.js +3 -3
  50. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +14 -6
  51. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +2 -2
  52. package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.js +9 -1
  53. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  54. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  55. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-template.ts +3 -3
  56. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +2 -2
  57. package/packages/omo-codex/plugin/components/ulw-loop/src/surface.ts +9 -1
  58. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-template.test.ts +1 -1
  59. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +1 -1
  60. package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-contract.test.ts +1 -1
  61. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  62. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  63. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  64. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  65. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  66. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  67. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  68. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  69. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  70. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  71. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  72. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  73. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  74. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  75. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  76. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  77. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  78. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  79. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  80. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  81. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  82. package/packages/omo-codex/plugin/package-lock.json +12 -12
  83. package/packages/omo-codex/plugin/package.json +1 -1
  84. package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +5 -5
  85. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +2 -2
  86. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +4 -4
  87. package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +3 -2
  88. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
  89. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +2 -2
  90. package/packages/omo-codex/scripts/install-dist/install-local.mjs +167 -51
  91. package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +5 -5
  92. package/packages/shared-skills/skills/refactor/SKILL.md +2 -2
  93. package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +4 -4
  94. package/packages/shared-skills/skills/ulw-execute/SKILL.md +3 -2
  95. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
  96. package/packages/shared-skills/skills/ulw-research/SKILL.md +2 -2
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // omo-codex-install:6df5dbbbb7ca9b9dce86fae98a525a9caa7de96caed85a4b77d4e8b4ab4d1501:525d7d1a12782e0247468ae49a5e6e0c3d6cd9dfe478d04dc8ff387cd70205e1
2
+ // omo-codex-install:6df5dbbbb7ca9b9dce86fae98a525a9caa7de96caed85a4b77d4e8b4ab4d1501:e74199a5638f8e39759b02aeeaddfba654bd4fa2265aa9dc8dbe866b56dbb1ba
3
3
  var __esm = (fn, res, err) => () => {
4
4
  if (fn)
5
5
  try {
@@ -106,37 +106,82 @@ var init_atomic_write = __esm(() => {
106
106
  ]);
107
107
  });
108
108
 
109
+ // packages/telemetry-core/src/day-claim.ts
110
+ import { closeSync as closeSync2, mkdirSync as mkdirSync2, openSync as openSync2, readdirSync, rmSync as rmSync2 } from "node:fs";
111
+ import { join as join33 } from "node:path";
112
+ function getTelemetryDayClaimFilePath(stateDir, dayUTC) {
113
+ return join33(stateDir, `${CLAIM_PREFIX}${dayUTC}${CLAIM_SUFFIX}`);
114
+ }
115
+ function claimUtcDay(stateDir, dayUTC) {
116
+ try {
117
+ mkdirSync2(stateDir, { recursive: true });
118
+ closeSync2(openSync2(getTelemetryDayClaimFilePath(stateDir, dayUTC), "wx"));
119
+ } catch (error) {
120
+ return error.code === "EEXIST" ? "already-claimed" : "unavailable";
121
+ }
122
+ pruneSupersededClaims(stateDir, dayUTC);
123
+ return "claimed";
124
+ }
125
+ function pruneSupersededClaims(stateDir, dayUTC) {
126
+ const currentClaim = `${CLAIM_PREFIX}${dayUTC}${CLAIM_SUFFIX}`;
127
+ let entries;
128
+ try {
129
+ entries = readdirSync(stateDir);
130
+ } catch {
131
+ return;
132
+ }
133
+ for (const entry of entries) {
134
+ if (entry === currentClaim)
135
+ continue;
136
+ if (!entry.startsWith(CLAIM_PREFIX) || !entry.endsWith(CLAIM_SUFFIX))
137
+ continue;
138
+ try {
139
+ rmSync2(join33(stateDir, entry), { force: true });
140
+ } catch {}
141
+ }
142
+ }
143
+ var CLAIM_PREFIX = "daily-active.", CLAIM_SUFFIX = ".claim";
144
+ var init_day_claim = () => {};
145
+
109
146
  // packages/telemetry-core/src/activity-state.ts
110
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync3 } from "node:fs";
111
- import { basename as basename6, join as join33 } from "node:path";
147
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3 } from "node:fs";
148
+ import { basename as basename6, join as join34 } from "node:path";
112
149
  function resolveTelemetryStateDir(product, options = {}) {
113
150
  const dataDir = resolveXdgDataDir(product.cacheDirName, {
114
151
  env: options.env,
115
152
  osProvider: options.osProvider
116
153
  });
117
- const xdgStateDir = options.env?.XDG_DATA_HOME === undefined ? undefined : join33(options.env.XDG_DATA_HOME, product.cacheDirName);
154
+ const xdgStateDir = options.env?.XDG_DATA_HOME === undefined ? undefined : join34(options.env.XDG_DATA_HOME, product.cacheDirName);
118
155
  if (dataDir === xdgStateDir || xdgStateDir === undefined && basename6(dataDir) === product.cacheDirName) {
119
156
  return dataDir;
120
157
  }
121
- return join33(dataDir, product.cacheDirName);
158
+ return join34(dataDir, product.cacheDirName);
122
159
  }
123
160
  function getTelemetryActivityStateFilePath(stateDir) {
124
- return join33(stateDir, POSTHOG_ACTIVITY_STATE_FILE);
161
+ return join34(stateDir, POSTHOG_ACTIVITY_STATE_FILE);
125
162
  }
126
163
  function getDailyActiveCaptureState(input) {
127
- const state = readPostHogActivityState(input.stateDir, input.diagnostics);
128
164
  const dayUTC = getUtcDayString(input.now ?? new Date);
129
- const captureDaily = state.lastActiveDayUTC !== dayUTC;
130
- if (captureDaily) {
165
+ if (capturedDaysByStateDir.get(input.stateDir) === dayUTC) {
166
+ return { dayUTC, captureDaily: false };
167
+ }
168
+ const state = readPostHogActivityState(input.stateDir, input.diagnostics);
169
+ if (state.lastActiveDayUTC === dayUTC) {
170
+ capturedDaysByStateDir.set(input.stateDir, dayUTC);
171
+ return { dayUTC, captureDaily: false };
172
+ }
173
+ const claim = claimUtcDay(input.stateDir, dayUTC);
174
+ capturedDaysByStateDir.set(input.stateDir, dayUTC);
175
+ if (claim === "already-claimed") {
176
+ return { dayUTC, captureDaily: false };
177
+ }
178
+ if (claim === "claimed") {
131
179
  writePostHogActivityState(input.stateDir, {
132
180
  ...state,
133
181
  lastActiveDayUTC: dayUTC
134
182
  }, input.diagnostics);
135
183
  }
136
- return {
137
- dayUTC,
138
- captureDaily
139
- };
184
+ return { dayUTC, captureDaily: true };
140
185
  }
141
186
  function getUtcDayString(date) {
142
187
  return date.toISOString().slice(0, 10);
@@ -169,7 +214,7 @@ function readPostHogActivityState(stateDir, diagnostics) {
169
214
  function writePostHogActivityState(stateDir, nextState, diagnostics) {
170
215
  const stateFilePath = getTelemetryActivityStateFilePath(stateDir);
171
216
  try {
172
- mkdirSync2(stateDir, { recursive: true });
217
+ mkdirSync3(stateDir, { recursive: true });
173
218
  writeFileAtomically(stateFilePath, `${JSON.stringify(nextState, null, 2)}
174
219
  `);
175
220
  } catch (error) {
@@ -181,26 +226,28 @@ function writePostHogActivityState(stateDir, nextState, diagnostics) {
181
226
  });
182
227
  }
183
228
  }
184
- var POSTHOG_ACTIVITY_STATE_FILE = "posthog-activity.json";
229
+ var POSTHOG_ACTIVITY_STATE_FILE = "posthog-activity.json", capturedDaysByStateDir;
185
230
  var init_activity_state = __esm(() => {
186
231
  init_atomic_write();
187
232
  init_xdg_data_dir();
233
+ init_day_claim();
234
+ capturedDaysByStateDir = new Map;
188
235
  });
189
236
 
190
237
  // packages/telemetry-core/src/constants.ts
191
238
  var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com", DEFAULT_POSTHOG_API_KEY = "phc_CFJhj5HyvA62QPhvyaUCtaq23aUfznnijg5VaaGkNk74", UNCONFIGURED_POSTHOG_API_KEY = "phc_REPLACE_ME_OMO_NATIVE";
192
239
 
193
240
  // packages/telemetry-core/src/diagnostics.ts
194
- import { appendFileSync, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync4 } from "node:fs";
195
- import { join as join34 } from "node:path";
241
+ import { appendFileSync, existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4 } from "node:fs";
242
+ import { join as join35 } from "node:path";
196
243
  function getTelemetryDiagnosticsFilePath(diagnosticsDir) {
197
- return join34(diagnosticsDir, DIAGNOSTICS_FILE_NAME);
244
+ return join35(diagnosticsDir, DIAGNOSTICS_FILE_NAME);
198
245
  }
199
246
  function writeTelemetryDiagnostic(input, options) {
200
247
  const now = options.now ?? new Date;
201
248
  try {
202
249
  cleanupTelemetryDiagnostics({ diagnosticsDir: options.diagnosticsDir, now });
203
- mkdirSync3(options.diagnosticsDir, { recursive: true });
250
+ mkdirSync4(options.diagnosticsDir, { recursive: true });
204
251
  appendFileSync(getTelemetryDiagnosticsFilePath(options.diagnosticsDir), `${JSON.stringify(toDiagnosticRecord(input, now))}
205
252
  `, "utf-8");
206
253
  } catch (error) {
@@ -269,7 +316,7 @@ function shouldRetainLine(line, cutoffMs) {
269
316
  function parseDiagnosticLine(line) {
270
317
  try {
271
318
  const parsed = JSON.parse(line);
272
- if (!isRecord8(parsed)) {
319
+ if (!isRecord9(parsed)) {
273
320
  return null;
274
321
  }
275
322
  return parsed;
@@ -280,7 +327,7 @@ function parseDiagnosticLine(line) {
280
327
  throw error;
281
328
  }
282
329
  }
283
- function isRecord8(value) {
330
+ function isRecord9(value) {
284
331
  return value !== null && typeof value === "object" && !Array.isArray(value);
285
332
  }
286
333
  function trimToMaxBytes(lines) {
@@ -5654,7 +5701,7 @@ function coerceBool(value) {
5654
5701
  function coerceString(value) {
5655
5702
  return typeof value == "string" ? value : undefined;
5656
5703
  }
5657
- function isRecord9(value) {
5704
+ function isRecord10(value) {
5658
5705
  return typeof value == "object" && value !== null && !Array.isArray(value);
5659
5706
  }
5660
5707
  function toRfc3339(timestamp) {
@@ -5676,7 +5723,7 @@ function relocateInto(properties, key, value) {
5676
5723
  properties[key] = value;
5677
5724
  }
5678
5725
  function buildV1Event(message) {
5679
- const sourceProperties = isRecord9(message.properties) ? message.properties : {};
5726
+ const sourceProperties = isRecord10(message.properties) ? message.properties : {};
5680
5727
  const properties = {
5681
5728
  ...sourceProperties
5682
5729
  };
@@ -7706,7 +7753,7 @@ var package_default;
7706
7753
  var init_package = __esm(() => {
7707
7754
  package_default = {
7708
7755
  name: "@oh-my-opencode/omo-codex",
7709
- version: "5.0.0-beta.79",
7756
+ version: "5.0.0-beta.80",
7710
7757
  type: "module",
7711
7758
  private: true,
7712
7759
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -7898,7 +7945,7 @@ var init_telemetry = __esm(() => {
7898
7945
 
7899
7946
  // packages/omo-codex/src/install/install-local-cli.ts
7900
7947
  import { readFile as readFile24 } from "node:fs/promises";
7901
- import { dirname as dirname13, join as join39, resolve as resolve11 } from "node:path";
7948
+ import { dirname as dirname13, join as join40, resolve as resolve11 } from "node:path";
7902
7949
  import { fileURLToPath as fileURLToPath2 } from "node:url";
7903
7950
 
7904
7951
  // packages/utils/src/runtime/spawn.ts
@@ -8166,7 +8213,7 @@ var defaultRunCommand = async (command, args, options) => {
8166
8213
  };
8167
8214
 
8168
8215
  // packages/omo-codex/src/install/install-codex.ts
8169
- import { join as join35, resolve as resolve10 } from "node:path";
8216
+ import { join as join36, resolve as resolve10 } from "node:path";
8170
8217
 
8171
8218
  // node_modules/.bun/zod@4.4.3/node_modules/zod/v4/core/core.js
8172
8219
  var _a;
@@ -13489,6 +13536,62 @@ var OmoConfigLayerSchema = object({
13489
13536
  legacy_migrations: record(string2(), unknown()).optional()
13490
13537
  }).strict();
13491
13538
 
13539
+ // packages/omo-config-core/src/schema/legacy-category-names.ts
13540
+ var LEGACY_CATEGORY_NAME_ALIASES = { deep: "deep-low" };
13541
+ function canonicalCategoryName(name) {
13542
+ return Object.hasOwn(LEGACY_CATEGORY_NAME_ALIASES, name) ? LEGACY_CATEGORY_NAME_ALIASES[name] : name;
13543
+ }
13544
+ function isRecord6(value) {
13545
+ return typeof value === "object" && value !== null && !Array.isArray(value);
13546
+ }
13547
+ function joinPath(path, segment) {
13548
+ return [...path, segment].join(".");
13549
+ }
13550
+ function canonicalizeCategoriesRecord(categories, path, renames) {
13551
+ const result = {};
13552
+ for (const [name, definition] of Object.entries(categories)) {
13553
+ const canonical = canonicalCategoryName(name);
13554
+ if (canonical === name) {
13555
+ result[name] = definition;
13556
+ continue;
13557
+ }
13558
+ const dropped = Object.hasOwn(categories, canonical);
13559
+ renames.push({ canonical, dropped, legacy: name, path: joinPath(path, name) });
13560
+ if (!dropped)
13561
+ result[canonical] = definition;
13562
+ }
13563
+ return result;
13564
+ }
13565
+ function canonicalizeValue(value, path, renames) {
13566
+ if (Array.isArray(value)) {
13567
+ return value.map((entry, index) => canonicalizeValue(entry, [...path, String(index)], renames));
13568
+ }
13569
+ if (!isRecord6(value))
13570
+ return value;
13571
+ const result = {};
13572
+ for (const [key, entry] of Object.entries(value)) {
13573
+ if (key === "categories" && isRecord6(entry)) {
13574
+ result[key] = canonicalizeCategoriesRecord(entry, [...path, key], renames);
13575
+ continue;
13576
+ }
13577
+ if (key === "category" && typeof entry === "string") {
13578
+ const canonical = canonicalCategoryName(entry);
13579
+ if (canonical !== entry) {
13580
+ renames.push({ canonical, dropped: false, legacy: entry, path: joinPath(path, key) });
13581
+ }
13582
+ result[key] = canonical;
13583
+ continue;
13584
+ }
13585
+ result[key] = canonicalizeValue(entry, [...path, key], renames);
13586
+ }
13587
+ return result;
13588
+ }
13589
+ function canonicalizeLegacyCategoryNames(document) {
13590
+ const renames = [];
13591
+ const canonicalized = isRecord6(document) ? canonicalizeValue(document, [], renames) : {};
13592
+ return { document: canonicalized, renames };
13593
+ }
13594
+
13492
13595
  // node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
13493
13596
  function createScanner(text, ignoreTrivia = false) {
13494
13597
  const len = text.length;
@@ -14569,21 +14672,21 @@ function hasUnsafeUnrecognizedKey(issues) {
14569
14672
  function hasTamperedPrototype(value) {
14570
14673
  if (Array.isArray(value))
14571
14674
  return value.some((entry) => hasTamperedPrototype(entry));
14572
- if (!isRecord6(value))
14675
+ if (!isRecord7(value))
14573
14676
  return false;
14574
14677
  const prototype = Object.getPrototypeOf(value);
14575
14678
  if (prototype !== Object.prototype && prototype !== null)
14576
14679
  return true;
14577
14680
  return Object.values(value).some((entry) => hasTamperedPrototype(entry));
14578
14681
  }
14579
- function isRecord6(value) {
14682
+ function isRecord7(value) {
14580
14683
  return typeof value === "object" && value !== null && !Array.isArray(value);
14581
14684
  }
14582
14685
  function containerAt(record, path) {
14583
14686
  let container = record;
14584
14687
  for (const segment of path) {
14585
14688
  const next = container[segment];
14586
- if (!isRecord6(next))
14689
+ if (!isRecord7(next))
14587
14690
  return null;
14588
14691
  container = next;
14589
14692
  }
@@ -14685,6 +14788,15 @@ function readConfigSource(path, scope, fileSystem) {
14685
14788
  value: parsedRecord
14686
14789
  };
14687
14790
  }
14791
+ function legacyCategoryDiagnostic(path, renames) {
14792
+ const detail = renames.map((rename) => rename.dropped ? `${rename.path} ignored because ${rename.canonical} is also configured` : `${rename.path} renamed to ${rename.canonical}`).join(", ");
14793
+ return {
14794
+ kind: "deprecated-keys",
14795
+ message: `Deprecated category name in ${path}: ${detail}. Rename it; the alias is removed in a future release.`,
14796
+ path,
14797
+ issuePaths: renames.map((rename) => rename.path)
14798
+ };
14799
+ }
14688
14800
  function loadOmoConfig(options = {}) {
14689
14801
  const fileSystem = options.fileSystem ?? DEFAULT_READ_FILE_SYSTEM;
14690
14802
  const cwd = options.cwd ?? process.cwd();
@@ -14703,8 +14815,12 @@ function loadOmoConfig(options = {}) {
14703
14815
  if (loaded.diagnostic !== undefined)
14704
14816
  diagnostics.push(loaded.diagnostic);
14705
14817
  if (loaded.value !== undefined) {
14706
- layers.push({ config: loaded.value, source: loaded.source });
14707
- merged = mergeOmoConfigRecords(merged, loaded.value);
14818
+ const canonicalized = canonicalizeLegacyCategoryNames(loaded.value);
14819
+ if (canonicalized.renames.length > 0) {
14820
+ diagnostics.push(legacyCategoryDiagnostic(candidate.path, canonicalized.renames));
14821
+ }
14822
+ layers.push({ config: canonicalized.document, source: loaded.source });
14823
+ merged = mergeOmoConfigRecords(merged, canonicalized.document);
14708
14824
  }
14709
14825
  }
14710
14826
  const requestedProfile = resolveOmoProfileName({
@@ -17304,10 +17420,10 @@ function readCatalogMultiAgentVersion(model, cachePath) {
17304
17420
  } catch {
17305
17421
  return null;
17306
17422
  }
17307
- if (!isRecord7(cache) || !Array.isArray(cache.models))
17423
+ if (!isRecord8(cache) || !Array.isArray(cache.models))
17308
17424
  return null;
17309
17425
  for (const entry of cache.models) {
17310
- if (!isRecord7(entry))
17426
+ if (!isRecord8(entry))
17311
17427
  continue;
17312
17428
  if (entry.slug !== model && entry.id !== model)
17313
17429
  continue;
@@ -17332,7 +17448,7 @@ function readRootModelCatalogPath(config) {
17332
17448
  const single = config.match(/^\s*model_catalog_json\s*=\s*'([^']+)'/m);
17333
17449
  return single?.[1] ?? null;
17334
17450
  }
17335
- function isRecord7(value) {
17451
+ function isRecord8(value) {
17336
17452
  return typeof value === "object" && value !== null && !Array.isArray(value);
17337
17453
  }
17338
17454
  function removeFeatureFlagSetting(config, featureName) {
@@ -19245,7 +19361,7 @@ async function runCodexInstaller(options = {}) {
19245
19361
  const env = options.env ?? process.env;
19246
19362
  const platform = options.platform ?? process.platform;
19247
19363
  const repoRoot = resolve10(options.repoRoot ?? findRepoRoot({ importerDir: import.meta.dir, env }));
19248
- const codexHome = resolve10(options.codexHome ?? env.CODEX_HOME ?? join35(homedir2(), ".codex"));
19364
+ const codexHome = resolve10(options.codexHome ?? env.CODEX_HOME ?? join36(homedir2(), ".codex"));
19249
19365
  const projectDirectory = resolve10(options.projectDirectory ?? env.OMO_CODEX_PROJECT ?? process.cwd());
19250
19366
  const binDir = resolveCodexInstallerBinDir({ binDir: options.binDir, codexHome, env });
19251
19367
  const runCommand = options.runCommand ?? defaultRunCommand;
@@ -19262,9 +19378,9 @@ async function runCodexInstaller(options = {}) {
19262
19378
  if (!gitBashResolution.found) {
19263
19379
  throw new Error(gitBashResolution.installHint);
19264
19380
  }
19265
- const codexPackageRoot = join35(repoRoot, "packages", "omo-codex");
19381
+ const codexPackageRoot = join36(repoRoot, "packages", "omo-codex");
19266
19382
  const marketplace = await readMarketplace(repoRoot, {
19267
- marketplacePath: join35(codexPackageRoot, "marketplace.json")
19383
+ marketplacePath: join36(codexPackageRoot, "marketplace.json")
19268
19384
  });
19269
19385
  const distributionManifest = await readDistributionManifest(repoRoot);
19270
19386
  const installed = [];
@@ -19310,7 +19426,7 @@ async function runCodexInstaller(options = {}) {
19310
19426
  if (runtimeLink !== null)
19311
19427
  log(`Linked ${runtimeLink.name} -> ${runtimeLink.target}`);
19312
19428
  else
19313
- log(`Warning: skipped the omo-agent-toolkit runtime wrapper because ${join35(repoRoot, "dist", "cli", "index.js")} is missing; omo-agent-toolkit ulw-loop commands will be unavailable until a package shipping dist/cli is installed`);
19429
+ log(`Warning: skipped the omo-agent-toolkit runtime wrapper because ${join36(repoRoot, "dist", "cli", "index.js")} is missing; omo-agent-toolkit ulw-loop commands will be unavailable until a package shipping dist/cli is installed`);
19314
19430
  }
19315
19431
  pluginSources.push({ name: entry.name, sourcePath });
19316
19432
  installed.push(plugin);
@@ -19377,13 +19493,13 @@ async function runCodexInstaller(options = {}) {
19377
19493
  continue;
19378
19494
  log(`Warning: deferred legacy Codex LSP daemon cleanup for v${cleanup.version}: ${cleanup.reason}`);
19379
19495
  }
19380
- const marketplaceRoot = join35(codexHome, "plugins", "cache", marketplace.name);
19496
+ const marketplaceRoot = join36(codexHome, "plugins", "cache", marketplace.name);
19381
19497
  await writeCachedMarketplaceManifest({
19382
19498
  marketplaceName: marketplace.name,
19383
19499
  marketplaceRoot,
19384
19500
  plugins: installed
19385
19501
  });
19386
- const configPath = join35(codexHome, "config.toml");
19502
+ const configPath = join36(codexHome, "config.toml");
19387
19503
  await updateCodexConfig({
19388
19504
  configPath,
19389
19505
  repoRoot: codexPackageRoot,
@@ -19442,7 +19558,7 @@ function findRepoRootFromImporter(importerDir) {
19442
19558
  for (let depth = 0;depth <= 7; depth += 1) {
19443
19559
  if (isRepoRootWithCodexPlugin(current))
19444
19560
  return current;
19445
- for (const wrapperPackageRoot of [join35(current, "node_modules", "oh-my-openagent"), join35(current, "oh-my-openagent")]) {
19561
+ for (const wrapperPackageRoot of [join36(current, "node_modules", "oh-my-openagent"), join36(current, "oh-my-openagent")]) {
19446
19562
  if (isRepoRootWithCodexPlugin(wrapperPackageRoot))
19447
19563
  return wrapperPackageRoot;
19448
19564
  }
@@ -19460,7 +19576,7 @@ function findRepoRoot(input) {
19460
19576
  return findRepoRootFromImporter(input.importerDir);
19461
19577
  }
19462
19578
  function isRepoRootWithCodexPlugin(repoRoot) {
19463
- return existsSync7(join35(repoRoot, "packages", "omo-codex", "plugin", ".codex-plugin", "plugin.json"));
19579
+ return existsSync7(join36(repoRoot, "packages", "omo-codex", "plugin", ".codex-plugin", "plugin.json"));
19464
19580
  }
19465
19581
  function codexMarketplaceSource(marketplaceRoot) {
19466
19582
  return { sourceType: "local", source: marketplaceRoot };
@@ -19773,12 +19889,12 @@ function shellQuote(value) {
19773
19889
  // packages/omo-codex/src/install/lazycodex-manual-update.ts
19774
19890
  import { spawn as spawn3, spawnSync as spawnSync2 } from "node:child_process";
19775
19891
  import { readFileSync as readFileSync5 } from "node:fs";
19776
- import { dirname as dirname12, join as join37 } from "node:path";
19892
+ import { dirname as dirname12, join as join38 } from "node:path";
19777
19893
  import { createInterface as createInterface2 } from "node:readline/promises";
19778
19894
  import { fileURLToPath } from "node:url";
19779
19895
 
19780
19896
  // packages/omo-codex/src/install/lazycodex-bun-global-paths.ts
19781
- import { join as join36 } from "node:path";
19897
+ import { join as join37 } from "node:path";
19782
19898
  function isBunGlobalEntrypointPath(invokedPath, env) {
19783
19899
  if (typeof invokedPath !== "string" || invokedPath.trim().length === 0)
19784
19900
  return false;
@@ -19789,8 +19905,8 @@ function resolveBunGlobalRoots(env) {
19789
19905
  const bunInstallRoot = env.BUN_INSTALL?.trim();
19790
19906
  const homeRoot = env.HOME?.trim();
19791
19907
  return [
19792
- ...bunInstallRoot ? [join36(bunInstallRoot, "bin"), join36(bunInstallRoot, "install", "global", "node_modules")] : [],
19793
- ...homeRoot ? [join36(homeRoot, ".bun", "bin"), join36(homeRoot, ".bun", "install", "global", "node_modules")] : []
19908
+ ...bunInstallRoot ? [join37(bunInstallRoot, "bin"), join37(bunInstallRoot, "install", "global", "node_modules")] : [],
19909
+ ...homeRoot ? [join37(homeRoot, ".bun", "bin"), join37(homeRoot, ".bun", "install", "global", "node_modules")] : []
19794
19910
  ].map(normalizePathForPrefix);
19795
19911
  }
19796
19912
  function normalizePathForPrefix(path) {
@@ -19883,7 +19999,7 @@ function resolveCurrentVersion(env) {
19883
19999
  if (env.LAZYCODEX_CURRENT_VERSION?.trim())
19884
20000
  return env.LAZYCODEX_CURRENT_VERSION.trim();
19885
20001
  const pluginRoot = dirname12(dirname12(fileURLToPath(import.meta.url)));
19886
- return readVersionManifest(resolveInstalledVersionPath(env, pluginRoot)) ?? readVersionManifest(join37(pluginRoot, "..", "..", "..", "package.json")) ?? readVersionManifest(join37(pluginRoot, ".codex-plugin", "plugin.json"));
20002
+ return readVersionManifest(resolveInstalledVersionPath(env, pluginRoot)) ?? readVersionManifest(join38(pluginRoot, "..", "..", "..", "package.json")) ?? readVersionManifest(join38(pluginRoot, ".codex-plugin", "plugin.json"));
19887
20003
  }
19888
20004
  function resolveLatestVersion(env) {
19889
20005
  if (env.LAZYCODEX_LATEST_VERSION?.trim())
@@ -19999,7 +20115,7 @@ function compareVersions(left, right) {
19999
20115
  function resolveInstalledVersionPath(env, pluginRoot) {
20000
20116
  if (env.LAZYCODEX_INSTALLED_VERSION_FILE?.trim())
20001
20117
  return env.LAZYCODEX_INSTALLED_VERSION_FILE.trim();
20002
- return join37(pluginRoot, INSTALLED_VERSION_FILE);
20118
+ return join38(pluginRoot, INSTALLED_VERSION_FILE);
20003
20119
  }
20004
20120
  function readVersionManifest(path) {
20005
20121
  try {
@@ -20016,10 +20132,10 @@ function readVersionManifest(path) {
20016
20132
  }
20017
20133
  // packages/omo-codex/src/install/codex-git-bash-mcp-env.ts
20018
20134
  import { readFile as readFile23, writeFile as writeFile13 } from "node:fs/promises";
20019
- import { join as join38 } from "node:path";
20135
+ import { join as join39 } from "node:path";
20020
20136
  var GIT_BASH_ENV_KEY2 = "OMO_CODEX_GIT_BASH_PATH";
20021
20137
  async function stampGitBashMcpEnv(input) {
20022
- const manifestPath = join38(input.pluginRoot, ".mcp.json");
20138
+ const manifestPath = join39(input.pluginRoot, ".mcp.json");
20023
20139
  if (!await fileExistsStrict(manifestPath))
20024
20140
  return false;
20025
20141
  const parsed = JSON.parse(await readFile23(manifestPath, "utf8"));
@@ -20066,7 +20182,7 @@ async function runLazyCodexInstallLocalCli(input) {
20066
20182
  return 0;
20067
20183
  }
20068
20184
  if (parsed.kind === "version") {
20069
- const packageJson = JSON.parse(await readFile24(join39(input.defaultRepoRoot, "package.json"), "utf8"));
20185
+ const packageJson = JSON.parse(await readFile24(join40(input.defaultRepoRoot, "package.json"), "utf8"));
20070
20186
  const version = typeof packageJson.version === "string" ? packageJson.version : "unknown";
20071
20187
  input.log(`lazycodex-ai ${version}`);
20072
20188
  return 0;
@@ -75,22 +75,22 @@ When the `team_*` tools are present, create a **debug-squad** team and split inv
75
75
  "members": [
76
76
  {
77
77
  "kind": "category",
78
- "category": "deep",
78
+ "category": "deep-low",
79
79
  "prompt": "You are the Runtime State Inspector. Your job: attach to the live process, hit breakpoints, read program state (variables, heap, goroutines, stack, registers depending on runtime), and report observed values verbatim. Never guess — if you don't see the value, say so. Report back via team_send_message with file:line / address references and captured values. Never edit source code. Never run git commands. If you need an instrumentation statement added (breakpoint(), debugger;, dbg!, etc.), ask the Lead first."
80
80
  },
81
81
  {
82
82
  "kind": "category",
83
- "category": "deep",
83
+ "category": "deep-low",
84
84
  "prompt": "You are the Log Archaeologist. Your job: grep server logs, stderr streams, SDK-internal debug output (DEBUG env, RUST_LOG, GODEBUG, PYTHONASYNCIODEBUG), and correlate timestamps. Produce a timeline of events with latencies. Flag anything that looks like a silent catch, a swallowed rejection, a panic recovered-and-ignored, a success response that contains failure signals (HTTP 200 with empty body, stopReason=error, exit 0 with error-in-stdout). Never edit source code."
85
85
  },
86
86
  {
87
87
  "kind": "category",
88
- "category": "deep",
88
+ "category": "deep-low",
89
89
  "prompt": "You are the Reproduction Engineer. Your job: build the smallest reliable repro — a curl command, a vitest/pytest/go test, a tmux script, a Playwright script for browser bugs, a pwntools script for binary targets. It must reproduce on first try and be copy-pasteable by the Lead. Document exact input, expected output, observed output. Save repro artifacts under /tmp/ and tell the Lead to journal them. If the bug is browser-based you MUST use Playwright CLI — do not simulate with curl."
90
90
  },
91
91
  {
92
92
  "kind": "category",
93
- "category": "deep",
93
+ "category": "deep-low",
94
94
  "prompt": "You are the Trace Correlator. Your job: take findings from the other members and cross-link them. Build a causal chain from symptom to suspected cause. Identify missing evidence. Propose the next single most-decisive runtime query. Never edit source code; only reason across already-captured evidence. If hypotheses diverge sharply after correlation, tell the Lead immediately — that is the signal for the Oracle Triple."
95
95
  }
96
96
  ]
@@ -117,7 +117,7 @@ task(subagent_type="explore", load_skills=[], run_in_background=true,
117
117
  Runtime state investigation for hypothesis 1: ...")
118
118
  task(subagent_type="explore", load_skills=[], run_in_background=true,
119
119
  prompt="Log/timing investigation for hypothesis 2: ...")
120
- task(category="deep", load_skills=[], run_in_background=true,
120
+ task(category="deep-low", load_skills=[], run_in_background=true,
121
121
  prompt="Reproduction minimizer for hypothesis 3: ...")
122
122
  ```
123
123
 
@@ -684,7 +684,7 @@ Record the chosen path in the TodoWrite list.
684
684
 
685
685
  Rationale for this composition:
686
686
  - **4 workers = team mode's parallel cap.** 5+ just queues.
687
- - **No verifier team member.** Verification needs \`deep\` reasoning (or \`unspecified-high\` fallback). In-team category routing downcasts to the category worker, which is weaker than required — the verifier runs OUTSIDE the team as a \`task(category="deep")\`.
687
+ - **No verifier team member.** Verification needs \`deep-high\` reasoning (or \`unspecified-high\` fallback). In-team category routing downcasts to the category worker, which is weaker than required — the verifier runs OUTSIDE the team as a \`task(category="deep-high")\`.
688
688
  - **quick × 2** for mechanical edits, **unspecified-low × 2** for reasoning edits — mirrors the plan's split.
689
689
 
690
690
  **Team lifecycle** (one team, reused until Phase 6 cleanup):
@@ -716,7 +716,7 @@ While any team task is \`pending | claimed | in_progress\`:
716
716
  - On a worker completion report, immediately dispatch an **external verifier** — verification runs OUTSIDE the team because team-member category routing downcasts to the category worker:
717
717
  \`\`\`
718
718
  task(
719
- category="deep",
719
+ category="deep-high",
720
720
  load_skills=[],
721
721
  run_in_background=true,
722
722
  description="verify step <N>",
@@ -160,9 +160,9 @@ File: src/bar.py
160
160
 
161
161
  Order rule (safest → riskiest): comments → dead code → defensive → duplication → complexity → abstraction/boundary → performance → tests → oversized-modules. This minimizes blast radius of any one change.
162
162
 
163
- ### Phase 4: Parallel slop removal via `deep` agents in batches of 5
163
+ ### Phase 4: Parallel slop removal via `deep-low` agents in batches of 5
164
164
 
165
- Files are processed by `deep` category agents with the `$omo:remove-ai-slops` skill loaded, **batched 5 at a time in parallel**. The executable skill name is `remove-ai-slops`. The `deep` category gives the agent enough thoroughness to correctly evaluate the 9 categories and respect the KEEP rules without slipping into surface fixes; the 5-wide batch is the sweet spot — more than 5 creates result-merging noise and context contention, fewer wastes parallelism.
165
+ Files are processed by `deep-low` category agents with the `$omo:remove-ai-slops` skill loaded, **batched 5 at a time in parallel**. The executable skill name is `remove-ai-slops`. The `deep-low` category gives the agent enough thoroughness to correctly evaluate the 9 categories and respect the KEEP rules without slipping into surface fixes; the 5-wide batch is the sweet spot — more than 5 creates result-merging noise and context contention, fewer wastes parallelism.
166
166
 
167
167
  **Batching protocol** (strict):
168
168
 
@@ -179,7 +179,7 @@ Files are processed by `deep` category agents with the `$omo:remove-ai-slops` sk
179
179
 
180
180
  ```
181
181
  task(
182
- category="deep",
182
+ category="deep-low",
183
183
  load_skills=["remove-ai-slops"],
184
184
  run_in_background=true,
185
185
  description="Slop removal: {filename}",
@@ -205,7 +205,7 @@ For each skipped issue, give reason.
205
205
  )
206
206
  ```
207
207
 
208
- **Batch failure handling**: a `multi_agent_v1.wait_agent` timeout only means no new mailbox update arrived, not that a `deep` agent failed. For long passes, require each child to send `WORKING: <file> - <current phase>` and `BLOCKED: <reason>` only when it cannot progress. Treat a running child as alive. Mark a file for retry only when the child is completed without the deliverable, ack-only after followup, explicitly `BLOCKED:`, or no longer running. Do NOT block the remaining 4 in that batch; collect successful results and retry the failed file once later. If retry also fails, escalate that file under "Issues Found & Fixed" in the final report.
208
+ **Batch failure handling**: a `multi_agent_v1.wait_agent` timeout only means no new mailbox update arrived, not that a `deep-low` agent failed. For long passes, require each child to send `WORKING: <file> - <current phase>` and `BLOCKED: <reason>` only when it cannot progress. Treat a running child as alive. Mark a file for retry only when the child is completed without the deliverable, ack-only after followup, explicitly `BLOCKED:`, or no longer running. Do NOT block the remaining 4 in that batch; collect successful results and retry the failed file once later. If retry also fails, escalate that file under "Issues Found & Fixed" in the final report.
209
209
 
210
210
  ### Phase 5: Verify with quality gates + critical review
211
211
 
@@ -143,13 +143,14 @@ When the plan annotates a todo with `Recommended task executor category:`, follo
143
143
  | `visual-engineering` (medium) | frontend, UI/UX, styling, animation |
144
144
  | `writing` (low) | documentation and prose |
145
145
  | `git` (low) | git operations |
146
- | `deep` (high) | hairy debugging, research-heavy or subtle cross-module work |
146
+ | `deep-low` (medium) | hairy debugging, research-heavy or subtle cross-module work the worker can settle from what it reads |
147
+ | `deep-high` (high) | the same, when the central decision cannot be settled from evidence: a trade-off, a cross-package contract, or correctness argued from invariants |
147
148
  | `ultrabrain` (high) | ONE genuinely hard, logic-heavy problem — hand it the goal, not step-by-step instructions |
148
149
 
149
150
  Sizing is a two-branch decision made per checkbox, before dispatch:
150
151
 
151
152
  - **Splittable work splits.** When the checkbox decomposes into independent pieces, dispatch them as a swarm of `quick`/`unspecified-low` workers in ONE parallel burst — many small cheap workers in parallel beat one large delegation.
152
- - **Cohesive hard work stays whole.** When splitting would sever shared reasoning (one algorithm, one migration, one subtle bug), send the WHOLE problem to `deep` or `ultrabrain` as ONE delegation. Never force-split work whose parts share one insight.
153
+ - **Cohesive hard work stays whole.** When splitting would sever shared reasoning (one algorithm, one migration, one subtle bug), send the WHOLE problem to `deep-low`, `deep-high` or `ultrabrain` as ONE delegation. Never force-split work whose parts share one insight.
153
154
 
154
155
  Each sub-task message must include:
155
156
 
@@ -155,7 +155,7 @@ No Metis, no plan file, no execution until the user approves. The UNCLEAR path a
155
155
  ## Commit strategy
156
156
  ## Success criteria
157
157
  ```
158
- > Target 5-8 todos per wave; fewer than 3 (except the final) means under-splitting. Implementation + Test = ONE todo. Each todo carries: exhaustive References (the executor has no interview context), agent-executable Acceptance criteria, happy + failure QA scenarios each with an evidence path, a Commit line, and a `Recommended task executor category:` line - the routing verdict the executor follows, with a one-line reason, in the omo category vocabulary: `quick` (mechanical / single-file - the default for every splittable piece), `unspecified-low` (small misc), `unspecified-high` (standard multi-file feature), `visual-engineering` (frontend/UI), `writing` (docs), `git` (git ops), `deep` (hairy debugging or cross-module reasoning), `ultrabrain` (ONE genuinely hard cohesive problem, delegated whole). Prefer many small `quick`-routable todos spread across parallel waves; when splitting would sever shared reasoning, keep ONE todo routed to `deep`/`ultrabrain` - never force-split work whose parts share one insight. Harnesses without categories map by difficulty: quick/unspecified-low/writing/git = low, unspecified-high/visual-engineering = medium, deep/ultrabrain = high.
158
+ > Target 5-8 todos per wave; fewer than 3 (except the final) means under-splitting. Implementation + Test = ONE todo. Each todo carries: exhaustive References (the executor has no interview context), agent-executable Acceptance criteria, happy + failure QA scenarios each with an evidence path, a Commit line, and a `Recommended task executor category:` line - the routing verdict the executor follows, with a one-line reason, in the omo category vocabulary: `quick` (mechanical / single-file - the default for every splittable piece), `unspecified-low` (small misc), `unspecified-high` (standard multi-file feature), `visual-engineering` (frontend/UI), `writing` (docs), `git` (git ops), `deep-low` (hairy debugging or cross-module reasoning the worker can settle from what it reads), `deep-high` (the same, when the central decision cannot be settled from evidence: a trade-off, a cross-package contract, or correctness argued from invariants), `ultrabrain` (ONE genuinely hard cohesive problem, delegated whole). Prefer many small `quick`-routable todos spread across parallel waves; when splitting would sever shared reasoning, keep ONE todo routed to `deep`/`ultrabrain` - never force-split work whose parts share one insight. Harnesses without categories map by difficulty: quick/unspecified-low/writing/git = low, unspecified-high/visual-engineering = medium, deep/ultrabrain = high.
159
159
 
160
160
  ## Plan artifact producer contract
161
161
 
@@ -253,7 +253,7 @@ Interest alone is not a trigger. Anything without one stays a queued lead in `ex
253
253
  Settle with executed code, not judgment, whenever sources disagree, a behavior is undocumented, a claim is performance- or compatibility-shaped, or the honest answer is "it should work". Spawn one verification worker per claim:
254
254
 
255
255
  ```
256
- task(category="deep", run_in_background=true, prompt="TASK: verify by execution: <claim>.
256
+ task(category="deep-low", run_in_background=true, prompt="TASK: verify by execution: <claim>.
257
257
  SOURCE: <where it came from>; CONTRADICTION: <opposing source, if any>.
258
258
  Write a minimal self-contained script that tests the claim; run it (uv run --with <deps> python / bun / direct compile); capture full stdout+stderr; pin versions.
259
259
  Reply with: the exact code, the full output, environment (OS, runtime, dependency versions), and a verdict — CONFIRMED / REFUTED / PARTIAL — grounded in the output.")
@@ -333,7 +333,7 @@ Asset workers (background, parallel, each fed `design-spec.md`) — visuals are
333
333
 
334
334
  **Verify the asset manifest before rendering.** List every asset the document references, assert each file exists and is non-empty on disk, and re-render whatever is missing. A document that renders with three broken diagrams is a document you will publish twice.
335
335
 
336
- Assembly worker — `task(category="deep", load_skills=["frontend", "visual-qa", "open-design", "data-scientist", "imagegen", "ulw-loop"], run_in_background=true, ...)`: before writing, read every available design and visualization skill and apply it — the report is a designed artifact, not a text dump; the worker's prompt carries `design-spec.md`. Use the template the user approved; absent a stronger house style the default skeleton is executive summary → key findings by theme → detailed analysis (quotes under 20 words with attribution, charts, Mermaid graphs, generated visuals, SHA-pinned permalinks, verification results) → comparative analysis when options compete → numbered sources with access dates → methodology appendix (workers, waves, searches, verifications, debate rounds) → correction log naming what verification overturned. Write it long and specific: every claim cites `[Source N]`, and the sources section lists every source the run actually used rather than a curated few.
336
+ Assembly worker — `task(category="deep-low", load_skills=["frontend", "visual-qa", "open-design", "data-scientist", "imagegen", "ulw-loop"], run_in_background=true, ...)`: before writing, read every available design and visualization skill and apply it — the report is a designed artifact, not a text dump; the worker's prompt carries `design-spec.md`. Use the template the user approved; absent a stronger house style the default skeleton is executive summary → key findings by theme → detailed analysis (quotes under 20 words with attribution, charts, Mermaid graphs, generated visuals, SHA-pinned permalinks, verification results) → comparative analysis when options compete → numbered sources with access dates → methodology appendix (workers, waves, searches, verifications, debate rounds) → correction log naming what verification overturned. Write it long and specific: every claim cites `[Source N]`, and the sources section lists every source the run actually used rather than a curated few.
337
337
 
338
338
  ### The delivery gates — every gate must PASS, in order
339
339