hermes - ✅(Solved) Fix feat: paplay audio bell + notify-on-interact for Wayland terminals [1 pull requests, 1 participants]

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…
GitHub stats
NousResearch/hermes-agent#25022Fetched 2026-05-14 03:49:43
View on GitHub
Comments
0
Participants
1
Timeline
5
Reactions
0
Author
Participants
Timeline (top)
labeled ×4cross-referenced ×1

Error Message

Both are fire-and-forget with silent error handling — no dependency required beyond paplay (shipped with PulseAudio/PipeWire on all major distros).

Fix Action

Fix / Workaround

Full patch diff available on request.

PR fix notes

PR #25042: feat: paplay audio bell + notify_on_interact for Wayland terminals (#25022)

Description (problem / solution / changelog)

What does this PR do?

Closes #25022.

Fixes the silent bell_on_complete on Wayland-native terminals (Foot, Kitty, ghostty) where the bare ASCII BEL (\a) is silently swallowed or only triggers a visual flash, and adds a sibling display.notify_on_interact config flag (default false) that fires the same audible cue whenever the agent pauses for user input (clarify / approval / sudo / secret prompts).

Two-pronged best-effort strategy in a shared helper on each surface — Python cli._ring_bell() and TUI ui-tui/src/lib/notify.ts → ringBell():

  • Write \a (ASCII BEL) to stdout — keeps legacy / SSH / tmux passthrough / classic iTerm2 paths working.
  • Spawn paplay /usr/share/sounds/freedesktop/stereo/message-new-instant.oga detached (start_new_session=True, /dev/null I/O) — covers Wayland / PipeWire / PulseAudio terminals.

Both legs are wrapped: missing paplay, sandboxed audio device, headless CI, and closed stdout never crash the agent loop. After the first ENOENT the TUI side caches paplayMissing = true so subsequent notifications skip the spawn cost on systems without paplay.

Related Issue

Closes #25022 — feat: paplay audio bell + notify-on-interact for Wayland terminals.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

