Hermes-style learning loops for Claude Code — correction detection, post-turn audit, skill capture, and a curator — layered on top of Claude Code's native memory store, which stays uncapped and unchanged.
Status:
v0.3.0— Loops 1, 4 and 3 are live. Loop 2 (the post-turn audit) is the last one, and ships disabled. Seedocs/design.md.
Claude Code's memory store is good: one fact per file, YAML frontmatter, uncapped, project-scoped, index-always / bodies-on-demand.
What it lacks is every mechanism that decides when a memory gets written and when it gets retired. Today that's the model's judgment in the moment — which means the memories that exist are the ones it happened to be in the mood to write.
Hermes Agent solves exactly that half. This plugin ports the loops and leaves the storage alone.
Storage unchanged. The loops are the product.
Hermes caps its curated memory at 2,200 + 1,375 characters and injects it whole every turn. The cap is a genuine feature — entries compete for space, so a stale one has to be actively defended or it gets evicted.
But an established Claude Code store can easily hold 40+ KB of real domain detail, and adopting the cap means a ~90% cut. Bounded-and-always-visible beats unbounded-and-lazy at noticing; unbounded wins at knowing. This project keeps the store that knows and imports the loops that notice. The rot that uncapped storage invites is answered by the hygiene pass, not by a ceiling.
| Loop | Hook | Cost | Default | Status |
|---|---|---|---|---|
| 1. Correction detector — catches "no, I told you" / "that's wrong", plus explicit "remember that…" / "from now on…" requests, and persists the lesson before the next answer | UserPromptSubmit |
free (regex, no LLM) | on | shipped in v0.1.1 |
| 4. Curator + hygiene — ages unused skills, reports rotting memories | PostToolUse + throttled SessionStart |
free | on, notify-only | shipped in v0.2.0 |
3. Skill capture — writes a structured SKILL.md after a complex reusable workflow, inline, while full context is live |
SessionStart policy |
negligible | on | shipped in v0.3.0 |
| 2. Post-turn audit — mines the finished transcript for durable facts | Stop |
tokens per turn | off | planned, last |
The curator ages only skills carrying memory-loops: captured, the marker Loop 3 writes.
Everything else — notably the dozens of plugin-vendored skills in a typical
~/.claude/skills/ — is left alone. A hand-written skill without the marker is invisible to
aging; the plugin manages what it created.
Rows are in build order, not numeric order. The audit is last because it is the only loop that spends tokens and the only one that writes unsupervised.
Precision, then recall. Loop 1 is a free regex over a single prompt, so it is tuned to fire rarely and be right when it does — a hook that cries wolf gets ignored, which is worse than no hook. Loop 2 has the whole transcript and a model, so it owns the semantic cases a regex structurally cannot see (a prompt that is only a correction because it contradicts something said a message earlier). The split is why the two loops are complementary rather than redundant.
Two design calls worth stating plainly, both inherited from the prior art because they're correct:
- The audit is forbidden from writing skills. A subprocess holding only a transcript snapshot authors bad procedures.
- The curator is notify-only by default and archives by moving, never deleting.
pinned: truefrontmatter is untouchable.
Neither prior-art project has this, and it's what makes an uncapped store survivable. Same weekly sweep, same notify-only posture, reports:
- memories referencing paths that no longer resolve — gated so globs, slash commands and HTTP endpoints are not mistaken for files; function and flag names are reported as unverifiable rather than guessed at
- near-duplicate memories, by token-set overlap on title + description
- memories older than 90 days, by
metadata.modifiedwith a file-mtime fallback - orphaned project directories — a memory dir whose slug decodes to a path that no longer exists. These strand silently today; a renamed home directory is enough to do it.
It never deletes. It surfaces a list and lets you decide.
This repo doubles as a single-plugin marketplace, so installation is two slash commands inside Claude Code:
/plugin marketplace add texastoast/claude-memory-loops
/plugin install memory-loops@claude-memory-loops
No build step and no npm install — Node 22 built-ins only, zero runtime dependencies, so
the hooks can't break from a bad transitive update.
All optional. Canonical list; the design doc defers to this table.
| Variable | Default | Effect |
|---|---|---|
MEMORY_LOOPS_AUDIT_ENABLED |
unset | 1 enables Loop 2, the post-turn audit |
MEMORY_LOOPS_CURATOR_ARCHIVE |
unset | 1 lets the curator move stale skills, not just report them |
MEMORY_LOOPS_CURATOR_INTERVAL_DAYS |
7 |
Minimum days between curator sweeps |
MEMORY_LOOPS_SKILL_STALE_DAYS |
30 |
Unused days before a skill is "stale" |
MEMORY_LOOPS_SKILL_ARCHIVE_DAYS |
90 |
Unused days before a skill is archivable |
MEMORY_LOOPS_MEMORY_STALE_DAYS |
90 |
Memory file mtime age before it's reported |
MEMORY_LOOPS_DUPE_THRESHOLD |
0.6 |
Jaccard threshold for reporting near-duplicate memories |
No character caps. No MEMORY.md / USER.md files. No migration of existing memories. No
changes to any long-term/semantic memory backend. Nothing reads or writes ~/.hermes/.
The architecture — the hook-to-mechanism mapping, the three-loop split, the
active → stale → archived aging model — comes from two projects. Neither carries a
license, so no code is reused; this implementation is written fresh under MIT. Credit
where it's due:
- alexanderop/claude-code-memory — worked out how Hermes' mechanics map onto Claude Code's hooks, and got the "audit must not write skills" call right.
- chandra447/pi-hermes-memory — the richest implementation of the loop model, for the Pi agent.
- Hermes Agent — the original. Issue #10835 requested MCP-exposed memory upstream and was closed, so no official path exists.
node --test # zero-dep, node:testTest-first: failing test, watched fail, then minimal implementation. Hook scripts are tested through their real stdin/stdout contract rather than by mocking the harness.
README.md and CHANGELOG.md are updated in the same commit as the change they describe.
MIT — see LICENSE.