A plain-language tour of a local code-search tool that finds code by its name or by what it does, answers with its sources, and keeps your code on your own machine.
You have just joined a project. Nobody has time to walk you through it, and you have two questions.
The first is precise:
Where is
ERR_CONN_RESEThandled?
The second is not:
How do we stop a user from logging in too many times?
The answer to the first question is a catch block that checks for that exact constant. A search that understands meaning but not exact names may show you three files about connections and errors, none of which contains the constant you typed.
The answer to the second is a function called throttleAuthAttempts. It never uses the words "logging in" or "too many times", so a plain text search will walk right past it.
Most tools are good at one of these questions. yodaman-ctx (ctx for short) is built to handle both. This article explains what it does for you, how, and where its limits are, based on version 1.3.4, the latest release.
What ctx is, in one paragraph
ctx is a command-line tool, published on npm as yodaman-ctx under the MIT licence. You point it at a project once and it builds an index in a local SQLite database. After that you can search the project, ask it questions and get answers that name the files and lines they came from, or hold a conversation about it with ctx chat. It can index many projects and search one or all of them.
1. It finds code whether or not you know its name
ctx runs two searches for every question and combines them.
- A keyword search finds the exact names you type: constants, error codes, function names.
- A meaning search finds code that does what you describe, even when it uses different words.
The two result lists are merged so that a piece of code both searches agree on rises to the top. Here is how that plays out for the ERR_CONN_RESET question:
| Piece of code | Keyword search | Meaning search | Combined score |
|---|---|---|---|
The catch block that handles ERR_CONN_RESET
|
2nd | 3rd | 0.976 |
A log message that mentions ERR_CONN_RESET
|
1st | 8th | 0.949 |
| A general retry helper | not found | 1st | 0.500 |
The catch block is first in neither list, but it is the answer both searches support, so it comes out on top.
ctx also understands how programmers write names. It keeps a name like getUserById whole and also splits it into get, user, by and id. Search for the exact name and you find it; ask about "get user by id" in plain words and you find it too.
2. It understands how code is organised
A search tool can only return the pieces it has indexed, so how it cuts files into pieces matters a great deal.
For TypeScript, JavaScript, Python, Go and Rust, ctx reads the actual structure of each file. Every function, class, type or Rust impl block becomes its own piece, together with the comments, decorators or attributes written just above it. The code in between (imports, constants, setup) is kept as well, so every line of a file ends up in exactly one piece; tests check this for TypeScript, Python, Go and Rust files.
For Markdown documentation, each heading stays together with everything under it, so a table is always found along with its title.
The result: when ctx shows you a match, you see a whole function with its doc comment, or a whole section with its heading, not a fragment cut off mid-thought.
3. Your code stays on your machine
ctx does not send your code anywhere.
- The embedding model that powers the meaning search runs on your own computer. It is about 340 MB and is cached in
~/.ctx/models. - Answers come from a local model served by Ollama.
- There is no cloud provider anywhere in the code path.
That matters for any team whose code is private or sensitive.
4. Quick to start, light on memory
Both searches run inside the SQLite database that already holds your index, so nothing has to be loaded into memory before ctx can answer. Measured on test projects:
| Project size | Ready to search | Meaning search, per query | Keyword search, per query |
|---|---|---|---|
| 25,000 pieces of code | about 5 ms | 0.13 s | 3 to 9 ms |
| 200,000 pieces of code | about 5 ms | 0.97 s | 60 to 198 ms |
The process holds almost no extra memory while it does this. Loading the same data into memory instead used about 1.1 GB and took several seconds at 200,000 pieces, before the first search could even start.
Keyword search uses SQLite's built-in full-text index. Meaning search uses an SQLite extension, sqlite-vec, which has prebuilt versions for Linux and macOS (x64 and arm64) and Windows (x64). On other platforms ctx still works; it loads the meaning-search data into memory to search it.
5. Answers come with their sources
When you use ctx ask, ctx searches first and only then asks the local model to answer, using what it found. Before the model sees anything, ctx:
- removes near-duplicate pieces, so the same code does not crowd out other evidence,
- keeps the most relevant pieces within a size budget, and
- places the strongest pieces at the start and end of what the model reads, because language models tend to use information there more reliably than information in the middle.
Every piece is labelled with its file path and line range, so the answer can point you to exactly where it came from.
If you ever want to see what the model was given, ctx ask --context-only --json shows you the assembled context without generating an answer. That makes it easy to check, rather than trust.
6. Scores you can actually read
Every result comes with a score from 0 to 1 that means something:
- 1.0: both searches ranked it first.
- About 0.5: one search ranked it first and the other did not find it.
That makes it easy to see at a glance which results both searches agree on, and a minimum-score filter on a 0 to 1 scale behaves the way you would expect.
7. Many projects, one conversation
You can index as many projects as you like and search one or all of them. In ctx chat, ctx works out which project a question is about:
- Name one project, and it searches that project.
- Name two, or ask to "compare" across named projects, and it searches them together.
- Say "this project" or "this repo", or set a focus with
/focus, and it stays there.
This is mostly done with simple rules rather than by asking the model, which keeps routing fast and predictable. Staying in the focused project also keeps answers quick when you have many projects indexed.
8. It tells you when an index needs refreshing
When the way ctx reads code improves, an index built the old way keeps working but quietly gives worse results. ctx records how each project's index was built. If it is out of date, ctx prints a warning with the exact command to rebuild it, and ctx check lists it as well, so an outdated index does not go unnoticed.
9. Tuned by measurement, not guesswork
ctx comes with its own test of search quality: 56 questions about ctx's own code, each paired with the files that answer it. It mixes exact-name questions, plain-language questions and documentation questions. On version 1.3.4, the right file is in the top five results for 86% of those questions.
Every recent improvement had to prove itself on that test before it stayed:
- Using the embedding model as its makers intended. The model's documentation says search queries should start with a short instruction. Adding it put the right file in the top five more often (80% of questions instead of 73%).
- Preferring code over documentation on close calls. Documentation describes features in plain words, so it can crowd out the code it describes. A small preference for code improved 12 questions and made none worse, including the documentation questions.
-
Keeping an optional step optional. ctx includes a second-pass ranking model, but testing showed it ranked tables and code lower, so it only runs when you ask for it with
ctx search --rerank.
The same evaluation command, ctx eval, is available to you, so you can measure how well search works on your own projects instead of taking anyone's word for it.
Where ctx is still improving
No search tool gets everything right, and it is better to know the limits up front.
- Some areas are harder than others. On the 56-question test, every question about the database and embedding code finds its answer first, though those groups are small (three and four questions), while questions about the chat agent are the weakest. When ctx misses, it usually finds the right part of the project but a neighbouring file, such as a file of type definitions next to the one you needed.
- Five languages are read by structure. TypeScript, JavaScript, Python, Go and Rust are split by function and class. Other languages, such as Java and C#, are split by size instead.
-
Names have to share something to match. A keyword search links
getUserByIdto "get user by id", but not "authenticate" tocheckLogin. For those, the meaning search does the work. - Long chats on very large projects. Each question searches the database afresh, which is what makes ctx quick to start. In a long chat on a project with 200,000 pieces, that means about a second per question for the meaning search.
- Some platforms load data into memory. Where sqlite-vec is not available, ctx still works, but meaning search needs more memory and time to get started.
Commands worth knowing
| Command | What it does |
|---|---|
ctx search "your question" |
Finds the 10 most relevant pieces of code |
ctx search "your question" --rerank |
Adds the optional second-pass ranking |
ctx ask "your question" |
Answers from your code, with sources |
ctx ask "your question" --context-only --json |
Shows exactly what the model would be given |
ctx chat |
A conversation about one or more projects; /focus keeps it on one |
ctx check |
Flags a project whose index needs rebuilding |
ctx eval |
Measures search quality against your own set of questions |
The short version
yodaman-ctx gives you one place to ask questions about your code, whether you know the exact name you are looking for or only what the code does. It runs entirely on your machine, has a project ready to search in milliseconds, shows you where every answer came from, and tells you when its index needs refreshing. Its improvements are measured rather than assumed, and its limits are stated plainly.
ctx is MIT-licensed and available at github.com/Yoda-Man/ctx.
Top comments (0)