feat(cli): configurable default interface (cli vs tui) + --cli flag#37782
Merged
Conversation
Add `display.interface` config key so users can make the modern TUI the
default for bare `hermes` / `hermes chat` without exporting HERMES_TUI=1 in
every shell. Default stays "cli" to preserve current behavior.
Add a `--cli` flag (mirrors `--tui`) so an explicit invocation can force the
classic prompt_toolkit REPL even when `display.interface: tui` is configured.
Precedence (highest first): `--cli` > `--tui`/`HERMES_TUI=1` > config
`display.interface` > classic REPL. Two resolvers enforce it:
* `_resolve_use_tui(args)` — the args-aware resolver used by `cmd_chat`
and the Termux fast-TUI path (uses full load_config()).
* `_wants_tui_early(argv)` — a dependency-free early resolver used by
mouse-residue suppression and the Termux fast paths, which run before
argparse / hermes_cli.config are importable (minimal cached YAML read).
Both `--cli` and `--tui` are registered via `_inherited_flag`, so they are
carried across self-relaunch automatically.
- config: add display.interface ("cli" default), bump _config_version 25->26.
The generic missing-field migration + load_config() deep-merge seed the key
for existing configs; no bespoke migration block needed.
- docs: document --cli flag and display.interface in cli-commands.md and
the TUI user guide.
- tests: new test_default_interface_resolution.py covering resolver
precedence at every layer, early resolver edge cases (missing/garbage
config), parser flags, and relaunch inheritance.
Contributor
🔎 Lint report:
|
| Rule | Count |
|---|---|
invalid-argument-type |
3 |
not-subscriptable |
1 |
unresolved-import |
1 |
First entries
tests/hermes_cli/test_default_interface_resolution.py:191: [invalid-argument-type] invalid-argument-type: Method `__getitem__` of type `Overload[(i: SupportsIndex, /) -> Unknown, (s: slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None], /) -> list[Unknown]]` cannot be called with key of type `Literal["interface"]` on object of type `list[Unknown]`
tests/hermes_cli/test_default_interface_resolution.py:191: [not-subscriptable] not-subscriptable: Cannot subscript object of type `int` with no `__getitem__` method
tests/hermes_cli/test_default_interface_resolution.py:28: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tests/hermes_cli/test_default_interface_resolution.py:191: [invalid-argument-type] invalid-argument-type: Method `__getitem__` of type `bound method str.__getitem__(key: SupportsIndex | slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None], /) -> str` cannot be called with key of type `Literal["interface"]` on object of type `str`
tests/hermes_cli/test_default_interface_resolution.py:191: [invalid-argument-type] invalid-argument-type: Method `__getitem__` of type `Overload[(i: SupportsIndex, /) -> str, (s: slice[SupportsIndex | None, SupportsIndex | None, SupportsIndex | None], /) -> list[str]]` cannot be called with key of type `Literal["interface"]` on object of type `list[str]`
✅ Fixed issues: none
Unchanged: 5021 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
tonydwb
approved these changes
Jun 3, 2026
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Overview
Adds a configurable default interface (hermes.default_interface: cli|tui) and a --cli flag. Well-designed with backward compatibility.
✅ Looks Good
- Clean implementation: reads
hermes.default_interfaceconfig key withclias fallback (maintains current behavior) --cliflag provides explicit override without needing to edit config- Config schema updated with the new field
- No regressions for existing users (default behavior unchanged)
- 312 additions, 9 deletions — well-scoped
- Proper type definitions and defaults
Reviewed by Hermes Agent
davidgut1982
pushed a commit
to davidgut1982/hermes-agent
that referenced
this pull request
Jun 5, 2026
…le-default-interface feat(cli): configurable default interface (cli vs tui) + --cli flag
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Make the TUI selectable as the default interface for bare
hermes/hermes chat, configurable viadisplay.interface, and add a--cliflag to force the classic REPL.Previously the only way to default to the TUI was
export HERMES_TUI=1in every shell. Now you can set it once in config, and still override per-invocation either direction.Behavior
New config key:
New flag
--cli(mirrors the existing--tui), available at the top level and underchat.Precedence (highest first):
--cli→ always classic REPL--tui/HERMES_TUI=1→ always TUIdisplay.interfaceconfig valueSo explicit flags always win over config — muscle memory and scripts keep working regardless of the configured default. The shipped default stays
cli, so existing installs are unchanged.Implementation
Two resolvers keep the precedence consistent across every decision point:
_resolve_use_tui(args)— args-aware resolver (uses fullload_config()), used bycmd_chatand the Termux fast-TUI path._wants_tui_early(argv)— dependency-free early resolver (minimal cached YAML read) used by mouse-residue suppression and the Termux fast CLI/TUI paths, which run before argparse andhermes_cli.configare importable.Both
--cliand--tuiare registered via_inherited_flag, so they're carried across self-relaunch automatically (verified by test).Config: bumped
_config_version25 → 26. The generic missing-field migration plusload_config()'s deep-merge seeddisplay.interfacefor existing configs — no bespoke migration block needed.Tests
New
tests/hermes_cli/test_default_interface_resolution.py(21 tests):_resolve_use_tuiprecedence at every layer (flag vs env vs config, case-insensitivity,load_configfailure → cli fallback)_wants_tui_earlyedge cases (config tui/cli, flag/env overrides, missing config, garbage YAML → cli fallback)--cli/--tuiparse at top level and underchat, and are relaunch-inheritedcliAll touched suites pass under the isolation wrapper (
./scripts/run_tests.sh):Docs
cli-commands.md: documented--cliand thedisplay.interfaceinteraction.tui.md: added thedisplay.interface: tuiconfig option and updated the "Reverting to the classic CLI" section.