Every time someone wants to “chat with their data,” the same answer shows up: build a RAG pipeline. Chunk the documents, generate embeddings, spin up a vector database, write a retriever, tune the top-k. It works, but it is a lot of machinery for what is often a simple question like “who were my top 10 customers last month?”
There is a lighter path. Instead of turning your data into vectors, you turn it into a connected network — and let Claude Code do the reading, connecting and querying. No embeddings. No vector DB. No RAG.
The Problem With RAG for Internal Data
RAG and embeddings are genuinely powerful. They shine when you have thousands of unstructured documents and you need fuzzy, meaning-based search across all of them.
But for most internal business data, RAG is the wrong shape of tool:
- Setup cost is high. Chunking strategy, embedding model choice, vector store, index refresh jobs — that is a small project before you get your first answer.
- It costs time and API calls. Every document has to be embedded, and re-embedded when it changes.
- It guesses instead of counting. Embeddings retrieve similar looking text. If you ask for a revenue total, similarity search is not the tool that gives you an exact number.
And here is the part that gets missed: your sales.csv already has structure. Columns, IDs, dates, foreign keys. Flattening that into text chunks throws away the very thing that makes the answer precise.
The Solution: Build a Data Network Instead
The idea is simple. Rather than a vector index, you build a small knowledge network — a graph of your entities and how they relate to each other.
Your CSVs, Excel sheets, JSON payloads, logs and notes all get pulled into one place. Claude Code figures out that customer_id in sales.csv is the same thing as id in customers.xlsx, writes the schema, loads the data, and then answers your questions by querying it instead of guessing at it.
Three steps, conceptually: connect your data, create the relationships, ask anything in natural language.
How It Works: 4 Steps
1. Load your data
Put everything in one folder. CSV, Excel, JSON, .txt notes, API exports — mixed formats are fine.
/my-data
sales.csv
customers.xlsx
products.json
notes.txt
2. Let Claude Code analyse it
Open Claude Code in that folder and ask it to inspect the files. It reads headers, sample rows, data types and value overlaps, then tells you what entities exist and how they appear to connect.
A prompt that works well:
Look at every file in this folder. For each one, list the columns, the data type, and a few sample values. Then tell me which fields link files together, and propose a schema. Do not write any code yet.
Reviewing this step before it builds anything is what keeps the whole approach reliable.
3. Build the network
Once you approve the schema, ask Claude Code to create it. It writes a loader script, creates the tables or nodes, defines the relationships, and reports row counts so you can sanity-check the load.
Create a local SQLite database called
brain.dbfrom this schema. Write one idempotent Python loader that imports all four files, enforces the foreign keys we identified, and prints row counts plus any rows it had to skip.
You now have a queryable brain instead of a pile of files.
4. Ask anything
From here you just talk to it. Claude Code translates your question into SQL (or Cypher), runs it, and gives you the answer with the query it used — so you can verify the number rather than trust it.
Worked Example
Your data: sales.csv, customers.xlsx, products.json, notes.txt
You ask: “Show me the top 10 customers by revenue in February.”
What happens: Claude Code joins sales to customers on the key it detected, filters the date range, sums revenue, sorts, limits to 10.
Answer:
| # | Customer | Revenue |
|---|---|---|
| 1 | ABC Corp | $52,340 |
| 2 | XYZ Ltd | $41,210 |
Exact figures, not a similarity guess. And because the relationships are real, follow-up questions work too: “Which products drove ABC Corp’s growth?” or “Any of my top 10 with an open complaint in notes.txt?”
The Tech Stack (Deliberately Simple)
- Claude Code — orchestrates everything: reads the files, infers the schema, writes the loader, runs the queries.
- A lightweight database — SQLite for simple relational work, DuckDB when you want fast analytics over larger files, or a local Neo4j instance if your data is genuinely graph-shaped (many-to-many, multi-hop paths).
- Schema inference — handled by Claude Code, reviewed by you.
- A natural language layer — which is just your terminal.
That is it. No vector store, no embedding model, no chunking config.
On privacy: your dataset stays on your machine — it never gets bulk-uploaded anywhere. Claude Code does send your questions, the schema and small samples to the model to reason about, so treat it like any cloud tool and mask sensitive columns before you start if you are working with regulated data.
Guardrails: Stop Accidental Deletes and Updates
Handing an AI agent a database and a terminal deserves a moment of caution. The good news is that a few cheap rules make destructive mistakes close to impossible.
Make the source files read-only. Your CSVs and spreadsheets are the ground truth, so lock them:
bash
chmod 444 /my-data/*.csv /my-data/*.xlsx
Better still, load from a copy and keep the originals in a folder Claude Code never opens.
Query through a read-only connection. This is the important one. Once the network is built, every question should go through a handle that physically cannot write:
python
# SQLite
con = sqlite3.connect("file:brain.db?mode=ro", uri=True)
# DuckDB
con = duckdb.connect("brain.db", read_only=True)
A stray DELETE on a read-only handle fails with an error instead of removing rows.
Split writing from reading. One script, load.py, is allowed to write, and you run it deliberately. Every ad-hoc question goes through query.py with the read-only handle.
Write the rules down. Drop a CLAUDE.md in the project folder so the agent reads them at the start of every session:
Never run DELETE, UPDATE, DROP, ALTER or TRUNCATE. All queries must be SELECT only and must use the read-only connection in
query.py. Data changes happen only by editingload.pyand asking me to re-run it. Show me the SQL before you execute it.
Keep it rebuildable. Commit load.py and the schema to git. Because brain.db can be regenerated from the source files with one command, even losing the whole database costs you a minute — not your data.
When You Should Still Use RAG
Being honest about the trade-off makes this approach more useful, not less.
Use the knowledge network when your data is structured or semi-structured and your questions are about facts, totals, filters and relationships.
Reach for RAG and embeddings when you have a large body of free-form text — support tickets, contracts, research papers, a wiki — and your questions are about meaning rather than numbers. “Find me anything about refund policy edge cases” is a retrieval problem. “What was Q2 churn?” is a query problem.
Plenty of real systems end up using both. The mistake is reaching for the vector database by reflex.
Frequently Asked Questions
Do I need to know SQL? No. Claude Code writes the queries. Being able to skim the SQL it shows you is a useful safety net, though.
How large can the data be? SQLite comfortably handles millions of rows. Move to DuckDB when scans start feeling slow. Only the query results go through the model, not the whole table, so size mostly affects your disk rather than your token bill.
What if my files are messy? Very common, and it is where this approach earns its keep. Ask Claude Code to profile the data first — nulls, duplicate IDs, inconsistent date formats — and to write the cleaning step into the loader so it stays reproducible.
Is this actually faster than RAG? For structured data, usually yes. You skip the embedding pass entirely, and updates mean re-running one loader script instead of re-indexing.
Can I add new files later? Yes. Ask Claude Code to extend the schema and update the loader. That is much less painful than reworking a chunking strategy.
Final Thoughts
RAG became the default answer to “chat with my data” so quickly that a lot of people never asked whether their problem needed it. If your data already has structure, you can keep that structure, build a small network out of it, and ask questions in plain English — with exact answers and a query you can check.
Start with one folder and four files. Get one real answer. Then decide whether you ever needed the vector database.
If you build something with this, I would like to hear what worked and what broke. And if you are experimenting with Claude Code in other ways, there is more on that here on the blog.