The Backend for a Coding Agent: Memory + Code Search + Impact Graph + Audit

Stand up everything a coding agent needs — project memory, semantic code search, a code-dependency impact graph, and a tamper-evident decision log — on ONE self-hosted database it queries over MCP or SQL. No stitching four datastores; your code never leaves your box.

All recipes· agents· 12 minutesintermediatesql
Instance: localhost:8080

Opens your running SynapCores (The Backend for a Coding Agent: Memory + Code Search + Impact Graph + Audit will be staged for a preview — nothing runs until you click Run). No instance yet? Install free in ~30s.

Share

Objective

The hard 80% of a coding agent isn't the model call — it's state and retrieval: remembering the codebase and past decisions, finding code by meaning, reasoning over how code connects, and proving what the agent did. Build that the usual way and you're running a vector DB + a graph DB + SQL + an audit store — four systems, network hops between every lookup, and your customers' source code scattered across four vendors' clouds.

This recipe stands up all four on one self-hosted SynapCores instance your agent talks to over MCP (or SDK, or plain SQL). The LLM reasoning stays in your agent; SynapCores is its brain — memory, code search, an impact graph, and an unforgeable decision log.

Runs on CPU, out of the box. No completion model, no GPU — only the embedding model (all-minilm), auto-pulled on first EMBED. Every query below returns in seconds.

Step 1: Project memory — what the agent must not forget

Store decisions and conventions once; recall them by meaning before the agent acts.

SELECT MEMORY_STORE('proj_acme', 'Auth hashes passwords with argon2 — never bcrypt (decided in PR #412).');
SELECT MEMORY_STORE('proj_acme', 'Rate limiting is a token bucket, 30 req/min per IP, in middleware/limiter.rs.');
SELECT MEMORY_STORE('proj_acme', 'All timestamps are stored UTC; never local time.');

Now recall by meaning — the agent asks a question, not a keyword:

SELECT content, similarity
FROM   MEMORY_RECALL('proj_acme', 'how do we hash passwords', 2);

The argon2 decision comes back on top, ranked by semantic similarity — the agent loads the right convention before it touches auth code, instead of re-deciding it.

Step 2: Semantic code search (RAG)

Index code chunks with a vector column, then search by intent.

CREATE TABLE code_chunks (
  id        INTEGER PRIMARY KEY,
  path      TEXT,
  symbol    TEXT,
  body      TEXT,
  embedding VECTOR(384)
);

INSERT INTO code_chunks (id, path, symbol, body) VALUES
 (1, 'auth/password.rs',      'hash_password',  'argon2 hash of the user password'),
 (2, 'auth/token.rs',         'validate_token', 'verify and decode the jwt access token'),
 (3, 'middleware/limiter.rs', 'rate_limit',     'token bucket, 30 requests per minute per ip');

-- Embed each chunk once (the embedding model auto-pulls on first call).
UPDATE code_chunks SET embedding = EMBED(symbol || ': ' || body);

"Where is JWT verified?" — by meaning, not grep:

SELECT path, symbol,
       COSINE_SIMILARITY(embedding, EMBED('where is the jwt verified')) AS score
FROM   code_chunks
ORDER  BY score DESC
LIMIT  2;

auth/token.rs :: validate_token ranks first — the agent gets the right file even though the query never says "token" or "jwt" literally the way the code does.

Step 3: The code knowledge graph — reason over how code connects

A coding agent's scariest question is "what breaks if I change this?" Vector search can't answer it — the answer follows the call structure, not text similarity. So model the call graph in the native graph engine, in the same instance, with Cypher.

Build the graph — nodes are functions, edges are calls (MERGE is idempotent, so re-running is safe):

MERGE (login:Fn    {name: 'handle_login'})
MERGE (refresh:Fn  {name: 'refresh_session'})
MERGE (validate:Fn {name: 'validate_token'})
MERGE (decode:Fn   {name: 'decode_jwt'})
MERGE (login)-[:CALLS]->(validate)
MERGE (refresh)-[:CALLS]->(validate)
MERGE (validate)-[:CALLS]->(decode);

Direct callers of a function:

MATCH (caller:Fn)-[:CALLS]->(:Fn {name: 'validate_token'})
RETURN caller.name AS caller;

GraphRAG — semantic seed, then graph walk. This is the combination pure vector RAG can't do: Step 2's search found the entry symbol by meaning (validate_token); now walk the graph from it to assemble the connected path — who reaches decode_jwt through validate_token, i.e. the callers that break if you touch the JWT decoder:

MATCH (caller:Fn)-[:CALLS]->(:Fn {name: 'validate_token'})-[:CALLS]->(:Fn {name: 'decode_jwt'})
RETURN caller.name AS must_review;

Returns handle_login and refresh_session — the blast radius, discovered by structure. The agent found where to start by meaning (vectors) and what connects by walking edges (graph) — GraphRAG, one engine, no separate graph database. (For bigger graphs the same engine has PageRank/Louvain to rank critical functions and detect subsystems.)

Tidy the graph up:

MATCH (n:Fn) DETACH DELETE n;

Step 4: A tamper-evident record of every change the agent made

When an agent edits code autonomously, someone will ask: "prove what it did, and prove the log wasn't altered." Log each decision to an immutable table.

CREATE IMMUTABLE TABLE agent_decisions (
  decision_id INTEGER PRIMARY KEY,
  ts          TIMESTAMP,
  file        TEXT,
  action      TEXT,
  rationale   TEXT
);

INSERT INTO agent_decisions (decision_id, ts, file, action, rationale) VALUES
 (1, '2026-07-25 10:00:00', 'auth/password.rs', 'EDIT',   'Replaced bcrypt with argon2 per project memory (PR #412).'),
 (2, '2026-07-25 10:04:00', 'auth/token.rs',    'REVIEW', 'Checked callers of validate_token before change; no signature change needed.');

The record is append-only — the engine physically refuses to rewrite history:

UPDATE agent_decisions SET rationale = 'nothing to see here' WHERE decision_id = 1;
DELETE FROM agent_decisions WHERE decision_id = 1;
Error: Cannot UPDATE immutable table 'agent_decisions'. Immutable tables are append-only.
Error: Cannot DELETE from immutable table 'agent_decisions'. Immutable tables are append-only.

Query the audit trail normally:

SELECT decision_id, file, action, rationale FROM agent_decisions ORDER BY ts;

That's "show every change the agent made, and it can't have been altered" — the control that makes an autonomous coding agent shippable in a real org.

Cleanup

DROP TABLE IF EXISTS code_chunks;
DROP TABLE IF EXISTS agent_decisions;
SELECT MEMORY_FORGET('proj_acme', id) FROM MEMORY_RECALL('proj_acme', '', 100);

(The graph was already cleared with DETACH DELETE at the end of Step 3.)

Expected Outcomes

  • Step 1 recalls the argon2 decision as the top memory for a natural-language question.
  • Step 2 returns auth/token.rs :: validate_token first for "where is the jwt verified".
  • Step 3 — direct callers of validate_token are handle_login + refresh_session; the GraphRAG walk returns the same two as the blast radius that reaches decode_jwt through it.
  • Step 4 rejects both UPDATE and DELETE on the decision log.

Use it from your agent

This is your coding agent's entire backend, reachable three ways — same instance, no glue:

  • MCP (native, on by default): point any MCP client (Claude Code, Cursor, a custom loop) at ws://<your-instance>/mcp?token=<jwt>. Memory, code search, the impact query, and the audit log all become tools the agent calls — one URL, no adapter code.
  • SDK / REST: every block here runs through POST /v1/query/execute (@synapcores/sdk, Python, Go, Java, PHP). Your agent runs the Step-2 search to ground an edit, the Step-3 query to check impact, and appends to the Step-4 log.
  • Why one database: the vector search, the impact walk, and the SQL join are one query in one process — no network hop between a vector store, a graph store, and an audit store. And it's self-hosted with local inference, so your source code and the agent's memory never leave your infrastructure — the thing a hosted agent platform structurally cannot promise.

Key Concepts Learned

  • MEMORY_STORE / MEMORY_RECALL give an agent semantic long-term memory in SQL — it recalls conventions by meaning, not keyword.
  • A VECTOR column + EMBED + COSINE_SIMILARITY is code RAG with no separate vector database.
  • A Cypher call graph (MERGE nodes/edges, MATCH the paths) plus the Step-2 vector search is GraphRAG: seed the entry point by meaning, then walk edges to assemble the connected blast radius — the "what breaks if I change this" answer that pure vector RAG can't reach, with no separate graph database.
  • CREATE IMMUTABLE TABLE turns the agent's decision log into tamper-evident audit — detection and prevention, in the same database that holds its memory and code.
  • All of it is one self-hosted binary reachable over MCP — the agent's brain, on your box, with your code never leaving it.

Tags

ai-agentcoding-agentmemoryragvector-searchgraphcyphergraphragimpact-analysisimmutableauditmcpself-hosted

Run this on your own machine

Install SynapCores Community Edition free, paste the SQL or Cypher above into the bundled web UI, and watch it run.

Download Free CE