Unified Agentic Memory Across Harnesses Using Hooks

Unified Agentic Memory Across Harnesses Using Hooks

通过 Hook 实现跨平台的统一智能体记忆

Agentic AI Unified Agentic Memory Across Harnesses Using Hooks How hook implementation gives Claude Code, Codex, and Cursor persistent memory via Neo4j, without locking you into any one of them. Tomaz Bratanic May 8, 2026 9 min read Share 智能体 AI:通过 Hook 实现跨平台的统一智能体记忆。本文探讨了如何通过 Hook 实现,让 Claude Code、Codex 和 Cursor 等工具通过 Neo4j 获得持久化记忆,且无需被绑定在任何单一平台。作者:Tomaz Bratanic,2026年5月8日,阅读时间 9 分钟。

LLMs are now so capable that the main debate isn’t about when the next better model drops, but about who will build the right harness around them. A harness is the scaffolding around the model: the agent loop, tool definitions, context management, memory, prompts, and workflows that turn a raw LLM into a useful product. The model is the engine, the harness is everything that makes it actually drive. Examples of harnesses are Cursor, Claude Desktop, and others. 大语言模型(LLM)如今已足够强大,主要的争论焦点不再是下一个更强的模型何时发布,而是谁能围绕它们构建出最合适的“外壳”(Harness)。外壳是指模型周围的脚手架:包括智能体循环、工具定义、上下文管理、记忆、提示词和工作流,它们将原始的 LLM 转化为实用的产品。模型是引擎,而外壳则是让它真正运转起来的一切。Cursor、Claude Desktop 等都是外壳的典型例子。

There’s a running debate in the AI coding tool space: does committing to a specific harness mean vendor lock-in? Memory is the sharpest edge of this. If your agent’s memory lives inside a closed harness or behind a proprietary API, you don’t really own it, and switching costs add up fast. But it doesn’t have to be that way. The idea is for this blog post is simple: keep the memory layer outside the harness, and let any harness plug into it. Unified agentic memory design. 在 AI 编程工具领域,一直存在一个争论:选择特定的外壳是否意味着被厂商锁定?记忆问题是其中最尖锐的痛点。如果你的智能体记忆存储在封闭的外壳内或专有 API 之后,你实际上并不拥有它,且切换成本会迅速增加。但情况不必如此。本文的核心思想很简单:将记忆层保留在外壳之外,并允许任何外壳接入它。这就是统一智能体记忆设计。

In this post, I’ll show how you can build a single, shared memory layer that works across three different coding agents — Claude Code, OpenAI’s Codex, and Cursor — using hooks as the integration mechanism and Neo4j as the persistent store. The code for hook integration is available on GitHub. 在本文中,我将展示如何构建一个单一的共享记忆层,使其能够跨越 Claude Code、OpenAI Codex 和 Cursor 这三种不同的编程智能体工作。我们将使用 Hook 作为集成机制,并以 Neo4j 作为持久化存储。Hook 集成的代码已在 GitHub 上开源。

MCP tools can only get you so far with memory. MCP (Model Context Protocol) servers are the go-to answer for giving agents access to external systems. And they work. You can expose a Neo4j database as an MCP tool and let the agent query it when it decides to. But MCP tools are agent-initiated. The model has to decide to call the tool, and it has to know when and why to do so. 在处理记忆问题时,MCP 工具的作用有限。MCP(模型上下文协议)服务器是让智能体访问外部系统的首选方案,而且确实有效。你可以将 Neo4j 数据库作为 MCP 工具暴露出来,让智能体在需要时进行查询。但 MCP 工具是由智能体主动发起的。模型必须决定调用该工具,并且必须知道何时以及为何调用它。

That means: The agent needs to “remember to remember”, it must proactively decide to store something worth recalling later. There’s no guarantee of consistency, one session might log everything, the next might log nothing. You’re relying on the model’s judgment about what’s important for memory, in real time, while it’s busy doing something else. 这意味着:智能体需要“记得去记忆”,它必须主动决定存储哪些值得日后回顾的内容。这无法保证一致性,可能一次会话记录了一切,而下一次却什么都没记录。你是在实时依赖模型对“什么对记忆重要”的判断,而此时它正忙于处理其他任务。

What you really want is passive, deterministic logging, which is something that captures every session event regardless of what the model is doing, without consuming any of its context or attention. This is exactly what hooks give you. Hooks allow you to write programmatical and deterministic flows based on predefined set of events. 你真正需要的是被动且确定性的日志记录,即无论模型在做什么,都能捕获每一个会话事件,且不消耗其任何上下文或注意力。这正是 Hook 所能提供的。Hook 允许你基于预定义的一组事件编写程序化且确定性的流程。

Enter hooks. Hooks are shell commands that fire automatically on lifecycle events: when a session starts, when the user submits a prompt, before and after every tool use, and when the session ends. The agent doesn’t decide to call them, they run programmatically. 引入 Hook。Hook 是在生命周期事件发生时自动触发的 Shell 命令:当会话开始时、用户提交提示词时、每次工具使用前后,以及会话结束时。智能体不需要决定是否调用它们,它们是程序化运行的。

