Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog

## 0.9.3 — Unreleased
## 0.9.4 — Unreleased

- Give every bundled Claude MCP launcher a 660-second Codex tool timeout so
Opus 5 XHigh reviews can use the bridge's full 600-second subprocess budget
and still return a schema-validated decision or fail-closed timeout result.

## 0.9.3 — 2026-07-26

- Raise the bounded Advisor approval loop from five to eight reviews while
preserving immediate approval exit and fail-closed plan, ledger, and
Expand Down
2 changes: 1 addition & 1 deletion plugins/codex-orchestration/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codex-orchestration",
"version": "0.9.3",
"version": "0.9.4",
"description": "Give Codex and audited external models safe, provider-pinned roles.",
"author": {
"name": "CJ Zafir",
Expand Down
3 changes: 3 additions & 0 deletions plugins/codex-orchestration/.mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"skills/codex-orchestration/scripts/fable_advisor_mcp.py"
],
"cwd": ".",
"tool_timeout_sec": 660,
"enabled": false
},
"fable-advisor-python": {
Expand All @@ -14,6 +15,7 @@
"skills/codex-orchestration/scripts/fable_advisor_mcp.py"
],
"cwd": ".",
"tool_timeout_sec": 660,
"enabled": false
},
"fable-advisor-py": {
Expand All @@ -23,6 +25,7 @@
"skills/codex-orchestration/scripts/fable_advisor_mcp.py"
],
"cwd": ".",
"tool_timeout_sec": 660,
"enabled": false
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,12 @@ Prerequisites:

The plugin packages three disabled MCP launcher variants for macOS, Linux, and Windows. Setup enables exactly one compatible variant through the plugin's namespaced config when either bundled Claude model is selected. At planning or review time the MCP server gives authentication and model subprocesses only a minimal platform environment. It preserves `HOME` plus canonical operating-system `USER` and `LOGNAME` on POSIX, or `USERPROFILE` on Windows, for first-party login discovery. It does not trust ambient POSIX identity values and does not inherit credential, config-redirection, provider/model/effort, endpoint/gateway, proxy/CA/mTLS, or telemetry override families. It invokes `claude --print --model <sealed-model-id>` with `--safe-mode`, no tools, no session persistence, prompt suggestions disabled, and JSON output. Advisor review additionally requires Claude Code's `--json-schema` capability. Each saved seat pins its model and effort; the root cannot replace them through tool arguments.

Each bundled launcher gives Codex a 660-second MCP tool timeout, slightly longer
than the bridge's 600-second Claude subprocess timeout. Keep the outer timeout
strictly greater than the inner timeout so an XHigh call can return either its
schema-validated result or the bridge's fail-closed timeout error instead of being
cancelled first by Codex's shorter default.

Fable effort is configurable per setup. The default is `high`; supported Claude Code values are `low`, `medium`, `high`, `xhigh`, and `max`. Accept `ultra` as an alias for `max`, save the effective Claude Code value, and disclose the alias mapping in setup output. Existing saved `max` routes remain valid.

Opus effort is also configurable and defaults to `high`. Its sealed set is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ def __init__(
"clientInfo": {
"name": "codex_orchestration_installer",
"title": "Codex Orchestration Installer",
"version": "0.9.3",
"version": "0.9.4",
},
"capabilities": {"experimentalApi": True},
},
Expand Down
2 changes: 1 addition & 1 deletion tests/plugin_lifecycle_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
MARKETPLACE_NAME = "codex-orchestration"
OLD_RELEASE = "a1d9c546665c3253cdcaa8fe5c0c060199a6126c"
OLD_VERSION = "0.5.0"
NEW_VERSION = "0.9.3"
NEW_VERSION = "0.9.4"
COMMAND_TIMEOUT_SECONDS = 60


Expand Down
23 changes: 20 additions & 3 deletions tests/test_packaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ def test_plugin_marketplace_and_skill_names_are_aligned(self) -> None:

self.assertEqual(manifest["name"], "codex-orchestration")
self.assertEqual(manifest["skills"], "./skills/")
self.assertEqual(manifest["version"], "0.9.3")
self.assertEqual(manifest["version"], "0.9.4")
self.assertEqual(manifest["mcpServers"], "./.mcp.json")
self.assertRegex(
manifest["version"],
Expand All @@ -278,7 +278,7 @@ def test_native_and_custom_configurators_are_packaged(self) -> None:
self.assertFalse((SKILL_ROOT / "scripts" / "update_plugin.py").exists())
self.assertIn("config/batchWrite", native.read_text(encoding="utf-8"))
self.assertIn('"--repair"', native.read_text(encoding="utf-8"))
self.assertIn('"version": "0.9.3"', native.read_text(encoding="utf-8"))
self.assertIn('"version": "0.9.4"', native.read_text(encoding="utf-8"))
self.assertIn("validate_routing_state", routing_state.read_text(encoding="utf-8"))
self.assertIn("Standalone custom agent", custom.read_text(encoding="utf-8"))

Expand Down Expand Up @@ -332,7 +332,24 @@ def test_fable_mcp_is_packaged_and_disabled_until_selected(self) -> None:
for server in servers.values():
self.assertFalse(server["enabled"])
self.assertEqual(server["cwd"], ".")
self.assertEqual(server["tool_timeout_sec"], 660)
self.assertIn("fable_advisor_mcp.py", server["args"][-1])
bridge = (
SKILL_ROOT / "scripts" / "fable_advisor_mcp.py"
).read_text(encoding="utf-8")
timeout_match = re.search(
r"(?m)^CLAUDE_TIMEOUT_SECONDS\s*=\s*(\d+)$",
bridge,
)
self.assertIsNotNone(timeout_match)
assert timeout_match is not None
bridge_timeout = int(timeout_match.group(1))
self.assertTrue(
all(
server["tool_timeout_sec"] > bridge_timeout
for server in servers.values()
)
)
self.assertTrue((SKILL_ROOT / "scripts" / "fable_advisor_mcp.py").is_file())

def test_explicit_and_natural_language_invocation_metadata_is_consistent(self) -> None:
Expand Down Expand Up @@ -453,7 +470,7 @@ def test_ci_runs_dual_version_plugin_lifecycle(self) -> None:
self.assertIn("@openai/codex@0.144.1", workflow)
smoke_text = smoke.read_text(encoding="utf-8")
self.assertIn('OLD_VERSION = "0.5.0"', smoke_text)
self.assertIn('NEW_VERSION = "0.9.3"', smoke_text)
self.assertIn('NEW_VERSION = "0.9.4"', smoke_text)
self.assertIn("old Advisor-only cache unexpectedly supports Planner", smoke_text)
self.assertIn("Upgraded installed skill is missing Planner contract", smoke_text)
self.assertIn("reused the Advisor-only 0.5.0 cache directory", smoke_text)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_release_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def commit(self, message: str) -> str:

class ReleaseCheckTests(unittest.TestCase):
def test_checkout_release_metadata_is_consistent(self) -> None:
self.assertEqual(RELEASE.run_check(REPO_ROOT, require_tag=False), "0.9.3")
self.assertEqual(RELEASE.run_check(REPO_ROOT, require_tag=False), "0.9.4")

def test_unreleased_checkout_is_not_tag_ready(self) -> None:
with self.assertRaisesRegex(RELEASE.ReleaseCheckError, "not tagged"):
Expand Down
Loading