Skip to content

fix(cli): --tui -model reaches the TUI - #1427

Merged
dennisonbertram merged 1 commit into
mainfrom
fix/1426-tui-model-flag
Sep 8, 2026
Merged

fix(cli): --tui -model reaches the TUI#1427
dennisonbertram merged 1 commit into
mainfrom
fix/1426-tui-model-flag

Conversation

@dennisonbertram

Copy link
Copy Markdown
Owner

Closes #1426

The bug

harnesscli --tui -model X parsed the flag and threw it away. The TUI started on the daemon default or — since #1424 — on the remembered model, which is precisely what someone passing -model is trying to override.

No warning, no error. A flag that errors teaches you something; a flag that is silently dropped trains you to distrust the CLI.

Cause

runTUI(*baseURL, workspacePath, *resume, *planMode)   // *model absent

*model never reached runTUI, and newTUIConfig never set TUIConfig.Model. The non-TUI path (main.go:216) passed the flag correctly all along, so the defect was confined to the TUI branch.

Fix

The model is threaded from the dispatch through runTUI into newTUIConfig, following the exact route planMode already takes.

Nothing in the TUI changed. selectedModel: cfg.Model and #1424's cfg.Model == "" guard were already correct — they simply had no producer of a non-empty value. I predicted that when filing #1424 ("the precedence guard is written so wiring it needs no further change"), and it held.

Precedence is now real: flag, then the model remembered from last session, then the daemon default.

The flag deliberately does not write to the persisted config. A flag is a one-off instruction, not a preference. A fix that made -model work by saving it would pass an "is the flag honored" test while silently overwriting the user's saved model — a worse bug than the one being fixed. That is why the verification below has two halves.

Verification

Two tests, red first (initially as a compile error, since the parameter did not exist):

  • TestNewTUIConfigCarriesExplicitModel — the flag's value becomes TUIConfig.Model.
  • TestNewTUIConfigWithoutModelLeavesItEmpty — the control. Empty must stay empty, or a fix that defaulted to some model would satisfy the first test while breaking feat(tui): remember the last used model across restarts #1424's remembered model and the daemon default.

runTUI requires a terminal and cannot be unit tested, so newTUIConfig is the closest honest seam. The consumer half is already pinned by TestExplicitModelBeatsRememberedModel in the tui package. Neither test alone proves the flag works — producer and consumer are pinned separately and only meet in a live run.

go test ./cmd/harnesscli/... -race green.

A live check is running now and I will post the result here before merging. It has two halves, matching the two ways this can be wrong: does the flag override an already-remembered model, and does the persisted config still hold the old model afterwards. I will not claim either until I have seen both.

Out of scope

Validating the model ID in the CLI. The TUI's existing unavailable-model handling (#1404) owns that, and a bad -model should get the same redirect and explanation rather than a hard startup failure.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WJGxhoFhA8JjkwZFcLGdS5

harnesscli --tui -model X parsed the flag and discarded it. The TUI
started on the daemon default or, since #1424, on the remembered model —
exactly what a user passing -model is trying to override. Silently: no
warning, no error.

main.go called runTUI without *model, and newTUIConfig never set
TUIConfig.Model. The non-TUI path passed the flag correctly all along,
so the defect was confined to the TUI branch.

The model is now threaded through the same route planMode already takes.
Nothing in the TUI changed: selectedModel: cfg.Model and #1424's
precedence guard were already right and simply had no producer.

Precedence is now real — flag, then remembered model, then daemon
default. The flag does not write to the persisted config: a flag is a
one-off instruction, not a preference, and silently rewriting the saved
model would be a worse bug than this one.

Closes #1426

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJGxhoFhA8JjkwZFcLGdS5
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@dennisonbertram

Copy link
Copy Markdown
Owner Author

Live verification — both halves hold

Driven through a pty against a real daemon on this branch's binaries, with HOME redirected throughout.

Seed a remembered model, without the flag. Selected Claude Fable 5 via /model:

Model: Claude Fable 5

Config after quitting:

{ "model": "claude-fable-5", "provider": "anthropic" }

(A) The flag overrides it. Relaunched with -model gpt-4.1-mini, touching nothing:

GPT-4.1 Mini

The flag's model, not the remembered claude-fable-5.

(B) The flag does not overwrite the preference. Config after that flagged run:

{ "model": "claude-fable-5", "provider": "anthropic" }

Unchanged. gpt-4.1-mini was never written — the flag behaved as a one-off instruction.

Remembered model still works. Relaunched with no flag:

Claude Fable 5

Precedence confirmed end to end: flag, then remembered, then daemon default.

Hygiene: the real ~/.config/harnesscli/config.json was checked before and after and still contains only starred_models, history_entries, theme — no model key. git status clean.

@dennisonbertram
dennisonbertram merged commit 68e2f3e into main Sep 8, 2026
2 checks passed
@dennisonbertram
dennisonbertram deleted the fix/1426-tui-model-flag branch September 8, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: harnesscli --tui -model X silently ignores the flag

1 participant