hermes - 💡(How to fix) Fix feat: Unified Agent Status API — real-time state detection, notifications, and status bar integration

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…

Propose a unified Agent Status API built into Hermes core that tracks agent lifecycle state in real-time, exposes it via a machine-readable status file, CLI command, and built-in status bar — consolidating and superseding several existing issues (#24632, #19302, #36698, #38024, #21442, #37416, #30389, #11757, #17837, #33836, #32299).

Error Message

"discord": {"state": "disconnected", "error": "..."} on: [attention, error, degraded]

Root Cause

Propose a unified Agent Status API built into Hermes core that tracks agent lifecycle state in real-time, exposes it via a machine-readable status file, CLI command, and built-in status bar — consolidating and superseding several existing issues (#24632, #19302, #36698, #38024, #21442, #37416, #30389, #11757, #17837, #33836, #32299).

Fix Action

Fix / Workaround

Code locationTriggerState
conversation_loop.py loop startAgent begins processingbusy
conversation_loop.py pre LLM callAbout to call LLMbusy, detail = "thinking..."
conversation_loop.py pre tool dispatchAbout to call toolbusy, detail = "calling tool: <name>"
conversation_loop.py approval waitNeeds user approvalattention
conversation_loop.py post approval responseUser respondedbusy
conversation_loop.py loop endTurn completeidle
gateway/run.py platform disconnectPlatform connection lostdegraded
gateway/run.py gateway stopGateway shutting downoffline

When state transitions to a notification-triggering state, dispatch via notify-send (Linux), osascript (macOS), or PowerShell toast (Windows). Falls back to terminal bell if desktop notification unavailable.

Code Example

{
  "state": "busy",
  "state_detail": "calling tool: web_search",
  "gateway": {"running": true, "pid": 203245},
  "current_turn": {
    "model": "anthropic/claude-sonnet-4",
    "provider": "anthropic",
    "reasoning_effort": "high",
    "tokens_used": 4500,
    "tokens_limit": 200000,
    "tools_called": ["web_search", "read_file"],
    "started_at": "2026-06-05T10:05:00Z",
    "duration_seconds": 12
  },
  "attention": {"needs_attention": false, "reason": null, "since": null},
  "platforms": {
    "telegram": {"state": "connected"},
    "discord": {"state": "disconnected", "error": "..."}
  },
  "last_error": null,
  "updated_at": "2026-06-05T10:05:24Z"
}

---

hermes status              # JSON to stdout
hermes status --format human   # Human-readable table
hermes status --watch      # Continuous mode (re-read on file change)

---

● idle  │ anthropic/claude-sonnet-44.5k/200k tokens │ telegram: connected │ 12s
◐ busy  │ calling tool: web_search │ 4.5k/200k tokens │ telegram: connected │ 12s
◆ attn  │ needs approval: terminal │ 4.5k/200k tokens │ telegram: connected │ 12s
▲ deg   │ telegram disconnected    │ 4.5k/200k tokens │ 12s

---

display:
  notifications:
    enabled: true
    on: [attention, error, degraded]
    method: desktop  # desktop | bell | both | none
    desktop_command: "notify-send"  # auto-detect on macOS/Windows
RAW_BUFFERClick to expand / collapse

Summary

Propose a unified Agent Status API built into Hermes core that tracks agent lifecycle state in real-time, exposes it via a machine-readable status file, CLI command, and built-in status bar — consolidating and superseding several existing issues (#24632, #19302, #36698, #38024, #21442, #37416, #30389, #11757, #17837, #33836, #32299).

Motivation

Currently, monitoring Hermes agent state requires either:

  1. External plugins (e.g. noctalia-hermes) that wire up hooks, write signal files, and poll for status — fragile, platform-specific, requires manual setup.
  2. Scattered CLI commands (hermes gateway status, checking logs) — no real-time awareness.
  3. Multiple disconnected feature PRs — tab titles (#36698), desktop notifications (#19302), system tray (#38024), status bar badges (#30389, #11757, #17837, #33836) — each solving a piece but no shared foundation.

Users running Hermes across multiple sessions, on headless servers, or via gateway have no way to know at a glance whether the agent is actively processing, blocked waiting for input, degraded, or offline.

Proposed Solution

Architecture: Extend existing infrastructure, not replace it

Hermes already has most of the building blocks — they just aren't connected to a unified status model:

Existing ComponentLocationWhat it already tracks
_touch_activity(desc)agent/conversation_loop.pyPer-iteration activity timestamp + description
_agent_runningcli.pyWhether agent is currently processing
get_activity_summary()run_agent.pyCurrent tool, API call count, budget
gateway_state.jsongateway/status.pyGateway PID, platform connections, active_agents
_status_bar_snapshot()cli.pyModel, tokens, cost, duration
bell_on_completecli.pyTerminal bell on response complete
status.update eventtui_gateway/server.pyPush status to TUI frontend
agent:start / agent:end hooksgateway/hooks.pyGateway-level agent lifecycle
_register_builtin_hooks()gateway/hooks.pyReserved stub for built-in hooks

The plan is to extend these into a coherent status system in three phases.

Phase 1: Status file (foundation)

New file: ~/.hermes/status.json — single source of truth for agent state.

Extend _touch_activity() in agent/conversation_loop.py to write a status file on every state transition (debounced 500ms to avoid high-frequency IO):

{
  "state": "busy",
  "state_detail": "calling tool: web_search",
  "gateway": {"running": true, "pid": 203245},
  "current_turn": {
    "model": "anthropic/claude-sonnet-4",
    "provider": "anthropic",
    "reasoning_effort": "high",
    "tokens_used": 4500,
    "tokens_limit": 200000,
    "tools_called": ["web_search", "read_file"],
    "started_at": "2026-06-05T10:05:00Z",
    "duration_seconds": 12
  },
  "attention": {"needs_attention": false, "reason": null, "since": null},
  "platforms": {
    "telegram": {"state": "connected"},
    "discord": {"state": "disconnected", "error": "..."}
  },
  "last_error": null,
  "updated_at": "2026-06-05T10:05:24Z"
}

State transitions:

Code locationTriggerState
conversation_loop.py loop startAgent begins processingbusy
conversation_loop.py pre LLM callAbout to call LLMbusy, detail = "thinking..."
conversation_loop.py pre tool dispatchAbout to call toolbusy, detail = "calling tool: <name>"
conversation_loop.py approval waitNeeds user approvalattention
conversation_loop.py post approval responseUser respondedbusy
conversation_loop.py loop endTurn completeidle
gateway/run.py platform disconnectPlatform connection lostdegraded
gateway/run.py gateway stopGateway shutting downoffline

New CLI command: hermes status

hermes status              # JSON to stdout
hermes status --format human   # Human-readable table
hermes status --watch      # Continuous mode (re-read on file change)

Implementation: new subcommand in hermes_cli/ that reads ~/.hermes/status.json + gateway_state.json, merges, and outputs. For --watch, use inotifywait or select.poll on the status file.

Also extend gateway_state.json via write_runtime_status() to include agent-level fields (current_agent_state, current_agent_detail) so gateway-only installs also expose agent state.

Phase 2: Built-in status bar + notifications (user-visible)

CLI status bar indicator — extend _get_status_bar_snapshot() and _build_status_bar_text() in cli.py to include a traffic-light state indicator:

● idle  │ anthropic/claude-sonnet-4 │ 4.5k/200k tokens │ telegram: connected │ 12s
◐ busy  │ calling tool: web_search │ 4.5k/200k tokens │ telegram: connected │ 12s
◆ attn  │ needs approval: terminal │ 4.5k/200k tokens │ telegram: connected │ 12s
▲ deg   │ telegram disconnected    │ 4.5k/200k tokens │ 12s
StateIconColorMeaning
idlegreenGateway running, waiting for input
busyblueThinking, calling tools
attentionamberNeeds user input (approval, clarify)
degradedorangePlatform issue, rate-limited
offlineredGateway not running

Config: display.status_indicator: true (default off for backward compat).

Desktop notifications — extend bell_on_complete into a full notification system:

display:
  notifications:
    enabled: true
    on: [attention, error, degraded]
    method: desktop  # desktop | bell | both | none
    desktop_command: "notify-send"  # auto-detect on macOS/Windows

When state transitions to a notification-triggering state, dispatch via notify-send (Linux), osascript (macOS), or PowerShell toast (Windows). Falls back to terminal bell if desktop notification unavailable.

TUI integration — the TUI already receives status.update events via tui_gateway/server.py. Add state transitions as status.update events with kind=agent_state so the Ink frontend can render a status indicator.

Phase 3: Hooks compatibility + plugin ecosystem (extensible)

Built-in status hook — register a built-in hook in _register_builtin_hooks() (gateway/hooks.py) that listens to agent:start, agent:end, session:start, session:end and updates the status file. This provides the same functionality as noctalia-hermes's hermes-status-hook but as a zero-config built-in.

New plugin hook: on_agent_state_change — add to VALID_HOOKS in hermes_cli/plugins.py. Fires on every state transition with {old_state, new_state, detail, context}. Plugins can register for this hook to build custom UI, send alerts, log to external systems, etc.

External script compatibility — the status file at ~/.hermes/status.json is the same interface that noctalia-hermes used (signal file pattern). Any external script that watched a signal file can watch this file instead. The hooks system is unchanged — third-party hooks still work alongside the built-in status tracking.

Backward compatibility:

  • All existing hooks continue to work unchanged
  • Status file writes are always-on (zero-config); user-visible features (status bar, notifications) are opt-in via config
  • No breaking changes to gateway_state.json schema (new fields only)
  • bell_on_complete still works; notifications config is additive

What this consolidates

Existing IssueHow this covers it
#24632 — terminal tab titles + desktop notificationsPhase 2 notifications + tab title via status file
#19302 — /notify desktop notificationsPhase 2 notification system
#36698 — CLI tab activity indicatorPhase 2 status bar + tab title from status file
#38024 — system tray (Desktop)Desktop reads status file for tray icon state
#21442 — gateway runtime healthPhase 1 hermes status includes gateway health
#37416 — request/tool lifecycle in TUIPhase 2 TUI status.update events
#30389 — hardware stats barPhase 2 status bar (optional hardware section)
#11757 — GPU monitor in status barPhase 2 status bar (optional)
#17837 — provider name in status barPhase 1 status file + Phase 2 status bar
#33836 — provider usage badgePhase 1 status file + Phase 2 status bar
#32299 — on_status_bar_render hookPhase 3 plugin hook reads from status file

Implementation priority

  1. Phase 1 (smallest diff): Extend _touch_activity() + add hermes status command + write status.json
  2. Phase 2 (user-visible): CLI status bar indicator + desktop notifications + TUI events
  3. Phase 3 (ecosystem): Built-in hook in _register_builtin_hooks() + on_agent_state_change plugin hook

Alternatives considered

  • Hooks-only approach: Rejected — hooks are the extension mechanism, not the implementation. The status tracking should be native in the agent loop, with hooks as a compatibility layer.
  • D-Bus / socket IPC: More complex, harder cross-platform. File-based status is simpler and works everywhere.
  • Only extend gateway_state.json: Insufficient — gateway doesn't have per-turn agent detail (tool names, tokens, reasoning effort). Need both gateway-level and agent-level status.

Additional context

The noctalia-hermes plugin demonstrated this pattern works: hook-driven signal file + status detection script + UI consumer. The key insight is that Hermes already has all the plumbing — _touch_activity(), gateway_state.json, status_callback, plugin hooks — it just needs to be wired into a unified status model. This proposal does exactly that, making the feature available to all users with zero external dependencies.

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