Q & Hermes
Hermes Phase 4 — Digest Sync View
Hermes' activity surfaces inside Mallory as a read-through feed — inbound-only, deduped, and voiced in Mallory's own tone.
Situation
Phase 4 surfaces "what Hermes is doing" inside Mallory, without breaking the edge-local invariant: Hermes pushes an activity feed *inbound* to the edge Worker on a cron, the Worker stores and composes a Mallory-voiced one-liner per event, and the web app shows it as a read-through panel at ?view=hermes.
The design deliberately keeps this read-only and one-directional — sending *to* Hermes from the web, a router that delegates Worker requests to Hermes, and an Android view are all explicitly deferred to later work.
Key decisions
Accumulating feed, not a snapshot
Mirrors the existing /updates surface, with its own read/unread state.
Dedupe ledger lives on the Worker
Hermes re-emits its recent activity window every run; INSERT OR IGNORE on a stable dedupe_key is the single source of truth for "already seen" — Hermes carries no local dedupe state, the same philosophy as mention-nudges.
Voice on first insert only
composeTeaser (reused from src/lib/teaser.ts) runs once, when a row is newly inserted — no Haiku spend on re-emitted duplicates.
Read-through, read-only
HermesView.svelte mirrors UpdatesView and the ?view= deep-link pattern; no write path back to Hermes in this phase.
Architecture
Mirrors the /context//nudge inbound pattern end to end: a Tower cron job, a CN-gated Worker ingest, a D1 dedupe ledger, and a read-through Svelte panel.
hermes_events table — dedupe_key PK, kind, summary, detail, url, voiced, event_ts, created_at, read_at.parseHermesDigestPayload — validates each event's kind/ts/summary/dedupe_key, mirroring parseNudgePayload.handleHermesDigest (POST, CN-gated), handleHermesList (GET), handleHermesRead (POST) — insert-or-ignore, voice-on-first-insert, list/read.*/30 cron.Risks & guardrails
Noisy feed
Every commit as an event would flood the view — scoped at v1 to dev (commits/PRs) + vault notes only.
Haiku cost
Voiced only on first insert; falls back to the raw summary if the voicing call is unavailable.
CN spoofing
The digest endpoint is gated to the Tower's service-token CN (HERMES_DIGEST_CN), mirroring /context.
Clock skew on event_ts
Both event_ts (Tower-supplied) and created_at (Worker receipt) are stored; display sorts by event_ts, dedupe stays keyed on dedupe_key.
Delivery
Worker (TDD)
Migration 013, payload parser, DB helpers, CN-gated route handlers, voice-on-first-insert — PR'd and merged first.
Web
HermesView.svelte + api client + ?view=hermes deep-link + menu entry.
Tower digest job
hermes-digest.sh + offline test, CF Access service-token creds, */30 cron.
Verify end-to-end
Cron POSTs → GET /hermes returns a deduped, voiced feed → re-running the cron produces no duplicate rows → a real Hermes commit appears within one cycle.
Out of scope
docs/superpowers/specs/2026-06-14-hermes-phase4-digest-sync-view-design.mdplan ·
docs/superpowers/plans/2026-06-14-hermes-phase4-digest-sync-view.md