hermes - 💡(How to fix) Fix /new and /clear hang on confirmation prompt — daemon-thread input() competes with prompt_toolkit stdin

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Typing /new or /clear in the CLI shows the 3-option confirmation prompt ([1] Approve Once, [2] Always Approve, [3] Cancel), but then freezes permanently. The user cannot type a choice — input() never returns.

Root Cause

_confirm_destructive_slash() in cli.py:8651 calls _prompt_text_input("Choice [1/2/3]: "). Slash commands are dispatched from process_loop (a daemon thread, cli.py:12749), not the main thread.

_prompt_text_input (cli.py:6018) checks threading.current_thread() is threading.main_thread(). When false, it falls back to direct input():

else:
    _ask()  # calls input() directly

But prompt_toolkit owns stdin in raw mode on the main thread. input() on a daemon thread is blocked waiting for stdin that ptk has already captured. This is a permanent hang.

Fix Action

Fix / Workaround

_confirm_destructive_slash() in cli.py:8651 calls _prompt_text_input("Choice [1/2/3]: "). Slash commands are dispatched from process_loop (a daemon thread, cli.py:12749), not the main thread.

Code Example

else:
    _ask()  # calls input() directly
RAW_BUFFERClick to expand / collapse

Description

Typing /new or /clear in the CLI shows the 3-option confirmation prompt ([1] Approve Once, [2] Always Approve, [3] Cancel), but then freezes permanently. The user cannot type a choice — input() never returns.

Root Cause

_confirm_destructive_slash() in cli.py:8651 calls _prompt_text_input("Choice [1/2/3]: "). Slash commands are dispatched from process_loop (a daemon thread, cli.py:12749), not the main thread.

_prompt_text_input (cli.py:6018) checks threading.current_thread() is threading.main_thread(). When false, it falls back to direct input():

else:
    _ask()  # calls input() directly

But prompt_toolkit owns stdin in raw mode on the main thread. input() on a daemon thread is blocked waiting for stdin that ptk has already captured. This is a permanent hang.

What Was Tried

Attempted to use asyncio.run_coroutine_threadsafe(run_in_terminal(_ask), loop):

  1. run_in_terminal(_ask) fails because the daemon thread has no event loop: RuntimeError: There is no current event loop in thread (Python 3.11 ensure_future requires one)
  2. Adding asyncio.set_event_loop(loop) before calling run_in_terminal fixes the RuntimeError, and input() now works — but then the CLI exits after choice selection (something in run_in_terminal / prompt_toolkit state restoration causes the exit)

Suggested Fix Direction

The destructive slash confirmation should probably not use input() at all from the daemon thread. Instead, it could:

  • Route the prompt through prompt_toolkit's composer/buffer system (like clarify does with _clarify_state)
  • Or use event.app.run_in_terminal() from the main thread directly, by deferring the confirmation prompt to the main thread via call_soon_threadsafe
  • Or handle /new inline on the UI thread like /model already does (line 11108)

Environment

  • macOS 26.4.1, Python 3.11.15
  • Hermes CLI (not TUI)
  • prompt_toolkit 3.x
  • Reproducible: always

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING