← Back to Blog
Tutorial · Aug 2026

How to Give Your AI Agent a Memory That Survives the Session

By the VEKTOR team  ·  11 min read
Share Article
Discuss on Medium ↗Discuss in Forum ↗

This is a straightforward walkthrough of how you can set up five custom SSH and graph memory tools that cover the whole job between them, plus we also advise on what to do when your agent writes something to a real file and gets it wrong and how you can fix it.

When you open a new chat with an AI coding assistant, the first ten minutes usually go the same way. You explain your stack. You mention your context, add skills, go back and forth, execute, refine, repeat, and then run out of tokens.

You restate a decision you already made last week because the tool has no way of knowing it was ever made. Close that window, and all of it disappears from the context, as the context window holds what’s in front of it right now and clears the moment the session ends. It was never built to hold anything longer than that.

The actual fix isn’t a larger context window that clogs up and burns through more tokens; it’s giving the agent somewhere to store your info and data outside of it. A memory layer that any agent can write to and read from, independent of which app happens to be open at the time.

The five tools

Once our memory tool is wired up, an agent has exactly five things it can do with it.

Store. Save something with an importance score attached. A preference, a decision, a fact about the codebase. Anything worth not re-explaining next week.

Recall. Semantic search against everything that’s been stored. Not a keyword match, an actual search for meaning, so asking “what did we decide about validation” surfaces the Zod note even if the word “validation” never appears in the query.

Graph. Traverse connections between related memories. A bug fix connects to the file it touched, which connects to the convention that caused the bug in the first place. Recall alone gives you a match. Graph gives you the surrounding context.

Delta. See what changed on a topic recently. Useful for catching up on a project after time away, or checking whether a decision from last month has since been reversed.

Status. A health check. Database path, size, when it was last written to. The boring tool, and also the one you reach for first when something feels off.

The five tools share one SQLite database sitting underneath all of them. The interesting part isn’t any single tool. It’s that every AI client you use points at the same one utilized in synergy across MCP.

Setting it up

The setup differs depending on whether you’re working through an MCP client or writing code directly against the SDK, but the underlying steps are the same shape either way: install, activate, connect.

If you’re using Claude Desktop, Claude Code, Cursor, or Windsurf, all four speak the Model Context Protocol, which means the same install path works for all of them.

The setup wizard detects whichever of those apps is installed and writes the MCP config automatically. Restart the app and look for the memory tools in the MCP tools list. If they show up, the agent can now call vektor_store and vektor_recall on its own, without you doing anything beyond talking to it normally.

If the wizard doesn’t catch your install, the manual config for Claude Desktop looks like this:

Cursor and Windsurf use the same block in their own mcp.json, just with the agent ID swapped to match. That agent ID matters more than it looks like it should: point two editors at the same database path and they share one memory graph, so a decision made in Cursor is visible to Windsurf the next time you open it.

If you’re building with the OpenAI Agents SDK or a raw API call, there’s no MCP client involved, so you skip the wizard and call the memory functions directly from code.

Recall before the model call, store after it. That’s the entire pattern. Everything else is in the details.

OpenRouter follows the identical shape, since it’s OpenAI-compatible under the hood. Same createMemory() call, same recall-then-store pattern, just a different base URL pointed at OpenRouter instead of OpenAI directly.

This is where the shared-memory idea actually pays off: route a coding question to one model and a quick classification task to a smaller one, and both read from and write to the same graph. Swapping which model answers a question doesn't mean losing what the last one knew.

Trying it once you’re connected

The fastest way to confirm any of this actually works is to give it something to remember and then ask for it back in a separate conversation.

Close that conversation. Start a new one. Ask:

If the answer comes back correctly, the memory layer is doing its job independent of whatever context window that particular chat happened to have.

One thing worth knowing up front: recall isn’t automatic on every single turn. The agent decides when a query looks worth checking memory for, and it won’t always guess right. If it seems to have missed something obvious, just say so directly. “Check what you remember about this first” works better than assuming it already did.

What actually goes wrong

Almost every setup problem traces back to one of two things.

The first is a mismatched database path. If it’s not set explicitly in every client’s config, each app falls back to its own default location, and you end up with two or three mostly-empty databases instead of one shared one, each client quietly convinced it has the full picture when it doesn’t. Worth checking directly rather than assuming it’s wired up right.

The second is duplicated memory instead of updated memory. The system deduplicates automatically in most cases, but when a preference changes, storing an explicit update is cleaner than letting the old and new versions sit there together, leaving the agent to guess which one is still true.

Advanced: What happens when the agent writes something broken?

Setup problems are one thing. The harder case is when an agent has already written a file somewhere on your behalf and the result doesn’t look right. Memory tells an agent what happened last time.

It doesn’t stop this week’s write from going wrong. That’s a separate discipline, because the failure pattern repeats more than you’d expect.

Here’s a straightforward version of a real sequence: An agent was asked to write a fairly large HTML file to a remote host. The upload appeared to succeed. The page, when loaded, was visibly broken: missing images, garbled layout, stray text at the bottom that clearly wasn’t part of the intended content.

