Skip to content

feat(hermes): capture session transcripts into Mem threads#194

Merged
wey-gu merged 4 commits intonowledge-co:mainfrom
HamsteRider-m:feat/hermes-session-thread-sync
Apr 15, 2026
Merged

feat(hermes): capture session transcripts into Mem threads#194
wey-gu merged 4 commits intonowledge-co:mainfrom
HamsteRider-m:feat/hermes-session-thread-sync

Conversation

@HamsteRider-m
Copy link
Copy Markdown

@HamsteRider-m HamsteRider-m commented Apr 14, 2026

Summary

Adds native Hermes session transcript capture to the Nowledge Mem provider.

Hermes now exposes a provider lifecycle hook for session end. The Nowledge Mem provider uses that hook to capture cleaned user / assistant transcript turns into Mem threads at real session boundaries, alongside the existing Working Memory bootstrap, pre-turn recall, and native nmem_* tools.

Behavior

  • imports the cleaned transcript the first time a Hermes session is flushed
  • appends only new turns on later flushes in the same live session
  • treats malformed transcript items and persistence failures as non-fatal
  • only advances the provider's local delta pointer after a successful write
  • sends transcript payloads through the Mem HTTP API, avoiding OS argv-size limits on long sessions
  • keeps durable memory save/update/delete behavior on the existing native nmem_* tools

Contract

This is real transcript capture, but it is session-boundary capture. It runs when Hermes ends or resets a session cleanly, such as normal exit, /new, /reset, or normal gateway expiry. It is not per-turn persistence and it cannot recover a transcript if the host process is killed before Hermes fires on_session_end.

Validation

  • python3 -m py_compile nowledge-mem-hermes/client.py nowledge-mem-hermes/provider.py
  • direct execution of nowledge-mem-hermes/tests/test_session_sync.py
  • python3 -m unittest tests.test_space_resolution -v inside nowledge-mem-hermes
  • git diff --check

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 14, 2026

📝 Walkthrough

Walkthrough

Adds automatic Hermes session transcript capture into Nowledge Mem via a new on_session_end lifecycle hook, client CLI-backed import_thread/append_thread methods, provider session-state tracking and message normalization, plus manifest, docs, and tests to support import/append semantics at real session boundaries. (49 words)

Changes

Cohort / File(s) Summary
Integration manifest
integrations.json
Bumped Hermes integration version 0.5.8 → 0.5.9; enabled capabilities.autoCapture; changed threadSave.method to cli-native; autonomy.threadsautomatic-capture; updated guidance text about native session-boundary transcript flushing.
Plugin manifest
nowledge-mem-hermes/plugin.yaml
Version 0.5.9 and added on_session_end lifecycle hook.
Client API
nowledge-mem-hermes/client.py
Added NowledgeMemClient.import_thread(...) and append_thread(...) to invoke nmem --json t import / t append; short-circuit when messages empty and return import/append counts.
Provider implementation
nowledge-mem-hermes/provider.py
Added per-session state (_session_id, _saved_message_count), on_session_end(messages) lifecycle handler to clean/normalize messages, build title, and call client import vs append (import on first flush, append deltas thereafter); includes helpers for text extraction and safe error handling/logging.
Docs / Changelog
nowledge-mem-hermes/CHANGELOG.md, nowledge-mem-hermes/README.md
Documented v0.5.9 behavior: session-end auto-capture using nmem t import then nmem t append for deltas; described lifecycle hook and recovery from SessionDB on shutdown.
Tests
nowledge-mem-hermes/tests/test_session_sync.py
New tests exercising on_session_end: first-call import behavior, append-on-subsequent-calls, filtering of non-user/assistant roles, text normalization, and failure handling semantics.

Sequence Diagram

sequenceDiagram
    participant Session as Hermes Session
    participant Provider as NowledgeMemProvider
    participant Client as NowledgeMemClient
    participant CLI as nmem CLI
    participant Mem as Mem Thread Store

    Session->>Provider: on_session_end(messages)
    Provider->>Provider: Clean & normalize messages (filter roles, extract text)
    Provider->>Provider: Derive thread title from first user message

    alt First flush (saved_count ≤ 0)
        Provider->>Client: import_thread(thread_id, cleaned_messages, title, source="hermes")
        Client->>CLI: nmem --json t import --id <id> -s hermes (JSON messages)
        CLI->>Mem: create thread with messages
        Mem-->>CLI: success + metadata
        CLI-->>Client: result
        Client-->>Provider: update _saved_message_count
    else Subsequent flush (saved_count > 0)
        Provider->>Provider: compute delta (new messages only)
        Provider->>Client: append_thread(thread_id, delta_messages)
        Client->>CLI: nmem --json t append --id <id> (JSON messages)
        CLI->>Mem: append messages
        Mem-->>CLI: success + metadata
        CLI-->>Client: result
        Client-->>Provider: update _saved_message_count
    end

    Provider-->>Session: complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Poem

