Skip to content

feat(cli): configurable default interface (cli vs tui) + --cli flag#37782

Merged
OutThisLife merged 1 commit into
mainfrom
bb/configurable-default-interface
Jun 3, 2026
Merged

feat(cli): configurable default interface (cli vs tui) + --cli flag#37782
OutThisLife merged 1 commit into
mainfrom
bb/configurable-default-interface

Conversation

@OutThisLife

Copy link
Copy Markdown
Collaborator

What

Make the TUI selectable as the default interface for bare hermes / hermes chat, configurable via display.interface, and add a --cli flag to force the classic REPL.

Previously the only way to default to the TUI was export HERMES_TUI=1 in every shell. Now you can set it once in config, and still override per-invocation either direction.

Behavior

New config key:

display:
  interface: cli   # "cli" (default, classic prompt_toolkit REPL) or "tui" (Ink TUI)

New flag --cli (mirrors the existing --tui), available at the top level and under chat.

Precedence (highest first):

  1. --cli → always classic REPL
  2. --tui / HERMES_TUI=1 → always TUI
  3. display.interface config value
  4. default → classic REPL

So 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 full load_config()), used by cmd_chat and 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 and hermes_cli.config are importable.

Both --cli and --tui are registered via _inherited_flag, so they're carried across self-relaunch automatically (verified by test).

Config: bumped _config_version 25 → 26. The generic missing-field migration plus load_config()'s deep-merge seed display.interface for existing configs — no bespoke migration block needed.

Tests

New tests/hermes_cli/test_default_interface_resolution.py (21 tests):

  • _resolve_use_tui precedence at every layer (flag vs env vs config, case-insensitivity, load_config failure → cli fallback)
  • _wants_tui_early edge cases (config tui/cli, flag/env overrides, missing config, garbage YAML → cli fallback)
  • parser: --cli/--tui parse at top level and under chat, and are relaunch-inherited
  • shipped default is cli

All touched suites pass under the isolation wrapper (./scripts/run_tests.sh):

test_default_interface_resolution.py  21 ✓
test_tui_mouse_residue_suppression.py  6 ✓
test_config.py                        87 ✓
test_tools_config.py / mcp / setup    99 ✓
test_subparser_routing_fallback / tui_resume / tui_npm_install / profiles  all ✓

Docs

  • cli-commands.md: documented --cli and the display.interface interaction.
  • tui.md: added the display.interface: tui config option and updated the "Reverting to the classic CLI" section.

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.
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: bb/configurable-default-interface vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 9701 on HEAD, 9696 on base (🆕 +5)

🆕 New issues (5):

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.

@alt-glitch alt-glitch added type/feature New feature or request comp/cli CLI entry point, hermes_cli/, setup wizard comp/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have labels Jun 3, 2026
@OutThisLife OutThisLife merged commit 918aef2 into main Jun 3, 2026
24 checks passed
@OutThisLife OutThisLife deleted the bb/configurable-default-interface branch June 3, 2026 02:16

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_interface config key with cli as fallback (maintains current behavior)
  • --cli flag 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants