# NousResearch/hermes-agent · CLI auto-scroll and refresh interval fixes

## Open now

- 2 issues, 0 PRs open on GitHub.
- #12884: \[Bug\]: The CLI window always automatically rotate to the bottom
- #53636: Fix: CLI auto-scrolls to bottom every second on Termux/Android (cli_refresh_interval=1.0)

Multiple issues and fixes address unwanted automatic scrolling to the bottom in CLI/TUI mode, primarily caused by refresh_interval behavior. One unrelated fix handles a UnicodeDecodeError during post-update config migration.

## TL;DR

- 9 member(s): 2 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 5 PR(s) closed without merging.
- A fix was merged to main in PR #49056. Verify it addresses your case.
- **Recommended:** read PR #49056 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `partially_resolved` · deciding PR(s): `pr-49056`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_PARTIAL`): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
- Members outside that structural core may belong to a different underlying problem.
- Pairwise link density `0.19`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Open related issues

- #12884: \[Bug\]: The CLI window always automatically rotate to the bottom
- #53636: Fix: CLI auto-scrolls to bottom every second on Termux/Android (cli_refresh_interval=1.0)

## Closed / duplicate issues

- #48309: cli\`: \`refresh_interval=1.0\` causes terminal auto-scroll-to-bottom in non-fullscreen mode

## Prior & competing PRs

- **#12886: fix(update): handle UnicodeDecodeError in post-update config migration prompt**. closed without merge · fix tier `suggested`
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#68497`, `#68497`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#49056: fix(cli): make idle refresh_interval configurable, default 0 (no auto-scroll)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `cli.py`, `hermes_cli/config.py`, `scripts/release.py`, `tests/hermes_cli/test_config.py`
  - fix hunks:
  - `cli.py`

    ```diff
    @@ -13527,13 +13527,13 @@ def _get_voice_status():
                 style=style,
                 full_screen=False,
                 mouse_support=False,
    -            # The status bar contains wall-clock read-outs (live prompt elapsed
    -            # and idle-since-last-turn). Once a turn finishes there may be no
    -            # further events to invalidate the app, so prompt_toolkit would keep
    -            # rendering the first post-turn value (usually ``✓ 0s``) forever.
    -            # A low-rate refresh keeps the clock honest without reintroducing a
    -            # custom repaint thread or touching conversation state.
    -            refresh_interval=1.0,
    +            # Read from display.cli_refresh_interval (default 0 = disabled).
    +            # When non-zero, prompt_toolkit redraws the UI on this cadence
    +            # during idle, keeping wall-clock status-bar read-outs ticking.
    +            # Set to 0 to suppress background redraws entirely — avoids
    +            # fighting terminal auto-scroll in non-fullscreen mode (Xshell,
    +            # iTerm2, Windows Terminal). See #48309.
    +            refresh_interval=float(CLI_CONFIG.get("display", {}).get("cli_refresh_interval", 0)),
                 # Erase the live bottom chrome (status bar, input box, separator
                 # rules) on exit instead of freezing a final copy into scrollback.
                 # Without this, prompt_toolkit's render_as_done teardown repaints
    ```
  - `hermes_cli/config.py`

    ```diff
    @@ -1581,6 +1581,12 @@ def _ensure_hermes_home_managed(home: Path):
             # TUI busy indicator style: kaomoji (default), emoji, unicode (braille
             # spinner), or ascii.  Live-swappable via `/indicator <style>`.
             "tui_status_indicator": "kaomoji",
    +        # Seconds between prompt_toolkit redraws in the classic CLI when idle.
    +        # 0 = disabled (no background refresh — the pre-0.15.2 behaviour).
    +        # Positive values e.g. 1.0 keep wall-clock status-bar read-outs
    +        # (idle-since-last-turn) ticking but may fight terminal auto-scroll in
    +        # non-fullscreen mode on some emulators (Xshell, iTerm2, etc.).
    +        "cli_refresh_interval": 0,
             "user_message_preview": {  # CLI: how many submitted user-message lines to echo back in scrollback
                 "first_lines": 2,
                 "last_lines": 2,
    ```
  - `scripts/release.py`

    ```diff
    @@ -1531,6 +1531,7 @@
         "[redacted:email]": "erikengervall",  # PR #28774 (firecrawl integration tag)
         "[redacted:email]": "egilewski",  # PR #30432 (MEDIA path traversal fix, GHSA-jmf9-9729-7pp8)
         "[redacted:email]": "McClean-Edison",  # PR #29817 (register_auxiliary_task plugin API)
    +    "[redacted:email]": "OYLFLMH",  # PR #48312 salvage (cli_refresh_interval config, #48309)
         "[redacted:email]": "SamuelZ12",  # PR #7480 (show recap after in-session resume)
         "[redacted:email]": "daizhonggeng",  # PR #9020 (numbered /resume selection)
         "[redacted:email]": "wanwan2qq",  # PR #10215 (strip brackets/quotes from /resume; gateway session-ID lookup)
    ```
  - `tests/hermes_cli/test_config.py`

    ```diff
    @@ -955,6 +955,16 @@ def test_migrate_to_v15_adds_interim_assistant_message_gate(self, tmp_path):
             assert raw["display"]["interim_assistant_messages"] is True
     
     
    +class TestCliRefreshIntervalConfig:
    +    """Test the CLI refresh_interval config default (#48309)."""
    +
    +    def test_default_config_disables_cli_refresh_interval(self):
    +        """cli_refresh_interval defaults to 0 (disabled) to avoid
    +        background redraws that fight terminal auto-scroll-on-output
    +        in non-fullscreen mode (Xshell, iTerm2, Windows Terminal)."""
    +        assert DEFAULT_CONFIG["display"]["cli_refresh_interval"] == 0
    +
    +
     class TestDiscordChannelPromptsConfig:
         def test_default_config_includes_discord_channel_prompts(self):
             assert DEFAULT_CONFIG["discord"]["channel_prompts"] == {}
    ```
- **#12982: fix(ui-tui): prevent stickyScroll re-activation after manual scroll-up**. closed without merge
  - maintainer direction: category `uncategorized`; implication `needs_llm`
- **#48319: fix(cli): make refresh_interval configurable, default to 0 (disabled)**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#48321`, `#48321`, `#48319`, `#48321`, `#48321`
- **#48321: fix(cli): disable idle refresh_interval in non-fullscreen mode to prevent auto-scroll**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#48319`, `#48309`, `#48319`
- **#74742: fix(ui-tui): prevent stickyScroll re-activation after manual scroll-up**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `#75439`, `#12884`, `#75439`

## Fix status

- Merged to main in PR #49056 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-06-19`.
- Subsystem: `hermes_cli`
