Skip to slide 1
01 / 20
VCN #48 · Total Recall · 2026-08-08 · Frontier Tower F9
doors 10:00 · walkthrough 10:15

TOTAL RECALL.

Give your coding agent a memory of your repo that survives the session ending.

This one is about your CODE, not your chat history. If you were at the older night with the same name, that was conversational memory. Today we index a codebase.

SAT AUG 8 Frontier Tower F9 Doors 10:00 Walkthrough 10:15 Hands-on 10:45 Demos 12:00

$10 early · $20 door · Frontier Tower members free, reach out to the team for a ticket

Your ticket includes z.ai and Claude Code for the session, and Nebius Token Factory credits to run the embeddings.

The problem
01 / 02

Every session, it meets your repo for the first time.

You open a fresh session. The agent has never seen your codebase. It re-derives the module map it worked out yesterday, opens the wrong files, and asks you where things live.

20 minre-explaining an architecture the agent already figured out once
0of what it learned yesterday that is still there this morning
every timehow often you pay that, because nothing carried over

An agent that forgets your repo is an agent you have to supervise.

And the cost is not only the twenty minutes. It is that you stop trusting it with anything structural, because you know it is guessing about a codebase it cannot see. So you use it for small local edits and do the real work yourself.

Whatever agent you use is fine for this. It needs to be able to read files and run a command you give it. That is the whole prerequisite, and step zero sets the rest up from scratch.

The problem
02 / 02

"Use a bigger context window" is not the answer.

The obvious fix is to paste more in. Windows are enormous now, so why not load the whole repo every turn and stop worrying about it?

everything you pastedone questionwhat mattered
01It is slow and it is billed. You pay to re-read the whole repo on every single turn.
02Accuracy gets worse, not better. Bury the right two hundred lines in two hundred thousand and the model has a harder time finding them, not an easier one.
03It still does not survive. Close the session and the whole thing is gone, so tomorrow you paste it all again.

So the fix is not more context. It is memory, which stores things once, and retrieval, which fetches only the slice this question needs. Everything after this slide is how those two are built.

The concept · 01 / 05
the spine of the morning

"Memory" is four different things.

They are not competing options. A working agent has several at once, and the useful way to tell them apart is not what they store, it is how the agent gets them back.

Always on Loaded into every session, whether or not it is needed. A project instruction file, a running notes file. Fetched by: nothing. It is just there.
Retrieval A searchable index over a big pile of content. Your codebase, embedded, so the right files can be found by meaning. Fetched by: similarity to the question.
Graph Things, and the named relationships between them. This function calls that one. This decision replaced that one, in March. Fetched by: following edges.
Working What happened just now, and in the last few sessions. The scratchpad, the session log, what you already tried. Fetched by: recency.

Almost every "our agent has memory" product is one or two of these four with a good name on it. When you evaluate one, the only question that matters is which rows it covers and which rows you are still on the hook for. Today you build rows two and three, and you get row one for free.

The concept · 02 / 05
retrieval memory

Retrieval, end to end.

Two separate pipelines that people constantly mistake for one. The top row runs when your code changes. The bottom row runs on every question, and it has to be fast.

Build time · runs when the repo changes
Ask time · runs on every question
01The two lit boxes are the only ones you have to think about. Chunking decides what CAN be found; the context block decides whether the agent can cite it.
02Embedding and indexing are a solved, boring middle. You will write about twenty lines for both.
03Nothing here is the agent being clever. It is a search engine you hand results to, and that is why it is reliable.
The concept · 03 / 05
where quality is decided

Bad chunks cannot be rescued later.

The most common way this whole thing fails is not the model and not the database. It is that the repo was cut into pieces that do not mean anything on their own.

Split every 500 tokens
    payload, algorithms=["HS256"])
        except jwt.ExpiredSignature:
            return None
        return claims
This is a real chunk from a real index. No function name, no file, no idea what it decides. It will match a search for "expired" and tell the agent nothing it can act on.
Split on function boundaries
// auth/tokens.py:41  verify_token
def verify_token(raw: str) -> Claims | None:
    """Validate a bearer token."""
    ...
Same code, cut where the language says a unit ends, and carrying its path and its name. Now it matches "where do we validate tokens" and the agent can open the file and cite the line.

The rule: retrieval quality is set at chunk time. If your results are junk, look at your chunks before you reach for a better embedding model or a reranker. Neither can put back a signature you cut off.

The concept · 04 / 05
context graphs

Three questions a vector index gets wrong.

