Skip to content

feat(memory): evidence-gated episodes with local FTS recall - #68265

Open
joelbrilliant wants to merge 2 commits into
NousResearch:mainfrom
joelbrilliant:feat/memory-evidence-episodes
Open

feat(memory): evidence-gated episodes with local FTS recall#68265
joelbrilliant wants to merge 2 commits into
NousResearch:mainfrom
joelbrilliant:feat/memory-evidence-episodes

Conversation

@joelbrilliant

Copy link
Copy Markdown
Contributor

Problem

Built-in memory today is two tight layers:

  1. MEMORY.md / USER.md - always injected into the system prompt (~1.3k tokens total). Great for standing facts; too small and too hot for durable lessons.
  2. session_search - FTS over chat history only. Great for "what did we discuss"; blind to skills, run notes, and checkpoint lessons that never appear in a transcript the same way.

External memory providers (Honcho, Mem0, etc.) help some installs, but many users run built-in only. There is no first-class place for evidence-gated lessons that should survive months without burning every-turn prompt budget.

Demand shape: power users who already curate markdown scars (fixes, review findings, env gotchas) want those searchable inside Hermes without standing up a provider.

What this adds

A built-in episode tool in the memory toolset (also on _HERMES_CORE_TOOLS):

Action Behaviour
remember Write ~/.hermes/memories/episodes/YYYY-MM-DD-slug.md with frontmatter. Refuses without evidence (path, commit SHA, PR/issue URL, or log path).
recall Local SQLite FTS5 (porter) over episodes + configured HERMES_HOME roots. Stdlib only.
list / get Browse and read episodes.
reindex Full rebuild of the on-disk index.

Properties that matter:

  • Episodes are not injected into the system prompt (prefix-cache safe; no always-on token tax).
  • No Honcho / Mem0 / network dependency.
  • Secret-shaped content refused; status-shaped content warns but still writes (heuristic only).
  • Subagents cannot call episode (same class as memory in DELEGATE_BLOCKED_TOOLS).
  • Config (defaults on):
memory:
  episodes_enabled: true
  episode_corpus_roots: [episodes, memories]  # optional: skills

Also tightens the memory tool schema: point durable proven lessons at episode, discourage phase/queue status snapshots in MEMORY.md.

Non-overlap

Open work Difference
#23684 shared agent memory (FastAPI) External service + multi-agent draft workflow. This PR is local-only built-in.
#20692 agent-memory-pack skill Portable cross-agent markdown pack via skill. No core tool.
#28636 git-as-memory skill Git-ref storage via skill. No core tool.
External memory.provider plugins Unchanged. Episodes are built-in alongside MEMORY.md, not a provider.

Edge kit for people who want multi-root private corpora outside HERMES_HOME remains optional: joelbrilliant/agent-memory-kit. This PR covers the default-install gap only.

Code touchpoints

  • tools/episode_memory.py - store, FTS index, tool + schema
  • toolsets.py - episode on core + memory toolset + platform bundles that list memory explicitly
  • hermes_cli/config.py - episodes_enabled, episode_corpus_roots
  • tools/memory_tool.py - schema hygiene cross-ref
  • tools/delegate_tool.py - block episode for children
  • website/docs/user-guide/features/memory.md - user docs
  • tests/tools/test_episode_memory.py - unit coverage

Validation

PYTHONPATH=. python -m pytest tests/tools/test_episode_memory.py tests/tools/test_memory_tool.py::TestMemorySchema -q
  • 14 passed (episode suite + memory schema)
  • ruff check tools/episode_memory.py tests/tools/test_episode_memory.py clean
  • git diff --check clean
  • Manual wiring probe: registry discovers episode; present in _HERMES_CORE_TOOLS and TOOLSETS['memory']; in DELEGATE_BLOCKED_TOOLS

Platforms exercised: local macOS, CPython via the live Hermes venv, HERMES_HOME redirected to temp dirs in tests.

Risk / footprint

  • One new core tool schema on the default tool list (memory toolset). Justification: fundamental gap next to memory + session_search; unreachable via terminal alone without every agent reinventing paths; not a third-party product.
  • FTS index is derived under memories/episodes.db (profile-scoped via get_hermes_home()).
  • Default corpus does not index all of skills/ until the user adds it (keeps first index small).