The key insight is that hooks are remarkably standardized across providers. Claude Code, Cursor, and others all support essentially the same lifecycle events: SessionStart (when the agent session begins), UserPromptSubmit (when the user sends a message), PreToolUse / PostToolUse (before and after each tool call), and Stop (when the session ends). The hook receives a JSON payload on stdin with the session ID, event name, tool details, and user prompt. And the hook can emit JSON on stdout to inject additional context back into the conversation. Same contract, three harnesses/clients. 关键在于,Hook 在不同提供商之间具有高度的标准化。Claude Code、Cursor 等工具本质上都支持相同的生命周期事件:SessionStart(会话开始)、UserPromptSubmit(用户发送消息)、PreToolUse / PostToolUse(工具调用前后)以及 Stop(会话结束)。Hook 通过标准输入(stdin)接收包含会话 ID、事件名称、工具详情和用户提示词的 JSON 数据包,并可以通过标准输出(stdout)返回 JSON,将额外的上下文注入回对话中。相同的契约,适用于三个不同的外壳/客户端。

Shared memory layer. Now we need somewhere to persist the memory. Quick disclaimer: I work at Neo4j, so we will be using it in this example. Session structure: The model is straightforward. Each agent session is a node, connected to a linked list of event nodes, one per hook invocation. Events are typed by the lifecycle event that triggered them: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop. A session ends up as an ordered timeline of everything that happened during that run. 共享记忆层。现在我们需要一个地方来持久化记忆。免责声明:我在 Neo4j 工作,因此本示例将使用它。会话结构:模型很简单。每个智能体会话都是一个节点,连接到一个事件节点的链表,每次 Hook 调用对应一个节点。事件根据触发它们的生命周期事件进行分类:SessionStart、UserPromptSubmit、PreToolUse、PostToolUse、Stop。最终,一个会话就形成了一个按时间顺序排列的运行记录。

All five event types are written to the store, which gives you a complete audit trail of every session across every harness. Two of them are also injection points. SessionStart fires before the agent reads its system prompt, so anything the hook emits there gets prepended to the system prompt. That is how persistent, agent-level memory makes its way into context. UserPromptSubmit fires just before the user message is sent, and anything emitted there gets appended to the user prompt. That is the hook for turn-level context, like pulling in memories relevant to what the user just typed. 所有五种事件类型都会被写入存储,这为你提供了跨所有外壳的完整会话审计追踪。其中两个事件也是注入点。SessionStart 在智能体读取系统提示词之前触发,因此 Hook 在此处输出的任何内容都会被预置到系统提示词中。这就是持久化的、智能体级别的记忆进入上下文的方式。UserPromptSubmit 在用户消息发送前触发,此处输出的内容会被附加到用户提示词中。这是用于轮次级上下文的 Hook,例如提取与用户刚刚输入内容相关的记忆。

So, what happens if we start a new session in any of these harnesses with active hooks, for example Cursor? Example interactions in Cursor. If we inspect the results in Neo4j browser. Example session persisted as graph in Neo4j. 那么,如果我们使用启用了 Hook 的外壳(例如 Cursor)开启新会话会发生什么?(此处展示 Cursor 中的交互示例)。如果我们查看 Neo4j 浏览器中的结果,可以看到会话以图谱形式持久化在 Neo4j 中。

One important constraint: hooks run outside the harness’s model session. You cannot reuse the LLM the agent is talking to. If you want LLM-powered work inside a hook you have to make your own model call, which adds latency to every event the agent fires. That is why the hooks here only do two things: log events and inject pre-computed memories. They stay fast and deterministic. 一个重要的限制:Hook 运行在外壳的模型会话之外。你无法重用智能体正在对话的 LLM。如果你想在 Hook 中使用 LLM 功能,必须发起自己的模型调用,这会增加智能体触发的每个事件的延迟。这就是为什么此处的 Hook 只做两件事:记录事件和注入预计算的记忆。它们保持了快速和确定性。

Dream phase. The actual memory work happens in a separate dream phase: extracting facts from sessions, summarizing what happened, updating the graph. This is just a batch job that runs every few hours, reads the events accumulated since the last run, and writes back to the memory store. You could in principle kick off a memory update asynchronously every time a session stops, but that feels like a bit too much; a periodic batch is simpler and works fine for this demonstration. “梦境”阶段。实际的记忆处理发生在独立的“梦境”阶段:从会话中提取事实、总结发生的事情、更新图谱。这只是一个每隔几小时运行一次的批处理作业,读取自上次运行以来积累的事件,并写回记忆存储。原则上,你可以在每次会话结束时异步启动记忆更新,但这似乎有点过度;定期批处理更简单,且足以满足本演示的需求。

The dream job pulls every event since the session’s last watermark, hands them to Claude along with the current memory store, and asks it to write back a small set of durable notes. The notes themselves imitate a markdown wiki, the same shape Karpathy and others… “梦境”作业会拉取自上次会话水印以来的所有事件,将它们与当前的记忆存储一起交给 Claude,并要求它写回一组持久化的笔记。这些笔记本身模仿了 Markdown 维基的格式,与 Karpathy 等人所采用的形式相同……