Build log · Month 7 of 12
Knowledge Graphs: Model the Relationships
the shared idea under CalDesk's "healthier swaps" and Aether's DeFi graph. Ontology design, entity resolution, GraphRAG, and why the questions worth asking are relational.
- Day 176
Knowledge-graph month. Two apps, one idea. CalDesk models food ("healthier swap for this?"). Aether models DeFi tokens ("is this the real USDC?"). Both are graphs because the valuable questions are about relationships — edges, not columns. Same spine, two domains.
- Day 177
Ontology first, always. Before a single node, I define entity and relation types. CalDesk: Food, Nutrient, Category; relations "is-source-of," "is-swap-for," "belongs-to." Get the schema wrong and every query fights you forever. The ontology is the constitution.
- Day 178
CalDesk's killer feature is "healthier swaps": log white rice, get brown rice or quinoa — same role in a meal, better Nutri-Score. That's a graph traversal: find foods sharing the "meal role" edge, rank by nutrition delta. A flat food table can't answer this.
- Day 179
Nutri-Score as a ranking function: it compresses a food's nutrition into a comparable grade (A–E). The swap engine finds foods in the same category and surfaces the better grades. The graph finds candidates; Nutri-Score ranks them. Structure plus scoring.
- Day 180
Entity resolution is the unglamorous heart of any graph. "Greek yogurt," "yogurt, greek," "yoghurt (greek)" are one node, not three. Get dedup wrong and your graph fragments into synonyms that don't connect. I spent more time merging than on any query.
- Day 181
🧵 Thread: how I build a knowledge graph that's useful, not a demo.
- Ontology first: define entity + relation types before ingesting anything.
- Extraction: pull entities + relations from your source into that schema.
- Resolution: merge duplicates ruthlessly. "Greek yogurt" and "yogurt, greek" are ONE node.
- Serving: GraphRAG — retrieve a relevant subgraph, feed it to the LLM as grounded context.
- Payoff: relational questions a table can't answer — "healthier swap," "same deployer as a scam."
- Day 182
GraphRAG is why CalDesk's AI doesn't hallucinate your nutrition. Instead of asking the LLM "is quinoa healthier than rice" from memory, I retrieve the relevant food subgraph and feed it as context. The LLM reasons over facts I gave it, not vibes it half-remembers.
- Day 183
The rule that keeps CalDesk honest: the LLM never invents a number. Macros, Nutri-Score, swap candidates all come from the graph. The AI's job is phrasing and reasoning over retrieved facts, never being the source of them. Hallucinated calories are worse than no app.
- Day 184
Aether's DeFi graph, same machinery: nodes are tokens/pools/protocols, edges are "paired-with," "deployed-by," "wrapped-version-of." "Is this token legit?" becomes "does its contract match the canonical node, and who deployed it?" Fraud detection is a graph query.
- Day 185
Deployer-reputation caught a scam token this month. The edge "deployed-by → address that also deployed 3 known scams" is a one-hop traversal. No price data, no ML model, just graph structure. Sometimes the fanciest-sounding feature is a well-designed JOIN.
- Day 186
🧵 Thread: ontology mistakes I made building the graphs, and the fixes.
- Modeled "Nutrient" as a property of Food. Couldn't ask "foods high in iron." → made it a node.
- Left Nutri-Score as a bare number. → gave it provenance so I can trace and fix it.
- Let swap edges cross categories (apple for rice). → constrained swaps to same role.
- Treated every extracted edge as certain. → added confidence scores; suppress the low ones.
- Rule: if you'll ever query FROM a thing, it's a node, not a field.
- Day 187
Graph storage decision: I don't run a heavyweight graph DB for these. The graphs are big-ish but bounded, so I model nodes/edges in the existing store with good indexes and traverse in code. A dedicated graph DB is a dependency I didn't need yet. Right-size the tool.
- Day 188
The "swap" edge needed a quality gate: a healthy swap must preserve the food's role. Suggesting an apple for rice is nutritionally "better" and culinarily insane. So swap edges are constrained to same-category. Unconstrained graphs suggest nonsense confidently.
- Day 189
Freshness problem: the DeFi graph decays fast — new tokens, pools, scams daily. A stale fraud graph is a dangerous one. I built incremental ingestion that updates edges continuously rather than rebuilding nightly. A knowledge graph is a living thing or a liability.
- Day 190
Opinion: "add AI" is usually the wrong instinct. "Add structure, then point AI at it" is almost always right. The graph makes the AI trustworthy. Without grounding, an LLM in a nutrition app is a confident liar with a nice UI. Structure turns a chatbot into a product.
- Day 191
Provenance matters: every fact should know where it came from. When CalDesk says a food's Nutri-Score, I can trace it to the source. When something's wrong (and it will be), provenance is how you fix the cause, not the symptom. Facts need footnotes.
- Day 192
Edge weights turned "healthier swap" from a list into a ranking. Not all swaps are equal — some a big nutrition win, some marginal, some the user won't accept. Weighting by nutrition delta and similarity gives an ordered list. Unweighted graphs give a pile.
- Day 193
Hard UX lesson: users don't want to see the graph. They want the answer it produces. I built a beautiful node-link visualization and nobody cared; they wanted "eat this instead." The graph is infrastructure, not interface. Hide the machinery, ship the outcome.
- Day 194
Cross-app reuse win: CalDesk's graph engine and Aether's share the same core traversal + resolution code, specialized by ontology. Two wildly different domains, one graph spine. The studio thesis in miniature — build the general engine once, specialize cheaply.
- Day 195
Confidence scores on extracted relations save you from your own graph. Not every edge is certain. Low-confidence swaps get suppressed or labeled. Treating every edge as gospel is how you confidently recommend nonsense. The graph should know what it doesn't know.
- Day 196
Month 7 lesson: knowledge graphs aren't academic. They're how you answer relational questions — swaps, lookalikes, "same deployer as" — a flat schema can't touch, and how you ground an LLM so it stops lying. Structure is a feature users feel without seeing.
- Day 197
Honest status: CalDesk and Aether are the smartest apps in the fleet and still early on users. Great engineering keeps not being the bottleneck. 197 days in, the graph, the wallet, the real-time system — none of it matters until someone installs it.
- Day 198
Next month I finally stop dodging money. RevenueCat, AdMob, paywall design, free-trial psychology, and — if it happens — the single most important tweet of the year: the first paying customer. Time to find out if any of this can pay for itself.
- Day 199
Before I leave graphs: the same GraphRAG pattern keeps GhostOS (the assistant) grounded — retrieve context, reason over it, never freewheel. The knowledge-graph spine quietly touches half the fleet. Build the general capability, harvest it everywhere.
- Day 200
Day 200. Two hundred days in public, and the through-line is loud: I can build almost anything, and I've sold almost nothing. Not failure, a diagnosis. The disease is distribution. Next month I start treating it directly, beginning with the money.