Skip to content

Commit 87f3b47

Browse files
committed
Stop forcing fast Codex service tier
1 parent f80f913 commit 87f3b47

8 files changed

Lines changed: 44 additions & 24 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ The plugin lets Claude Code launch one Codex agent or several Codex agents in pa
1111
- Codex binary: prefers `/Applications/Codex.app/Contents/Resources/codex` when the Codex desktop app is installed, then falls back to configured overrides and `codex` on `PATH`.
1212
- Sandbox: `read-only`.
1313
- Approvals: non-interactive `approval_policy="never"`.
14+
- Service tier: omitted by default so Codex uses its normal account/default service tier. Pass `service_tier` only when you explicitly want one.
1415
- Transport: stdio MCP, launched by Claude Code for the active session. No daemon is required.
1516
- Prompt delivery: stdin, not command-line arguments.
1617

dist/index.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21450,7 +21450,6 @@ function buildCodexExecArgs(options, outputPath, env = process.env) {
2145021450
const model = resolveRequestedModel(options, env);
2145121451
const reasoningEffort = options.reasoningEffort ?? defaultReasoningEffort(env);
2145221452
const sandbox = options.sandbox ?? "read-only";
21453-
const serviceTier = options.serviceTier ?? "fast";
2145421453
const ephemeral = options.ephemeral ?? true;
2145521454
const args = [
2145621455
"exec",
@@ -21463,8 +21462,6 @@ function buildCodexExecArgs(options, outputPath, env = process.env) {
2146321462
`approval_policy=${tomlString("never")}`,
2146421463
"-c",
2146521464
`model_reasoning_effort=${tomlString(reasoningEffort)}`,
21466-
"-c",
21467-
`service_tier=${tomlString(serviceTier)}`,
2146821465
"--output-last-message",
2146921466
outputPath
2147021467
];
@@ -21480,6 +21477,9 @@ function buildCodexExecArgs(options, outputPath, env = process.env) {
2148021477
if (options.reasoningSummary) {
2148121478
args.push("-c", `model_reasoning_summary=${tomlString(options.reasoningSummary)}`);
2148221479
}
21480+
if (options.serviceTier) {
21481+
args.push("-c", `service_tier=${tomlString(options.serviceTier)}`);
21482+
}
2148321483
if (options.subagentRuntime?.maxThreads !== void 0) {
2148421484
args.push("-c", `agents.max_threads=${options.subagentRuntime.maxThreads}`);
2148521485
}
@@ -21622,7 +21622,7 @@ async function runAgent(options) {
2162221622
modelPreset: options.modelPreset,
2162321623
reasoningEffort: options.reasoningEffort ?? defaultReasoningEffort(childEnv),
2162421624
sandbox: options.sandbox ?? "read-only",
21625-
serviceTier: options.serviceTier ?? "fast",
21625+
serviceTier: options.serviceTier,
2162621626
exitCode,
2162721627
signal,
2162821628
finalMessage: final.text,
@@ -21717,8 +21717,9 @@ var usageGuide = [
2171721717
"Default operating rules:",
2171821718
"- Keep sandbox read-only unless the user explicitly asks for a different sandbox.",
2171921719
"- Approvals are non-interactive; do not expect Codex to ask permission.",
21720-
'- Prefer model_preset "spark" for fast focused checks, small reviews, UI iteration, and responsive sidecar analysis.',
21720+
'- Prefer model_preset "spark" for responsive focused checks, small reviews, UI iteration, and sidecar analysis.',
2172121721
'- Use reasoning_effort "medium" by default, "low" for simple checks, and "high" or "xhigh" only for difficult analysis.',
21722+
"- Do not set service_tier by default. Let Codex use its normal account/default service tier unless the user explicitly asks for a service tier.",
2172221723
"- Pass project_dir whenever Claude knows the active project directory so Codex works in the same tree as Claude Code.",
2172321724
"- Ask Codex for concise results with file paths, line references, and actionable findings when reviewing code.",
2172421725
"",
@@ -21770,13 +21771,15 @@ var commonInputSchema = {
2177021771
"Exact Codex model, for example gpt-5.3-codex. Omit to use model_preset, the plugin default, or Codex default."
2177121772
),
2177221773
model_preset: modelPresetSchema.optional().describe(
21773-
"Convenience model preset. Use `spark` for fast Codex Spark work; it maps to gpt-5.3-codex-spark."
21774+
"Convenience model preset. Use `spark` for responsive Codex Spark work; it maps to gpt-5.3-codex-spark."
2177421775
),
2177521776
reasoning_effort: reasoningEffortSchema.optional().describe(
2177621777
"Codex model reasoning effort. Prefer medium by default, low for simple checks, high/xhigh only for difficult analysis."
2177721778
),
2177821779
sandbox: sandboxModeSchema.default("read-only").describe("Codex sandbox mode. Keep read-only unless the user explicitly asks otherwise."),
21779-
service_tier: serviceTierSchema.default("fast").describe("Codex service tier. Defaults to fast for responsiveness."),
21780+
service_tier: serviceTierSchema.optional().describe(
21781+
"Optional Codex service tier. Omit by default; only set this when the user explicitly asks for a service tier."
21782+
),
2178021783
model_verbosity: modelVerbositySchema.optional().describe("Optional GPT-5 model verbosity override."),
2178121784
reasoning_summary: reasoningSummarySchema.optional().describe("Optional Codex reasoning summary setting."),
2178221785
cwd: external_exports.string().trim().min(1).optional().describe("Compatibility alias for project_dir."),
@@ -21902,7 +21905,7 @@ server.registerTool(
2190221905
"run_agent",
2190321906
{
2190421907
title: "Run one Codex agent",
21905-
description: "Launch one OpenAI Codex agent via codex exec. Use automatically when the user asks Claude to use Codex, ask Codex, get a Codex second opinion, run a Codex subagent, use Codex Spark, or delegate one read-only analysis task. Defaults to the Codex desktop app binary when installed, read-only sandbox, fast service tier, and non-interactive approvals.",
21908+
description: "Launch one OpenAI Codex agent via codex exec. Use automatically when the user asks Claude to use Codex, ask Codex, get a Codex second opinion, run a Codex subagent, use Codex Spark, or delegate one read-only analysis task. Defaults to the Codex desktop app binary when installed, read-only sandbox, Codex's normal service tier, and non-interactive approvals.",
2190621909
inputSchema: {
2190721910
prompt: external_exports.string().min(1).describe(
2190821911
"Concrete instructions for the Codex agent. Include scope, read-only expectation, desired output shape, and file/line reference requirements when reviewing code."
@@ -22046,7 +22049,7 @@ server.registerTool(
2204622049
defaultModel: defaultModel(),
2204722050
defaultReasoningEffort: defaultReasoningEffort(),
2204822051
defaultSandbox: "read-only",
22049-
defaultServiceTier: "fast",
22052+
defaultServiceTier: "codex-default",
2205022053
modelPresets: {
2205122054
codex: "gpt-5.3-codex",
2205222055
spark: "gpt-5.3-codex-spark"

skills/codex-subagents/SKILL.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ When Claude wants Codex to work in the same repository or folder as the active C
2424

2525
Prefer `reasoning_effort: "medium"` for exploration and `high` or `xhigh` only when the task is complex enough to justify the extra latency and token usage.
2626

27-
Use `model_preset: "spark"` for fast, focused work such as UI iteration, narrow exploration, small reviews, and quick sidecar checks.
27+
Use `model_preset: "spark"` for responsive, focused work such as UI iteration, narrow exploration, small reviews, and quick sidecar checks.
28+
29+
Do not set `service_tier` by default. Let Codex use its normal account/default service tier unless the user explicitly asks for a service tier.
2830

2931
Use `codex_status` only when diagnosing installation or binary resolution, or after a failed Codex tool call. Normal delegation should start with `run_agent` or `run_agents`.
3032

src/index.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ const usageGuide = [
3131
"Default operating rules:",
3232
"- Keep sandbox read-only unless the user explicitly asks for a different sandbox.",
3333
"- Approvals are non-interactive; do not expect Codex to ask permission.",
34-
"- Prefer model_preset \"spark\" for fast focused checks, small reviews, UI iteration, and responsive sidecar analysis.",
34+
"- Prefer model_preset \"spark\" for responsive focused checks, small reviews, UI iteration, and sidecar analysis.",
3535
"- Use reasoning_effort \"medium\" by default, \"low\" for simple checks, and \"high\" or \"xhigh\" only for difficult analysis.",
36+
"- Do not set service_tier by default. Let Codex use its normal account/default service tier unless the user explicitly asks for a service tier.",
3637
"- Pass project_dir whenever Claude knows the active project directory so Codex works in the same tree as Claude Code.",
3738
"- Ask Codex for concise results with file paths, line references, and actionable findings when reviewing code.",
3839
"",
@@ -134,7 +135,7 @@ const commonInputSchema = {
134135
model_preset: modelPresetSchema
135136
.optional()
136137
.describe(
137-
"Convenience model preset. Use `spark` for fast Codex Spark work; it maps to gpt-5.3-codex-spark.",
138+
"Convenience model preset. Use `spark` for responsive Codex Spark work; it maps to gpt-5.3-codex-spark.",
138139
),
139140
reasoning_effort: reasoningEffortSchema
140141
.optional()
@@ -145,8 +146,10 @@ const commonInputSchema = {
145146
.default("read-only")
146147
.describe("Codex sandbox mode. Keep read-only unless the user explicitly asks otherwise."),
147148
service_tier: serviceTierSchema
148-
.default("fast")
149-
.describe("Codex service tier. Defaults to fast for responsiveness."),
149+
.optional()
150+
.describe(
151+
"Optional Codex service tier. Omit by default; only set this when the user explicitly asks for a service tier.",
152+
),
150153
model_verbosity: modelVerbositySchema
151154
.optional()
152155
.describe("Optional GPT-5 model verbosity override."),
@@ -376,7 +379,7 @@ server.registerTool(
376379
{
377380
title: "Run one Codex agent",
378381
description:
379-
"Launch one OpenAI Codex agent via codex exec. Use automatically when the user asks Claude to use Codex, ask Codex, get a Codex second opinion, run a Codex subagent, use Codex Spark, or delegate one read-only analysis task. Defaults to the Codex desktop app binary when installed, read-only sandbox, fast service tier, and non-interactive approvals.",
382+
"Launch one OpenAI Codex agent via codex exec. Use automatically when the user asks Claude to use Codex, ask Codex, get a Codex second opinion, run a Codex subagent, use Codex Spark, or delegate one read-only analysis task. Defaults to the Codex desktop app binary when installed, read-only sandbox, Codex's normal service tier, and non-interactive approvals.",
380383
inputSchema: {
381384
prompt: z
382385
.string()
@@ -545,7 +548,7 @@ server.registerTool(
545548
defaultModel: defaultModel(),
546549
defaultReasoningEffort: defaultReasoningEffort(),
547550
defaultSandbox: "read-only",
548-
defaultServiceTier: "fast",
551+
defaultServiceTier: "codex-default",
549552
modelPresets: {
550553
codex: "gpt-5.3-codex",
551554
spark: "gpt-5.3-codex-spark",

src/runner.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export interface AgentRunResult {
7272
modelPreset?: ModelPreset;
7373
reasoningEffort: ReasoningEffort;
7474
sandbox: SandboxMode;
75-
serviceTier: ServiceTier;
75+
serviceTier?: ServiceTier;
7676
exitCode: number | null;
7777
signal: NodeJS.Signals | null;
7878
finalMessage: string;
@@ -199,7 +199,6 @@ export function buildCodexExecArgs(
199199
const model = resolveRequestedModel(options, env);
200200
const reasoningEffort = options.reasoningEffort ?? defaultReasoningEffort(env);
201201
const sandbox = options.sandbox ?? "read-only";
202-
const serviceTier = options.serviceTier ?? "fast";
203202
const ephemeral = options.ephemeral ?? true;
204203

205204
const args = [
@@ -213,8 +212,6 @@ export function buildCodexExecArgs(
213212
`approval_policy=${tomlString("never")}`,
214213
"-c",
215214
`model_reasoning_effort=${tomlString(reasoningEffort)}`,
216-
"-c",
217-
`service_tier=${tomlString(serviceTier)}`,
218215
"--output-last-message",
219216
outputPath,
220217
];
@@ -231,6 +228,9 @@ export function buildCodexExecArgs(
231228
if (options.reasoningSummary) {
232229
args.push("-c", `model_reasoning_summary=${tomlString(options.reasoningSummary)}`);
233230
}
231+
if (options.serviceTier) {
232+
args.push("-c", `service_tier=${tomlString(options.serviceTier)}`);
233+
}
234234
if (options.subagentRuntime?.maxThreads !== undefined) {
235235
args.push("-c", `agents.max_threads=${options.subagentRuntime.maxThreads}`);
236236
}
@@ -400,7 +400,7 @@ export async function runAgent(options: AgentRunOptions): Promise<AgentRunResult
400400
modelPreset: options.modelPreset,
401401
reasoningEffort: options.reasoningEffort ?? defaultReasoningEffort(childEnv),
402402
sandbox: options.sandbox ?? "read-only",
403-
serviceTier: options.serviceTier ?? "fast",
403+
serviceTier: options.serviceTier,
404404
exitCode,
405405
signal,
406406
finalMessage: final.text,

test/claude-autodiscovery.mjs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ try {
7878
7979
Work in this exact project directory: ${projectDir}
8080
81-
Codex should stay read-only and include the token AUTODISCOVERY_OK in its reply. Use a fast focused Codex configuration.
81+
Codex should stay read-only and include the token AUTODISCOVERY_OK in its reply. Use Codex Spark, but do not set an explicit service_tier.
8282
8383
After the Codex result comes back, return exactly one compact JSON object and no markdown. Shape: {"ok": boolean, "tokenSeen": boolean, "model": string, "cwd": string}. Set ok true when the Codex tool call completed successfully.`;
8484

@@ -156,6 +156,11 @@ After the Codex result comes back, return exactly one compact JSON object and no
156156
"Fake Codex should be launched with the Spark preset",
157157
calls[0],
158158
);
159+
assert(
160+
!calls[0].args.some((arg) => arg.includes("service_tier=")),
161+
"Fake Codex should not be launched with an explicit service tier by default",
162+
calls[0],
163+
);
159164

160165
console.log(
161166
`Claude autodiscovery passed in ${envelope.duration_ms}ms, cost $${envelope.total_cost_usd}`,

test/reliability-matrix.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ try {
7171
assert(defaultAgent?.ok, "run_agent should succeed with CLAUDE_PROJECT_DIR", defaultProject);
7272
assert(defaultAgent.cwd === projectDir, "run_agent should default to CLAUDE_PROJECT_DIR", defaultAgent);
7373
assert(defaultAgent.sandbox === "read-only", "run_agent should default to read-only", defaultAgent);
74+
assert(defaultAgent.serviceTier === undefined, "run_agent should not default service_tier", defaultAgent);
75+
assert(
76+
!defaultAgent.commandPreview.some((arg) => arg.includes("service_tier=")),
77+
"run_agent should omit service_tier unless explicitly requested",
78+
defaultAgent.commandPreview,
79+
);
7480
assert(
7581
defaultAgent.eventSummary?.commands?.[0]?.command === "rg example",
7682
"run_agent should parse command events",

test/runner.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ afterEach(async () => {
2323
});
2424

2525
describe("buildCodexExecArgs", () => {
26-
it("defaults to read-only, non-interactive approvals, fast tier, and stdin prompt input", () => {
26+
it("defaults to read-only, non-interactive approvals, Codex default service tier, and stdin prompt input", () => {
2727
const args = buildCodexExecArgs({ cwd: "/repo" }, "/tmp/out.md", {});
2828

2929
expect(args).toContain("exec");
@@ -32,7 +32,7 @@ describe("buildCodexExecArgs", () => {
3232
expect(args[args.indexOf("--sandbox") + 1]).toBe("read-only");
3333
expect(args).toContain('approval_policy="never"');
3434
expect(args).toContain('model_reasoning_effort="medium"');
35-
expect(args).toContain('service_tier="fast"');
35+
expect(args.some((arg) => arg.includes("service_tier="))).toBe(false);
3636
expect(args).toContain("--cd");
3737
expect(args[args.indexOf("--cd") + 1]).toBe("/repo");
3838
expect(args.at(-1)).toBe("-");

0 commit comments

Comments
 (0)