Happy to shrink further (e.g. episodes-only corpus, or optional-skill instead of core) if maintainers prefer a lower rung.

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard comp/tools Tool registry, model_tools, toolsets tool/memory Memory tool and memory providers area/memory Memory subsystem: store, providers, sync, background reviews needs-decision Awaiting maintainer decision before any implementation sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Jul 20, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the focused local-only design and the explicit cache-safety rationale. There are blocking correctness issues to address before this can be evaluated on its feature merits.

Problems

  • get_episode() accepts every regular file below HERMES_HOME (tools/episode_memory.py:519), not only episode files. That bypasses the established read_file credential guard (tools/file_tools.py:1194-1203) and redaction pass (tools/file_tools.py:1310-1313); the guard explicitly covers .env and auth.json (agent/file_safety.py:194-337).
  • FTS5 setup is unconditional (tools/episode_memory.py:168-180). A missing FTS5 module can make remember_episode() write the file and then fail while indexing (tools/episode_memory.py:458-460). Current session search handles unavailable FTS/tokenizers as a degraded mode (hermes_state.py:2003-2028).
  • The config default location has moved: current main imports defaults from hermes_cli/config_defaults.py (hermes_cli/config.py:933), where the memory section now resides (hermes_cli/config_defaults.py:1514-1537).

Suggested changes

  • Confine get to the episodes directory and test protected-file rejection.
  • Add an FTS-unavailable path that returns structured behavior without losing the durable write.
  • Place the config defaults in config_defaults.py during salvage.

This is an automated hermes-sweeper review.

Comment thread tools/episode_memory.py Outdated
Comment thread tools/episode_memory.py
@joelbrilliant
joelbrilliant force-pushed the feat/memory-evidence-episodes branch from f3f88f4 to 8efd65c Compare July 30, 2026 03:33
@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:blast-massive Sweeper blast radius: massive — everyone, every turn (invariant surface) labels Jul 30, 2026
@joelbrilliant

Copy link
Copy Markdown
Contributor Author

Thanks, all three blockers are addressed in 8efd65cf6.

get is confined to memories/episodes, including symlink escape handling, with protected .env and auth.json rejection tests. Missing FTS5 now returns structured degraded search status while remember retains a successful durable markdown write. list and get remain available.

The defaults now live in config_defaults.py. The focused memory, toolset, registry and delegate suite is 179 passed, with ruff clean.

@joelbrilliant

joelbrilliant commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

The shared Vercel fixture fix has now landed on main via #74576 as 8eb06e75b, so I closed my duplicate #74586.

I rebased this PR onto the corrected main. GitHub rejected two runs before creating any jobs with an internal Actions error, and upstream rerun requires admin rights. After the repository queue drained, I refreshed the signed no-op CI trigger as 1a5700c52. Replacement run 30514860263 is fully green.

Add a built-in episode tool beside MEMORY.md/USER.md and session_search.
Episodes store durable lessons under HERMES_HOME/memories/episodes with a
mandatory evidence field, stay out of the system prompt, and are searchable
via stdlib SQLite FTS5 over episodes plus optional HERMES_HOME roots.

Does not require Honcho or any external memory provider. Subagents cannot
write episodes (same class as memory). Overlap: not shared FastAPI memory,
portable pack skill, or git-as-memory skill.

Signed-off-by: joelbrilliant <joelbrilliant1@gmail.com>
@joelbrilliant
joelbrilliant force-pushed the feat/memory-evidence-episodes branch from 8efd65c to 2f202b3 Compare July 30, 2026 04:33
Signed-off-by: joelbrilliant <joelbrilliant1@gmail.com>
@joelbrilliant
joelbrilliant force-pushed the feat/memory-evidence-episodes branch from bb8f6dc to 1a5700c Compare July 30, 2026 04:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/memory Memory subsystem: store, providers, sync, background reviews comp/cli CLI entry point, hermes_cli/, setup wizard comp/tools Tool registry, model_tools, toolsets needs-decision Awaiting maintainer decision before any implementation P3 Low — cosmetic, nice to have sweeper:blast-massive Sweeper blast radius: massive — everyone, every turn (invariant surface) sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data tool/memory Memory tool and memory providers type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants