oh-my-opencode 4.5.12 → 4.6.0

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 (147) hide show
  1. package/.agents/skills/opencode-qa/SKILL.md +194 -0
  2. package/.agents/skills/opencode-qa/references/cli-commands.md +188 -0
  3. package/.agents/skills/opencode-qa/references/db-investigation.md +197 -0
  4. package/.agents/skills/opencode-qa/references/events-hooks.md +110 -0
  5. package/.agents/skills/opencode-qa/references/sdk.md +96 -0
  6. package/.agents/skills/opencode-qa/references/server-api.md +200 -0
  7. package/.agents/skills/opencode-qa/references/testing-harness.md +218 -0
  8. package/.agents/skills/opencode-qa/references/tui-tmux.md +52 -0
  9. package/.agents/skills/opencode-qa/scripts/db-session-by-id.sh +53 -0
  10. package/.agents/skills/opencode-qa/scripts/db-session-by-name.sh +57 -0
  11. package/.agents/skills/opencode-qa/scripts/db-session-by-text.sh +158 -0
  12. package/.agents/skills/opencode-qa/scripts/export-roundtrip.sh +57 -0
  13. package/.agents/skills/opencode-qa/scripts/lib/common.sh +216 -0
  14. package/.agents/skills/opencode-qa/scripts/server-smoke.sh +64 -0
  15. package/.agents/skills/opencode-qa/scripts/sse-hook-probe.sh +106 -0
  16. package/.agents/skills/opencode-qa/scripts/tui-smoke.sh +89 -0
  17. package/README.ja.md +13 -3
  18. package/README.ko.md +13 -3
  19. package/README.md +24 -14
  20. package/README.ru.md +13 -3
  21. package/README.zh-cn.md +13 -3
  22. package/bin/oh-my-opencode.js +4 -3
  23. package/bin/oh-my-opencode.test.ts +35 -7
  24. package/bin/platform.d.ts +1 -1
  25. package/bin/platform.js +4 -4
  26. package/bin/platform.test.ts +31 -9
  27. package/dist/cli/cleanup-command.d.ts +4 -0
  28. package/dist/cli/cleanup.d.ts +11 -0
  29. package/dist/cli/cli-program.d.ts +2 -1
  30. package/dist/cli/index.js +1837 -450
  31. package/dist/cli/install-codex/codex-cache.d.ts +1 -0
  32. package/dist/cli/install-codex/codex-cleanup-config.d.ts +6 -0
  33. package/dist/cli/install-codex/codex-cleanup.d.ts +21 -0
  34. package/dist/cli/install-codex/codex-config-mcp.d.ts +1 -0
  35. package/dist/cli/install-codex/codex-config-permissions.d.ts +1 -0
  36. package/dist/cli/install-codex/codex-config-reasoning.d.ts +1 -0
  37. package/dist/cli/install-codex/codex-config-toml.d.ts +2 -1
  38. package/dist/cli/install-codex/codex-installation-detection.d.ts +36 -0
  39. package/dist/cli/install-codex/codex-package-layout.d.ts +1 -0
  40. package/dist/cli/install-codex/codex-project-local-cleanup-best-effort.d.ts +7 -0
  41. package/dist/cli/install-codex/codex-project-local-cleanup.d.ts +35 -0
  42. package/dist/cli/install-codex/git-bash.d.ts +35 -0
  43. package/dist/cli/install-codex/index.d.ts +4 -0
  44. package/dist/cli/install-codex/toml-section-editor.d.ts +2 -0
  45. package/dist/cli/install-codex/types.d.ts +20 -0
  46. package/dist/cli/run/event-state.d.ts +1 -0
  47. package/dist/cli/run/poll-for-completion.d.ts +1 -0
  48. package/dist/cli/run/prompt-start.d.ts +7 -0
  49. package/dist/cli/star-request.d.ts +9 -0
  50. package/dist/config/schema/hooks.d.ts +0 -1
  51. package/dist/create-hooks.d.ts +0 -1
  52. package/dist/features/builtin-skills/skills/debugging.d.ts +2 -0
  53. package/dist/features/builtin-skills/skills/index.d.ts +1 -0
  54. package/dist/hooks/index.d.ts +0 -1
  55. package/dist/index.js +267 -114
  56. package/dist/plugin/hooks/create-core-hooks.d.ts +0 -1
  57. package/dist/plugin/hooks/create-session-hooks.d.ts +1 -2
  58. package/dist/plugin/messages-transform.d.ts +8 -1
  59. package/dist/plugin/user-abort-interrupted-recovery-guard.d.ts +6 -0
  60. package/dist/shared/prompt-async-gate/recent-dispatches.d.ts +14 -0
  61. package/dist/shared/prompt-async-gate/semantic-dedupe.d.ts +7 -0
  62. package/dist/shared/prompt-async-gate/session-idle-dispatch.d.ts +1 -0
  63. package/dist/shared/prompt-async-gate/timing.d.ts +1 -0
  64. package/dist/shared/prompt-async-gate/types.d.ts +2 -0
  65. package/dist/shared/prompt-async-gate.d.ts +1 -1
  66. package/package.json +22 -17
  67. package/packages/git-bash-mcp/dist/cli.js +367 -0
  68. package/packages/omo-codex/plugin/.mcp.json +11 -0
  69. package/packages/omo-codex/plugin/components/comment-checker/README.md +1 -1
  70. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +29 -0
  71. package/packages/omo-codex/plugin/components/git-bash/package.json +23 -0
  72. package/packages/omo-codex/plugin/components/git-bash/src/cli.ts +33 -0
  73. package/packages/omo-codex/plugin/components/git-bash/src/codex-hook.ts +180 -0
  74. package/packages/omo-codex/plugin/components/git-bash/src/index.ts +10 -0
  75. package/packages/omo-codex/plugin/components/git-bash/test/codex-hook.test.ts +195 -0
  76. package/packages/omo-codex/plugin/components/git-bash/tsconfig.build.json +13 -0
  77. package/packages/omo-codex/plugin/components/git-bash/tsconfig.json +25 -0
  78. package/packages/omo-codex/plugin/components/lsp/README.md +1 -1
  79. package/packages/omo-codex/plugin/components/lsp/src/cli.ts +5 -5
  80. package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +33 -0
  81. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +19 -27
  82. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-cli.test.ts +28 -0
  83. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-errors.test.ts +55 -0
  84. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +7 -5
  85. package/packages/omo-codex/plugin/components/rules/README.md +1 -1
  86. package/packages/omo-codex/plugin/components/rules/bundled-rules/windows-git-bash.md +10 -0
  87. package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +3 -1
  88. package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +97 -0
  89. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +5 -4
  90. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +22 -0
  91. package/packages/omo-codex/plugin/components/ultrawork/README.md +2 -2
  92. package/packages/omo-codex/plugin/components/ultrawork/agents/codex-ultrawork-reviewer.toml +1 -0
  93. package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +8 -7
  94. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +2 -1
  95. package/packages/omo-codex/plugin/components/ultrawork/directive.md +31 -5
  96. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +27 -4
  97. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +25 -0
  98. package/packages/omo-codex/plugin/components/ulw-loop/README.md +1 -1
  99. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +27 -205
  100. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +230 -0
  101. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +102 -5
  102. package/packages/omo-codex/plugin/hooks/hooks.json +24 -2
  103. package/packages/omo-codex/plugin/package-lock.json +19 -0
  104. package/packages/omo-codex/plugin/package.json +3 -1
  105. package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +16 -1
  106. package/packages/omo-codex/plugin/scripts/build-components.mjs +2 -1
  107. package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +87 -0
  108. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +27 -2
  109. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +20 -0
  110. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +27 -205
  111. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +230 -0
  112. package/packages/omo-codex/plugin/test/aggregate.test.mjs +23 -8
  113. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +56 -11
  114. package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +34 -0
  115. package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +21 -0
  116. package/packages/omo-codex/plugin/test/node-install-surface.test.mjs +48 -0
  117. package/packages/omo-codex/plugin/test/subagent-guidance.test.mjs +76 -0
  118. package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +66 -0
  119. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +32 -2
  120. package/packages/omo-codex/scripts/install/cache.mjs +5 -3
  121. package/packages/omo-codex/scripts/install/cli-args.mjs +112 -0
  122. package/packages/omo-codex/scripts/install/config.mjs +36 -1
  123. package/packages/omo-codex/scripts/install/delegated-command.mjs +25 -0
  124. package/packages/omo-codex/scripts/install/git-bash.mjs +99 -0
  125. package/packages/omo-codex/scripts/install/git-bash.test.mjs +174 -0
  126. package/packages/omo-codex/scripts/install/mcp-runtime-cache.mjs +5 -1
  127. package/packages/omo-codex/scripts/install/multi-agent-v2-config.mjs +7 -1
  128. package/packages/omo-codex/scripts/install/permissions.d.mts +1 -0
  129. package/packages/omo-codex/scripts/install/permissions.mjs +26 -0
  130. package/packages/omo-codex/scripts/install/project-local-cleanup.mjs +229 -0
  131. package/packages/omo-codex/scripts/install/reasoning-config.mjs +14 -0
  132. package/packages/omo-codex/scripts/install/source-package-build.mjs +20 -0
  133. package/packages/omo-codex/scripts/install/toml-editor.mjs +19 -2
  134. package/packages/omo-codex/scripts/install-cli-args.test.mjs +146 -0
  135. package/packages/omo-codex/scripts/install-config-autonomous.test.mjs +48 -0
  136. package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +62 -0
  137. package/packages/omo-codex/scripts/install-config.test.mjs +206 -0
  138. package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +129 -0
  139. package/packages/omo-codex/scripts/install-local-git-bash-preflight.test.mjs +145 -0
  140. package/packages/omo-codex/scripts/install-local.mjs +91 -8
  141. package/packages/omo-codex/scripts/install-local.test.mjs +15 -0
  142. package/packages/omo-codex/scripts/install-mcp-runtime.test.mjs +60 -0
  143. package/packages/omo-codex/scripts/install-packaged-local.test.mjs +67 -0
  144. package/packages/omo-codex/scripts/install-project-local-cleanup.test.mjs +277 -0
  145. package/packages/shared-skills/skills/review-work/SKILL.md +27 -2
  146. package/packages/shared-skills/skills/start-work/SKILL.md +20 -0
  147. package/dist/hooks/context-window-monitor.d.ts +0 -19