Five tools cover this kind of work:

Execute runs a single command. Read-only commands, ls, cat, grep, wc, run immediately. Anything that writes to disk or changes a running service comes back pending instead of running silently.

Approve is the other half of that pair: it confirms a pending write, takes an automatic backup first, and runs a health check right after.

Plan batches several commands into one approval when a fix is genuinely one multi-step operation rather than five separate ones.

Credential vault keeps access keys off the machine being managed entirely, pulling them out only for the moment they're needed.

File append handles the narrower case of adding lines to a remote file without rewriting the whole thing.

Two of those, execute and approve, do almost all the real work in what follows.

Step one, confirm the file actually exists. Before touching anything else:

In this case, the file wasn’t there at all. The original write had used a heredoc, a shell trick for pasting multi-line content into a file in one shot, and it had failed silently partway through.

No error, no file, just nothing where a sizeable HTML document should have been. A command reporting success and a command that actually finished writing are not the same claim, and treating them as equivalent is how broken output ends up live in the first place.

Step two, re-upload, then check again, not just assume. The fix for a failed heredoc write is usually simpler than fighting the heredoc: transfer the file over directly instead. That part worked cleanly. But “the upload succeeded” and “the page renders correctly” are two different claims, so the same checks ran again:

That last one caught something specific: two DOCTYPE declarations in a file that should have exactly one, a duplicate fragment left over from the earlier broken write. One targeted edit removed it, and a re-check confirmed the count was back to normal, rather than assuming the edit had worked.

Step three, look at the raw bytes when the visible symptom doesn’t explain itself. The page was now valid at a structural level but still looked wrong: broken images, jumbled formatting, none of it explained by a duplicate tag. Instead of guessing, the literal characters around a broken image reference got pulled directly:

The output showed every quotation mark inside the file’s HTML attributes had an extra backslash in front of it, as literal text, not src="/icon.svg" but src=\"/icon.svg\". Something in the original write process had escaped every quote and never unescaped them going back in. A full count confirmed the scale:

Hundreds of lines affected. Not a two-character typo. A systemic problem across the whole file.

Step four, fix the actual cause, not the symptom. Patching only the broken image references would have left every other broken attribute in the file untouched, every class, every style block, every inline script string, waiting to cause the next visible glitch somewhere else on the page.

The real fix touched the whole file at once:

Run through the execute tool, this came back as a pending write rather than running silently. Approving it triggered an automatic backup first, so if the replacement had somehow made things worse, there was a clean way back. It didn’t, and a follow-up request confirmed the page now returned valid, well-formed HTML.

Step five, don’t stop at “it renders.” The page displayed correctly now, except for a block of garbled text sitting at the very bottom, stray characters that looked suspiciously like leftover debug output that had somehow ended up saved inside the file itself rather than staying separate from it. Searching for the file’s actual closing tag found it well before the end of the file:

Everything after that line was unrelated leftover content, appended by mistake and never cleaned up. It looked like part of the page. It wasn’t. The fix was one line:

Truncate at the last line that actually belongs, verify the new line count matches, verify the file still ends with </html>. Both checked out.

The pattern underneath all five steps

None of the individual problems here were complicated on their own. A missing file, a duplicate tag, a batch of escaped characters, some trailing debris. Each one is a fast fix once you know exactly what’s wrong.

The actual discipline is refusing to guess. Every step followed the same shape: look at the real bytes, form one specific hypothesis, check it directly, then act, and check again afterward that the action did what it was supposed to.

Not “the images are probably a path issue,” but pulling the literal characters around one src attribute and reading them before deciding anything.

That’s also why approval and backups matter as much as the fixes themselves. Every actual write, unescaping the file, trimming trailing content, went through a step where a backup got taken automatically before anything changed.

That turns a wrong guess into a five-second rollback instead of a broken page staying live while someone tries to work out what happened after the fact.

Memory and careful writes solve two different problems, and it’s worth keeping them separate in your head. Memory means an agent doesn’t re-diagnose the same bug from zero next month.

Careful, verified writes mean this month’s fix doesn’t quietly break something else on its way out the door. You want both running at the same time, not one standing in for the other.

Built in backups

Automated backups complete the full cycle of events. Execute classifies a command the moment it’s submitted, read or write. If it’s a write, approve doesn’t just confirm the command should run, it takes a snapshot of whatever’s about to change before anything actually happens.

The command runs only after that snapshot exists, and a health check runs immediately after, so the result is confirmed in the same step rather than assumed. If any of that goes wrong, there’s a version to return to that predates the mistake, not a memory of what the file used to look like.

That’s what turns a wrong guess into a rollback instead of an incident: the backup isn’t a separate habit you remember to do sometimes, it’s built into the same system with an approval step that lets the write happen.

Full setup instructions for Claude Desktop, Claude Code, Cursor, Windsurf, the OpenAI Agents SDK, and OpenRouter, including the manual config for each, live at vektormemory.com/docs/agent-memory-setup.