Type: Spec Status: Accepted Systems: Sources, Plugins Author: Phil / Claude Date: 2026-07-20 Related: LLP 0000, LLP 0012, LLP 0016, LLP 0026, LLP 0035, LLP 0049, LLP 0119, LLP 0120, LLP 0121, LLP 0122, LLP 0123, LLP 0124
Capture Hermes Agent activity into HypAware so hermes sessions appear in
ai_gateway_messagesalongside Claude and Codex. The capture seam (pull from hermes's own store) is LLP 0119; the dataset choice is LLP 0120; packaging is LLP 0121; the buildable design is LLP 0122.
Hermes Agent is an open-source
AI agent (interactive TUI, messaging gateway daemon, cron scheduler) that talks
to arbitrary OpenAI-compatible providers. On a machine where hermes runs,
HypAware today records nothing about it: hermes sessions are invisible to
hyp query, the usage reports, and the context graph, even though the same
machine's Claude and Codex activity is fully captured.
Hermes keeps a rich local record of its own activity:
~/.hermes/state.db(SQLite, WAL mode): the canonical conversation store. Asessionstable (id, source, model, cwd, parent_session_id, started_at/ended_at, input/output/cache_read/cache_write/reasoning token counts, cost estimates, api_call_count) and amessagestable (session_id, role, content, tool_calls, tool_name, tool_call_id, reasoning, timestamp, token_count, finish_reason). Hermes's own docs call state.db "the canonical message store", and its logging layer redacts secrets before persisting.~/.hermes/logs/*.log: rotating plain-text operational logs.- An observer-hook plugin contract (
hermes.observer.v1) that can push sanitized per-call telemetry to in-process plugins.
"Hermes logs" in this spec means the structured conversation record (sessions and messages), the data that makes hermes activity comparable to Claude/Codex capture. The plain-text operational logs are a non-goal.
One new client adapter, @hypaware/hermes, in the same family as
@hypaware/claude and @hypaware/codex (read the client's native on-disk
record, LLP 0026): a backfill
provider for history plus a polling source for ongoing capture, both
materializing into ai_gateway_messages through the existing
ai_gateway.projected_exchange materializer.
- R1. Hermes sessions and messages MUST land in
ai_gateway_messagesas canonical rows, shape-identical to rows produced by the Claude/Codex backfills (client_name = 'hermes'), so every existing consumer (query, reports, graph projection, sinks, purge) works on them unchanged. - R2. Capture MUST be idempotent: re-running the backfill or the poll over
already-imported data writes no duplicate rows. Identity (
message_id,part_id) MUST be deterministic, derived from hermes's own stable keys. - R3. Usage policy MUST be honored at the capture seam: a hermes session
whose
cwdresolves toignorevia the shared resolver (LLP 0049 R1/R4, LLP 0050) is never written, in both backfill and poll paths. Sessions matched by the local-only machinery (LLP 0069, LLP 0103) get the same treatment as any other captured row with thatcwd. - R4. Token usage MUST be normalized per LLP 0035, from the token counts hermes already persists (input, output, cache read, cache write, reasoning).
- R5. Capture MUST be strictly read-only against hermes state: open
state.dbread-only, tolerate WAL activity and lock contention without disturbing a running hermes, and never modify anything under~/.hermes/. - R6. Ongoing capture MUST be automatic: new hermes sessions and new
messages in open sessions appear in the cache without manual action, with
lag bounded by a configurable poll interval. Explicit history import is
hyp backfill hermeswith the standard--sincewindow. - R7. The adapter MUST be observable per the log-driven-development
conventions: structured logs/spans around poll ticks and backfill runs
(
component, rows written, watermark position,error_kind), and the sourcestatus()reports state, rows written, and last error. - R8. Capture MUST NOT touch hermes's live LLM traffic: no proxying, no config changes to hermes, no alteration of its calls. The seam is store-side only (LLP 0119).
- R9. When no hermes installation exists on the machine (no
~/.hermes/state.db), the source MUST idle cleanly (no errors, no busy polling noise) and report that state viastatus(). - R10. Messaging-channel sessions (Telegram, Discord, Slack, WhatsApp,
Signal, Email) MUST carry the canonical policy scope path
~/.hermes/channels/<source>as theircwd(LLP 0124), so the standard marking machinery governs them: captured and sync-eligible by default (full), per-channel opt-down tolocal-onlyorignorevia the machine-local list or a.hypignore, with no hermes-specific policy config.
- Operational text logs.
~/.hermes/logs/*.log(agent.log, gateway.log, errors.log) are unstructured and secondary; forwarding them (plausibly into the otellogsdataset) is future work, not this spec. - Wire capture via the AI gateway. Pointing hermes's
model.base_urlat the HypAware gateway would capture raw LLM traffic inline. Rejected as the seam in LLP 0119; it also remains possible later as a complement, not a replacement. - A hermes-side observer plugin. Pushing telemetry out of hermes via its
hermes.observer.v1hooks requires shipping and enabling Python code in every hermes install. Also rejected in LLP 0119. - Channel-specific default hardening. Messaging-channel sessions are
captured by default and policy-addressable per R10; whether any channel
should default to something stricter than
full(e.g. org-pushed local-only for third-party content) is future policy work layered on the LLP 0124 scope paths, not part of this spec.