🐰
When sessions close, I hop and hum,
I gather turns—each word become,
First import wide, then gentle append,
Threads stitched tight from start to end.
A carrot cheer for Hermes' mem!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.39% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR fully implements the requirements from issue #186 by adding session-lifecycle sync, import/append CLI wrappers, provider-level on_session_end hook for automatic thread capture, and documentation updates achieving Claude Code plugin parity.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing automatic Hermes session-to-thread sync and supporting infrastructure; no unrelated modifications detected.
Title check ✅ Passed The title accurately summarizes the main change: adding automatic session transcript capture into Mem threads for the Hermes integration via the new on_session_end lifecycle hook.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e24f15e6a7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread nowledge-mem-hermes/client.py Outdated
Comment thread nowledge-mem-hermes/provider.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@integrations.json`:
- Line 450: The "threads" value currently set to "automatic" violates the
allowed autonomy enum; update the autonomy.threads entry (the JSON key
"threads": "automatic") to one of the valid values listed in the schema (for
example "automatic-capture", "explicit-save", "handoff-only", "import-only", or
"none") so consumers and schema validators accept it; pick the semantics you
need (e.g., use "automatic-capture" if threads should be auto-created and saved)
and replace "automatic" accordingly.
- Around line 443-455: autonomy.threads contains an invalid value; update the
autonomy.threads field from "automatic" to one of the schema's allowed enums
(most likely "automatic-capture") to satisfy the schema, and ensure the change
is applied where autonomy is defined (look for the autonomy object and its
threads key). Also verify that the new threadSave.method value
"cli-import-append" is intentional and documented so it aligns with supported
provider behavior.

In `@nowledge-mem-hermes/provider.py`:
- Around line 608-610: The loop over messages assumes each item is a dict and
uses message.get(...) which will raise for non-dict entries; update the cleaning
loop that iterates over messages (the for message in messages or [] block) to
first guard each item (e.g., isinstance(message, dict)) and skip any non-dict or
malformed entries before accessing message.get("role"), so the sync pass won't
fail; ensure you still strip/validate role and only process items with role in
{"user","assistant"}.
- Around line 358-373: In on_session_end, wrap calls to
self._client.import_thread(...) and self._client.append_thread(...) in
try/except so failures are non-fatal: catch Exception around the import_thread
and append_thread invocations (both places where import_thread and append_thread
are called), log the error (including exception details) and continue execution,
and still update self._saved_message_count appropriately only on successful
persistence; use existing symbols cleaned_messages, session_id, title (from
_build_thread_title) and self._saved_message_count to locate the spots to
change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6b58ca79-6335-4221-a99b-470a1922222f

📥 Commits

Reviewing files that changed from the base of the PR and between 6434ef2 and e24f15e.

📒 Files selected for processing (7)
  • integrations.json
  • nowledge-mem-hermes/CHANGELOG.md
  • nowledge-mem-hermes/README.md
  • nowledge-mem-hermes/client.py
  • nowledge-mem-hermes/plugin.yaml
  • nowledge-mem-hermes/provider.py
  • nowledge-mem-hermes/tests/test_session_sync.py

Comment thread integrations.json Outdated
Comment thread integrations.json Outdated
Comment thread nowledge-mem-hermes/provider.py
Comment thread nowledge-mem-hermes/provider.py
@wey-gu
Copy link
Copy Markdown
Member

wey-gu commented Apr 15, 2026

wow @HamsteRider-m 牛逼,i didnt realize they provide the abstractions of hermes hook on thread sync!!!

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
nowledge-mem-hermes/tests/test_session_sync.py (1)

101-101: Consider iterable unpacking for list extension.

Static analysis suggests using unpacking instead of concatenation.

Suggested change
-    next_messages = first_messages + [{"role": "user", "content": "next step"}]
+    next_messages = [*first_messages, {"role": "user", "content": "next step"}]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nowledge-mem-hermes/tests/test_session_sync.py` at line 101, Replace the list
concatenation that builds next_messages from first_messages and the new dict
with iterable unpacking: locate the expression assigning next_messages (variable
name next_messages and source list first_messages) and construct next_messages
using list unpacking of first_messages plus the single new message element to
produce the combined list.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@nowledge-mem-hermes/tests/test_session_sync.py`:
- Line 101: Replace the list concatenation that builds next_messages from
first_messages and the new dict with iterable unpacking: locate the expression
assigning next_messages (variable name next_messages and source list
first_messages) and construct next_messages using list unpacking of
first_messages plus the single new message element to produce the combined list.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a36a3499-e550-43b2-87db-3e5f1960d9f0

📥 Commits

Reviewing files that changed from the base of the PR and between e24f15e and 218f73e.

📒 Files selected for processing (5)
  • integrations.json
  • nowledge-mem-hermes/CHANGELOG.md
  • nowledge-mem-hermes/README.md
  • nowledge-mem-hermes/provider.py
  • nowledge-mem-hermes/tests/test_session_sync.py
✅ Files skipped from review due to trivial changes (1)
  • nowledge-mem-hermes/CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • nowledge-mem-hermes/README.md
  • integrations.json

@wey-gu wey-gu changed the title feat: auto-save Hermes sessions to Mem threads feat(hermes): capture session transcripts into Mem threads Apr 15, 2026
@wey-gu wey-gu merged commit 59fac16 into nowledge-co:main Apr 15, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants