Hermes Agent plugin that records every gateway chat message — any platform — to an Obsidian-style Markdown vault, with voice transcripts and image descriptions.
Project description
hermes-chat-recorder
A Hermes Agent plugin that records every chat message the gateway sees — on any connected platform (Matrix, Telegram, Discord, Slack, Signal, WhatsApp, IRC, email, …) — into an Obsidian-style Markdown vault. Voice notes are transcribed and images are described inline, using whatever STT and vision providers Hermes is already configured for.
Status: alpha (pre-1.0). APIs and config schema may change. Used in production at Northbound.
What it does
| Inbound | Behaviour |
|---|---|
| Text | Append the message to vault_root/<platform>/<chat>/<YYYY-MM-DD>.md. Pass through unmodified — Hermes's normal wake settings decide whether the agent replies. |
| Voice note | Transcribe via Hermes's built-in STT (tools.transcription_tools). Append placeholder + transcript section. Rewrite event.text to the transcript so the agent has usable content if it wakes. |
| Image / sticker | Describe via Hermes's built-in vision (tools.vision_tools). Append placeholder + description section. Rewrite event.text to caption + description + OCR'd text. |
| Video / file / location | Recorded as-is (caption + media provenance), no processing. |
| Reaction | Ignored (not recorded as a message section). |
| Outbound (the agent's own replies, every platform) | Recorded with a reply_to: link back to the trigger when available. |
This plugin is recording-only. It does NOT decide whether the agent wakes up — use Hermes's native mention/allowlist settings for that. It also records before Hermes's auth/pairing checks, so messages from unpaired senders land in the vault too; treat the vault path as sensitive.
Pretty names for free. Every Hermes adapter ships the chat title
and sender display name on the unified event (source.chat_name /
source.user_name), so folders come out as telegram/Family-Chat/
and headers as ### 09:14 Annika · voice (0:12). On Matrix the plugin
additionally queries the live client (m.room.name, profile display
names, DM peers) for rooms the event metadata doesn't cover. Unnamed
DMs use the peer's name. All resolutions are cached for the process
lifetime — restart the gateway to pick up renames.
No third-party deps. STT and vision are delegated to Hermes's built-in tools, so whatever provider Hermes is configured for — local faster-whisper, Groq, OpenAI, Mistral, xAI for STT; the main LLM or an auxiliary vision provider for images — is what the recorder uses. The only runtime requirement is Hermes itself.
Install
pip install hermes-chat-recorder
Hermes auto-discovers pip-installed plugins via the
hermes_agent.plugins entry-point group. Then enable it:
hermes plugins enable chat_recorder
(or add it to plugins.enabled in config.yaml by hand, as below).
Restart the gateway and you should see chat_recorder in
hermes plugins list.
For development against an unreleased version:
git clone https://github.com/northbound-run/hermes-chat-recorder
cd hermes-chat-recorder
pip install -e .[dev]
Configure
Add to your Hermes config.yaml:
plugins:
enabled:
- chat_recorder
chat_recorder:
enabled: true
vault_root: /data/vault/transcripts
record_outbound: true
timezone: America/Los_Angeles
# Optional: restrict recording to specific platforms.
# Empty / omitted = record everything the gateway dispatches.
platforms: [] # e.g. [matrix, telegram]
# Optional: display name for the bot's own outbound sections.
# Default resolves via the bot's Matrix profile, else "bot".
bot_name: ""
# "group" (default) keeps the per-platform/per-chat subfolders.
# "1on1" assumes the bot only ever lives in a single DM and
# flattens to <vault_root>/<YYYY-MM-DD>.md — no subfolders.
bot_type: "group"
# Optional: manual name overrides, keyed by raw platform IDs.
# Useful when a Signal/WhatsApp bridge user has no display name,
# or to rename a chat's folder. Overrides win over all lookups.
name_overrides:
rooms:
"!abcdef1234:example.org": "Family Signal"
users:
"@signal_2c991545-...:example.org": "Annika"
STT and vision are configured at the Hermes top level, not here:
stt:
enabled: true
provider: "local" # or "groq" / "openai" / "mistral" / "xai"
local:
model: "base"
auxiliary:
vision:
provider: "main" # use the main LLM, or override per Hermes docs
model: ""
Optional env vars:
TRANSCRIPT_TZ— overridestimezone.
Vault format
Per-platform, per-chat, per-day files at
<vault_root>/<platform>/<chat-slug>/<YYYY-MM-DD>.md, sections
separated by ---, each anchored by an HTML comment:
<!-- event:$abcd1234:server -->
### 09:14 Annika · voice (0:12) · stage:transcribed
**mxc:** mxc://server/abcdef
**duration_sec:** 12
> okay so the deck was titled "what ai can do for your business" and
> we showed it to the meridian team last thursday
---
<!-- event:$efgh5678:server -->
### 09:14 Recorder · reply · stage:sent
**reply_to:** $abcd1234:server
You bet — the AI-for-business one. I'll drop a refresher in your daily note.
---
Idempotency comes from the HTML-comment anchor — re-delivery of the same event ID finds the existing section and either updates its stage in-place or no-ops if already at a terminal stage. The vault stays greppable and Obsidian-friendly: no databases, no sidecar indexes.
Upgrading from ≤ 0.6.x
v0.7.0 added the platform folder level. Existing Matrix-only vaults move with one command:
mkdir -p <vault_root>/matrix && mv <vault_root>/<each-room-folder> <vault_root>/matrix/
(bot_type: "1on1" flat layouts are unaffected.)
Troubleshooting
Plugin not showing up? Hermes has verbose discovery logs:
HERMES_PLUGINS_DEBUG=1 hermes plugins list
Common causes: the plugin isn't in plugins.enabled, or the gateway
wasn't restarted after install. See the
Hermes plugin guide
for the full debugging walkthrough.
Architecture in one paragraph
The plugin registers a single pre_gateway_dispatch hook. Inbound, it
normalizes Hermes's unified MessageEvent (any platform) into a typed
EventInfo, writes a placeholder section, runs voice/image events
through Hermes's STT/vision tools, finalizes the section, and rewrites
event.text so the agent sees the transcript/description. On the
first dispatch it also wraps send on every live platform adapter
so outbound replies land in the vault; the Matrix adapter additionally
contributes its client for name lookups and a media-download fallback.
Failure policy: per-event errors degrade to *_failed sections;
startup/config errors fail registration loudly. See
docs/DESIGN.md for the full design.
License
MIT — Copyright (c) 2026 Northbound.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hermes_chat_recorder-0.7.2.tar.gz.
File metadata
- Download URL: hermes_chat_recorder-0.7.2.tar.gz
- Upload date:
- Size: 68.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f65f1c18abc63e7c8c5b1a08ab03c0c717dea337c40c56a2904130a1b4d2862c
|
|
| MD5 |
9754cf62bf4c63b48a6beb07bfaa30f0
|
|
| BLAKE2b-256 |
ecd2437c9bc6525b4e34a5ff66782d481049d7e7471d8fd3bdd8bcadf651bfca
|
Provenance
The following attestation bundles were made for hermes_chat_recorder-0.7.2.tar.gz:
Publisher:
publish.yml on Northbound-Run/hermes-chat-recorder
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hermes_chat_recorder-0.7.2.tar.gz -
Subject digest:
f65f1c18abc63e7c8c5b1a08ab03c0c717dea337c40c56a2904130a1b4d2862c - Sigstore transparency entry: 1793407946
- Sigstore integration time:
-
Permalink:
Northbound-Run/hermes-chat-recorder@5ea6712d4c55bfb9b626d1dac0c117102957d53c -
Branch / Tag:
refs/tags/v0.7.2 - Owner: https://github.com/Northbound-Run
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5ea6712d4c55bfb9b626d1dac0c117102957d53c -
Trigger Event:
release
-
Statement type:
File details
Details for the file hermes_chat_recorder-0.7.2-py3-none-any.whl.
File metadata
- Download URL: hermes_chat_recorder-0.7.2-py3-none-any.whl
- Upload date:
- Size: 43.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09d334109589b8793e78dad3900c929d0d27bbcff3028a3a5575d56fa75d73a3
|
|
| MD5 |
ab02c2d2e9c5104418df1a2d8905a28c
|
|
| BLAKE2b-256 |
0ccd48947a13f5015047bfffe036ada4eb604a9a135764a15b349b473bc24f0e
|
Provenance
The following attestation bundles were made for hermes_chat_recorder-0.7.2-py3-none-any.whl:
Publisher:
publish.yml on Northbound-Run/hermes-chat-recorder
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hermes_chat_recorder-0.7.2-py3-none-any.whl -
Subject digest:
09d334109589b8793e78dad3900c929d0d27bbcff3028a3a5575d56fa75d73a3 - Sigstore transparency entry: 1793408650
- Sigstore integration time:
-
Permalink:
Northbound-Run/hermes-chat-recorder@5ea6712d4c55bfb9b626d1dac0c117102957d53c -
Branch / Tag:
refs/tags/v0.7.2 - Owner: https://github.com/Northbound-Run
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5ea6712d4c55bfb9b626d1dac0c117102957d53c -
Trigger Event:
release
-
Statement type: