Uh oh!
There was an error while loading. Please reload this page.
hermes log forwarding adapter (LLP 0118-0125) - #339
Merged
Conversation
…reader
Repo-wide `engines` floor moves to >=22.12 and CI pins a setup-node matrix
of Node 22 and 24 (LLP 0125), so node:sqlite is guaranteed present for
every later hermes task's tests.
Adds the read-only state.db reader for the @hypaware/hermes adapter
(LLP 0119, LLP 0122#sqlite): node:sqlite DatabaseSync opened
{ readOnly: true }, a one-line activation probe that turns a missing
builtin into a clear HermesStateDbError refusal instead of a crash, a
bounded SQLITE_BUSY/SQLITE_LOCKED retry, and queries for sessions,
messages-by-session, and the changed-session aggregate that the poll
model (T4) will re-project from (LLP 0122#watermark). Row and watermark
shapes live in src/types.d.ts.
Tests build a small state.db fixture with node:sqlite mirroring the
hermes schema (sessions + messages incl. tool calls, reasoning, NULL
cwd) and cover readonly-open enforcement, the activation probe, bounded
busy retry (unit + through the reader), changed-session detection, and
the missing-file probe.
Task-Id: T1Add the hermes projector (src/projector.js) that turns full HermesStateDb sessions into AiGatewayProjectedExchange items via projectedExchangeItem: deterministic message_id/part_id minted from (session id, message id, part index), session_id namespaced hermes-<id>, provider normalized from billing/base_url fields, LLP 0035 usage mapping, tool-call and reasoning part expansion, and deriveRepoFromCwd repo enrichment for interactive sessions. Channel sessions (telegram, discord, slack, whatsapp, signal, email) are stamped with the canonical policy scope path ~/.hermes/channels/<source>, with the real daemon cwd preserved in attributes (LLP 0124). The shared usage-policy resolver is consulted against the effective scope before any row is built, so ignored sessions are skipped up front (LLP 0050). A synthetic session-end part is appended once ended_at is set, with a stable id derived from (session id, session_end), carrying end_reason, final totals, and costs (LLP 0122#session-end-part). Add src/git_repo.js (deriveRepoFromCwd, redactRemoteUserinfo), mirroring the claude/codex adapters' git-shell-out convention: remote + toplevel only, never HEAD, since a derived sha would be anachronistic for historical sessions. Tests: golden projection of the T1 fixture (open + ended sessions), id determinism across re-runs, ignored-cwd session skipped before any row is built, channel session stamped and governed by a marked channel scope, NULL-cwd interactive session recorded unconditionally, session-end part present exactly once for an ended session and absent for an open one, plus unit coverage for deriveRepoFromCwd and provider normalization. Task-Id: T2
Add the @hypaware/hermes backfill provider (src/backfill.js): ctx.backfills.register contribution, --since/--until windowing via the shared resolveWindow/filterByWindow (windowing selects sessions by started_at, not individual messages, so a session's identity always comes from its full row set), one ai_gateway.projected_exchange item per session via projectHermesSession (T2), and provenance carrying the state.db path. A missing state.db degrades to a clean no-op (spec R9) rather than an error, matching the claude/codex backfills. Tests cover window filtering (since/until/no-window), an empty store and a missing store as no-ops, provenance shape, the delegated usage-policy skip, and rerun determinism. Task-Id: T3
Add startHermesSource: idle mode when ~/.hermes/state.db is missing
(spec R9), a per-tick poll loop that finds changed sessions against a
persisted watermark (LLP 0122#watermark), re-projects each changed
session whole through projectHermesSession, and appends through the
shared ai_gateway.projected_exchange materializer so its pre-write
part_id dedupe turns a whole-session re-projection into "append only
the new tail". The watermark ({ max_message_id, ended_at } per
session) persists as a sidecar JSON in the plugin's kernel-managed
state dir. status()/reload()/stop() round out the StartedSource
lifecycle, with a hermes.poll span and structured logs per spec R7.
Tests cover the missing-store idle path, watermark advance and
persistence, dedupe-reliant re-projection writing only the new tail,
an ended_at transition with no new messages still landing the
session-end part, and a clean idempotent stop().
Task-Id: T4Adds hypaware.plugin.json for @hypaware/hermes (requires.plugins maps @hypaware/ai-gateway as a hard dependency, contributes the [hermes] config_section and the hermes source, no datasets of its own since rows land in ai_gateway_messages via the shared materializer). src/config.js validates the [hermes] section (enabled, state_db, poll_interval), reusing DURATION_RE from T4's source.js. src/index.js activate() registers the config section, the hermes poll source, and the hermes backfill provider, and starts the poll source unless enabled=false (a static kill switch that only gates ongoing-poll auto-start, not backfill or the source's own idle-on-missing-state.db behavior). Registers @hypaware/hermes in V1_BUNDLED_PLUGIN_ALLOWLIST beside claude/codex so it default-activates like the other adapters, and bumps cli_bundled_plugins_activated's expected plugins_skipped count from 5 to 6 to account for the newly bundled-but-unconfigured plugin. Adds manifest and config validation tests under test/plugins/. Task-Id: T5
Add hermes_backfill_roundtrip.js: boots @hypaware/ai-gateway and @hypaware/hermes against a fixture state.db under a tmp HYP_HOME (the live poll source disabled so hyp backfill hermes is the sole writer), then asserts the LLP 0123 T6 contract end to end - included-session rows land in ai_gateway_messages with client_name/conversation_source 'hermes', a .hypignore-scoped session is dropped at the capture seam (spec R3), a second backfill run writes zero new rows on the same deterministic ids (spec R2), and the internal telemetry proving the hermes-specific path ran (backfill.provider_finish/backfill.write spans tagged provider: 'hermes', the hermes.backfill.scan_complete log, and the component: 'hermes' usage_policy_drop log) is present. Task-Id: T6 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
philcunliffe
commented
Jul 21, 2026
ContributorAuthor
Neutral review - |
philcunliffe
marked this pull request as ready for review
July 21, 2026 00:55
Uh oh!
There was an error while loading. Please reload this page.
philcunliffe added a commit
that referenced
this pull request
Jul 21, 2026
The hermes log-forwarding change set (LLP 0118-0125) shipped in PR #339, but the design-first flip to Active (LLP 0016 Shipped-is-Active) did not ride the implementation PR, so neutral implementable kept re-surfacing the design as owed-implementation. This lifecycle move marks it shipped. Co-authored-by: neutral-loop <neutral-loop@localhost>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the
@hypaware/hermeslog-forwarding adapter designed in the LLP 0118-0125 cluster (spec 0118, design 0122, plan 0123).Tasks (all verified-merged, --no-ff)
Neutral pipeline: design-first cluster merged to master (#331), seeded integration/hermes-log-forwarding, implemented by the neutral wave-loop across 6 dependency-ordered tasks. Held for review.
@ref LLP 0122 [implements]
Change-Set: hermes-log-forwarding