Skip to content

[Bug]: dashboard status/update miss running dashboards when --profile appears before the subcommand #44035

@Lx

Description

@Lx

Bug Description

Hermes can miss a running hermes dashboard process when the command has --profile before the dashboard subcommand. In that shape, hermes dashboard --status, hermes dashboard --stop, and the dashboard cleanup in hermes update can all behave as though no dashboard is running.

In my case, the dashboard process was supervised by a custom local macOS LaunchAgent (my own setup, not a standard Hermes-managed dashboard service). The important part is the command shape:

$HOME/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main \
  --profile $PROFILE \
  dashboard \
  --host 0.0.0.0 \
  --insecure \
  --port 9119 \
  --no-open \
  --skip-build

The failure showed up after hermes update: Hermes rebuilt the Web UI and restarted the gateway under the updated checkout, but left this dashboard backend running on its old Python process until I restarted my custom supervisor.

The likely cause is the fixed substring matching in hermes_cli/main.py::_find_stale_dashboard_pids():

patterns = [
    "hermes dashboard",
    "hermes_cli.main dashboard",
    "hermes_cli/main.py dashboard",
]

Those patterns don’t match python -m hermes_cli.main --profile $PROFILE dashboard ..., because --profile $PROFILE sits between the module name and the dashboard subcommand.

(To be clear: this report is only about detecting an already-running dashboard—whether Hermes should offer a first-class macOS dashboard LaunchAgent is a separate issue.)

Steps to Reproduce

  1. On macOS, start hermes dashboard via the module entrypoint with a global profile argument before the dashboard subcommand. This can be done manually or through any external supervisor; it doesn’t depend on launchd.

    $HOME/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main \
      --profile $PROFILE \
      dashboard \
      --host 0.0.0.0 \
      --insecure \
      --port 9119 \
      --no-open \
      --skip-build
  2. Confirm the real dashboard listener exists:

    lsof -nP -iTCP:9119 -sTCP:LISTEN

    Observed:

    python3.11 <pid> ... TCP *:9119 (LISTEN)
    
  3. Run the direct module status command:

    $HOME/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main \
      --profile $PROFILE \
      dashboard \
      --status
  4. Run hermes update while that dashboard is running.

Expected Behavior

hermes dashboard --status should report the running dashboard PID. hermes dashboard --stop and the stale-dashboard cleanup path in hermes update should detect the same process. Profile-qualified dashboard commands should be detected in all of these forms:

  • hermes --profile $PROFILE dashboard ...
  • python -m hermes_cli.main --profile $PROFILE dashboard ...
  • python hermes_cli/main.py --profile $PROFILE dashboard ...

Actual Behavior

The dashboard stays bound to port 9119, but direct module status doesn’t see it:

$HOME/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main \
  --profile $PROFILE \
  dashboard \
  --status
No hermes dashboard processes running.
exit=0

At the same time, lsof shows the dashboard running:

python3.11 <pid> ... TCP *:9119 (LISTEN)

During the update, Hermes rebuilt the Web UI and restarted the gateway, but the dashboard process stayed on the old backend. Restarting my custom supervisor fixed it.

There is also a related false-positive shape with the console-script wrapper: hermes dashboard --status can match the short-lived shell/wrapper command line containing the words hermes dashboard --status, rather than the long-running dashboard PID.

Affected Component

Setup / Installation, Configuration (config.yaml, .env, hermes setup)

Messaging Platform (if gateway-related)

No response

Debug Report

Not attaching a public debug bundle because this is a process-matching bug and the reproduction above avoids publishing local configuration.  I can provide a redacted debug bundle if needed.

Operating System

macOS 26.5.1 build 25F80

Python Version

No response

Hermes Version

Hermes Agent v0.16.0 (2026.6.5) - upstream 3e74f75

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

hermes_cli/main.py::_find_stale_dashboard_pids() scans process command lines using fixed substrings:

patterns = [
    "hermes dashboard",
    "hermes_cli.main dashboard",
    "hermes_cli/main.py dashboard",
]

That misses valid CLI shapes where global options appear before the subcommand:

python -m hermes_cli.main --profile $PROFILE dashboard ...

The existing tests cover python3 -m hermes_cli.main dashboard --port 9119, but not global arguments between hermes_cli.main and dashboard.

Proposed Fix (optional)

Parse the command arguments rather than relying on the current fixed substrings.

Suggested properties:

  1. Recognise global Hermes options before the dashboard subcommand, including
    --profile $PROFILE.
  2. Restrict matches to the current UID and, where possible, the current Hermes
    install/venv path.
  3. Avoid matching the current dashboard --status/--stop invocation, its
    transient shell wrapper, or chat/test commands that merely contain the words
    hermes and dashboard.
  4. Add regression coverage for:
    • python -m hermes_cli.main --profile $PROFILE dashboard --port 9119
    • hermes --profile $PROFILE dashboard --port 9119
    • python hermes_cli/main.py --profile $PROFILE dashboard --port 9119
    • hermes dashboard --status not reporting its own wrapper as a dashboard

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/cliCLI entry point, hermes_cli/, setup wizardtype/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