Skip to content
Merged
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: 4 additions & 4 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
"email": "hi@okis.dev"
},
"description": "Multi-model orchestration marketplace for Claude Code.",
"version": "0.0.40",
"version": "0.0.41",
"plugins": [
{
"name": "grok",
"source": "./plugins/grok",
"displayName": "Grok Companion",
"description": "Local Grok CLI delegation: task, review, resumable history, best-of-n tournaments, background jobs, stats, and setup health checks.",
"version": "0.0.40",
"version": "0.0.41",
"author": {
"name": "Harry Yep"
},
Expand All @@ -34,7 +34,7 @@
"source": "./plugins/codex",
"displayName": "Codex Companion",
"description": "First party local Codex CLI delegation for tasks, reviews, resumable threads, and durable background jobs.",
"version": "0.0.40",
"version": "0.0.41",
"author": {
"name": "Harry Yep"
},
Expand All @@ -55,7 +55,7 @@
"source": "./plugins/fusion",
"displayName": "Fusion Orchestrator",
"description": "Multi-model orchestration: tier agents, routing rules, blind panel, ultra fleet, model config, and drift doctor.",
"version": "0.0.40",
"version": "0.0.41",
"author": {
"name": "Harry Yep"
},
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# changelog

## 0.0.41

- the worker token budget stops eating deliverables: a one shot wind down lands at 85 percent of the output token budget telling the worker to stop calling tools and write the deliverable, and after the limit trips exactly one final `Write` is still permitted (`terminalWriteGraceUsedAt`) while every other tool stays denied with the deny reason naming the grace; the subagent start announcement and all three worker prompts state both (observed live: three of four mining workers lost their final report write to the old hard deny)
- settlement grammar sheds its two most repeated stumbles: a bare `/fusion:stats` invocation now renders the plain report because the empty argument list joins the value free direct family, and a single `--record` flag accepts multiple `<id>=<verdict>` pairs identically in the strict direct family and the raw args transport parser (seven contract errors across four sessions in one mining window motivated both)
- codex telemetry gets discriminating about time: per SKU trends add a near cap share (timeout deaths plus finishes within 30 seconds of the 570 second deadline), terminal ledger records carry `timeoutMs` and `failureKind` so ledger recovered timeouts stop understating `timeoutShare`, and peer wrapper ledger records derive `packageType` from an explicit `package-type:` line, then a `--write` or `--transport-default-write` token before the `--` separator, then the verification heuristic, instead of blanket `consult` (120 of 131 live jobs were mislabeled)
- grok reaches observability parity: the jobs observer emits `model-audit.jsonl` rows for terminal grok jobs (`appendModelAuditObservation` moves to `fusion-stats.mjs` exports) and its token rows gain `repositoryKey`; `--prune-dead` also sweeps orphaned `acceptance.jsonl` sidecars, dead since the 0.0.27 settlement cutover bypassed their writer and 0.0.35 deleted it
- the codex companion survives its two observed run killers: a job whose cwd resolves inside a repository subdirectory without an explicit `--cwd` gets a warning diagnostic plus stderr line instead of silently sandboxing to the subtree (two zero delivery rejections came from a leaked shell cwd), and an oversized JSONL event is skipped with one diagnostic while the run continues, failing as `resource` only when the protocol cannot complete after a skip, which also removes the broken pipe exit 143 race; both contract docs restate the behavior and the stale `--record-acceptance` reference is gone
- the narrow wave advisory becomes decline aware: when the transcript tail shows a `fleet-decline:` line after the last user message the stdout nudge is suppressed while the audit warn records `declineStated: true` (19 of 27 live advisories were firing at sessions with stated declines); the stop gate rereads cancellation records from disk before demanding `TaskStop` so a worker that turned terminal after the snapshot is no longer demanded, and the task id splice tolerates leading blank lines in an envelope brief
- breaker-check tests are hermetic: the suite builds a sandbox home with stripped `FUSION_`, `GROK_`, and `CODEX_` inheritance so live lane failures can no longer redden a local run, and the orchestration rules state that claude worker briefs are envelope first (`fusion-brief: v1` on line one, header prose after) with the rules manifest regenerated

## 0.0.40

- routing becomes capability first: a package routes by its load bearing capability instead of its surface task type, capability monopolies hard route ahead of every task type default (X and live platform reads to grok `live-web` even when digest shaped, Claude tool surface and privacy to Claude workers, judgment dense authorship to the main session), and lane defaults are named as cached capability observations that fresh observations override per package; grounded in a same day controlled probe where grok `web_fetch` returned a full x.com post body while the codex web surface returned empty HTML for the same URL
Expand Down
4 changes: 2 additions & 2 deletions docs/codex-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ The companion does not add a shell command allow list and does not rewrite the u

Model and reasoning effort remain unset unless explicitly requested. The Codex configuration remains authoritative for defaults. The companion explicitly sets web search to disabled and workspace-write network access to false by default. `--web` opts a read-only or write task into live Codex web search. `--network` requires `--write` and opts the workspace-write sandbox into network access. Task mode `--output-schema <path>` validates a regular JSON Schema file up to 256 KiB and parses the final agent message once, while the Codex CLI `review` subcommand accepts but silently ignores `--output-schema`, unchanged from 0.144.6 through the live-verified 0.145.0.

The companion writes the final prompt to Codex stdin. Prompts are never interpolated into a shell command. Programmatic callers use `--request-stdin` and pipe the complete raw companion request through stdin, leaving fixed argv free of request bytes. Claude Code's Bash tool does not expose stdin, so slash commands and wrapper Agents retain a private token-named staging compatibility path: the command model writes the raw request through its Write tool before invoking a fixed companion command containing only that token. Once the staging write has landed, the parser preserves positional whitespace, newlines, quotes, and backslashes byte for byte while removing recognized adapter options. The staged compatibility path is not an end-to-end byte-exact transport because a model performs the Write step. SessionEnd removes verified staging files owned by that Claude session, and later transport creation prunes other verified staging files after one hour. Final response text comes from the bounded JSONL stream, so Codex never receives an unbounded fallback output path. Prompts, individual JSONL events, final responses, raw event ledgers, logs, and rendered diagnostics have explicit byte limits. Oversized input or output fails as `resource` before it can inflate durable state. Resume accepts only a persisted Codex thread ID or a companion-selected terminal task record. `--resume-last` is restricted to the current Claude session when its id is available and otherwise selects the newest eligible workspace task. Active jobs are never resume candidates. `--fresh` rejects combination with either resume form and forces a new thread.
The companion writes the final prompt to Codex stdin. Prompts are never interpolated into a shell command. Programmatic callers use `--request-stdin` and pipe the complete raw companion request through stdin, leaving fixed argv free of request bytes. Claude Code's Bash tool does not expose stdin, so slash commands and wrapper Agents retain a private token-named staging compatibility path: the command model writes the raw request through its Write tool before invoking a fixed companion command containing only that token. Once the staging write has landed, the parser preserves positional whitespace, newlines, quotes, and backslashes byte for byte while removing recognized adapter options. The staged compatibility path is not an end-to-end byte-exact transport because a model performs the Write step. SessionEnd removes verified staging files owned by that Claude session, and later transport creation prunes other verified staging files after one hour. Final response text comes from the bounded JSONL stream, so Codex never receives an unbounded fallback output path. Prompts, individual JSONL events, final responses, raw event ledgers, logs, and rendered diagnostics have explicit byte limits. An oversized single JSONL event is skipped with a diagnostic and the run continues; the run fails as `resource` when the protocol cannot complete after a skip, and oversized prompts or final responses still fail as `resource` before they can inflate durable state. Resume accepts only a persisted Codex thread ID or a companion-selected terminal task record. `--resume-last` is restricted to the current Claude session when its id is available and otherwise selects the newest eligible workspace task. Active jobs are never resume candidates. `--fresh` rejects combination with either resume form and forces a new thread.

## Review execution

Expand Down Expand Up @@ -115,7 +115,7 @@ Protocol fixtures cover every supported event type, unknown extensions, malforme

## Fusion integration

Codex records are the primary source for transport status, delivery, semantic status, model request, resolved model and effort, token usage, thread identity, Claude session identity, repository identity, and job duration. Without a state override, Fusion reads only the canonical `codex-claude-code-fusion/state` root. The old `codex-openai-codex/state` root is included only through `/fusion:stats --include-legacy` or `FUSION_CODEX_INCLUDE_LEGACY=1`, is always read only, and is never copied or mutated. The new `/codex:result` command cannot collect an old plugin deliverable. `CODEX_COMPANION_DATA` selects only its own state root, just as the Fusion state overrides select only one root. Fusion observes those records without taking ownership of their lifecycle. A `done` Codex job remains `unverified` until the orchestrator checks its completion criteria or verification command and records `accepted` or `rejected`. `/fusion:stats --record-acceptance` writes that verdict through the companion's `record-acceptance` subcommand. Marking a job accepted after transport failure requires the explicit `--accept-failed-transport` override, and the stats report exposes acceptance anomalies.
Codex records are the primary source for transport status, delivery, semantic status, model request, resolved model and effort, token usage, thread identity, Claude session identity, repository identity, and job duration. Without a state override, Fusion reads only the canonical `codex-claude-code-fusion/state` root. The old `codex-openai-codex/state` root is included only through `/fusion:stats --include-legacy` or `FUSION_CODEX_INCLUDE_LEGACY=1`, is always read only, and is never copied or mutated. The new `/codex:result` command cannot collect an old plugin deliverable. `CODEX_COMPANION_DATA` selects only its own state root, just as the Fusion state overrides select only one root. Fusion observes those records without taking ownership of their lifecycle. A `done` Codex job remains `unverified` until the orchestrator checks its completion criteria or verification command and records `accepted` or `rejected`. `/fusion:stats --record` writes the verdict into the Codex job record through the companion's `record-acceptance` subcommand. Marking a job accepted after transport failure requires the explicit `--accept-failed-transport` override, and the stats report exposes acceptance anomalies.

`record-acceptance` requires `--reason` for a rejected verdict and accepts `--failure-kind` with one of `intent_override`, `scope_rewrite`, `wrong_approach`, or `style_mismatch` to classify judgment shaped rejections; the kind lands in `semanticFailureKind`.

Expand Down
2 changes: 1 addition & 1 deletion docs/companion-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ The shared failure kinds are:
- `cancelled`: The plugin cancel command, companion signal forwarding, or session cleanup intentionally marked the job cancelled.
- `input`: The request was rejected before job creation, for example because the working directory was invalid.
- `died`: The driving process exited without recording an outcome, or no driving pid or engine child pid was recorded before the pidless launcher grace window elapsed.
- `resource`: The adapter rejected an artifact that exceeded a bounded resource limit or could not acquire an exclusive runtime resource, including because of an active session lease or an ambiguous legacy id.
- `resource`: The adapter rejected an artifact that exceeded a bounded resource limit, a run whose protocol was left incomplete by skipped oversized events, or could not acquire an exclusive runtime resource, including because of an active session lease or an ambiguous legacy id.

Engine adapters may define additional typed failure kinds beyond this shared set. The current Codex instance adds `protocol`, for a required structured lifecycle stream that was malformed, incomplete, or incompatible with the adapter, `process`, for an engine process that exited because of an unexpected signal or other unrequested process termination, and `policy`, for a forbidden Codex collaboration tool call. The Grok instance adds `sandbox`, for sandbox initialization or enforcement failure, `transport`, for prompt delivery or structured envelope failure, and `policy`, for missing positive tool-policy evidence or a fallback, unmappable, or unmatched tool-policy warning.

Expand Down
2 changes: 1 addition & 1 deletion plugins/codex/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "codex",
"displayName": "Codex Companion",
"version": "0.0.40",
"version": "0.0.41",
"description": "First party local Codex CLI delegation for tasks, reviews, resumable threads, and durable background jobs.",
"author": {
"name": "Harry Yep"
Expand Down
22 changes: 20 additions & 2 deletions plugins/codex/scripts/codex-companion.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const RECORD_ACCEPTANCE_VALUES = new Set(["accepted", "rejected", "unverified"])
const RECORD_ACCEPTANCE_SOURCES = new Set(["collector", "main-loop", "stats"]);
const SEMANTIC_FAILURE_KINDS = new Set(["intent_override", "scope_rewrite", "wrong_approach", "style_mismatch"]);
const SOL_FOREGROUND_WRITE_WARNING = "warning: sol p90 wall clock exceeds the 600s foreground cap. Split the brief or name gpt-5.6-terra.";
const IMPLICIT_SUBDIRECTORY_CWD_WARNING = (cwd, workspaceRoot) => `Codex cwd ${cwd} sits below repository top level ${workspaceRoot} without an explicit --cwd; the sandbox roots at this subdirectory. Pass --cwd to pin the intended workspace.`;
let activeCommandArgv = null;

class CompanionError extends Error {
Expand Down Expand Up @@ -1208,7 +1209,7 @@ function inheritedRouting(record, options, defaultServiceTier) {
return { effort, inherited, model, serviceTier };
}

function createReservedJob({ background, brief, codexVersion, cwd, dataDir, jobClass, mode, request }) {
function createReservedJob({ background, brief, codexVersion, cwd, dataDir, explicitCwd, jobClass, mode, request }) {
brief = boundedPrompt(brief);
const ownerIdentity = background ? null : currentProcessIdentity();
const reserveWorkspace = (reservedRequest) => withWorkspaceLock(dataDir, cwd, () => {
Expand Down Expand Up @@ -1239,7 +1240,7 @@ function createReservedJob({ background, brief, codexVersion, cwd, dataDir, jobC
pid: background ? null : process.pid,
pidIdentity: ownerIdentity,
pidOwnsProcessGroup: false,
request: reservedRequest,
request: explicitCwd ? { ...reservedRequest, explicitCwd: true } : reservedRequest,
workspaceRoot: canonicalWorkspaceRoot(cwd)
});
const file = jobFilePath(dataDir, cwd, id);
Expand Down Expand Up @@ -1342,6 +1343,13 @@ function structuredOutputOutcome(request, outcome) {
}
}

function implicitSubdirectoryCwdWarning(record) {
if (record.request?.explicitCwd === true || record.repositoryTopLevel == null || record.workspaceRoot === record.cwd) {
return null;
}
return IMPLICIT_SUBDIRECTORY_CWD_WARNING(record.cwd, record.workspaceRoot);
}

function finishExecutionFailure(file, record, error, env = process.env) {
const rawMessage = oneLine(error?.message ?? error, "Codex companion execution failed.");
appendJobLog(record.logFile, rawMessage);
Expand Down Expand Up @@ -1463,6 +1471,10 @@ async function executeRecord(found) {
if (isSolForegroundWriteTask(completedRecord)) {
diagnostics.push({ type: "warning", message: SOL_FOREGROUND_WRITE_WARNING });
}
const cwdWarning = implicitSubdirectoryCwdWarning(completedRecord);
if (cwdWarning) {
diagnostics.push({ type: "warning", message: cwdWarning });
}
return finishJob(found.file, {
cumulativeTokenUsage: outcome.cumulativeTokenUsage,
diagnostics,
Expand Down Expand Up @@ -1685,6 +1697,10 @@ async function dispatchJob(found, asJson) {
if (isSolForegroundWriteTask(completed)) {
process.stderr.write(`${SOL_FOREGROUND_WRITE_WARNING}\n`);
}
const cwdWarning = implicitSubdirectoryCwdWarning(completed);
if (cwdWarning) {
process.stderr.write(`${cwdWarning}\n`);
}
renderRecord(completed, asJson);
collectRenderedJob(found.file, completed);
if (completed.status !== "done") {
Expand Down Expand Up @@ -1739,6 +1755,7 @@ async function handleTask(rawArgv, transport = {}) {
codexVersion: probe.version,
cwd,
dataDir,
explicitCwd: options.cwd != null,
jobClass: "task",
mode: write ? "write" : "consult",
request
Expand Down Expand Up @@ -1830,6 +1847,7 @@ async function handleReview(rawArgv, adversarial = false, transport = {}) {
codexVersion: probe.version,
cwd,
dataDir,
explicitCwd: options.cwd != null,
jobClass: adversarial ? "adversarial-review" : "review",
mode: "consult",
request
Expand Down
Loading
Loading