Skip to content

Hermes integration

Hermes Usage Insights supports two integration modes:

  1. no-source-change collector mode
  2. structured JSONL emitter mode

The collector path is operationally simplest. The JSONL path is the long-term answer when you need richer attribution.

Which mode should you use?

Use collector mode when:

  • Hermes is already running
  • you want to backfill or continuously collect usage without patching Hermes source
  • accurate session totals matter more than exact per-tool attribution

Use JSONL emitter mode when:

  • you can emit structured events upstream
  • you need exact event-level fields on the same record
  • you want precise per-tool or per-skill attribution where available

Collector mode: what it can and cannot tell you

Collector mode reads Hermes' persisted artifacts. That gives you a useful local database without changing Hermes, but it also sets the fidelity boundary.

Collector mode gives you:

  • accurate session-level token and cost deltas when state.db is present
  • tool-call events and tool-call counts from session transcripts
  • incremental imports into the local SQLite database

Collector mode does not give you:

  • exact per-tool token attribution from transcript-only tool-call events
  • exact per-message token attribution when Hermes does not persist per-message usage blocks

Practical consequence:

  • report breakdown --by tool is reliable for tool frequency in collector mode
  • it should not be interpreted as exact token spend by tool unless those totals were emitted upstream

Default no-source-change collector

Hermes already persists the data needed for no-source-change import under its home directory.

Expected artifacts:

  • HERMES_HOME/state.db โ€” source of truth for cumulative session totals in current Hermes builds
  • HERMES_HOME/sessions/sessions.json โ€” session index and compatibility fallback for older snapshots
  • HERMES_HOME/sessions/session_<session_id>.json โ€” per-session transcript metadata and tool-call traces

One-shot import:

uv run hui \
  --db artifacts/hermes-usage.db \
  import-hermes \
  --hermes-home /path/to/hermes-home

Imported event families

Collector mode generates two main event families.

1. Session delta events

These carry the session-level totals derived from Hermes cumulative state.

They are used for:

  • total token accounting
  • estimated cost tracking
  • per-session and per-day reporting

Important behavior:

  • prefer state.db when present so totals match Hermes' SQLite session store
  • fall back to sessions.json totals when state.db is absent or a session is missing there
  • import only new deltas relative to prior collector progress

2. Tool-call events

These are derived from session transcript tool-call metadata.

They are used for:

  • tool frequency analysis
  • search across tool-call notes and metadata
  • correlating tool names with sessions, models, and timestamps

Important behavior:

  • tool-call events are idempotent
  • repeated imports reuse deterministic event ids
  • transcript-derived tool-call events do not imply exact tool-level token accounting

Idempotency and incrementality

Collector progress is stored in the SQLite database.

That means:

  • session summary imports add only new deltas since the prior import
  • tool-call imports do not duplicate already-imported transcript events
  • if Hermes rotates to a new session_id for the same session_key, the collector can reset summary state for that key and continue from the new series

Always-on collection

For a continuous collector loop, run watch-hermes:

uv run hui \
  --db artifacts/hermes-usage.db \
  watch-hermes \
  --hermes-home /path/to/hermes-home \
  --interval-seconds 60

For a bounded test run, use --iterations:

uv run hui \
  --db artifacts/hermes-usage.db \
  watch-hermes \
  --hermes-home /path/to/hermes-home \
  --interval-seconds 5 \
  --iterations 2

Operational model:

  • Hermes continues writing its normal persisted artifacts
  • watch-hermes polls those artifacts on an interval
  • the usage database accumulates normalized history for reports, search, exports, and plots

If you do not want a long-running process, run import-hermes from cron or another scheduler instead.

Example collector-mode workflow

uv run hui \
  --db artifacts/hermes-usage.db \
  import-hermes \
  --hermes-home /path/to/hermes-home

uv run hui --db artifacts/hermes-usage.db report summary
uv run hui --db artifacts/hermes-usage.db report breakdown --by session
uv run hui --db artifacts/hermes-usage.db report breakdown --by tool
uv run hui --db artifacts/hermes-usage.db export csv --output artifacts/hermes-usage.csv
uv run hui --db artifacts/hermes-usage.db plot daily-tokens --output artifacts/hermes-daily.png

Structured JSONL emitter mode

If you are willing to emit structured events upstream, JSONL mode is the preferred long-term path because it keeps attribution attached to the event itself.

Ingest command:

uv run hui --db usage.db ingest-jsonl /path/to/hermes-usage-events.jsonl

Minimal Python-side emitter

from pathlib import Path

from hermes_usage_insights.hooks import append_event_jsonl

OUTPUT = Path("/path/to/hermes-usage-events.jsonl")

append_event_jsonl(
    OUTPUT,
    {
        "timestamp": "2026-04-08T16:30:00Z",
        "session_id": "session-123",
        "conversation_id": "conv-456",
        "provider": "openai",
        "model": "gpt-5.4",
        "role": "assistant",
        "tool_name": "browser_navigate",
        "skill_name": "mise-tool-management",
        "source": "tool_call",
        "prompt_tokens": 120,
        "completion_tokens": 30,
        "total_tokens": 150,
        "cost_usd": 0.0125,
        "notes": "navigated to target page",
        "metadata": {"chat_id": "589084909"},
    },
)

Suggested attribution strategy

Emit events at the smallest useful unit you can measure reliably.

Recommended hierarchy:

  • model response event
  • tool call event
  • skill load or skill use event
  • session rollup event

If exact attribution is unavailable, still emit partial data rather than dropping the event entirely.

For example, this is still valuable:

  • known session_id
  • known model
  • known total_tokens
  • unknown tool_name

That preserves session-level and model-level reporting now while keeping the schema forward-compatible.

Portable commands vs Hermes-runtime commands

General documentation uses the portable form:

uv run hui --db usage.db report summary

Inside the Hermes runtime used in this environment, the equivalent command is often wrapped as:

/opt/hermes-runtime/tools/mise/use-mise.sh uv run hui --db usage.db report summary

The wrapper is an environment-specific convenience, not a package requirement.