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
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cc",
"version": "1.4.0",
"version": "1.4.1",
"description": "Claude Code Plugin for Codex. Delegate code reviews, investigations, and tracked tasks to Claude Code from inside Codex.",
"author": {
"name": "Sendbird, Inc.",
Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
# Changelog

## v1.4.1

- Stop defaulting reasoning effort per model. v1.4.0 gave every friendly alias a `high` default, which duplicated a catalog that belongs to the host CLI — exactly like the pinned model IDs removed in that same release — and was wrong for `haiku`, since Haiku 4.5 is not in the reasoning-effort model tier. `--effort` is now forwarded only when you pass it, so each model keeps whatever effort Claude Code defaults to and Claude Code stays the authority on which levels a model supports. `--model` still defaults to `opus`. Users who relied on the v1.2.0 `opus` + `xhigh` behavior should pass `--effort xhigh` explicitly.
- Gate `--model` and `--effort` on their resolved values in `buildArgs()`. Both resolvers return `undefined` for whitespace-only input, so a blank flag value pushed `undefined` into the spawn argv and failed with `ERR_INVALID_ARG_TYPE`. Blank values are now dropped like any other unset flag.

## v1.4.0

- Delegate Claude model resolution to Claude Code. `--model` now forwards every value through unchanged, the friendly aliases `fable`, `opus`, `sonnet`, and `haiku` are matched case-insensitively, and the plugin no longer pins `claude-opus-4-7[1m]` / `claude-sonnet-4-6[1m]` or forces the 1M-context variant. Run `/model` in Claude Code to discover what your account and provider actually offer. Every friendly alias now defaults to `high` effort, so `opus` moves from `xhigh` to `high` and `haiku` moves from unset to `high` unless you pass `--effort`.
- Delegate Claude model resolution to Claude Code. `--model` now forwards every value through unchanged, the friendly aliases `fable`, `opus`, `sonnet`, and `haiku` are matched case-insensitively, and the plugin no longer pins `claude-opus-4-7[1m]` / `claude-sonnet-4-6[1m]` or forces the 1M-context variant. Run `/model` in Claude Code to discover what your account and provider actually offer. Effort is also no longer inferred from the model; see v1.4.1, which corrects the per-alias `high` default this release introduced.
- Add `fable` as a supported model alias across `review`, `adversarial-review`, and `rescue`, forwarded to Claude Code rather than pinned to a version-specific model ID.
- Stop pinning `spawn_agent` routing to a Codex-owned catalog. Codex 0.145 only advertises `agent_type` when custom agents are configured and dropped `gpt-5.4-mini` / `gpt-5.4` from the child-model catalog, which broke every built-in background forwarding spawn. The forwarding children now omit `agent_type` and `model`, inheriting the built-in default agent and the parent model while keeping `reasoning_effort: "medium"`.
- Request targeted `sandbox_permissions: "require_escalated"` for the single Claude companion command in the review, adversarial-review, and rescue forwarding paths. Codex's default `workspace-write` sandbox has no outbound network, so the companion previously started Claude Code only for it to fail with `API Error: Unable to connect to API (ENOTFOUND)`. Global `network_access` is still not required.
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,20 +117,20 @@ Quick routing rule:
Standard read-only review of your current work.

```text
$cc:review # review uncommitted changes (default: opus + high effort)
$cc:review # review uncommitted changes (default: opus)
$cc:review --base main # review branch vs main
$cc:review --scope branch # explicitly compare branch tip to base
$cc:review --background # run in background, check with $cc:status later
$cc:review --model sonnet # switch to sonnet (defaults to high effort)
$cc:review --model fable # use Fable (defaults to high effort)
$cc:review --model sonnet # switch to sonnet
$cc:review --model fable # use Fable
$cc:review --model opus --effort xhigh # explicitly raise opus effort
```

**Flags:** `--base <ref>`, `--scope <auto|working-tree|branch>`, `--wait`, `--background`, `--model <model>`, `--effort <low|medium|high|xhigh|max>`

**Defaults:** model `opus` with `high` effort. After trimming surrounding whitespace, the friendly aliases `fable`, `opus`, `sonnet`, and `haiku` are matched case-insensitively and canonicalized to lowercase; every friendly alias defaults to `high` effort. Every other `--model` value passes through unchanged for Claude Code to resolve, including full model IDs and provider-specific names, and receives no inferred effort. Pass `--model` and `--effort` to override.
**Defaults:** model `opus`, and no effort at all. After trimming surrounding whitespace, the friendly aliases `fable`, `opus`, `sonnet`, and `haiku` are matched case-insensitively and canonicalized to lowercase; every other `--model` value passes through unchanged for Claude Code to resolve, including full model IDs and provider-specific names. `--effort` is forwarded only when you pass it, so each model keeps whatever effort Claude Code defaults to. Claude Code owns which effort levels each model supports, so check `/model` rather than assuming a level applies everywhere.

**Model discovery:** run `/model` in Claude Code to see the models and effort levels available to your current account and provider, then pass the selected alias or full ID to this plugin. The plugin intentionally does not maintain a static model catalog or force `[1m]`; Claude Code owns alias versions, managed restrictions, provider routing, and extended-context eligibility.
**Model discovery:** run `/model` in Claude Code to see the models and effort levels available to your current account and provider, then pass the selected alias or full ID to this plugin. The plugin intentionally does not maintain a static model catalog, a per-model effort table, or force `[1m]`; Claude Code owns alias versions, supported effort levels, managed restrictions, provider routing, and extended-context eligibility.

Scope `auto` (the default) inspects `git status` and chooses between working-tree and branch automatically.

Expand Down Expand Up @@ -175,7 +175,7 @@ $cc:rescue --model sonnet --effort medium investigate the flaky test
| `--fresh` | Force a new task (don't resume) |
| `--write` | Allow file edits (default) |
| `--model <model>` | Any Claude Code model alias, full model ID, or provider-specific name; defaults to `opus`. Run `/model` in Claude Code to discover options available to your account and provider. |
| `--effort <level>` | Reasoning effort: `low`, `medium`, `high`, `xhigh`, `max` (default: `high` for every friendly model alias) |
| `--effort <level>` | Reasoning effort: `low`, `medium`, `high`, `xhigh`, `max`. Unset by default, so the model keeps Claude Code's own effort default. Claude Code owns which levels each model supports. |
| `--prompt-file <path>` | Read task description from a file |

**Resume behavior:** If you don't pass `--resume` or `--fresh`, rescue checks for a resumable Claude session and asks once whether to continue or start fresh. Your phrasing guides the recommendation — "continue the last run" → resume, "start over" → fresh.
Expand Down
2 changes: 1 addition & 1 deletion internal-skills/cli-runtime/runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Command selection:

Routing controls:
- Treat `--model`, `--effort`, `--resume`, `--resume-last`, `--fresh`, `--prompt-file`, `--view-state`, `--owner-session-id`, and `--job-id` as routing controls, not task text.
- Leave `--model` and `--effort` unset unless the user explicitly asks for a specific model or effort. The companion command applies these defaults itself: model defaults to `opus`; fable, opus, sonnet, and haiku each default to `high` effort.
- Leave `--model` and `--effort` unset unless the user explicitly asks for a specific model or effort. The companion command defaults model to `opus` and forwards no `--effort` at all, so `fable`, `opus`, `sonnet`, and `haiku` each keep whatever effort Claude Code defaults to for them. Claude Code owns which effort levels each model supports; this plugin owns no per-model effort table.
- Forward an explicit `--model` value unchanged to the companion. The companion trims surrounding whitespace, canonicalizes the friendly aliases `fable`, `opus`, `sonnet`, and `haiku` to lowercase, then forwards every other `--model` value unchanged to Claude Code. Claude Code owns alias resolution; `/model` is the authoritative picker for the current account and provider.
- `--view-state on-success` means the user will see this companion result in the current turn, so the companion may mark it viewed on success.
- `--view-state defer` means the parent is not waiting, so the companion must leave the result unread until the user explicitly checks it.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cc-plugin-codex",
"version": "1.4.0",
"version": "1.4.1",
"description": "Claude Code Plugin for Codex by Sendbird",
"type": "module",
"author": {
Expand Down
11 changes: 4 additions & 7 deletions scripts/claude-companion.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* - Uses claude-cli.mjs instead of app-server/broker
* - Friendly model aliases canonicalize to lowercase; other names pass through
* - Default model when --model is unset: opus
* - Default effort for friendly model aliases: high
* - No effort default: --effort is forwarded only when the user passes it
* - Claude CLI effort values: low, medium, high, xhigh, max
* - Legacy effort aliases: none|minimal -> low
* - Review gate matches upstream setup semantics: Stop hook runs when enabled
Expand Down Expand Up @@ -45,7 +45,6 @@ import {
resolveModel,
resolveEffort,
resolveDefaultModel,
resolveDefaultEffort,
SANDBOX_READ_ONLY_TOOLS,
createSandboxSettings,
cleanupSandboxSettings,
Expand Down Expand Up @@ -1512,7 +1511,6 @@ async function handleReviewCommand(argv, config) {

const requestedModel = resolveModel(options.model);
const resolvedModel = resolveDefaultModel(requestedModel);
const resolvedEffort = resolveDefaultEffort(resolvedModel, options.effort);

await withReleasedReservation(workspaceRoot, explicitJobId, async () => {
// Validate inside the reservation guard so failures do not leak markers.
Expand All @@ -1537,7 +1535,7 @@ async function handleReviewCommand(argv, config) {
base: options.base,
scope: options.scope,
model: resolvedModel,
effort: resolvedEffort,
effort: options.effort,
focusText,
reviewName: config.reviewName,
markViewedOnSuccess
Expand All @@ -1559,7 +1557,7 @@ async function handleReviewCommand(argv, config) {
base: options.base,
scope: options.scope,
model: resolvedModel,
effort: resolvedEffort,
effort: options.effort,
focusText,
reviewName: config.reviewName,
onProgress: progress,
Expand Down Expand Up @@ -1613,8 +1611,7 @@ async function handleTask(argv) {

const requestedModel = resolveModel(options.model);
const model = resolveDefaultModel(requestedModel);
const resolvedEffort = resolveDefaultEffort(model, options.effort);
const effort = resolvedEffort ? resolveEffort(resolvedEffort) : null;
const effort = options.effort ? resolveEffort(options.effort) : null;
const prompt = readTaskPrompt(cwd, options, positionals);
const markViewedOnSuccess = resolveMarkViewedOnSuccess(
options["view-state"],
Expand Down
33 changes: 14 additions & 19 deletions scripts/lib/claude-cli.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -648,28 +648,18 @@ export const DEFAULT_MODEL = "opus";

const FRIENDLY_ALIASES = new Set(["fable", "opus", "sonnet", "haiku"]);

export const DEFAULT_EFFORT_BY_MODEL = new Map([
["fable", "high"],
["opus", "high"],
["sonnet", "high"],
["haiku", "high"],
]);

// No per-model effort defaults. Which effort levels a model supports — and what
// it falls back to — is owned by Claude Code, not this plugin: Haiku 4.5 is not
// in the reasoning-effort model tier at all. Any table here would have to track
// the host's model catalog and would rot exactly like the pinned model IDs did,
// so `--effort` is forwarded only when the user asks for it.
export function resolveDefaultModel(model) {
if (model == null || String(model).trim() === "") {
return DEFAULT_MODEL;
}
return model;
}

export function resolveDefaultEffort(model, effort) {
if (effort != null && String(effort).trim() !== "") {
return effort;
}
const key = String(model ?? "").trim().toLowerCase();
return DEFAULT_EFFORT_BY_MODEL.get(key);
}

export function resolveModel(model) {
if (model == null) return undefined;
const normalized = String(model).trim();
Expand Down Expand Up @@ -719,11 +709,16 @@ export function buildArgs(prompt, options = {}) {
if (options.noSessionPersistence) {
args.push("--no-session-persistence");
}
if (options.model) {
args.push("--model", resolveModel(options.model));
// Gate on the resolved value, not the raw input: both resolvers return
// undefined for whitespace-only strings, and pushing undefined into argv
// throws ERR_INVALID_ARG_TYPE in spawn().
const model = resolveModel(options.model);
if (model) {
args.push("--model", model);
}
if (options.effort) {
args.push("--effort", resolveEffort(options.effort));
const effort = resolveEffort(options.effort);
if (effort) {
args.push("--effort", effort);
}
if (options.sessionId) {
args.push("--session-id", options.sessionId);
Expand Down
6 changes: 3 additions & 3 deletions skills/adversarial-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: adversarial-review
description: 'Run a design-challenging Claude Code review of local git changes in this repository. Args: --wait, --background, --base <ref>, --scope <auto|working-tree|branch>, --model <model>, --effort <low|medium|high|xhigh|max>, [focus text]. Defaults to opus + high effort. Use only when the user wants stronger scrutiny than a normal review, such as explicit tradeoff challenge, risky-change review, or custom focus text.'
description: 'Run a design-challenging Claude Code review of local git changes in this repository. Args: --wait, --background, --base <ref>, --scope <auto|working-tree|branch>, --model <model>, --effort <low|medium|high|xhigh|max>, [focus text]. Defaults to opus with no forced effort. Use only when the user wants stronger scrutiny than a normal review, such as explicit tradeoff challenge, risky-change review, or custom focus text.'
---

# Claude Code Adversarial Review
Expand All @@ -16,9 +16,9 @@ Unlike `$cc:review`, this skill accepts custom focus text after the flags. The m
Resolve `<plugin-root>` as two directories above this `SKILL.md` file. Always run the companion from that active plugin root:
`node "<plugin-root>/scripts/claude-companion.mjs" adversarial-review ...`

Supported arguments: `--wait`, `--background`, `--base <ref>`, `--scope auto|working-tree|branch`, `--model <model>`, `--effort <low|medium|high|xhigh|max>`, plus optional focus text after the flags (defaults: model=opus; fable, opus, sonnet, and haiku each default to high effort)
Supported arguments: `--wait`, `--background`, `--base <ref>`, `--scope auto|working-tree|branch`, `--model <model>`, `--effort <low|medium|high|xhigh|max>`, plus optional focus text after the flags (defaults: model=opus and no effort; `fable`, `opus`, `sonnet`, and `haiku` each keep Claude Code's own effort default, and Claude Code owns which effort levels each model supports)

Forward `--model` unchanged to the companion. The companion trims surrounding whitespace, canonicalizes the friendly aliases `fable`, `opus`, `sonnet`, and `haiku` to lowercase, then forwards every other `--model` value unchanged to Claude Code. Claude Code owns alias resolution; `/model` is the authoritative picker for the current account and provider.
Forward `--model` unchanged to the companion. The companion trims surrounding whitespace, canonicalizes the friendly aliases `fable`, `opus`, `sonnet`, and `haiku` to lowercase, then forwards every other `--model` value unchanged to Claude Code. Claude Code owns alias resolution and supported effort levels; `/model` is the authoritative picker for the current account and provider.

Raw slash-command arguments:
`$ARGUMENTS`
Expand Down
6 changes: 3 additions & 3 deletions skills/rescue/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: rescue
description: 'Delegate a substantial diagnosis, implementation, or follow-up task to Claude Code through the tracked-job runtime. Args: --background, --wait, --resume, --resume-last, --fresh, --write, --model <model>, --effort <low|medium|high|xhigh|max>, --prompt-file <path>, [task text]. Defaults to opus + high effort. Use when Claude should investigate or change things, not when the user only wants review findings.'
description: 'Delegate a substantial diagnosis, implementation, or follow-up task to Claude Code through the tracked-job runtime. Args: --background, --wait, --resume, --resume-last, --fresh, --write, --model <model>, --effort <low|medium|high|xhigh|max>, --prompt-file <path>, [task text]. Defaults to opus with no forced effort. Use when Claude should investigate or change things, not when the user only wants review findings.'
---

# Claude Code Rescue
Expand All @@ -24,9 +24,9 @@ Raw slash-command arguments:

Supported arguments: `--background`, `--wait`, `--resume`, `--resume-last`, `--fresh`, `--write`, `--model <model>`, `--effort <low|medium|high|xhigh|max>`, `--prompt-file <path>`, plus free-text task text

Companion defaults: model=opus; fable, opus, sonnet, and haiku each default to high effort.
Companion defaults: model=opus, and no effort. The companion forwards `--effort` only when the user passes it, so `fable`, `opus`, `sonnet`, and `haiku` each keep Claude Code's own effort default. Claude Code owns which effort levels each model supports.

Forward `--model` unchanged to the companion. The companion trims surrounding whitespace, canonicalizes the friendly aliases `fable`, `opus`, `sonnet`, and `haiku` to lowercase, then forwards every other `--model` value unchanged to Claude Code. Claude Code owns alias resolution; `/model` is the authoritative picker for the current account and provider.
Forward `--model` unchanged to the companion. The companion trims surrounding whitespace, canonicalizes the friendly aliases `fable`, `opus`, `sonnet`, and `haiku` to lowercase, then forwards every other `--model` value unchanged to Claude Code. Claude Code owns alias resolution and supported effort levels; `/model` is the authoritative picker for the current account and provider.

Main-thread routing rules:
- If the user explicitly invoked `$cc:rescue` or `Claude Code Rescue`, do not keep the work in the main Codex thread. Delegate it.
Expand Down
Loading