Skip to content

Orphaned agent-browser daemons accumulate after force-closed sessions, eventually freezing CLI input #13793

@tintin006

Description

@tintin006

Description

When using the browser tool in the CLI, agent-browser daemon processes () accumulate over time and eventually cause the CLI to stop accepting keyboard input (prompt_toolkit becomes unresponsive — input field is visible but nothing can be typed).

Steps to Reproduce

  1. Start a normal hermes CLI session
  2. Use browser tool heavily (navigate, click, snapshot across multiple turns)
  3. After several tool-heavy turns (~5-6 browser interactions), CLI input freezes
  4. User is forced to close the terminal tab (killing the process)
  5. Repeat 3-4 times in a day — each time orphans additional daemons

Root Cause

The browser tool spawns agent-browser daemon processes that are cleaned up via atexit.register(_emergency_cleanup_all_sessions). However:

  • When the CLI freezes due to prompt_toolkit corruption, the user must force-kill the terminal
  • Force-killing bypasses atexit handlers, leaving daemons orphaned
  • The orphan reaper () runs on clean session startup, but may not catch all cases
  • Over a day of usage, 10+ orphaned daemons can accumulate

Evidence

Before cleanup — 11 orphaned agent-browser daemons found, oldest from 4:25 AM:

chlinder  29687  ??  Ss   12:15PM   0:02.37 node .../agent-browser/dist/daemon.js
chlinder  11603  ??  Ss    5:52AM   0:02.67 node .../agent-browser/dist/daemon.js
chlinder  11109  ??  Ss    5:41AM   0:02.54 node .../agent-browser/dist/daemon.js
... (8 more)

Environment

  • OS: macOS (11-year-old Mac)
  • Hermes version: latest (git install)
  • Model: xiaomi/mimo-v2-pro via Nous Portal
  • Platform: CLI (terminal)

Suggested Fixes

  1. Signal-based cleanup: Revisit the SIGINT/SIGTERM handler approach. The comment in browser_tool.py mentions this conflicts with prompt_toolkit, but a handler that only calls _emergency_cleanup_all_sessions() (without sys.exit()) and then re-raises the signal might avoid the corruption.

  2. Per-daemon heartbeat: Each daemon writes a heartbeat file with its owner PID. A startup sweep already exists but could be more aggressive.

  3. Daemon limit: Cap the number of concurrent agent-browser daemons per user (e.g., 3). Oldest gets killed when limit is exceeded.

  4. Session-level cleanup on browser_tool init: Run the orphan reaper every time the browser tool is first used in a session, not just at process startup.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/cliCLI entry point, hermes_cli/, setup wizardtool/browserBrowser automation (CDP, Playwright)type/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions