code-yeongyu / code-yeongyu/lazycodex
Bound Codex bootstrap thread limits for token control
- Dominant language
- TypeScript
- Stars
- 3.5k
- Forks
- 216
- PR merge metrics
- No merged PRs in 30d
Description
## Problem Situation
Codex token optimization lowered local agent thread limits to 4, but LazyCodex/OMO bootstrap provisioning could restore high defaults. The shipped OMO bundles still set `CODEX_SUBAGENT_THREAD_LIMIT = 1000` and `CODEX_MULTI_AGENT_V2_THREAD_LIMIT = 16`, so a session-start/worker provisioning pass can undo local token-control settings.
## Reproduction Logs
RED regression before the fix, from a fresh `code-yeongyu/lazycodex` worktree at `895b70c`:
```text
node --test test/codex-token-thread-limits.test.mjs
fails because shipped bundles do not contain `var CODEX_SUBAGENT_THREAD_LIMIT = 4;` or `var CODEX_MULTI_AGENT_V2_THREAD_LIMIT = 4;`.
```
Manual smoke before completing the fix also showed the bootstrap worker lowered `[agents].max_threads` but left existing `[features.multi_agent_v2].max_concurrent_threads_per_session = 16`, because the helper returned early when that setting already existed.
## Root Cause
The generated OMO bootstrap/install helper has two token-cost problems:
- It ships high concurrency defaults: `CODEX_SUBAGENT_THREAD_LIMIT = 1000` and `CODEX_MULTI_AGENT_V2_THREAD_LIMIT = 16`.
- It skips rewriting `features.multi_agent_v2.max_concurrent_threads_per_session` when the setting already exists, so existing installs can remain at `16` even after lowering the constant.
## Verified Fix
Lower both shipped defaults to `4`, remove the early return so existing `features.multi_agent_v2.max_concurrent_threads_per_session` values are replaced with the bounded value, and add a Node test that runs the bootstrap worker against a temporary Codex home with `1000/16` configured.
```diff
diff --git a/plugins/omo/components/bootstrap/dist/cli.js b/plugins/omo/components/bootstrap/dist/cli.js
index 43fc26a..6fa7ac1 100755
--- a/plugins/omo/components/bootstrap/dist/cli.js
+++ b/plugins/omo/components/bootstrap/dist/cli.js
@@ -3006,8 +3006,8 @@ import { dirname as dirname7, isAbsolute as isAbsolute5, join as join17 } from "
var CODEX_AGENTS_HEADER = "agents";
var CODEX_MULTI_AGENT_V2_HEADER = "features.multi_agent_v2";
var CODEX_MULTI_AGENT_V2_THREAD_LIMIT_KEY = `${CODEX_MULTI_AGENT_V2_HEADER}.max_concurrent_threads_per_session`;
-var CODEX_SUBAGENT_THREAD_LIMIT = 1000;
-var CODEX_MULTI_AGENT_V2_THREAD_LIMIT = 16;
+var CODEX_SUBAGENT_THREAD_LIMIT = 4;
+var CODEX_MULTI_AGENT_V2_THREAD_LIMIT = 4;
function ensureCodexMultiAgentV2Config(config, options = {}) {
const featureFlag = removeFeatureFlagSetting(config, "multi_agent_v2");
const v2Preferred = options.multiAgentVersion === "v2";
@@ -3015,8 +3015,6 @@ function ensureCodexMultiAgentV2Config(config, options = {}) {
const agentsConfig = v2Preferred ? removeAgentsMaxThreads(featureFlag.config) : modelKnown ? ensureAgentsMaxThreads(featureFlag.config) : raiseExistingAgentsMaxThreads(featureFlag.config);
const preserveDisable = featureFlag.value === false && !v2Preferred;
const featureConfig = preserveDisable ? setMultiAgentV2Disable(agentsConfig) : v2Preferred ? removeMultiAgentV2Disable(agentsConfig) : agentsConfig;
- if (hasTomlSetting(featureConfig, CODEX_MULTI_AGENT_V2_THREAD_LIMIT_KEY))
- return featureConfig;
const section = findTomlSection(featureConfig, CODEX_MULTI_AGENT_V2_HEADER);
if (!section) {
const enabledSetting = preserveDisable ? `enabled = false
diff --git a/plugins/omo/dist/cli-node/index.js b/plugins/omo/dist/cli-node/index.js
index c41f475..e971294 100755
--- a/plugins/omo/dist/cli-node/index.js
+++ b/plugins/omo/dist/cli-node/index.js
@@ -98168,8 +98168,8 @@ import { dirname as dirname14, isAbsolute as isAbsolute7, join as join38 } from
var CODEX_AGENTS_HEADER = "agents";
var CODEX_MULTI_AGENT_V2_HEADER = "features.multi_agent_v2";
var CODEX_MULTI_AGENT_V2_THREAD_LIMIT_KEY = `${CODEX_MULTI_AGENT_V2_HEADER}.max_concurrent_threads_per_session`;
-var CODEX_SUBAGENT_THREAD_LIMIT = 1000;
-var CODEX_MULTI_AGENT_V2_THREAD_LIMIT = 16;
+var CODEX_SUBAGENT_THREAD_LIMIT = 4;
+var CODEX_MULTI_AGENT_V2_THREAD_LIMIT = 4;
function ensureCodexMultiAgentV2Config(config3, options = {}) {
const featureFlag = removeFeatureFlagSetting(config3, "multi_agent_v2");
const v2Preferred = options.multiAgentVersion === "v2";
@@ -98177,8 +98177,6 @@ function ensureCodexMultiAgentV2Config(config3, options = {}) {
const agentsConfig = v2Preferred ? removeAgentsMaxThreads(featureFlag.config) : modelKnown ? ensureAgentsMaxThreads(featureFlag.config) : raiseExistingAgentsMaxThreads(featureFlag.config);
const preserveDisable = featureFlag.value === false && !v2Preferred;
const featureConfig = preserveDisable ? setMultiAgentV2Disable(agentsConfig) : v2Preferred ? removeMultiAgentV2Disable(agentsConfig) : agentsConfig;
- if (hasTomlSetting(featureConfig, CODEX_MULTI_AGENT_V2_THREAD_LIMIT_KEY))
- return featureConfig;
const section = findTomlSection(featureConfig, CODEX_MULTI_AGENT_V2_HEADER);
if (!section) {
const enabledSetting = preserveDisable ? `enabled = false
diff --git a/plugins/omo/dist/cli/index.js b/plugins/omo/dist/cli/index.js
index a2e6bbb..a128de5 100755
--- a/plugins/omo/dist/cli/index.js
+++ b/plugins/omo/dist/cli/index.js
@@ -98112,8 +98112,8 @@ import { dirname as dirname14, isAbsolute as isAbsolute7, join as join38 } from
var CODEX_AGENTS_HEADER = "agents";
var CODEX_MULTI_AGENT_V2_HEADER = "features.multi_agent_v2";
var CODEX_MULTI_AGENT_V2_THREAD_LIMIT_KEY = `${CODEX_MULTI_AGENT_V2_HEADER}.max_concurrent_threads_per_session`;
-var CODEX_SUBAGENT_THREAD_LIMIT = 1000;
-var CODEX_MULTI_AGENT_V2_THREAD_LIMIT = 16;
+var CODEX_SUBAGENT_THREAD_LIMIT = 4;
+var CODEX_MULTI_AGENT_V2_THREAD_LIMIT = 4;
function ensureCodexMultiAgentV2Config(config3, options = {}) {
const featureFlag = removeFeatureFlagSetting(config3, "multi_agent_v2");
const v2Preferred = options.multiAgentVersion === "v2";
@@ -98121,8 +98121,6 @@ function ensureCodexMultiAgentV2Config(config3, options = {}) {
const agentsConfig = v2Preferred ? removeAgentsMaxThreads(featureFlag.config) : modelKnown ? ensureAgentsMaxThreads(featureFlag.config) : raiseExistingAgentsMaxThreads(featureFlag.config);
const preserveDisable = featureFlag.value === false && !v2Preferred;
const featureConfig = preserveDisable ? setMultiAgentV2Disable(agentsConfig) : v2Preferred ? removeMultiAgentV2Disable(agentsConfig) : agentsConfig;
- if (hasTomlSetting(featureConfig, CODEX_MULTI_AGENT_V2_THREAD_LIMIT_KEY))
- return featureConfig;
const section = findTomlSection(featureConfig, CODEX_MULTI_AGENT_V2_HEADER);
if (!section) {
const enabledSetting = preserveDisable ? `enabled = false
diff --git a/test/codex-token-thread-limits.test.mjs b/test/codex-token-thread-limits.test.mjs
new file mode 100644
index 0000000..a13311b
--- /dev/null
+++ b/test/codex-token-thread-limits.test.mjs
@@ -0,0 +1,71 @@
+import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
+import assert from "node:assert/strict";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+import { spawnSync } from "node:child_process";
+import { describe, test } from "node:test";
+
+const repoRoot = new URL("..", import.meta.url).pathname;
+
+const shippedBundles = [
+ "plugins/omo/components/bootstrap/dist/cli.js",
+ "plugins/omo/dist/cli/index.js",
+ "plugins/omo/dist/cli-node/index.js",
+];
+
+describe("Codex token-control thread limits", () => {
+ for (const relativePath of shippedBundles) {
+ test(`${relativePath} keeps bootstrap thread limits bounded`, () => {
+ const source = readFileSync(join(repoRoot, relativePath), "utf8");
+
+ assert.match(source, /var CODEX_SUBAGENT_THREAD_LIMIT = 4;/);
+ assert.match(source, /var CODEX_MULTI_AGENT_V2_THREAD_LIMIT = 4;/);
+ });
+ }
+
+ test("bootstrap worker lowers existing Codex thread limits", () => {
+ const smokeRoot = mkdtempSync(join(tmpdir(), "lazycodex-thread-limit-"));
+ const codexHome = join(smokeRoot, "codex");
+ const home = join(smokeRoot, "home");
+ mkdirSync(codexHome);
+ mkdirSync(home);
+ writeFileSync(
+ join(codexHome, "config.toml"),
+ [
+ 'model = "gpt-5.5"',
+ 'model_provider = "ly-chatai"',
+ "",
+ "[features]",
+ "multi_agent = true",
+ "",
+ "[agents]",
+ "enabled = true",
+ "max_threads = 1000",
+ "",
+ "[features.multi_agent_v2]",
+ "max_concurrent_threads_per_session = 16",
+ "",
+ ].join("\n"),
+ );
+
+ const result = spawnSync(
+ process.execPath,
+ [
+ join(repoRoot, "plugins/omo/components/bootstrap/dist/cli.js"),
+ "worker",
+ "--codex-home",
+ codexHome,
+ "--once",
+ ],
+ {
+ encoding: "utf8",
+ env: { ...process.env, HOME: home },
+ },
+ );
+
+ assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`);
+ const config = readFileSync(join(codexHome, "config.toml"), "utf8");
+ assert.match(config, /^max_threads = 4$/m);
+ assert.match(config, /^max_concurrent_threads_per_session = 4$/m);
+ });
+});
```
## Verification
- RED: `node --test test/codex-token-thread-limits.test.mjs` failed before the fix because all three shipped bundles still used high thread limits.
- GREEN focused: `node --test test/codex-token-thread-limits.test.mjs` -> 4 tests passed.
- GREEN suite: `npm test` -> 13 tests passed.
- Manual QA: `node plugins/omo/components/bootstrap/dist/cli.js worker --codex-home --once` rewrote a temporary config from `agents.max_threads = 1000` and `features.multi_agent_v2.max_concurrent_threads_per_session = 16` to `4` and `4`.
---
This fix was debugged, implemented, and verified with [LazyCodex](https://github.com/code-yeongyu/lazycodex).
Tag: lazycodex-generated
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with test/codex-token-thread-limits.test.mjs and inspect the three shipped bundles it names: plugins/omo/components/bootstrap/dist/cli.js, plugins/omo/dist/cli/index.js, and plugins/omo/dist/cli-node/index.js. Run the focused Node test first, then npm test; done means the bootstrap rewrites both existing limits to 4 and all tests pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- cli, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 30/100