Building Code Context v2
How I built a semantic and agentic code search layer for my AI agent workflow, especially for large brownfield codebases.

I first committed Code Context v2 on February 20, 2026.
Since then, it has slowly become one of those tools I keep reaching for when I am working with AI coding agents.
Not because the agents are bad at searching. Modern coding agents already have impressive built-in search tools. Many of them combine lexical search, syntax-aware search, file reads, and in some environments even LSP context like definitions and references.
That is already strong.
The problem I wanted to solve was a little different.
I wanted a persistent semantic layer that understood the codebase across sessions, worked well from the terminal, and gave agents the right chunks of context without forcing me to manually assemble everything again.
# Why I built it
Most of my work today touches software, AI workflows, automation, and product building. I move between projects a lot, and I use agents to help me understand code, change things, and keep momentum when the codebase is too large to hold in my head at once.
But agents still need context.
If I give them too much code, the conversation gets noisy. If I give them too little, they start filling the gaps themselves. Sometimes that works. Sometimes it creates subtle mistakes.
The missing piece for me was not only search. It was a better way to let the agent build context.
For example, I wanted to ask:
cc2 search "authentication middleware" \
--intent implementation
cc2 search "where the rate limit is enforced" \
--intent debug
cc2 search-file src/server/auth.ts \
"session validation"
And I wanted the answer to come back as useful code chunks with file paths, line numbers, symbols, relevance scores, and enough surrounding metadata for the agent to act on it.
# Brownfield codebases are different
I think this matters most in brownfield software development.
A greenfield project starts from a clean slate. You can decide the structure, naming, conventions, and architecture as you go.
A brownfield codebase is different. The system already exists. There are old decisions, half-refactored modules, mixed conventions, hidden coupling, tests that explain behavior better than docs, and business logic living in places you would not choose today.
This is where search becomes more than convenience.
In a large existing codebase, finding the right context is part of the work itself.
Lexical and syntax search are great when you already know what to look for. LSP tools are great when you have a symbol, file, or reference chain to follow. But sometimes the task starts as a concept:
- "where is the user access policy enforced?"
- "which code creates the live session token?"
- "what path handles daily usage limits?"
- "which module owns this business rule?"
That is the space where I wanted cc2 to help.
# What cc2 does
Code Context v2, or cc2, is a semantic retrieval tool for CLI-driven agent workflows.
At a high level, it lets me:
- index a project locally
- search with natural language
- filter by intent, directory, file type, language, and tests
- search inside one indexed file
- sync only changed files
- keep projects fresh with watchers
- index Markdown memory notes
- search indexed technical books
- expose search through MCP tools
- run higher-level research workflows on top of search
The common command is simple:
./cc2.sh search "auth middleware" \
-p my-project
When I am already inside an indexed project, the CLI can infer the project from the current directory:
./cc2.sh search "database connection handling"
That small detail matters. The less ceremony there is, the more likely I am to actually use the tool during real work.
# How it works
The core flow is straightforward.
| Step | What happens |
|---|---|
| Parse | Tree-sitter parses code into functions, classes, methods, SQL objects, docs, and file-level chunks where needed. |
| Embed | Chunks are embedded with Voyage AI. |
| Store | Vectors and metadata are stored locally, usually with Postgres, pgvector, pgvectorscale, and the Timescale Docker image. |
| Search | A query gets embedded, candidate chunks are retrieved, and then reranked. |
| Return | cc2 returns useful chunks with paths, lines, symbols, and scores. |
Right now I use the Voyage 4 model family. One thing I like about it is the shared embedding space: cc2 can use voyage-4-large for indexed documents and voyage-4-lite for query embeddings.
That fits this use case well. The codebase is embedded less often. Queries happen all the time. So I can spend more quality on the indexed corpus and keep queries cheaper and faster.
The recommended backend is Postgres with pgvector and pgvectorscale through Docker:
docker volume create code-context-pgdata
docker compose up -d postgres
There is also a LanceDB fallback for a no-Docker setup.
The part I care about most is that retrieval is shaped for agents, not only for humans. Search results should be small enough to fit into context, but specific enough that an agent can make a useful change without asking for five more files.
# Keeping the index fresh
One practical detail that matters a lot is keeping the semantic index close to the real codebase.
If the index gets stale, the tool becomes less useful. The agent may find old code, miss a recent change, or spend time reasoning from context that is not true anymore.
So cc2 tracks file hashes and chunk hashes. When I run sync, it can skip unchanged files and reindex only what changed.
cc2 check my-project
cc2 sync my-project
There is also a watcher flow:
cc2 watch ~/projects/my-project
cc2 watch-all
That is important for how I actually use it. I do not want semantic search to become a separate maintenance task. I want the index to quietly follow the codebase while I work.
# Where agentic search fits
The most useful version of cc2 is not only cc2 search.
On top of the raw search command, I also built research harnesses for agent workflows. In PI, I use cc2 research to let an agent run multiple searches, follow leads, and return a structured source map. I now have a Codex-facing version of that too.
That makes the flow more agentic.
Instead of asking for one search result and manually deciding what to open next, the agent can do something closer to:
- search for the main concept
- inspect the highest-signal files
- search for related symbols or call sites
- compare candidates
- return a short map of what matters
This is where cc2 starts feeling less like a search command and more like a research layer for code.
It still works with normal agent tools. It does not replace lexical search, syntax search, or LSP navigation. It gives those tools a semantic index and a memory layer to work with.
# What I learned
The main lesson is that good AI workflows are not only about better models.
Models matter, obviously. But the surrounding tools matter too: search, memory, project conventions, local setup, and the way context is assembled.
I also learned that retrieval tools need to fit the way I already work. If a command takes too long, returns too much, or requires too much setup, I will not use it in the middle of a real task.
There is still plenty to improve:
- better graph-aware retrieval
- cleaner type coverage
- stronger MCP parity
- better public benchmarks
- more docs for new users
But cc2 is already useful to me.
It came from a real problem in my own workflow, and after a few months of using it, I wanted to make the project public.