Summary
Ship v2.5.0 as the next stable release: everything currently on develop (including #5416), with an explicit minor bump so this is not published as 2.4.18.
GitVersion on both main and develop is increment: Patch. A blank Prepare Release will still tag v2.4.18. Use Version override = 2.5.0.
Shipped: v2.5.0-beta.1 (2026-09-03), then stable v2.5.0 (2026-09-11) via #5673. Back-merge #5674 open.
Why 2.5.0 (not 2.4.18, not 3.0.0)
| Option |
Verdict |
| 2.5.0 |
Recommended. Same pattern as v2.2.3 → v2.4.0. v2 is still the product generation. |
2.4.18 |
Do not. Patch with breaking API (View.Text, IAcceptTarget, CM deletion). |
3.0.0 |
Only if we want to honor Terminal.Gui/README.md literally (“MAJOR for breaking changes”) and start treating 2.x as frozen. Bigger product statement than 2.4.0 was. |
#5411 (MEC shims, [Obsolete]) already shipped in v2.4.17. 2.5.0 is the hard-removal / remaining-breaks train.
Beta vs stable: beta first — v2.5.0-beta.1 is live. Stable cut is the remaining user decision after soak.
Current state (2026-09-11)
| Surface |
State |
| Latest stable |
v2.5.0 on main / GitHub Release (2026-09-11 ~6:18am MT). NuGet push succeeded (indexing may lag). |
| Previous prerelease |
v2.5.0-beta.1 (2026-09-03) |
| Release PR |
#5673 merged ece73d25 (merge commit) |
| Back-merge |
#5674 open (main → develop) |
| #5416 / #5656 |
Merged earlier on the train |
| Ecosystem |
All 10 canaries had validated on 2.5.0-beta.1; bump to stable 2.5.0 is follow-up |
Breaking changes in 2.5.0
On develop / in v2.5.0-beta.1
| PR |
What broke |
Consumer action |
| #5371 (fixes #5366) |
View.Text is non-virtual; CWP TextChanging / OnTextChanging(string) / OnTextChanged() |
Replace override of Text with CWP overrides; TextField no longer hides Text with new |
| #5395 (fixes #5369) |
IAcceptTarget moved to Terminal.Gui.Input |
Fix usings |
| #5416 (fixes #4367) |
Deletes legacy ConfigurationManager / [ConfigurationProperty] / scope types that #5411 only marked [Obsolete]; nested config.json only |
Migrate to TuiConfigurationBuilder + Settings POCOs; run Tools/MigrateConfig on custom config.json |
Notable non-breaking already on develop
Leave other open drafts out unless they merge first: #5606, #5456.
Workstream 1 — Finish #5416 (gate) — DONE
Workstream 2 — Version bump on develop — DONE except stable override
GitVersion keeps increment: Patch on develop. #5656 landed +semver: minor (commit/PR title/merge message all minor-only; do not also put +semver: major in the message — GitVersion 6 major regex wins).
Note: Terminal.Gui/README.md says develop increments Minor, but GitVersion.yml actually increments Patch. Out of scope unless we want to fix it here; +semver: minor + version override are enough for 2.5.0.
Workstream 3 — Docs before the tag — DONE
Landed with #5416 unless noted.
API docs deploy from develop via api-docs.yml. Docs leftovers closed in #5658 before the beta tag.
Workstream 4 — Ecosystem validation (gate) — DONE
All dependents validated and merged against public Terminal.Gui 2.5.0-beta.1 (after earlier canaries on 2.5.0-develop.55 / winprint on .57).
Dependent tui-cs repos: Editor, cli, Terminal.Gui.templates, PSTui, TerminalGuiDesigner, Examples, ai, clet, mdv. Plus tig/winprint. Not TG-dependent: tuirec, VTTest, F7History, NStack.
Per-repo checklist (all done):
| Repo |
PR |
Result |
| Editor |
#287 |
merged |
| cli |
#43 |
merged |
| Terminal.Gui.templates |
#39 |
merged |
| PSTui |
#30 |
merged |
| TerminalGuiDesigner |
#326 |
merged |
| Examples |
#4 |
merged |
| ai |
#3 |
merged |
| clet |
#202 |
merged |
| mdv |
#7 |
merged |
| winprint |
#272 |
merged (incl. AOT after #5659) |
tig/winprint specifics:
Docs follow-up: ai-v2-primer.md / llms.txt Schemes.Resolve row — done in #5658 (SchemeManager.GetScheme; Schemes has no Resolve).
Issue tracker — close (or decide) before Prepare Release
Gate-found regressions:
Train regressions:
Release tasks:
Verify-and-close after #5416 merges:
Decide (gate or explicitly defer to 2.6):
Workstream 5 — Release execution — BETA DONE; STABLE SHIPPED 2026-09-11
Follow CONTRIBUTING.md Release Process. Do not tag by hand. Prepare Release always checks out develop.
Pre-flight
Prepare Release — beta (DONE 2026-09-03)
| Input |
Value used |
| Release type |
beta |
| Version override |
2.5.0 |
After Finalize — beta (DONE)
Prepare Release — stable (DONE 2026-09-11)
Soak v2.5.0-beta.1, then:
| Input |
Value |
| Release type |
stable |
| Version override |
2.5.0 (required; never blank) |
GitHub Release notes (paste at top after finalize)
Already applied on v2.5.0-beta.1. Reuse for stable:
## Breaking changes
This is a minor bump because v2 still accepts planned API breaks. Apps that compiled against 2.4.17 may need source changes.
1. **`View.Text` is no longer virtual** (#5371 / #5366)
- Use `OnTextChanging(string proposedValue)` / `TextChanging` to validate or cancel.
- Use `OnTextChanged()` for post-change sync.
- `TextField` uses `View.Text` directly (no `new` hider).
2. **`IAcceptTarget` moved to `Terminal.Gui.Input`** (#5395 / #5369)
- Add `using Terminal.Gui.Input;`.
3. **Legacy `ConfigurationManager` removed** (#5416 / #4367)
- Replacement: `TuiConfigurationBuilder` and Settings POCOs (`ButtonSettings.Current`, etc.).
- `config.json` is nested only. Convert old flat-key files with `Tools/MigrateConfig`.
- Types marked `[Obsolete]` in 2.4.17 (#5411) are gone.
See the configuration deep dive and the 2.5.0 migration notes.
## Highlights
- Editable NumericUpDown
- TableView horizontal scrolling for wide content
- Native ANSI size detection; platform detection cleanup
- SynchronizationContext fix
- Kitty protocol: preserve repeated legacy input after detection
- DropDownList: hide active popover on DeRegister (#5635)
- NativeAOT: RuneJsonConverter no longer trips IL2026 (#5659)
Sequence — DONE
v2.5.0-beta.1 → soak → Prepare Release stable → #5673 merge → tag v2.5.0 + GitHub Release → NuGet + #5674 back-merge → close #5630
Out of scope
Summary
Ship v2.5.0 as the next stable release: everything currently on
develop(including #5416), with an explicit minor bump so this is not published as2.4.18.GitVersion on both
mainanddevelopisincrement: Patch. A blank Prepare Release will still tagv2.4.18. Use Version override =2.5.0.Shipped:
v2.5.0-beta.1(2026-09-03), then stablev2.5.0(2026-09-11) via #5673. Back-merge #5674 open.Why 2.5.0 (not 2.4.18, not 3.0.0)
v2.2.3→v2.4.0. v2 is still the product generation.2.4.18View.Text,IAcceptTarget, CM deletion).3.0.0Terminal.Gui/README.mdliterally (“MAJOR for breaking changes”) and start treating 2.x as frozen. Bigger product statement than 2.4.0 was.#5411 (MEC shims,
[Obsolete]) already shipped in v2.4.17. 2.5.0 is the hard-removal / remaining-breaks train.Beta vs stable: beta first —
v2.5.0-beta.1is live. Stable cut is the remaining user decision after soak.Current state (2026-09-11)
v2.5.0onmain/ GitHub Release (2026-09-11 ~6:18am MT). NuGet push succeeded (indexing may lag).v2.5.0-beta.1(2026-09-03)ece73d25(merge commit)main→develop)2.5.0-beta.1; bump to stable2.5.0is follow-upBreaking changes in 2.5.0
On
develop/ inv2.5.0-beta.1View.Textis non-virtual; CWPTextChanging/OnTextChanging(string)/OnTextChanged()overrideofTextwith CWP overrides;TextFieldno longer hidesTextwithnewIAcceptTargetmoved toTerminal.Gui.InputConfigurationManager/[ConfigurationProperty]/ scope types that #5411 only marked[Obsolete]; nestedconfig.jsononlyTuiConfigurationBuilder+ Settings POCOs; runTools/MigrateConfigon customconfig.jsonNotable non-breaking already on
developNumericUpDowntext mode (Fixes #5469 - Add editable text mode to NumericUpDown #5587)SynchronizationContextfix (Fixes #5579. SynchronizationContext is not correctly implemented in v2 #5588) + session-scoped context (Fixes #5636 - Scope MainLoopSyncContext to running sessions (await-before-RunAsync deadlock) #5641 / IApplication.RunAsync deadlocks after await on ambient SynchronizationContext #5636)RuneJsonConverterIL2026 fix (Fixes NativeAOT IL2026 in RuneJsonConverter #5659)Leave other open drafts out unless they merge first: #5606, #5456.
Workstream 1 — Finish #5416 (gate) — DONE
origin/developintotig/remove-cm-followup; resolve conflictsResources/config.json, peek-and-warn for legacy flat keys, deleteScopeJsonConverterCM.Enable())Tools/MigrateConfigas a non-shipping aid; document it fromdocfx/docs/config.mddevelop(8c9b818d, 2026-09-02 6:16pm MT)developpush published2.5.0-develop.N(see Workstream 2). The 5416 merge itself published2.4.18-develop.54.Workstream 2 — Version bump on
develop— DONE except stable overrideGitVersion keeps
increment: Patchon develop. #5656 landed+semver: minor(commit/PR title/merge message all minor-only; do not also put+semver: majorin the message — GitVersion 6 major regex wins).developcommit whose message contains+semver: minor(Addresses #5630. Bump next version to 2.5.0 for breaking API +semver: minor #5656 /3b848938)2.5.0-develop.N(2.5.0-develop.55….58on nuget.org)2.5.0→v2.5.0-beta.12.5.0again. Do not leave it blanknext-version: 2.5.0toGitVersion.yml(the tag is the source of truth after release)Note:
Terminal.Gui/README.mdsaysdevelopincrements Minor, butGitVersion.ymlactually increments Patch. Out of scope unless we want to fix it here;+semver: minor+ version override are enough for 2.5.0.Workstream 3 — Docs before the tag — DONE
Landed with #5416 unless noted.
docfx/docs/config.mdaroundTuiConfigurationBuilder, Settings POCOs, nested JSON,Tools/MigrateConfigdocfx/docs/newinv2.md(MEC samples; points leftover CM atmigrate-cm-to-mec.md)docfx/docs/migratingfromv1.md(point v1 CM users at MEC) — PR #5658 mergedView.TextCWP,IAcceptTargetnamespace, CM deletion,config.jsonshape) — PR #5658 (docfx/docs/breaking-changes-2.5.0.md) mergedTerminal.Gui/README.mdversioning table vs what we actually ship — PR #5658 merged (table now Patch ++semver: minornote)ConfigurationManager.Enablecalls in UICatalog / examples (leftover mentions are specs + migrate table)docfx/docs/migrate-cm-to-mec.mdexistsAPI docs deploy from
developviaapi-docs.yml. Docs leftovers closed in #5658 before the beta tag.Workstream 4 — Ecosystem validation (gate) — DONE
All dependents validated and merged against public
Terminal.Gui 2.5.0-beta.1(after earlier canaries on2.5.0-develop.55/ winprint on.57).Dependent tui-cs repos: Editor, cli, Terminal.Gui.templates, PSTui, TerminalGuiDesigner, Examples, ai, clet, mdv. Plus
tig/winprint. Not TG-dependent: tuirec, VTTest, F7History, NStack.Per-repo checklist (all done):
Terminal.Guito public2.5.0-beta.1from nuget.orgView.TextCWP,IAcceptTargetnamespace, CM deletion)tig/winprintspecifics:2.5.0-beta.1(via2.5.0-develop.57for AOT proof, then public beta)ConfigurationManager.EnablewithTuiConfigurationBuilder, preserving config locationsWinPrint.TUI.UnitTests,WinPrint.TUI.UITests); five AOT publishes green./.tui/wp.config.jsonpreserved in the portDocs follow-up:
ai-v2-primer.md/llms.txtSchemes.Resolverow — done in #5658 (SchemeManager.GetScheme;Schemeshas noResolve).Issue tracker — close (or decide) before Prepare Release
Gate-found regressions:
IApplication.RunAsyncdeadlock afterawaiton ambientSynchronizationContext(fixed in Fixes #5636 - Scope MainLoopSyncContext to running sessions (await-before-RunAsync deadlock) #5641, shipped in FIXES #4367 - BREAKING CHANGE - Remove legacy ConfigurationManager after MEC migration #5416)LinearRangelegend stray characters (fixed in Fixes #5640. Prevent custom renderer text overdraw #5642)TextViewnew-Text setter guard flag not cleared infinally(Fixes #5639. Harden TextView text synchronization #5645)Train regressions:
TextFieldlong-Text vertical expansion / overdraw (Fixes #5366 - BREAKING CHANGE - Make View.Text notifications CWP-compliant and non-virtual #5371 fallout; fixed in Fixes #5640. Prevent custom renderer text overdraw #5642 /e4ece860)DropDownListstale popover contents after handled Enter (PR #5657 mergedb2b26ae7, 2026-09-03 12:53pm MT)Release tasks:
tui-config-schema.json→ nested MEC shape (in FIXES #4367 - BREAKING CHANGE - Remove legacy ConfigurationManager after MEC migration #5416)Verify-and-close after #5416 merges:
[ModuleInitializer]deadlock (verified gone after FIXES #4367 - BREAKING CHANGE - Remove legacy ConfigurationManager after MEC migration #5416; remainingInitializeConfigurationonly binds known Settings POCOs, does not walk assemblies)Decide (gate or explicitly defer to 2.6):
"Theme"now silently ignored (CM threw); text-field cursor now underline;Popovernow a screen-filling transparent overlay; ANSI driver sizes asynchronously;Selectorpads fixed-width labels; M.E.Configuration floor 10.0.11 → NU1605.Workstream 5 — Release execution — BETA DONE; STABLE SHIPPED 2026-09-11
Follow CONTRIBUTING.md Release Process. Do not tag by hand. Prepare Release always checks out
develop.Pre-flight
developrequired CI green at beta cut (Build Validation, Unit Tests 3 OS, Integration Tests 3 OS). Performance Gate / V2 has severe performance regressions #5323 deferred — not a blocker2.5.0-develop.*before the beta tag2.5.0-beta.1(Workstream 4)v2.5.0-beta.1)Prepare Release — beta (DONE 2026-09-03)
beta2.5.0main: PR #5660 (release/v2.5.0-beta.1)v2.5.0-beta.1, notv2.4.18GitVersion.ymlmain label set tobetarelease/After Finalize — beta (DONE)
v2.5.0-beta.1existsTerminal.GuiandTerminal.Gui.Interop.Spectre2.5.0-beta.1main→develop,145585dd)developNuGet is2.5.1-develop.N(publish after Back-merge v2.5.0-beta.1 from main into develop #5661; check nuget.org)tui-cs/Terminal.Gui.templatesbumped via #39tui-cs/Editorbumped via #287Prepare Release — stable (DONE 2026-09-11)
Soak
v2.5.0-beta.1, then:stable2.5.0(required; never blank)main: PR #5673 (release/v2.5.0)v2.5.0, notv2.4.18/ not another betaGitVersion.ymlmain label is''(stable)ece73d25(2026-09-11 ~6:17am MT)v2.5.0existsTerminal.GuiandTerminal.Gui.Interop.Spectre2.5.0(workflow 34598229813; package page may lag a few minutes)main→develop) — merge when CI greenGitHub Release notes (paste at top after finalize)
Already applied on
v2.5.0-beta.1. Reuse for stable:Sequence — DONE
Out of scope
developincrement from Patch → Minor (README already claims Minor)git tag/ pushingmainfrom a stale localmain2.4.18-develop.54unless we explicitly decide to