Similarity search finds text that resembles your question. That is the right tool most of the time, and it is the wrong tool in three specific cases you will hit this week.

Ask"What breaks if I change this function's signature?"
Callers do not look like the function they call. Similarity returns other functions that resemble it, which is exactly the set you do not want. The thing you need is who depends on this, and that is an edge, not a resemblance.
Ask"Which of these two config patterns is the current one?"
Both chunks match, equally well. The index has no idea one of them was replaced in March. A vector has no notion of time, so a dead pattern retrieves as confidently as the live one and the agent copies the dead one.
Ask"Who owns the service that writes this table?"
Three hops: table, then writer, then owner. No single chunk contains all three, so no single similarity query can return it. It is a traversal wearing a question's clothes.
StoreEntities and typed edges. calls, imports, owns, supersedes. Extracted once, not guessed per query.
StampEvery edge gets a time. When it became true, and when it stopped. Now "current" is answerable.
QueryFollow edges instead of measuring distance. Multi-hop questions get exact answers.

Do not start here. A graph costs an extraction step that can be wrong, and a schema you have to maintain. Build the vector index first, use it for a week, and write down the questions it answered badly. If they all look like the three above, add edges. If they do not, you just saved yourself a system.

The concept · 05 / 05
the landscape

What is actually out there.

Sorted by which of the four rows they cover. Not a ranking, and not an endorsement: the only useful question is whether a tool stores the thing your failing query needs.

ToolRow it coversWhat it storesReach for it when
FilesAlways on Plain text your agent reads at startup. A project instruction file, a notes file. Always. It is free, it is versioned with your code, and it is the highest-value memory per line you will ever write.
ChromaRetrieval Embeddings plus metadata, on your disk. Open source. You want repo retrieval today with no service to run. This is what the lab uses.
pgvectorRetrieval The same vectors, in a Postgres you already operate. You have Postgres and would rather not add a second datastore.
PineconeRetrieval A hosted vector index, managed and scaled for you. The index has outgrown one machine, or you do not want to run it.
Mem0Working + always on Facts extracted from conversations, recalled per user and session. The thing you need to remember is about a person or a session, not about a codebase.
Zep / GraphitiGraph A knowledge graph where every edge carries time, so facts can supersede each other. "What was true when" is a real question in your domain. This is the temporal case from the last slide.
CogneeGraph + retrieval A pipeline that ingests documents and builds the graph and the vectors together. You want the extraction step handled rather than writing it yourself. Open source.
LettaAlways on, self-editing Memory blocks the agent rewrites itself as it learns, inside a stateful agent runtime. You want the agent to curate its own always-on tier instead of you doing it by hand.

The honest default: row one plus Chroma covers most of what most teams need from a coding agent. Everything below that line exists because someone hit a query the first two rows could not answer. Find your failing query first, then come back to this table and pick the row that answers it.

Product names are used descriptively to identify the tools. No affiliation or endorsement implied.

Case study · 01 / 03
measured this morning

One agent, six memories.

This is the personal automation repo running on the laptop in front of you. It is not a demo, it has been in daily use for months, and it grew every one of the four rows without anybody planning to. Every number here was measured this morning.

