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 firstEMBED. 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_tokenfirst for "where is the jwt verified". - Step 3 — direct callers of
validate_tokenarehandle_login+refresh_session; the GraphRAG walk returns the same two as the blast radius that reachesdecode_jwtthrough it. - Step 4 rejects both
UPDATEandDELETEon 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_RECALLgive an agent semantic long-term memory in SQL — it recalls conventions by meaning, not keyword.- A
VECTORcolumn +EMBED+COSINE_SIMILARITYis code RAG with no separate vector database. - A Cypher call graph (
MERGEnodes/edges,MATCHthe 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 TABLEturns 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.