You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
harnesscli --tui -model X silently ignores -model. The TUI starts on whatever the daemon defaults to (or, since #1424, on the remembered model), and nothing tells the user their flag was discarded.
Silent is the operative word: no warning, no error, no note in the status bar. The flag parses, validates, and is thrown away.
Found while building #1424. Recorded in docs/logs/engineering-log.md under the 2026-09-08 #1424 entry as a known gap.
Expected behavior
harnesscli --tui -model X starts the TUI on model X.
Invariant: an explicitly requested model outranks every other source. Precedence, highest first: the -model flag, then the model remembered from the last session (#1424), then the daemon default.
A flag is a one-off instruction, not a preference: -model X must not overwrite the stored last-used model. If the user then picks a different model with /model inside that session, that selection is a choice and is persisted as usual.
Reproduction
harnesscli --tui -model gpt-4.1-mini (or via a go-code TUI launch).
Look at the status-bar model.
Actual: the model is the daemon default, or the remembered model from a previous session. The requested model is absent, with no diagnostic.
Reproduction rate: 100%.
User and operational impact
Affected users: anyone scripting or aliasing a TUI launch against a specific model, and anyone trying a one-off model without disturbing their saved preference.
Severity: moderate on its own — the workaround is /model after launch. It is sharper now than before #1424, because the TUI has a persisted model to fall back to, so the flag is not merely ignored, it is overridden by a stale preference. A user who passes -model to escape their remembered model gets exactly the thing they were trying to override.
The worst part is the silence. A flag that errors teaches; a flag that is quietly dropped trains people to distrust the CLI.
Data/security: none.
Workaround: launch the TUI and run /model.
Suspected seam and search evidence
Owning code: cmd/harnesscli/main.go.
main.go:149 — flags.String("model", "", "model override for this run"). Parsed.
main.go:179 — runTUI(*baseURL, workspacePath, *resume, *planMode). *model is not among the arguments, so it cannot reach the TUI. This is the defect.
main.go:538 — newTUIConfig(baseURL, workspace, resumeConversationID) builds tui.TUIConfig and never sets Model.
main.go:216 — the non-TUI path passes Model: *model into runCreateRequest, so the flag works correctly there. The bug is confined to the TUI branch.
Precedent for the fix: planMode reaches the TUI as an explicit runTUI parameter, then tuiCfg.PlanMode = planMode (main.go:579). The same route is available for the model.
Consumer already in place: cmd/harnesscli/tui/model.go sets selectedModel: cfg.Model at construction, and #1424's restore is guarded on cfg.Model == "", so a non-empty TUIConfig.Model already wins over the remembered value. TestExplicitModelBeatsRememberedModel pins that precedence today with no live producer of a non-empty cfg.Model — this issue supplies the producer.
Commands used: grep -n "runTUI(" cmd/harnesscli/main.go; grep -n "func newTUIConfig\|newTUIConfig(" cmd/harnesscli/*.go; sed -n 170,185p and 574,596p of main.go.
Evidence that rules out adjacent seams: the TUI already honors TUIConfig.Model (proven by TestExplicitModelBeatsRememberedModel and by selectedModel: cfg.Model at tui/model.go:501), and the non-TUI path already honors -model. Nothing needs to change in either; only the wiring between the flag and TUIConfig is missing.
Blast-radius impact map
Callers and data flow: main.go only — the runTUI call, its signature, and newTUIConfig. No TUI, server, protocol, or provider change.
Config/env/defaults: none. -model keeps its "" default, so "empty means no override" is unchanged and the precedence guard needs no edit.
API/CLI/wire formats/tools: -model begins doing what its help text already claims. No new flag, no changed help semantics.
Persistence/schema/cache: none, and deliberately so — the flag must not write to ~/.config/harnesscli/config.json. A one-off override that silently rewrote the saved preference would be a worse bug than the one being fixed.
Concurrency/lifecycle: none.
Security/auth/permissions/privacy: none. A model ID is not a secret.
TUI/web/macOS/other clients: TUI only. macapp builds its own config; the non-TUI streaming path is untouched.
Provider/model/tool catalog: a flag may name a model that does not exist or whose provider has no key. The TUI already handles an unavailable model with the #1404 redirect and explanation; that path should be exercised rather than assumed, and must not become a hard startup failure.
Deployment/observability/runbooks: website/docs/cli/ if it documents --tui flags.
Compatibility: strictly additive in effect. Anyone currently passing -model with --tui is having it ignored, so no working behavior changes — only a broken one starts working. Someone relying on the flag being ignored is relying on a bug.
Existing tests/fixtures: cmd/harnesscli/main_test.go calls newTUIConfig at four sites (:187, :203, :331, :342). If the model becomes a parameter rather than a post-hoc field assignment, those four calls need updating — worth it for a directly testable seam, since runTUI itself needs a terminal and cannot be unit tested.
Documentation: docs/logs/engineering-log.md, and the #1424 entry's "noted, not fixed" line should be updated so the log does not keep advertising a gap that has been closed.
Regression test first
cmd/harnesscli/main_test.go:
TestNewTUIConfigCarriesExplicitModel — newTUIConfig with a model returns a TUIConfig whose Model is that value. Red today: the function neither accepts nor sets it.
TestNewTUIConfigWithoutModelLeavesItEmpty — the control. An empty model must stay empty, so the remembered model and the daemon default still apply. Without this, a fix that defaulted to something would pass test 1 and break feat(tui): remember the last used model across restarts #1424.
Red command: go test ./cmd/harnesscli -run TestNewTUIConfig -v.
Expected failure: a compile error (no such parameter) followed, once wired, by Model = "" want "gpt-4.1-mini" if the value is dropped.
Why that proves the bug: newTUIConfig is the exact point where the flag's value must become TUIConfig.Model. runTUI cannot be unit tested — it requires a terminal — so this is the closest honest seam.
False-positive controls: keep TestExplicitModelBeatsRememberedModel (in tui) green, which proves the value is not merely stored but actually outranks the remembered model. Together the two tests cover producer and consumer; neither alone proves the flag works.
Fix boundaries
In scope:
Pass *model from the TUI dispatch into runTUI and on to TUIConfig.Model.
Before: launch with -model X, and the status bar shows the daemon default or the remembered model. No message anywhere mentions X.
After: the status bar shows X, and ~/.config/harnesscli/config.json is unchanged — the second half matters as much as the first, since a flag that rewrites the saved preference would be a regression against #1424.
Verification plan
Red: go test ./cmd/harnesscli -run TestNewTUIConfig -v before the change.
Green: same after.
Targeted: go test ./cmd/harnesscli/... -race.
Full regression: go test ./cmd/... ./internal/....
Real path, required, and it has two halves:
With a model already remembered from a previous session, launch harnesscli --tui -model <different-model> and confirm the status bar shows the flag's model, not the remembered one.
Quit and confirm ~/.config/harnesscli/config.json still holds the previously remembered model — proving a one-off override did not overwrite the preference.
Single PR to main; picked up on the next scripts/install.sh or Homebrew --HEAD. No migration or persisted-state change. Rollback is reverting the commit, which restores the flag being ignored.
Rollback trigger: -model overwriting the stored preference, or a bad model ID turning into a hard startup failure instead of the existing redirect.
Work type
Bug / regression
Observed behavior
harnesscli --tui -model Xsilently ignores-model. The TUI starts on whatever the daemon defaults to (or, since #1424, on the remembered model), and nothing tells the user their flag was discarded.Silent is the operative word: no warning, no error, no note in the status bar. The flag parses, validates, and is thrown away.
Found while building #1424. Recorded in
docs/logs/engineering-log.mdunder the 2026-09-08 #1424 entry as a known gap.Expected behavior
harnesscli --tui -model Xstarts the TUI on model X.Invariant: an explicitly requested model outranks every other source. Precedence, highest first: the
-modelflag, then the model remembered from the last session (#1424), then the daemon default.A flag is a one-off instruction, not a preference:
-model Xmust not overwrite the stored last-used model. If the user then picks a different model with/modelinside that session, that selection is a choice and is persisted as usual.Reproduction
harnesscli --tui -model gpt-4.1-mini(or via ago-codeTUI launch).Actual: the model is the daemon default, or the remembered model from a previous session. The requested model is absent, with no diagnostic.
Reproduction rate: 100%.
User and operational impact
Affected users: anyone scripting or aliasing a TUI launch against a specific model, and anyone trying a one-off model without disturbing their saved preference.
Severity: moderate on its own — the workaround is
/modelafter launch. It is sharper now than before #1424, because the TUI has a persisted model to fall back to, so the flag is not merely ignored, it is overridden by a stale preference. A user who passes-modelto escape their remembered model gets exactly the thing they were trying to override.The worst part is the silence. A flag that errors teaches; a flag that is quietly dropped trains people to distrust the CLI.
Data/security: none.
Workaround: launch the TUI and run
/model.Suspected seam and search evidence
Owning code:
cmd/harnesscli/main.go.main.go:149—flags.String("model", "", "model override for this run"). Parsed.main.go:179—runTUI(*baseURL, workspacePath, *resume, *planMode).*modelis not among the arguments, so it cannot reach the TUI. This is the defect.main.go:574—func runTUI(baseURL, workspace, resumeConversationID string, planMode bool).main.go:538—newTUIConfig(baseURL, workspace, resumeConversationID)buildstui.TUIConfigand never setsModel.main.go:216— the non-TUI path passesModel: *modelintorunCreateRequest, so the flag works correctly there. The bug is confined to the TUI branch.Precedent for the fix:
planModereaches the TUI as an explicitrunTUIparameter, thentuiCfg.PlanMode = planMode(main.go:579). The same route is available for the model.Consumer already in place:
cmd/harnesscli/tui/model.gosetsselectedModel: cfg.Modelat construction, and #1424's restore is guarded oncfg.Model == "", so a non-emptyTUIConfig.Modelalready wins over the remembered value.TestExplicitModelBeatsRememberedModelpins that precedence today with no live producer of a non-emptycfg.Model— this issue supplies the producer.Commands used:
grep -n "runTUI(" cmd/harnesscli/main.go;grep -n "func newTUIConfig\|newTUIConfig(" cmd/harnesscli/*.go;sed -n 170,185pand574,596pofmain.go.Evidence that rules out adjacent seams: the TUI already honors
TUIConfig.Model(proven byTestExplicitModelBeatsRememberedModeland byselectedModel: cfg.Modelattui/model.go:501), and the non-TUI path already honors-model. Nothing needs to change in either; only the wiring between the flag andTUIConfigis missing.Blast-radius impact map
Callers and data flow:
main.goonly — therunTUIcall, its signature, andnewTUIConfig. No TUI, server, protocol, or provider change.Config/env/defaults: none.
-modelkeeps its""default, so "empty means no override" is unchanged and the precedence guard needs no edit.API/CLI/wire formats/tools:
-modelbegins doing what its help text already claims. No new flag, no changed help semantics.Persistence/schema/cache: none, and deliberately so — the flag must not write to
~/.config/harnesscli/config.json. A one-off override that silently rewrote the saved preference would be a worse bug than the one being fixed.Concurrency/lifecycle: none.
Security/auth/permissions/privacy: none. A model ID is not a secret.
TUI/web/macOS/other clients: TUI only.
macappbuilds its own config; the non-TUI streaming path is untouched.Provider/model/tool catalog: a flag may name a model that does not exist or whose provider has no key. The TUI already handles an unavailable model with the #1404 redirect and explanation; that path should be exercised rather than assumed, and must not become a hard startup failure.
Deployment/observability/runbooks:
website/docs/cli/if it documents--tuiflags.Compatibility: strictly additive in effect. Anyone currently passing
-modelwith--tuiis having it ignored, so no working behavior changes — only a broken one starts working. Someone relying on the flag being ignored is relying on a bug.Existing tests/fixtures:
cmd/harnesscli/main_test.gocallsnewTUIConfigat four sites (:187,:203,:331,:342). If the model becomes a parameter rather than a post-hoc field assignment, those four calls need updating — worth it for a directly testable seam, sincerunTUIitself needs a terminal and cannot be unit tested.Documentation:
docs/logs/engineering-log.md, and the #1424 entry's "noted, not fixed" line should be updated so the log does not keep advertising a gap that has been closed.Regression test first
cmd/harnesscli/main_test.go:TestNewTUIConfigCarriesExplicitModel—newTUIConfigwith a model returns aTUIConfigwhoseModelis that value. Red today: the function neither accepts nor sets it.TestNewTUIConfigWithoutModelLeavesItEmpty— the control. An empty model must stay empty, so the remembered model and the daemon default still apply. Without this, a fix that defaulted to something would pass test 1 and break feat(tui): remember the last used model across restarts #1424.Red command:
go test ./cmd/harnesscli -run TestNewTUIConfig -v.Expected failure: a compile error (no such parameter) followed, once wired, by
Model = "" want "gpt-4.1-mini"if the value is dropped.Why that proves the bug:
newTUIConfigis the exact point where the flag's value must becomeTUIConfig.Model.runTUIcannot be unit tested — it requires a terminal — so this is the closest honest seam.False-positive controls: keep
TestExplicitModelBeatsRememberedModel(intui) green, which proves the value is not merely stored but actually outranks the remembered model. Together the two tests cover producer and consumer; neither alone proves the flag works.Fix boundaries
In scope:
*modelfrom the TUI dispatch intorunTUIand on toTUIConfig.Model.newTUIConfigcall sites.Out of scope:
tui/model.go. Already correct; this issue only supplies the producer.Diagnostic and observability evidence
Before: launch with
-model X, and the status bar shows the daemon default or the remembered model. No message anywhere mentions X.After: the status bar shows X, and
~/.config/harnesscli/config.jsonis unchanged — the second half matters as much as the first, since a flag that rewrites the saved preference would be a regression against #1424.Verification plan
go test ./cmd/harnesscli -run TestNewTUIConfig -vbefore the change.go test ./cmd/harnesscli/... -race.go test ./cmd/... ./internal/....harnesscli --tui -model <different-model>and confirm the status bar shows the flag's model, not the remembered one.~/.config/harnesscli/config.jsonstill holds the previously remembered model — proving a one-off override did not overwrite the preference.-modelpath still works, and that launching with no-modelstill resumes the remembered model (feat(tui): remember the last used model across restarts #1424 unbroken).Rollout and rollback
Single PR to
main; picked up on the nextscripts/install.shor Homebrew--HEAD. No migration or persisted-state change. Rollback is reverting the commit, which restores the flag being ignored.Rollback trigger:
-modeloverwriting the stored preference, or a bad model ID turning into a hard startup failure instead of the existing redirect.Documentation and handoff
docs/logs/engineering-log.md: new entry, and amend the feat(tui): remember the last used model across restarts #1424 entry's "noted, not fixed" line so the log stops advertising a closed gap.website/docs/cli/: if--tuiflags are documented, state the precedence — flag, then remembered, then daemon default.Definition of done
-modelreachesTUIConfig.Modelfrom the TUI dispatch-modelstill resumes the remembered modelgo test ./cmd/harnesscli/... -racegreen; full regression green