You have a problem and you don't know it yet: your documentation started lying the moment you published it. You change a file, move a folder, rename a component — and the README, the diagram and the internal wiki keep describing last week's site. Context Driven Development flips the order so that can't happen: context is specified first and is in charge, code is its consequence, and a validator keeps the two from contradicting each other.
The problem: documentation that ages faster than you can write it
Almost all software is documented afterwards. First you write the code, and once it works, someone writes a README or draws a diagram to explain it. The problem is structural: as soon as the code changes again —and it changes every day— that documentation stops being true and nobody updates it. You end up with two versions of the truth that contradict each other, and people (or an AI) make decisions by reading the wrong one.
The root cause isn't laziness, it's the order. If documentation comes last, it's always behind. The only way for it to stop lying is for it to stop coming last.
The idea: context is in charge, code is its consequence
This site isn't born in the code editor, but in a blueprint. Before a single component exists, it's already written down what sections there will be, how they relate, and what pieces each one is made of. I call this way of working Context Driven Development: context is specified first and code is its consequence.
It's an applied variant of Spec-Driven Development. The difference: instead of one spec per feature that gets filed away, I keep a living map of the whole project. The entire site rests on three layers that speak the same language: the Context —the blueprint that's in charge—, the design system —the tokens and components it's built with— and apps/web —the Next application that assembles the other two—. What's interesting isn't each layer on its own, but how they connect.
«Code is the consequence of the blueprint, not its origin. If the Context and the code contradict each other, the Context wins.»
How the pieces connect
What follows is that system made interactive. Each box is a real layer of the site and each arrow, a relationship: the Context specifies the nodes, each node declares which design system components it uses and where its code lives, and apps/web assembles everything. Drag the boxes to follow the connections.
Diagrama hecho con React Flow: el artículo enseñando, en vivo, cómo está conectada la web que lo muestra.
Two connections deserve attention, and each one solves a specific problem. The dotted burgundy arrow is the bidirectional synchronization: it attacks the aging problem. And Connections —Obsidian, Figma, the databases— attacks another: copying data that then goes stale. They're living sources consulted on demand, not copied into the blueprint. Let's look at the two pieces that hold all of this together: what's inside a node, and why the synchronization doesn't break.
What's inside a node: five layers
The «where do I touch this?» problem is solved in the node. Each page lives in the Context as a node: a file whose frontmatter has five layers, each one answering a different question:
- Semantic identity — what this concept is and what it relates to (its hypernym, its hyponyms, its siblings). It's the layer that weaves the knowledge graph.
- SEO + URL — its title, its description, its canonical slug, its
hreflang. So that people find it. - GEO — the question it answers and the short, extractable answer. So that ChatGPT, Perplexity or the AI Overviews cite it.
- Technical sitemap — priority, change frequency, languages.
- Implementation — and here's the most useful one day to day: the hot-paths, the exact path of the files that make the page work, plus the design system components it uses.
Thanks to the hot-paths there's no need to read the whole repository to touch a section. I open the node, read its implementation layer and go straight to the right file. An AI does the same: it finds the spot on the first try, without getting lost among folders. The node turns «find where this is» into «I already know where this is».
The bidirectional synchronization isn't magic: it's protocol plus validator
Here's the honest question: if the code and the Context live in different places, what stops them from diverging again? The answer isn't a magic daemon running in the background. It's two much simpler things:
- Protocol. When I move or create code, I update the node's implementation layer in the same commit. It's not a separate step to be postponed: it's part of the change.
- Validator. A script (
pnpm validate:context) checks that everyruta-codigoand every component a node declares actually exist. If I moved a file and forgot to update the node, validation fails.
That's why it's bidirectional: the node tells you where to write the code (Context → code), and the validator stops you from lying if the code moved and the node stayed behind (code → Context). Neither direction depends on good memory. The aging problem isn't solved with heroic discipline, but by making the lie break the build.
Links or vectors? What each one is for
When I explain this, the technical question I get asked most is: does the knowledge graph work with Obsidian-style links or with vectors (embeddings)? Today the answer is clear: links, not vectors. And it's worth understanding why, because each tool solves a different problem.
The Context's relationships are wikilinks ([[Another term]]) in the frontmatter, which a script resolves into typed, explicit relationships: is-a (hypernym ↑), type-of (hyponym ↓), related (↔). A typed link says exactly why two concepts touch. A vector would only say they're close, without the reason.
| Typed links (what I use) | Vectors / embeddings | |
|---|---|---|
| What they assert | «X is a type of Y», with the why | «X is close to Y», without the why |
| Strong at | precision and citability | fuzzy discovery |
| In git | one reviewable, diffable line | opaque; you have to re-embed |
| Best for | the graph's backbone | «similar articles», semantic search |
The defensible conclusion is links first: they're deterministic, they're reviewed in a pull request like any line of code, and each relationship carries its reason —which the site itself shows by telling you why one term is close to another—. Vectors are a useful future layer for what links don't cover: linking a concept mentioned with words other than its name. It's not «both today»; it's links for structure, vectors when you need recall.
The design system: a single source of components
The second layer solves the same underlying problem —things contradicting each other— but in the visual realm. Without a design system, each page reinvents its buttons and its color, and sooner or later they stop looking like each other. With it, the brand tokens —color, typography, spacing— and the reusable components live in a single place. apps/web doesn't invent buttons: it takes them from there. That way, a brand change is made once in the tokens and propagates to the whole site, without going page by page.
The diagram above is itself an example: it's not a standalone drawing, it's the ds:integrations/flow component from the design system. The article uses the same pieces it describes.
In practice
Before changing a glossary term I open its node, read its hot-paths and edit only that. If I move the code, I update the node's implementation layer in the same commit. Bidirectional synchronization, no exceptions.
This is, deep down, what Context Driven Development solves: thinking and building stop being two separate phases with a handoff in between —that point where documentation falls behind— and become a single system, where the blueprint, the design system and the code always tell the same story.