Four conventional-commits commits, all single-author, no behavior change for users who don't opt in:

  • commit 1 — feat(cli) (cli.py, hermes_cli/config.py, hermes_cli/callbacks.py, +105 / -7): new _ring_bell() helper; both bell_on_complete call sites in cli.py route through it; notify_on_interact attribute populated from display.notify_on_interact (default false); _clarify_callback, _sudo_password_callback, _approval_callback (cli.py) and clarify_callback, prompt_for_secret, approval_callback (callbacks.py) ring the bell when the flag is on.
  • commit 2 — feat(tui) (ui-tui/src/lib/notify.ts new + createGatewayEventHandler.ts, useMainApp.ts, useConfigSync.ts, interfaces.ts, gatewayTypes.ts, +128 / -12): TUI parity. ringBell({ stdout }) from message.complete (when bell_on_complete) and from the four *.request events (when notify_on_interact); applyDisplay / hydrateFullConfig get an optional setNotifyOnInteract setter so existing 3-arg call sites stay green.
  • commit 3 — docs (cli-config.yaml.example, website/docs/user-guide/configuration.md, website/docs/user-guide/cli.md, hermes_cli/tips.py, +19 / -5): first-run config dump documents notify_on_interact; user guide explains the paplay + ASCII BEL pair and the Wayland coverage; rotating tip points at the new flag next to the existing bell_on_complete tip.
  • commit 4 — test (tests/cli/test_ring_bell.py new — 9 cases, ui-tui/src/__tests__/notify.test.ts new — 9 cases, ui-tui/src/__tests__/useConfigSync.test.ts — +4 cases, +330 lines):
    • test_ring_bell.py (Python, 9 cases) — ASCII BEL always written + flushed; paplay invoked detached with /dev/null I/O when on PATH; shutil.which → None short-circuits cleanly; OSError from subprocess.Popen and ValueError from a closed stdout are both swallowed; _maybe_ring_interact_bell respects the flag, fires _ring_bell when on, no-ops on stub CLIs missing the attribute (back-compat); DEFAULT_CONFIG ships notify_on_interact = bell_on_complete = False.
    • notify.test.ts (TS, 9 cases) — ASCII BEL only when stdout.isTTY; canonical spawn(paplay, [sound], { detached: true, stdio: 'ignore' }) invocation; custom soundPath option threads through; ENOENT trips the paplayMissing cache so subsequent calls skip spawn; non-ENOENT errors do not trip the cache (transient audio contention shouldn't disable the feature); synchronous spawn() throws and stdout.write throws are both swallowed.
    • useConfigSync.test.ts → applyDisplay → notify_on_interact (TS, 4 cases) — optional setNotifyOnInteract setter fires with the bool value, defaults to false when key missing, no-ops when omitted (back-compat with existing 3-arg call sites), coerces 0/1 to booleans the same way bell_on_complete does.

No production code modified outside the commits listed above; no new runtime dependency added (paplay ships with PulseAudio/PipeWire on every major distro's default install via sound-theme-freedesktop).

How to Test

  1. Check out this branch and ensure .venv is set up: python3 -m venv .venv && source .venv/bin/activate && pip install -e ".[all,dev]".
  2. Run the new Python tests on their own:
    scripts/run_tests.sh tests/cli/test_ring_bell.py -v
    Expected: 9 passed.
  3. Run the approval-UI suite to confirm no regression in the existing prompt callbacks:
    scripts/run_tests.sh tests/cli/test_cli_approval_ui.py tests/cli/test_ring_bell.py
    Expected: 20 passed.
  4. Run the TUI tests:
    cd ui-tui && npx vitest run src/__tests__/notify.test.ts src/__tests__/useConfigSync.test.ts
    Expected: 44 passed.
  5. Manual smoke on a Wayland terminal (Foot / Kitty / ghostty):
    • display.bell_on_complete: true — terminal rings audibly via paplay after each agent response (was a silent flash before).
    • display.notify_on_interact: true — terminal rings on each clarify / sudo / approval / secret prompt.
    • Both flags false (default) — completely silent, identical to today's behavior.
    • paplay not installed — falls back to \a only, no errors logged, agent loop unaffected.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (feat(cli), feat(tui), docs, test for the four commits)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run scripts/run_tests.sh tests/cli/test_ring_bell.py and all tests pass
  • I've added tests for my changes (9 Python + 9 TS + 4 applyDisplay = 22 new test cases)
  • I've tested on my platform: macOS 15.2 (Darwin 24.6.0), Python 3.12, Node 22.15.0

Documentation & Housekeeping

  • I've updated relevant documentation — website/docs/user-guide/configuration.md, website/docs/user-guide/cli.md, hermes_cli/tips.py
  • I've updated cli-config.yaml.example for the new notify_on_interact key
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A (no architectural change)
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guidepaplay leg is Linux-only; macOS/Windows fall through to the ASCII BEL path with no errors. Both helpers gate on shutil.which / paplayMissing before spawning, so no missing-binary noise on non-Linux.
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A (display-only feature, no tool surface)

Screenshots / Logs

$ scripts/run_tests.sh tests/cli/test_ring_bell.py -v
4 workers [9 items]
============================== 9 passed in 1.46s ==============================

$ scripts/run_tests.sh tests/cli/test_cli_approval_ui.py tests/cli/test_ring_bell.py
============================== 20 passed in 1.46s ==============================

$ cd ui-tui && npx vitest run src/__tests__/notify.test.ts src/__tests__/useConfigSync.test.ts
 Test Files  2 passed (2)
      Tests  44 passed (44)

$ cd ui-tui && npm run type-check
> tsc --noEmit -p tsconfig.json
(clean)

$ cd ui-tui && npx vitest run
 Test Files  63 passed | 1 skipped (64)
      Tests  698 passed | 3 skipped (701)

Changed files

  • cli-config.yaml.example (modified, +15/-3)
  • cli.py (modified, +75/-7)
  • hermes_cli/callbacks.py (modified, +23/-0)
  • hermes_cli/config.py (modified, +7/-0)
  • hermes_cli/tips.py (modified, +1/-0)
  • tests/cli/test_ring_bell.py (added, +149/-0)
  • ui-tui/src/__tests__/notify.test.ts (added, +121/-0)
  • ui-tui/src/__tests__/useConfigSync.test.ts (modified, +60/-0)
  • ui-tui/src/app/createGatewayEventHandler.ts (modified, +17/-3)
  • ui-tui/src/app/interfaces.ts (modified, +1/-0)
  • ui-tui/src/app/useConfigSync.ts (modified, +20/-7)
  • ui-tui/src/app/useMainApp.ts (modified, +11/-2)
  • ui-tui/src/gatewayTypes.ts (modified, +1/-0)
  • ui-tui/src/lib/notify.ts (added, +78/-0)
  • website/docs/user-guide/cli.md (modified, +1/-1)
  • website/docs/user-guide/configuration.md (modified, +2/-1)

Code Example

sys.stdout.write("\a")
sys.stdout.flush()

---

subprocess.Popen(
    ["paplay", "/usr/share/sounds/freedesktop/stereo/message-new-instant.oga"],
    stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
)
RAW_BUFFERClick to expand / collapse

Problem

On Wayland terminals (Foot, Kitty, ghostty), the ASCII BEL character (\x07) used by bell_on_complete is silently ignored or only triggers a visual flash — no audible notification. Users miss task completion alerts.

Additionally, there is currently no sound notification when the agent needs user input (clarify, approval, sudo, secret prompts), forcing users to constantly watch the terminal.

Proposed Changes

Two complementary features already implemented and tested locally:

1. Replace \a with paplay for bell_on_complete

Files: cli.py, ui-tui/src/app/createGatewayEventHandler.ts

Instead of:

sys.stdout.write("\a")
sys.stdout.flush()

Use paplay to play a system notification sound:

subprocess.Popen(
    ["paplay", "/usr/share/sounds/freedesktop/stereo/message-new-instant.oga"],
    stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
)

The TUI React side (createGatewayEventHandler.ts) uses the same paplay + \x07 dual strategy via a shared ringBell() helper.

2. New notify_on_interact config option

When enabled, plays the same sound for:

  • Clarify questions
  • Approval requests
  • Sudo password prompts
  • Secret input prompts

Config key: display.notify_on_interact (boolean, default false)

Files modified: cli.py, hermes_cli/callbacks.py, ui-tui/src/app/createGatewayEventHandler.ts, ui-tui/src/app/interfaces.ts, ui-tui/src/app/useConfigSync.ts, ui-tui/src/app/useMainApp.ts, ui-tui/src/gatewayTypes.ts

New utility: ui-tui/src/lib/notify.ts

Shared ringBell() function that:

  1. Writes \x07 to TTY stdout as a best-effort terminal bell
  2. Also fires paplay as a reliable fallback on PulseAudio/PipeWire systems

Both are fire-and-forget with silent error handling — no dependency required beyond paplay (shipped with PulseAudio/PipeWire on all major distros).

Implementation Notes

  • paplay is available on all Linux distros with PulseAudio or PipeWire (virtually all desktop Linux in 2026)
  • Both CLI (prompt_toolkit mode) and TUI (ink React UI) are covered
  • Backward compatible: bell_on_complete still works as before, notify_on_interact defaults to false

Full patch diff available on request.

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

hermes - ✅(Solved) Fix feat: paplay audio bell + notify-on-interact for Wayland terminals [1 pull requests, 1 participants]