Hermes integration¶
Hermes Usage Insights supports two integration modes:
- no-source-change collector mode
- 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.dbis 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 toolis 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 buildsHERMES_HOME/sessions/sessions.jsonโ session index and compatibility fallback for older snapshotsHERMES_HOME/sessions/session_<session_id>.jsonโ per-session transcript metadata and tool-call traces
One-shot import:
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.dbwhen present so totals match Hermes' SQLite session store - fall back to
sessions.jsontotals whenstate.dbis 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_idfor the samesession_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-hermespolls 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:
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:
Inside the Hermes runtime used in this environment, the equivalent command is often wrapped as:
The wrapper is an environment-specific convenience, not a package requirement.