WhatRowSize, measuredHow it got there
CLAUDE.mdAlways on75,767 bytes Hand-written project instructions. Read in full at the start of every single session.
memory/*.mdAlways on + graph313 files
535 links
One fact per file, cross-linked to each other. 245 unique link targets, so it is a graph that nobody sat down to design.
MEMORY.mdAlways on141 lines The index over those 313 files. One line each, so the agent knows what exists without loading it.
graph.yamlGraph4,493 people
264 companies
Derived, never hand-edited. Regenerated from message history and event data by a command.
kernel_index.jsonRetrieval478 verbs
77 modules
Built by parsing the source, not embedding it. Exact lookup of every capability the repo has. No vectors involved.
pgvector farmRetrieval768-dim
HNSW
Postgres on a cluster node, embedding research papers and video transcripts for semantic search.

Read the third column as a warning, not a scoreboard. Nobody chose this mix. Each row was added the day a specific question could not be answered without it, which is exactly the order slide 7 recommends, arrived at by accident rather than on purpose.

Case study · 02 / 03
what it costs

The cheapest tier to build is the most expensive to run.

Each row has a completely different cost shape, and picking the wrong one for a given fact is how memory systems quietly get expensive.

Always on Costs nothing to build, and is re-read on every session, every time, whether or not it is relevant. Those 75,767 bytes are paid before you have typed anything. Budget it like a subscription, not a purchase.
Retrieval Costs an indexing pass up front, then almost nothing per question because you only fetch a handful of chunks. Scales to a repo you could never paste.
Graph The most expensive to build, because extraction can be wrong and the schema needs maintaining. Cheap and exact to query once it exists. Pay this only for questions edges answer.
Working Free while the session lives, gone when it ends. The tier everyone accidentally relies on and then loses.

Put a fact in the always-on tier only if the agent needs it in nearly every session.

Everything else belongs in an index it can go and get. The instinct is always to add one more line to the instruction file, because it works immediately. It works immediately and it charges you forever.

Case study · 03 / 03
the useful part

Four things that went wrong, so they do not go wrong for you.

Every one of these was expensive to learn and cheap to avoid if somebody tells you first.

01 · Memory goes stale silently
The always-on file says the repo has 425 capabilities. The generated index, built from the source this morning, has 478. The file was right when it was written and the code kept moving. Found while building this deck, in the repo on this slide. Nothing warned anybody, because a confident wrong number reads exactly like a right one.
02 · Derived memory must not be hand-editable
The people graph carries a hard rule: never edit it by hand, regenerate it. The one time a value gets hand-patched, the file and the thing it describes disagree forever, and nothing detects it. If a memory is derived, make regenerating it the only way to change it.
03 · A graph nobody queries is a science project
We built a proper temporal fact graph: entity resolution, relationship extraction, one fact superseding another over time. It worked. Then it sat there, because no consumer was ever wired to ask it anything. Write the query that fails today, and build backwards from it. Never forwards from the schema.
04 · The index is only true at index time
A retrieval store reflects the repo as it was when you built it. Delete a file and it happily keeps citing it, with line numbers, in a tone of total confidence. Re-index on a hook or a timer, or accept that the agent is describing last week's codebase.

The pattern under all four: memory fails quietly. A slow agent is obvious and a wrong memory is not, so the only defence is to make staleness visible on purpose. Step 4 of the lab does exactly that.

Lab · step 0 of 4
10:45
Step 00

Pick a repo and get the dependencies in.

Use a codebase you actually work in. The bigger and messier it is, the better the demo lands, because you already know which questions it is hard to answer.

from inside the repo you picked
# a scratch folder inside your repo. everything today lives here.
mkdir -p .recall && cd .recall
uv init -q && uv add -q openai chromadb

# the embedding endpoint. the key is on your ticket.
export NEBIUS_API_KEY=paste-yours
export EMBED_BASE_URL=https://api.studio.nebius.com/v1
# a scratch folder inside your repo. everything today lives here.
mkdir -p .recall && cd .recall
uv init -q && uv add -q openai chromadb

# the embedding endpoint. the key is on your ticket.
export NEBIUS_API_KEY=paste-yours
export EMBED_BASE_URL=https://api.studio.nebius.com/v1
# PowerShell. note $env: instead of export.
mkdir .recall; cd .recall
uv init -q; uv add -q openai chromadb

# the embedding endpoint. the key is on your ticket.
$env:NEBIUS_API_KEY = "paste-yours"
$env:EMBED_BASE_URL = "https://api.studio.nebius.com/v1"
# on a cloud box, same thing, and add the repo you want to index
git clone <your-repo> work && cd work
mkdir -p .recall && cd .recall
uv init -q && uv add -q openai chromadb

export NEBIUS_API_KEY=paste-yours
export EMBED_BASE_URL=https://api.studio.nebius.com/v1
Checkpointuv run python -c "import chromadb, openai; print('ok')" prints ok. If it does not, flag a facilitator now rather than at 11:30. Nothing else today works until this line does.
Lab · step 1 of 4
11:00
Step 01

Cut the repo where the language says a unit ends.

One chunk per function or class, carrying its file, its name and its start line. This is the step that decides whether the rest works.

.recall/chunk.py
# Python's own parser. No install, exact boundaries, real line numbers.
import ast, pathlib, json
SKIP  = {".git", ".venv", "node_modules", ".recall", "dist"}
KINDS = (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)
def chunks_for(path):
    src = path.read_text(encoding="utf-8", errors="ignore")
    try: tree = ast.parse(src)
    except SyntaxError: return
    lines = src.splitlines()
    for n in tree.body:                       # top level only, on purpose
        if isinstance(n, KINDS):
            yield {"path": str(path), "symbol": n.name, "line": n.lineno,
                   "code": "\n".join(lines[n.lineno - 1 : n.end_lineno])[:6000]}

def walk(root=".."):
    for p in pathlib.Path(root).rglob("*.py"):
        if not SKIP & set(p.parts): yield from chunks_for(p)

out = list(walk())
pathlib.Path("chunks.json").write_text(json.dumps(out))
print(f"{len(out)} chunks from {len({c['path'] for c in out})} files")
Checkpointuv run python chunk.py prints a count. Open chunks.json and read one at random: it should start with a def or class and be something you could hand a colleague. If it starts mid-expression, your boundaries are wrong and nothing downstream can fix it.

Not a Python repo? Same shape, different parser. tree-sitter gives the identical node types for JavaScript, TypeScript, Go, Rust and forty more: swap the parser, keep every other line. Python's ast is used here only because it needs no toolchain.

Lab · step 2 of 4
11:20
Step 02

Turn every chunk into a vector, and keep it.

The boring, solved middle of the pipeline. Twenty lines, and afterwards your repo is searchable by meaning instead of by filename.

.recall/index.py
import os, json, chromadb
from openai import OpenAI

client = OpenAI(base_url=os.environ["EMBED_BASE_URL"],
                api_key=os.environ["NEBIUS_API_KEY"])
db  = chromadb.PersistentClient(path="store")
col = db.get_or_create_collection("repo")

def embed(texts):
    r = client.embeddings.create(model="BAAI/bge-en-icl", input=texts)
    return [d.embedding for d in r.data]

chunks = json.load(open("chunks.json"))
for i in range(0, len(chunks), 64):                # batch, or you will wait
    b = chunks[i : i + 64]
    col.upsert(
        # id = path:line makes re-indexing idempotent. run it again on a
        # changed repo and only the chunks that moved get rewritten.
        ids=[f"{c['path']}:{c['line']}" for c in b],
        # embed the LOCATION with the code. "verify_token in auth/tokens.py"
        # is signal, and it is why a search for a concept finds the file.
        embeddings=embed([f"{c['symbol']} in {c['path']}\n{c['code']}" for c in b]),
        metadatas=[{"path": c["path"], "symbol": c["symbol"], "line": c["line"]} for c in b],
        documents=[c["code"] for c in b])
    print(f"indexed {min(i+64, len(chunks))}/{len(chunks)}")
CheckpointThe counter reaches your chunk total and a store/ folder exists on disk. That folder is the memory. It survives this session, your laptop closing, and the walk home.
Lab · step 3 of 4
11:35
Step 03

Hand the agent the right files, with line numbers.

A command your agent can run whenever it needs to know where something lives. It returns real paths and real lines, so the answer can be checked instead of trusted.

.recall/ask.py
import sys
from index import col, embed          # reuse the collection you just built
def retrieve(query, k=6):
    hits = col.query(query_embeddings=embed([query]), n_results=k)
    return "\n\n".join(
        f"// {m['path']}:{m['line']}  ({m['symbol']})\n{doc}"
        for doc, m in zip(hits["documents"][0], hits["metadatas"][0]))

print(retrieve(" ".join(sys.argv[1:])))
then tell your agent it exists (add this to the repo's instruction file)
## Finding code in this repo
Before answering where something lives, run:
    uv run python .recall/ask.py "<the question>"
Cite the path and line it returns. Do not guess at file locations.
CheckpointAsk your agent the question it always got wrong. It should run the command, come back with three or four real paths, and cite line numbers you can open. That is the moment the morning is for.

Next step up: expose retrieve as an MCP tool so the agent calls it as a real function instead of shelling out. Same code behind it. A transport change, not a rethink, and not worth debugging mid-sprint.

Lab · step 4 of 4
11:50
Step 04

Persist what it learns, then add the edge vectors cannot give you.

The index already survives on disk. What does not survive is everything the agent worked out along the way, and the one relationship it will keep asking for.

A · the notes that survive
.recall/MEMORY.md · read at every startup
# Repo notes
## Map
- token validation: auth/tokens.py:41, NOT the middleware
- the event state machine is 11 stages, events/__init__.py

## Conventions
- never hand-edit data/graph.yaml, regenerate it

## Stale check
- index built: 2026-08-08. Re-run index.py after a big merge.
B · the edge: who calls this
.recall/edges.py · same parse, one more pass
import ast, json, collections
from chunk import walk, SKIP

calls = collections.defaultdict(set)
for c in walk():
    for n in ast.walk(ast.parse(c["code"])):
        if isinstance(n, ast.Call) and isinstance(n.func, ast.Name):
            calls[n.func.id].add(f"{c['path']}:{c['line']}")

# now "what breaks if I change verify_token" is a lookup, not a guess
json.dump({k: sorted(v) for k, v in calls.items()},
          open("edges.json", "w"))
CheckpointOpen a brand new session, with no history at all, and ask the slide-2 question. The agent reads the notes file, runs the retrieval command, and answers with paths. Then look up a function in edges.json and see every caller listed. That second file is a context graph with one edge type in it, built in nine lines. Everything on slide 8 is that, with more edge types and a real query language.
Gotchas
before you take this to work

Where this bites you next week.

All four of these have already happened to somebody in this room's future. They are cheap to prevent and annoying to diagnose.

Stale index The store is a photograph of the repo at index time. Delete a file and it keeps citing it confidently. Fix: re-run the indexer on a git hook or a timer, and write the build date into the notes file so a human can see the age.
Bad chunks If recall is junk, it is almost never the model. Fix: print ten random chunks and read them. If a human cannot tell what one does, neither can a vector.
Secrets leave Embedding sends your code to an API. Fix: honour .gitignore, skip .env and key material, and keep the store local. For a repo that cannot leave the building, run the embedding model locally instead. Same code, different base URL.
Confident wrong Retrieval makes the agent sound certain, including when it is citing something deleted. Fix: every answer carries a path and a line, so a claim is one click from being checked. Never let it cite a file it did not retrieve.
Humans stay in Retrieval informs the agent. It does not authorise it. Fix: the agent proposes an edit and you approve it. Better memory raises the quality of the proposal, never the permission.

Notice that four of the five are about knowing when the memory is wrong, not about making it better. That ratio is correct, and it is the part most retrieval write-ups skip.

Leave with
12:00 · demos and coffee

What is on your laptop that was not there at 10am.

Four files and a folder, on a repo you actually work in.

01chunk.py splits your codebase on real function boundaries, carrying path, symbol and line.
02index.py embeds those chunks into a store that persists on disk and re-indexes idempotently.
03ask.py returns the right files, by meaning, formatted for the agent to cite.
04edges.json answers "who calls this", which no vector index can. A context graph with one edge type.
05MEMORY.md carries what the agent learned into every future session, for free.

The proof is the new session. Close everything, open a fresh one, and ask the question your agent has never once got right. If it answers with a path and a line, you did not just learn retrieval this morning, you shipped it. Show your team on Monday.

Resources
what your ticket included

Everything you used this morning.

Two of these came with your ticket. The rest are open source and yours to keep running for nothing.

Included with your ticket
z.ai and Claude Code for the session. The agent you spent the morning giving a memory to. Provisioned for the duration of the workshop.
Included with your ticket
Nebius Token Factory credits, which ran every embedding in step 2. Credits are scoped per event, so there was no API bill on your card today.
The store
Chroma, open source, running from a folder on your disk. Swap it for pgvector if you already run Postgres, or a hosted index when it outgrows one machine.
The parser
Python's built-in ast for today. tree-sitter for everything else, with the same node types across forty-odd languages.
Swap the model
Today ran BAAI/bge-en-icl. Try Qwen/Qwen3-Embedding-8B on the same endpoint and re-run step 2 to compare what comes back. Same code, one string changed.
Going further
Expose ask.py over MCP so the agent calls it as a real tool. Then revisit slide 8 with the query your index got wrong this week.

Product names are used descriptively to identify the tools used in the lab. No affiliation or endorsement is implied by their appearance here.

VCN #48 · Total Recall
thank you

Your agent knows your codebase by name now.

Keep it. Re-index it. Bring the question it still gets wrong to the next one.

Next · Wed Aug 12
#49 The Swarm. Parallel agents fanned out across git worktrees, all working the same repo at once. Floor 10, 7pm. The memory you built today is what stops them all re-deriving the same map.
Then · Sat Aug 15
#50 Own the Stack. The capstone. Self-host the whole rig, zero API bill, everything from the season tied together. Floor 9, 10am.
Join
Telegram t.me/+EBFzKXmJAVk5ZGU0
Site vibecodingnights.com
Teach a night
We take builder-led talks and live demos. If you shipped a pattern, bring it. Reach the Facilitator, Rayyan Zahid.

Show somebody on Monday. That is the whole point.

Hosted by Vibe Coding Nights: Rayyan Zahid (Immersive Commons), Michalis Vasileiadis (Hacker Bob), Eric Mockler (AI Geneticist), Devinder Sodhi (Learning Layer Labs). Facilitator: Rayyan Zahid.