@@ -0,0 +1,55 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { runLspPostToolUseHook } from "../src/codex-hook.js";
4
+
5
+ describe("codex PostToolUse diagnostics errors", () => {
6
+ it("#given diagnostics runner throws for a mutated file #when the hook evaluates diagnostics #then it returns blocked output with the thrown message", async () => {
7
+ // given
8
+ const output = await runLspPostToolUseHook(
9
+ {
10
+ tool_name: "write",
11
+ tool_input: { path: "src/missing.ts" },
12
+ tool_response: { ok: true },
13
+ },
14
+ async (filePath) => {
15
+ expect(filePath).toBe("src/missing.ts");
16
+ throw new Error("ENOENT: no such file or directory, open 'src/missing.ts'");
17
+ },
18
+ );
19
+
20
+ // when
21
+ const parsed: unknown = JSON.parse(output);
22
+ if (!isPostToolUseHookOutput(parsed)) throw new TypeError("Expected PostToolUse hook output");
23
+
24
+ // then
25
+ expect(parsed.reason).toBe(
26
+ "LSP diagnostics after editing src/missing.ts:\n\nENOENT: no such file or directory, open 'src/missing.ts'",
27
+ );
28
+ expect(parsed.hookSpecificOutput.additionalContext).toBe(parsed.reason);
29
+ });
30
+ });
31
+
32
+ interface PostToolUseHookOutput {
33
+ readonly decision: "block";
34
+ readonly reason: string;
35
+ readonly hookSpecificOutput: {
36
+ readonly hookEventName: "PostToolUse";
37
+ readonly additionalContext: string;
38
+ };
39
+ }
40
+
41
+ function isPostToolUseHookOutput(value: unknown): value is PostToolUseHookOutput {
42
+ if (!isRecord(value)) return false;
43
+ const hookSpecificOutput = value["hookSpecificOutput"];
44
+ return (
45
+ value["decision"] === "block" &&
46
+ typeof value["reason"] === "string" &&
47
+ isRecord(hookSpecificOutput) &&
48
+ hookSpecificOutput["hookEventName"] === "PostToolUse" &&
49
+ typeof hookSpecificOutput["additionalContext"] === "string"
50
+ );
51
+ }
52
+
53
+ function isRecord(value: unknown): value is Record<string, unknown> {
54
+ return typeof value === "object" && value !== null && !Array.isArray(value);
55
+ }
@@ -56,6 +56,7 @@ describe("plugin package metadata", () => {
56
56
  const hooksJson = readHooksJson("hooks/hooks.json");
57
57
  const mcpJson = readMcpJson(".mcp.json");
58
58
  const cliSource = readFileSync("src/cli.ts", "utf8");
59
+ const codexHookCliSource = readFileSync("src/codex-hook-cli.ts", "utf8");
59
60
  const codexHookSource = readFileSync("src/codex-hook.ts", "utf8");
60
61
  const sourceFiles = readdirSync("src");
61
62
 
@@ -79,11 +80,12 @@ describe("plugin package metadata", () => {
79
80
  expect(lspServer?.command).toBe("node");
80
81
  expect(lspServer?.args).toEqual(["../../../../lsp-tools-mcp/dist/cli.js", "mcp"]);
81
82
  expect(cliSource).not.toContain("./lazy-lsp-mcp.js");
82
- expect(cliSource).not.toContain("@code-yeongyu/lsp-tools-mcp");
83
- expect(cliSource).toContain("../../../../../lsp-tools-mcp/dist/cli.js");
84
- expect(codexHookSource).not.toContain("@code-yeongyu/lsp-tools-mcp");
85
- expect(codexHookSource).toContain("../../../../../lsp-tools-mcp/dist/lsp/manager.js");
86
- expect(codexHookSource).toContain("../../../../../lsp-tools-mcp/dist/tools.js");
83
+ expect(cliSource).toContain("@code-yeongyu/lsp-tools-mcp/dist/cli.js");
84
+ expect(cliSource).not.toContain("../../../../../lsp-tools-mcp/dist/cli.js");
85
+ expect(codexHookCliSource).toContain("@code-yeongyu/lsp-tools-mcp/dist/lsp/manager.js");
86
+ expect(codexHookSource).toContain("@code-yeongyu/lsp-tools-mcp/dist/tools.js");
87
+ expect(codexHookCliSource).not.toContain("../../../../../lsp-tools-mcp/dist/lsp/manager.js");
88
+ expect(codexHookSource).not.toContain("../../../../../lsp-tools-mcp/dist/tools.js");
87
89
  expect(sourceFiles.filter((name) => name.startsWith("lazy-mcp") || name === "lazy-lsp-mcp.ts")).toEqual([]);
88
90
  });
89
91
 
@@ -43,7 +43,7 @@ Prefer strict TypeScript and keep runtime imports ESM-compatible.
43
43
  ## Install Locally
44
44
 
45
45
  ```bash
46
- bunx lazycodex install
46
+ npx lazycodex-ai install
47
47
  ```
48
48
 
49
49
  The local installer builds the plugin and copies a clean cache entry to:
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Windows Git Bash guidance for Codex
3
+ alwaysApply: true
4
+ ---
5
+
6
+ On Windows native Codex sessions, prefer Git Bash for shell commands.
7
+
8
+ Use `shell: "bash"` when `bash.exe` is on PATH. Otherwise use the absolute Git Bash path from `OMO_CODEX_GIT_BASH_PATH` or `C:\Program Files\Git\bin\bash.exe`.
9
+
10
+ Use PowerShell only for Windows-native operations that need PowerShell.
@@ -1,4 +1,4 @@
1
- import { readFileSync } from "node:fs";
1
+ import { readdirSync, readFileSync } from "node:fs";
2
2
  import { describe, expect, it } from "vitest";
3
3
 
4
4
  type PackageJson = {
@@ -51,6 +51,7 @@ describe("plugin package metadata", () => {
51
51
  const pluginJson = readPluginJson(".codex-plugin/plugin.json");
52
52
  const hooksJson = readHooksJson("hooks/hooks.json");
53
53
  const cliSource = readFileSync("src/cli.ts", "utf8");
54
+ const bundledRules = readdirSync("bundled-rules").sort();
54
55
 
55
56
  // when
56
57
  const hookConfig = hooksJson.hooks;
@@ -69,6 +70,7 @@ describe("plugin package metadata", () => {
69
70
  expect(packageJson.dependencies ?? {}).toEqual({ picomatch: "^4.0.3" });
70
71
  expect(packageJson.bin["omo-rules"]).toBe("./dist/cli.js");
71
72
  expect(packageJson.files).toContain("bundled-rules");
73
+ expect(bundledRules).toContain("windows-git-bash.md");
72
74
  expect(pluginJson.hooks).toBe("./hooks/hooks.json");
73
75
  expect(cliSource.startsWith("#!/usr/bin/env node")).toBe(true);
74
76
  expect(commands).toEqual([
@@ -0,0 +1,97 @@
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+
6
+ import { runSessionStartHook, type CodexSessionStartInput } from "../src/codex-hook.js";
7
+ import { findPluginBundledCandidates } from "../src/rules/finder.js";
8
+
9
+ const WINDOWS_RULE_DESCRIPTION = "Windows Git Bash guidance for Codex";
10
+ const WINDOWS_RULE_PATH = "bundled-rules/windows-git-bash.md";
11
+ const WINDOWS_GUIDANCE = "On Windows native Codex sessions, prefer Git Bash for shell commands.";
12
+ const BUNDLED_ONLY_ENV = {
13
+ CODEX_RULES_ENABLED_SOURCES: "plugin-bundled",
14
+ };
15
+ const PROJECT_AND_BUNDLED_ENV = {
16
+ CODEX_RULES_ENABLED_SOURCES: ".omo/rules,plugin-bundled",
17
+ };
18
+ const tempDirectories: string[] = [];
19
+ let originalPluginRoot: string | undefined;
20
+
21
+ afterEach(() => {
22
+ restoreEnv("PLUGIN_ROOT", originalPluginRoot);
23
+ for (const directory of tempDirectories.splice(0)) {
24
+ rmSync(directory, { recursive: true, force: true });
25
+ }
26
+ });
27
+
28
+ function makeProject(): { readonly root: string; readonly pluginData: string } {
29
+ originalPluginRoot = process.env["PLUGIN_ROOT"];
30
+ process.env["PLUGIN_ROOT"] = process.cwd();
31
+ const root = mkdtempSync(join(tmpdir(), "codex-rules-windows-git-bash-project-"));
32
+ const pluginData = mkdtempSync(join(tmpdir(), "codex-rules-windows-git-bash-data-"));
33
+ tempDirectories.push(root, pluginData);
34
+ writeFileSync(join(root, "package.json"), JSON.stringify({ name: "fixture" }));
35
+ return { root, pluginData };
36
+ }
37
+
38
+ function sessionStartInput(root: string): CodexSessionStartInput {
39
+ return {
40
+ session_id: "session-1",
41
+ transcript_path: null,
42
+ cwd: root,
43
+ hook_event_name: "SessionStart",
44
+ model: "gpt-5.5",
45
+ permission_mode: "default",
46
+ source: "startup",
47
+ };
48
+ }
49
+
50
+ function restoreEnv(name: string, value: string | undefined): void {
51
+ if (value === undefined) {
52
+ delete process.env[name];
53
+ return;
54
+ }
55
+ process.env[name] = value;
56
+ }
57
+
58
+ function occurrenceCount(value: string, search: string): number {
59
+ return value.split(search).length - 1;
60
+ }
61
+
62
+ describe("Windows Git Bash bundled rule", () => {
63
+ it("#given packaged bundled rules #when discovering plugin-bundled candidates #then Windows Git Bash rule is included", () => {
64
+ const candidates = findPluginBundledCandidates({ pluginRoot: process.cwd() });
65
+
66
+ expect(candidates.map((candidate) => candidate.relativePath)).toContain(WINDOWS_RULE_PATH);
67
+ });
68
+
69
+ it("#given bundled rules enabled #when SessionStart runs #then Windows Git Bash guidance is injected once", async () => {
70
+ const { root, pluginData } = makeProject();
71
+
72
+ const output = await runSessionStartHook(sessionStartInput(root), {
73
+ pluginDataRoot: pluginData,
74
+ env: BUNDLED_ONLY_ENV,
75
+ });
76
+
77
+ expect(occurrenceCount(output, WINDOWS_GUIDANCE)).toBe(1);
78
+ });
79
+
80
+ it("#given project rule with same description #when static rules load #then project guidance overrides bundled guidance", async () => {
81
+ const { root, pluginData } = makeProject();
82
+ const projectGuidance = "Project-specific Windows shell policy.";
83
+ mkdirSync(join(root, ".omo", "rules"), { recursive: true });
84
+ writeFileSync(
85
+ join(root, ".omo", "rules", "windows-git-bash.md"),
86
+ ["---", `description: ${WINDOWS_RULE_DESCRIPTION}`, "alwaysApply: true", "---", "", projectGuidance].join("\n"),
87
+ );
88
+
89
+ const output = await runSessionStartHook(sessionStartInput(root), {
90
+ pluginDataRoot: pluginData,
91
+ env: PROJECT_AND_BUNDLED_ENV,
92
+ });
93
+
94
+ expect(output).toContain(projectGuidance);
95
+ expect(output).not.toContain(WINDOWS_GUIDANCE);
96
+ });
97
+ });
@@ -18,10 +18,11 @@ You are mid-flight on a Prometheus work plan. The turn just ended without finish
18
18
  1. Read `{{PLAN_PATH}}` AND `{{LEDGER_PATH}}` first — ground truth for what remains and what evidence has already been recorded. The plan checkbox and the ledger are the only sources of truth; do not trust your own memory of prior turns.
19
19
  2. Pick the FIRST unchecked top-level checkbox in `## TODOs` or `## Final Verification Wave`. Ignore nested checkboxes under Acceptance Criteria / Evidence / Definition of Done.
20
20
  3. Follow the `start-work` skill in full. The skill is already loaded from your earlier turn — re-read its file at `packages/omo-codex/plugin/skills/start-work/SKILL.md` if you have lost context.
21
- 4. Decompose the checkbox into atomic sub-tasks. Dispatch them in PARALLEL via `spawn_agent` calls in this same response unless a sub-task has a NAMED blocking dependency (input from another sub-task or shared file).
22
- 5. Every sub-task message MUST include all 7 sections and name one Manual-QA channel with its exact tool and exact invocation (the literal `curl` / `send-keys` / `page.click` with concrete inputs and the binary PASS/FAIL observable), plus the applicable ultraqa adversarial classes, a captured artifact, and a cleanup receipt. Channels: HTTP call (`curl -i`); tmux (`send-keys` + `capture-pane`); browser use — use Chrome to drive the page, else download and use agent-browser (https://github.com/vercel-labs/agent-browser); computer use — OS-level GUI automation for a desktop app. Tests are the floor; the channel artifact plus probed adversarial classes are the ceiling. All are required.
23
- 6. After verification of ALL sub-tasks under this checkbox: `apply_patch` the plan to change `- [ ]` `- [x]`, re-read the plan to confirm the count decreased, append a `task-completed` line to the ledger, then continue.
24
- 7. Do not start fresh on a sub-agent failure. Re-dispatch the same `task_name` with a fix-message: `FAILED: <exact error>` + `Diagnosis: <observation>` + `Fix: <instruction>`.
21
+ 4. Decompose the checkbox into atomic sub-tasks. Dispatch them in PARALLEL via `spawn_agent` calls in this same response unless a sub-task has a NAMED blocking dependency (input from another sub-task or shared file). Prefer `fork_turns: "none"` unless full history is truly required. Every dispatch sets `agent_type`; `model` + `reasoning_effort` alone creates a default agent, not the requested role.
22
+ 5. Every sub-task message MUST be self-contained and start with `TASK: <imperative assignment>`, then name `DELIVERABLE`, `SCOPE`, and `VERIFY`. State that it is an executable assignment, not a context handoff. It must include all 7 sections and name one Manual-QA channel with its exact tool and exact invocation (the literal `curl` / `send-keys` / `page.click` with concrete inputs and the binary PASS/FAIL observable), plus the applicable ultraqa adversarial classes, a captured artifact, and a cleanup receipt. Channels: HTTP call (`curl -i`); tmux (`send-keys` + `capture-pane`); browser use — use Chrome to drive the page, else download and use agent-browser (https://github.com/vercel-labs/agent-browser); computer use — OS-level GUI automation for a desktop app. Tests are the floor; the channel artifact plus probed adversarial classes are the ceiling. All are required.
23
+ 6. Use `wait_agent` for completion signals, but treat `wait_agent` as a mailbox signal, not proof of completion, content, or errors. After two waits with no substantive result, send one targeted followup: `TASK STILL ACTIVE: return <deliverable> or BLOCKED: <reason>`. If still silent or ack-only, record inconclusive, do not count it as pass/review approval, close if safe, and respawn a smaller `fork_turns: "none"` task with the missing deliverable.
24
+ 7. After verification of ALL sub-tasks under this checkbox: `apply_patch` the plan to change `- [ ]` `- [x]`, re-read the plan to confirm the count decreased, append a `task-completed` line to the ledger, then continue.
25
+ 8. Do not start fresh on a sub-agent failure. Re-dispatch the same `task_name` with a fix-message: `FAILED: <exact error>` + `Diagnosis: <observation>` + `Fix: <instruction>`.
25
26
 
26
27
  # Hard constraints
27
28
 
@@ -49,6 +49,28 @@ describe("start-work Stop hook", () => {
49
49
  expect(parsed.reason).toContain("- Your session id in boulder.json: `codex:sess_abc`");
50
50
  });
51
51
 
52
+ it("#given active codex work #when continuation directive is emitted #then subagent guidance is reliable", () => {
53
+ // given
54
+ const fs = createMemoryFs({
55
+ [BOULDER_PATH]: createBoulderJson({
56
+ sessionIds: ["codex:sess_abc"],
57
+ status: "active",
58
+ }),
59
+ [PLAN_PATH]: ["# Plan", "", "## TODOs", "- [ ] First"].join("\n"),
60
+ });
61
+
62
+ // when
63
+ const output = runStopHook(createStopInput(), fs);
64
+
65
+ // then
66
+ const parsed = parseBlockOutput(output);
67
+ expect(parsed.reason).toMatch(/TASK:/);
68
+ expect(parsed.reason).toMatch(/fork_turns:\s*"none"/);
69
+ expect(parsed.reason).toMatch(/wait_agent.*signal, not proof/);
70
+ expect(parsed.reason).toMatch(/one targeted followup/);
71
+ expect(parsed.reason).toMatch(/respawn.*smaller/);
72
+ });
73
+
52
74
  it("#given active work belongs to another harness #when hook runs #then returns empty output", () => {
53
75
  // given
54
76
  const fs = createMemoryFs({
@@ -20,7 +20,7 @@ The directive is currently 10,951 chars / 231 lines and follows the GPT-5.5 prom
20
20
  ## Install (via this marketplace)
21
21
 
22
22
  ```bash
23
- bunx lazycodex install
23
+ npx lazycodex-ai install
24
24
  ```
25
25
 
26
26
  The installer copies the plugin into `~/.codex/plugins/cache/sisyphuslabs/omo/0.1.0`, writes the stable Codex marketplace snapshot at `~/.codex/.tmp/marketplaces/sisyphuslabs/`, registers the `sisyphuslabs` marketplace from the `lazycodex` Git repository, enables `omo@sisyphuslabs` in `~/.codex/config.toml`, registers the `UserPromptSubmit` hook, and installs the bundled agent TOMLs into `~/.codex/agents/` (symlinks on Unix, copies on Windows). A `.installed-agents.json` manifest is written next to the bundled TOMLs' source root for clean uninstall tracking.
@@ -49,7 +49,7 @@ Expect `<ultrawork-mode>` ... directive body.
49
49
 
50
50
  ## Agent role smoke test
51
51
 
52
- Run `bunx omo install --platform=codex`, then inspect `~/.codex/agents/`. On Linux / macOS you should see symlinks; on Windows you should see file copies. Each TOML should declare a non-empty `name`, `description`, and `developer_instructions`.
52
+ Run `npx lazycodex-ai install`, then inspect `~/.codex/agents/`. On Linux / macOS you should see symlinks; on Windows you should see file copies. Each TOML should declare a non-empty `name`, `description`, and `developer_instructions`.
53
53
 
54
54
  ## License
55
55
 
@@ -8,6 +8,7 @@ developer_instructions = """You are the ultrawork verification reviewer.
8
8
  Review only. Do not implement.
9
9
 
10
10
  Input should include the goal, success criteria, full diff, QA evidence, and notepad path.
11
+ If Codex delivers parent review context as inter-agent commentary, treat the latest parent message with goal/diff/evidence as your active review assignment, not passive context.
11
12
 
12
13
  Verdict rules:
13
14
  - Return `UNCONDITIONAL APPROVAL` only when the diff satisfies every success criterion and the evidence proves the real surface works.
@@ -55,7 +55,7 @@ If the user names a version ("React 18", "Next.js 14", "v2.x"):
55
55
 
56
56
  ## Step 4 - targeted investigation
57
57
  - `webfetch(<specific-doc-page-from-sitemap>)`.
58
- - If a docs-indexer / library-index tool is available, query it for the specific topic. Otherwise rely on the sitemap-driven webfetch pages.
58
+ - If `context7` is available, query it for the specific topic. Otherwise rely on the sitemap-driven webfetch pages.
59
59
 
60
60
  ## Skip Phase 0.5 when
61
61
  - TYPE B (implementation) - you're cloning the repo anyway.
@@ -70,7 +70,7 @@ If the user names a version ("React 18", "Next.js 14", "v2.x"):
70
70
  Run Phase 0.5 first, then in parallel:
71
71
  - `web_search` for current-year usage examples + best practices.
72
72
  - `webfetch` for the targeted doc pages identified by the sitemap.
73
- - `gh search code "<usage pattern>" --language <lang>` for real-world code samples.
73
+ - `grep_app` for broad GitHub code search; fall back to `gh search code "<usage pattern>" --language <lang>`.
74
74
 
75
75
  ## TYPE B - IMPLEMENTATION REFERENCE
76
76
  Execute in sequence:
@@ -81,9 +81,9 @@ Execute in sequence:
81
81
 
82
82
  Parallel acceleration (4+ calls in one batch when independent):
83
83
  - Shallow clone.
84
- - `gh search code "<function-name>" --repo <owner>/<repo>`.
84
+ - `grep_app` broad code search or `gh search code "<function-name>" --repo <owner>/<repo>`.
85
85
  - `gh api repos/<owner>/<repo>/commits/HEAD --jq '.sha'`.
86
- - Sitemap-targeted `webfetch` of the relevant docs page for the same API surface.
86
+ - `context7` or sitemap-targeted `webfetch` of the relevant docs page for the same API surface.
87
87
 
88
88
  ## TYPE C - CONTEXT & HISTORY
89
89
  Execute in parallel (4+ calls):
@@ -100,7 +100,7 @@ For a specific issue / PR:
100
100
  ## TYPE D - COMPREHENSIVE
101
101
  Run Phase 0.5 first, then execute 6+ parallel calls:
102
102
  - 2 docs calls: `webfetch` targeted doc pages + (if available) a docs-indexer query.
103
- - 2 code-search calls: `gh search code` with varied queries (different angles).
103
+ - 2 code-search calls: `grep_app` or `gh search code` with varied queries (different angles).
104
104
  - 1 source clone for deep inspection.
105
105
  - 1 issues/PRs query for context.
106
106
 
@@ -147,8 +147,9 @@ Never link to a branch name (`/blob/main/...`) - always pin to a SHA so the line
147
147
  - Sitemap -> `webfetch(<base>/sitemap.xml)` (fallbacks: `/sitemap-0.xml`, `/sitemap_index.xml`).
148
148
  - Read a specific page -> `webfetch(<page-url>)`.
149
149
  - Latest info -> `web_search("<query> <CURRENT_YEAR>")`.
150
- - Code search (fast, broad) -> `gh search code "<query>" --language <lang>` (org-wide or repo-scoped).
151
- - Code search (deep, repo-scoped) -> after cloning, `rg` / `ast_grep_search` over the clone.
150
+ - Docs index -> `context7` when available; use sitemap-driven pages when it is not.
151
+ - Code search (fast, broad) -> `grep_app` for web-scale GitHub search; `gh search code "<query>" --language <lang>` when you need GitHub CLI filters.
152
+ - Code search (deep, repo-scoped) -> after cloning, `rg` / `ast_grep` over the clone.
152
153
  - Clone -> `gh repo clone <o>/<r> "${TMPDIR:-/tmp}/<name>" -- --depth 1`.
153
154
  - Issues / PRs -> `gh search issues|prs`, `gh issue|pr view <n> --comments`.
154
155
  - Release info -> `gh api repos/<o>/<r>/releases/latest`.
@@ -29,7 +29,8 @@ Never plan blind. Fire parallel research BEFORE drafting:
29
29
  - Spawn parallel read-only subagents for internal-source aspects (codebase patterns, conventions, existing implementations, test infrastructure, naming/registration patterns). One subagent per aspect.
30
30
  - Spawn parallel read-only subagents for external-source aspects (official docs, OSS reference implementations, API contracts, RFCs). One subagent per aspect.
31
31
  - While they run, use direct read-only tools (`read`, `rg`, `ast_grep_search`, `lsp_*`) for immediate context. Do not idle.
32
- - The role's own system prompt determines each subagent's output shape. Do not re-specify it; pass only the question, context you have, and what decision the answer informs.
32
+ - The role's own system prompt determines each subagent's output shape. Do not re-specify it; pass only a self-contained `TASK: <question to answer now>`, the minimal context you have, `DELIVERABLE`, and what decision the answer informs.
33
+ - Prefer `fork_turns: "none"` for research subagents unless full history is truly required. Treat `wait_agent` as a signal, not proof; if a child is silent or ack-only after one targeted followup, mark that lane inconclusive and answer from direct evidence or respawn smaller.
33
34
 
34
35
  Wait for context to converge before drafting. Rushed plans fail.
35
36
 
@@ -185,8 +185,31 @@ Until every success-criteria scenario PASSES with BOTH evidence pieces:
185
185
 
186
186
  Parallel-batch independent reads / searches / subagents within a step,
187
187
  but NEVER parallelise RED and GREEN of the same criterion.
188
- Do not use `list_agents` as a polling or status tool in long or high-context runs; it can replay large agent status and latest-message payloads.
189
- Track spawned agent names locally, use `wait_agent` for completion, send targeted followups only when needed, and `close_agent` after integrating each result.
188
+
189
+ # Codex subagent reliability
190
+ Every `spawn_agent` message is self-contained and starts with
191
+ `TASK: <imperative assignment>`, then names `DELIVERABLE`, `SCOPE`, and
192
+ `VERIFY`. State that it is an executable assignment, not a context
193
+ handoff. Prefer `fork_turns: "none"` unless full history is truly
194
+ required; paste only the context the child needs. Full-history forks can
195
+ make the child continue old parent context instead of the delegated task.
196
+
197
+ Do not use `list_agents` as a polling or status tool in long or
198
+ high-context runs; it can replay large agent status and latest-message
199
+ payloads. Track spawned agent names locally. Plan and reviewer agents
200
+ may run for a long time; spawn them in the background, keep doing
201
+ independent root work, and poll with short wait_agent cycles. Never use
202
+ a single long blocking wait for them. Use `wait_agent` for completion
203
+ signals, but treat `wait_agent` as a mailbox signal, not proof of
204
+ completion, content, or errors. A worker/reviewer counts only after you
205
+ receive substantive output and verify its diff/evidence.
206
+ After two waits with no substantive result, send one targeted followup:
207
+ `TASK STILL ACTIVE: return <deliverable> or BLOCKED: <reason>`. If it is
208
+ still silent or ack-only, record the result as inconclusive, do not
209
+ count it as approval/pass, close it if safe, and respawn a smaller
210
+ `fork_turns: "none"` task with the missing deliverable. Use targeted
211
+ followups only when needed, and `close_agent` after integrating each
212
+ result.
190
213
 
191
214
  # Verification gate (TRIGGERED, NOT OPTIONAL)
192
215
 
@@ -197,9 +220,12 @@ Trigger when ANY apply:
197
220
  anything the user called deep.
198
221
 
199
222
  Procedure (NON-NEGOTIABLE):
200
- 1. Spawn agent_type `codex-ultrawork-reviewer` (or any `gpt-5.2`
201
- xhigh reviewer if unavailable). Pass: goal, success-criteria,
202
- scenario evidence, full diff, notepad path.
223
+ 1. Spawn `agent_type="codex-ultrawork-reviewer"` with
224
+ `fork_turns: "none"`. If unavailable, spawn `agent_type="worker"`
225
+ with a self-contained reviewer assignment and tight scope. `model` +
226
+ `reasoning_effort` alone creates a default agent, not a reviewer.
227
+ Pass: goal, success-criteria, scenario evidence, full diff, notepad
228
+ path.
203
229
  2. Treat the reviewer's verdict as binding. There is NO "false
204
230
  positive". Every concern is real. Do not argue. Do not minimise. Do
205
231
  not explain it away.
@@ -161,11 +161,34 @@ describe("codex ultrawork hook", () => {
161
161
  const directive = parsed.hookSpecificOutput.additionalContext;
162
162
  expect(directive).toMatch(/list_agents/);
163
163
  expect(directive).toMatch(/polling or status tool/);
164
- expect(directive).toMatch(/replay large agent status and latest-message payloads/);
164
+ expect(directive).toMatch(/replay large agent status and latest-message\s+payloads/);
165
165
  expect(directive).toMatch(/Track spawned agent names locally/);
166
- expect(directive).toMatch(/wait_agent.*completion/);
167
- expect(directive).toMatch(/targeted followups only when needed/);
168
- expect(directive).toMatch(/close_agent.*after integrating each result/);
166
+ expect(directive).toMatch(/wait_agent[\s\S]*completion/);
167
+ expect(directive).toMatch(/targeted\s+followups only when needed/);
168
+ expect(directive).toMatch(/close_agent[\s\S]*after integrating each\s+result/);
169
+ expect(directive).toMatch(/Plan and reviewer agents\s+may run for a long time/);
170
+ expect(directive).toMatch(/short wait_agent cycles/);
171
+ expect(directive).toMatch(/single long blocking wait/);
172
+ });
173
+
174
+ it("#given directive #when inspected #then hardens Codex subagent assignment ambiguity", () => {
175
+ // given
176
+ const payload = {
177
+ hook_event_name: "UserPromptSubmit",
178
+ prompt: "please ultrawork",
179
+ };
180
+
181
+ // when
182
+ const output = runUserPromptSubmitHook(payload);
183
+ const parsed = parseHookOutput(output);
184
+
185
+ // then
186
+ const directive = parsed.hookSpecificOutput.additionalContext;
187
+ expect(directive).toMatch(/TASK:/);
188
+ expect(directive).toMatch(/fork_turns:\s*"none"/);
189
+ expect(directive).toMatch(/wait_agent[\s\S]*signal, not\s+proof/);
190
+ expect(directive).toMatch(/one targeted followup/);
191
+ expect(directive).toMatch(/respawn.*smaller/);
169
192
  });
170
193
  });
171
194
 
@@ -34,6 +34,31 @@ describe("codex ultrawork package metadata", () => {
34
34
  expect(hookCommands).toContain(`node "${pluginRoot}/dist/cli.js" hook user-prompt-submit`);
35
35
  expect(hookCommands).not.toContainEqual(expect.stringMatching(/\bpython3?\b|ultrawork-detector\.py/));
36
36
  });
37
+
38
+ it("#given explorer guidance #when inspected #then names the packaged code-search MCP surface", () => {
39
+ // given
40
+ const explorer = readFileSync("agents/explorer.toml", "utf8");
41
+
42
+ // when
43
+ const guidance = explorer.toLowerCase();
44
+
45
+ // then
46
+ expect(guidance).toContain("ast_grep");
47
+ expect(guidance).toContain("structural");
48
+ });
49
+
50
+ it("#given librarian guidance #when inspected #then names the packaged research MCP surfaces", () => {
51
+ // given
52
+ const librarian = readFileSync("agents/librarian.toml", "utf8");
53
+
54
+ // when
55
+ const guidance = librarian.toLowerCase();
56
+
57
+ // then
58
+ expect(guidance).toContain("grep_app");
59
+ expect(guidance).toContain("context7");
60
+ expect(guidance).toContain("ast_grep");
61
+ });
37
62
  });
38
63
 
39
64
  function readJson(path: string): unknown {
@@ -47,7 +47,7 @@ npm pack --dry-run
47
47
  ## Local Codex Installation
48
48
 
49
49
  ```bash
50
- bunx lazycodex install
50
+ npx lazycodex-ai install
51
51
  ```
52
52
 
53
53
  The installer builds and copies the plugin into `~/.codex/plugins/cache/sisyphuslabs/omo/0.1.0`, registers the `sisyphuslabs` marketplace from the `lazycodex` Git repository, installs runtime dependencies there, and enables: