External Brain Now Auto-Links AI Agent Memories
New feature in External Brain: every memory an agent writes gets auto-linked to any other it mentions by title, with no manual review step.
In short: External Brain (the shared memory and knowledge graph for AI agents I build) just shipped auto-linking: when an agent creates a new memory, the system links it on its own to any other memory in the same project whose title is mentioned in the content. No manual review, nobody has to remember to do it.
The problem it solves
External Brain is a dashboard where assistants like Claude Code, Cursor or Codex store and recall a project’s decisions, architecture and history through the Model Context Protocol (MCP). None of that is worth much if memories stay disconnected: a knowledge graph with no edges is, in practice, just a list. And since agents write memory autonomously (there’s no human filling out a form each time), asking them to also remember to link every related memory is asking an optional step to always happen. In practice, it didn’t: memories ended up orphaned.
How it works
The matching is deliberately simple: case-insensitive substring matching of one memory’s title inside another’s content, with a minimum length of 4 characters to avoid false positives on short words.
def find_lexical_matches(
content: str,
candidates: list[tuple[UUID, str]],
min_len: int = 4,
) -> list[UUID]:
"""Ids of `candidates` whose title appears as a substring (case-insensitive) in `content`."""
if not content:
return []
content_lower = content.lower()
return [
candidate_id
for candidate_id, title in candidates
if title and len(title) >= min_len and title.lower() in content_lower
]
No embeddings, no LLM judging relevance: pure lexical matching, testable without a database, fast and predictable. memory_service.create() runs this right after saving the memory and creates a "mentions" link for every match within the same project.
The hard part wasn’t the matching, it was the wiring
Auto-linking only works if it runs on every path that can create a memory. There were three: the REST API, the MCP server, and autonomous agent runs. The first two already went through MemoryService; the third, agent_runner_service.py, had been building its own MemoryService without link_repo, so memories written by the autonomous agent stayed unlinked even though the rest of the system linked them fine. The real fix was unifying all three entry points to share the same composition, not bolting on a new function.
Along the way, the autonomous agent also started saving traceability metadata on every memory it writes (agent_role, run_id, run_trigger, iteration) pulled from the agents table and the current run. Before, that metadata was always empty.
Why this isn’t a minor detail
I’ve been enforcing this manually in my own projects: in this very repo, CLAUDE.md has an explicit rule: “after every add_memory, ALWAYS create the add_memory_link… no orphaned memories.” That’s a discipline that works if something enforces it every single time, not most of the time. Automating it in the product moves that responsibility out of the agent’s short-term memory and into the system itself: exactly the kind of architecture decision that separates “works in the demo” from “works in production, unsupervised, every day.”
If you’re building something where multiple AI agents write state autonomously and you’re worried about that state drifting inconsistent over time, let’s talk.