Skip to content

From data to answers

It all comes down to this: you have data, you want answers. Everything else — ingestion, model, query, chart, deployment — is in service of that single trip. Anything that isn't reducing the distance between "I have a question" and "I have an answer that changes what I do next" is overhead.

This doc is about the route. The smallest possible architecture you can start with, and how it grows one question at a time. Each question becomes a Stride card, and each card moves the architecture exactly far enough to answer it. No further.

The frame

Build for the question on the card, not the question you might one day be asked.

Architecture earns its place by answering a question. If no card needs it, it doesn't get built. The shape of the system at any moment is a record of the questions you've actually faced — not a prediction of the ones you might.

The starting rung — one sheet, one module, one page

The simplest architecture that delivers an answer:

LayerWhat it isWhy it's enough
DataA CSV, a Google Sheet, or a single API endpointWhatever you can read with one function call is your source
AccessA Python script using Pandas to load, shape, and write the answer to a JSON fileOne file. Pandas does the heavy lifting; you write almost no glue.
ViewA page in the app-starter (TypeScript, Next.js) that reads the JSON and renders itYour answer, visible.

That's three files. No database, no ORM, no migrations, no scheduled jobs. It runs locally, it answers the question, and it can be thrown away without grief if the question changes.

Two languages, deliberately. Pandas is the right tool for shaping data — slicing, joining, aggregating — and the Python ecosystem around it is unbeatable. The app-starter is the right tool for the page — TypeScript, Next.js, shadcn. Don't force one language to do both. The handoff is a JSON file the Python script writes and the page reads. That's the whole interface between them.

If your first question is "how much did we invoice each customer last quarter?" and the data is in a spreadsheet, this is the architecture. Building more is You Ain't Gonna Need It ("YAGNI").

If there's no spreadsheet — the source is a SaaS API only — the shape doesn't change. The Python script hits the API instead of reading a file, writes the same JSON. Same three layers, same simplicity.

The Stride loop — one card per question

Each question becomes a Linear issue. The card carries:

  • The question — phrased in business terms, not technical ones
  • The CRAFT prompt — what Claude needs to know to answer it
  • The deliverable — usually a chart, a table, or a number on the page

The card moves: Backlog → Todo → In progress → In review → Done. Done means the answer is on the page and someone has looked at it.

CardArchitecture moveWhat grew
"How much did we invoice each customer last quarter?"Python loads the sheet and sums by customer; the page renders the tableThe spreadsheet, the Python script, the page
"Which customers are buying less than last year?"Add a year-over-year column to the Pandas output; the page picks it upOne function
"Same question but split by region"Group by region in Pandas; add a column to the tableOne column
"Compare invoicing against Stripe payments"Two sources. This is the moment.Time for a data model in the middle

Each card is a stepping stone. None of them build infrastructure speculatively. The architecture is a record of the questions you've been asked, not a guess at the ones you haven't.

When to climb a rung

The architecture grows when the current shape stops being the simplest answer. The signals are predictable:

SignalWhat it meansWhat to do
Two sources, one questionYou need a join across systemsClimb to a data model in the middle
The same query written three timesA helper is formingExtract a function in the access module
The page takes 5+ seconds to loadYou're re-parsing the sheet per requestCache, or load into SQLite
The spreadsheet is too largeMemory pressure, slow scansMove into SQLite — the sheet stays as source of truth, the DB is the working copy
The question depends on yesterday's dataYou need a refresh storyAdd a scheduled pull, even if it's a manual script for now
Someone else wants to ask their own questionsThe page is your interface; they want to typeAdd an LLM-writes-SQL chat box over the model

Don't pre-empt these. Wait until one of them is in your face. Friction is the cue — the system tells you when it's ready to grow, you don't decide in advance.

What YAGNI feels like in practice

The discipline is to not build a long list of plausibly-useful things on day one. The list looks like this:

  • No database until two sources need joining
  • No ORM until there's a schema worth migrating
  • No scheduled jobs until "yesterday's data" is no longer good enough
  • No auth until someone outside the team needs to see the page
  • No deploy pipeline until "runs on my laptop" stops being an acceptable deploy target
  • No charting library until a plain table stops being readable
  • No abstractions in the access module until the third caller asks for the same thing

Each of these is a real piece of work. Building them in advance means doing the work, and maintaining the result, and reasoning around them — all before any question has asked for it.

An unused column is not foresight. An unused job is not foresight. An unused abstraction is not foresight. They are clutter the next agent — human or Claude — has to understand before it can help.

What never gets skipped

YAGNI applies to architecture. It does not apply to the loop itself.

AlwaysWhy
Atomic commitsOne question per commit. When the answer turns out to be wrong, you can revert exactly the change that produced it.
A card per questionThe card is the record of what was asked and why. Without it, the architecture is a pile of code with no story.
CRAFT promptsThe prompt is the contract between you and Claude. A vague prompt produces a vague answer.
The answer is on the pageNot in the chat history, not in a notebook nobody opens. Done means visible.
Spot-check the number before acting on itClaude will confidently produce a wrong join. Before a decision rides on an answer, verify it against a hand-calculated row.

These are cheap on day one and expensive to retrofit. They pay their way regardless of how small the system is.

So — what's the simplest path?

StageArchitectureTrigger to climb
1. First questionSheet (or API) + Pandas script + app-starter page, JSON between them
2. More questions, same shapeAdd helpers to the Pandas scriptThe third repeated query
3. New source entersA data model in the middle — SQLite + ORMA question that needs a join
4. Many questions, many sourcesThe model is the app; the dashboard is one view of itThe model has earned its place
5. Outside the teamPostgres, deploy, authA real user who isn't you

Each rung is a response to a question, not a prediction of one. Claude builds exactly what the next card asks for. The card is the unit. The question is the trigger. The answer is the proof.

That's the whole loop.

Further reading