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
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Verified on 2026-06-11 with codex-cli 0.139.0 unless a fact gives a newer versio
| Skill invocation | `$<skill>`, for example `$no-mistakes`; `/<skill>` is Claude-only and Codex rejects it as "Unrecognized command". |
| Resume | `codex resume <session-id>`, using the id printed on quit. |
| Model flag | `--model <model>`. |
| Effort flag | `-c 'model_reasoning_effort="<low\|medium\|high\|xhigh>"'`, verified on codex-cli 0.142.1 whose installed schema contains `model_reasoning_effort`, active config uses it, and bundled catalog advertises only these four values while omitting `max`. |
| Effort flag | `-c 'model_reasoning_effort="<low\|medium\|high\|xhigh\|max>"'`, verified on 2026-09-08 with codex-cli 0.153.4 whose installed schema contains `model_reasoning_effort` and bundled catalog advertises low, medium, high, xhigh, max, and ultra. Firstmate's shared effort vocabulary does not expose `ultra`. |
| Model discovery | Open the current interactive session's `/model` picker. |

A directory trust dialog appears on the first run for a repository root: "Do you trust the contents of this directory?"
Expand Down
2 changes: 1 addition & 1 deletion bin/fm-bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,7 @@ crew_dispatch_validate() {
if $e == null then true
elif ($e | type) != "string" then false
elif $h == "claude" then (["low","medium","high","xhigh","max"] | index($e))
elif $h == "codex" then (["low","medium","high","xhigh"] | index($e))
elif $h == "codex" then (["low","medium","high","xhigh","max"] | index($e))
elif $h == "grok" then (["low","medium","high"] | index($e))
elif $h == "pi" or $h == "pi-signed" then (["low","medium","high","xhigh","max"] | index($e))
elif $h == "muse" then (["low","medium","high","xhigh","max"] | index($e))
Expand Down
8 changes: 4 additions & 4 deletions bin/fm-spawn.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1685,11 +1685,11 @@ effort_flag_for_harness() {
esac
;;
codex)
# The installed codex config schema uses model_reasoning_effort, and the
# bundled model catalog advertises low|medium|high|xhigh. Omit max rather
# than passing an unsupported value.
# The installed codex config schema uses model_reasoning_effort.
# codex-cli 0.153.4's catalog advertises up to max, plus ultra. Firstmate's
# --effort set does not accept ultra, so it stays omitted.
case "$effort" in
low|medium|high|xhigh) printf -- '-c %s ' "$(shell_quote "model_reasoning_effort=\"$effort\"")" ;;
low|medium|high|xhigh|max) printf -- '-c %s ' "$(shell_quote "model_reasoning_effort=\"$effort\"")" ;;
esac
;;
grok)
Expand Down
4 changes: 2 additions & 2 deletions tests/fm-bootstrap.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1151,7 +1151,7 @@ test_crew_dispatch_validation() {
done <<'ROWS'
malformed dispatch config is flagged^{"rules":[^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - malformed JSON
unverified dispatch harness is flagged^{"rules":[{"when":"anything","use":{"harness":"spaceship"}}],"default":{"harness":"codex"}}^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - unverified harness: spaceship
unsupported codex max effort is flagged^{"rules":[{"when":"big feature","use":{"harness":"codex","model":"gpt-5","effort":"max"}}]}^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - invalid effort: codex:max
codex max effort is accepted^{"rules":[{"when":"big feature","use":{"harness":"codex","model":"gpt-5","effort":"max"}}]}^empty^
unsupported grok max effort is flagged^{"rules":[{"when":"deep current work","use":{"harness":"grok","model":"grok-4","effort":"max"}}]}^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - invalid effort: grok:max
unsupported grok xhigh effort is flagged^{"rules":[{"when":"deep current work","use":{"harness":"grok","model":"grok-4","effort":"xhigh"}}]}^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - invalid effort: grok:xhigh
pi max effort is accepted^{"rules":[{"when":"deep coding","use":{"harness":"pi","model":"openai-codex/gpt-5.6-sol","effort":"max"}}]}^empty^
Expand All @@ -1172,7 +1172,7 @@ empty array use is flagged^{"rules":[{"when":"big feature","use":[]}]}^exact^CRE
array profile without harness is flagged^{"rules":[{"when":"big feature","use":[{"model":"gpt-5.5"}]}]}^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - each use profile needs harness
array profile with malformed model is flagged^{"rules":[{"when":"big feature","use":[{"harness":"codex","model":5}]}]}^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - use profile model and effort must be non-empty strings when present
unknown select is flagged^{"rules":[{"when":"big feature","use":[{"harness":"claude"},{"harness":"codex"}],"select":"mystery"}]}^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - unknown select: mystery
array profile unsupported effort is flagged^{"rules":[{"when":"big feature","use":[{"harness":"codex","effort":"max"}]}]}^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - invalid effort: codex:max
array profile codex max effort is accepted^{"rules":[{"when":"big feature","use":[{"harness":"codex","effort":"max"}]}]}^empty^
empty default array is flagged^{"default":[]}^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - default needs at least one profile
non-object default array entry is flagged^{"default":["codex"]}^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - each default profile must be an object
default array profile without harness is flagged^{"default":[{"model":"gpt-5.5"}]}^exact^CREW_DISPATCH: invalid config/crew-dispatch.json - each default profile needs harness
Expand Down
13 changes: 6 additions & 7 deletions tests/fm-spawn-dispatch-profile.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -432,21 +432,20 @@ test_codex_disables_interactive_update_check() {
pass "codex disables the interactive update check for unattended launches"
}

test_codex_omits_invalid_max_effort() {
test_codex_threads_model_and_max_effort() {
local rec id out status launch
id=profile-codex-max-z4
rec=$(make_spawn_case profile-codex-max codex "$id")
read_case_record "$rec"

out=$(run_ship_spawn "$HOME_DIR" "$WT_DIR" "$FAKEBIN_DIR" "$LAUNCH_LOG" "$id" "$PROJ_DIR" --model gpt-5 --effort max)
status=$?
expect_code 0 "$status" "codex spawn with unsupported max effort should omit the effort flag"
expect_code 0 "$status" "codex spawn with max effort should succeed"
assert_meta_profile "$HOME_DIR/state/$id.meta" codex gpt-5 max
launch=$(cat "$LAUNCH_LOG")
assert_contains "$launch" "codex --model 'gpt-5' --dangerously-bypass-approvals-and-sandbox" \
"codex launch did not preserve the model flag when max effort was omitted"
assert_not_contains "$launch" "model_reasoning_effort" "codex launch must omit unsupported max reasoning effort"
pass "codex omits unsupported max effort instead of passing a bad config value"
assert_contains "$launch" "codex --model 'gpt-5' -c 'model_reasoning_effort=\"max\"' --dangerously-bypass-approvals-and-sandbox" \
"codex launch did not preserve the model flag and thread max reasoning effort"
pass "codex receives --model and max model_reasoning_effort profile flags"
}

test_grok_threads_model_and_reasoning_effort() {
Expand Down Expand Up @@ -824,7 +823,7 @@ test_active_dispatch_profile_allows_raw_launch_command
test_claude_threads_model_and_effort
test_codex_threads_model_and_effort
test_codex_disables_interactive_update_check
test_codex_omits_invalid_max_effort
test_codex_threads_model_and_max_effort
test_grok_threads_model_and_reasoning_effort
test_grok_omits_invalid_max_reasoning_effort
test_grok_omits_invalid_xhigh_reasoning_effort
Expand Down
Loading