0The one-line idea
A knowledge graph is not a pile of transcripts. It's a deduplicated set of atomic facts, each filed under one owner, each tagged by what kind of thing it is, each carrying a trust level — connected by edges. That structure is what makes it grow usefully instead of turning into a swamp.
Everything below is in service of that sentence.
1Why a graph (and not just a database or a vector store)
You could dump interview transcripts into a folder and RAG over them. That gets you recall, not a model of the person. A graph gives you three things a blob of text can't:
- Identity — every fact belongs to a specific person's namespace, so "their voice" stays theirs and never bleeds across clients.
- Structure — a topic, a story, a claim, and a hot-take are different kinds of node with different downstream uses. You can ask "show me every recurring theme for this person, ranked by how often it lands" — impossible over raw text.
- Trust — a half-formed idea from a signal scrape and a confirmed core message are not equal. The graph tracks that difference and only lets confirmed material drive output.
Use a graph DB for the knowledge (nodes + edges); use a normal relational DB for the metrics (view counts, watch-through, follower deltas). Keep them separate — see §6.
2The data model
Node
The atom. One durable idea. In our system a node looks like:
{
"id": "topic_ai_agents_replacing_sdrs", // stable, human-readable, unique
"type": "concept", // concept | observation
"name": "AI agents will replace SDRs", // concise, searchable title
"domain": "hot_take", // what KIND of thing this is (see §3)
"owner": "jane-doe", // the namespace — one person (see §4)
"trust": "validated", // emergent | validated | core (see §5)
"description": "Jane's recurring argument that outbound SDR teams get replaced by
agentic pipelines within 2 years. Framed around cost-per-meeting,
not headcount. She tells the '3-person team outperformed 30' story
when making this point.",
"properties": { "first_seen": "interview-2026-05", "times_used": 4 }
}
Two rules that matter more than they look:
descriptionis the real body, self-contained, and >15 characters. If it's a stub, it's useless downstream — a generator can't do anything with "AI stuff." Write the whole idea.- One idea per node. Not a wall of text, not a trivial fragment. If a transcript paragraph contains three distinct claims, that's three nodes.
Edge
The relationship. Directed, typed. Examples for a content graph:
elaborates_on— a story node → the topic it illustratescontradicts— a newer take → an older one (people evolve; capture it)belongs_to— every node → its structural parent (see §7)sourced_from— a node → the interview / post / signal it came fromperforms_well_as— a topic → a format (short-form, thread, newsletter)
Edges are where the compounding value lives. "What topics elaborate on this pillar theme, and which format did each perform best in?" is one traversal.
3domain — what kind of node this is
domain is the most important tag. It drives how the node is used and
where it's filed. For a content system, a starter taxonomy:
| domain | meaning | feeds… |
|---|---|---|
pillar | a core theme the person owns | interview prompts, series planning |
topic | a specific subject under a pillar | individual pieces |
hot_take | an opinion / contrarian stance | high-engagement short-form |
story | a personal anecdote / example | hooks, B-roll narration |
claim | a factual assertion they make | credibility, citations |
voice_rule | how they phrase things / what they avoid | style-matching the generator |
signal | something surfaced from a platform (comment theme, trending question) | next interview questions |
persona | who they're talking to | angle selection |
Adjust to taste — but pick a closed set and stick to it. A freeform tag field turns into chaos within a month.
Note the split: pillar/topic/hot_take/story/claim/voice_rule are
knowledge. signal is raw input that gets
refined into knowledge. Metrics (views, likes) are not nodes at all (§6).
4owner (namespace) — one canonical value, never an alias
Every node belongs to exactly one owner. For your model this is elegant:
- One namespace per personal brand —
jane-doe,john-smith, etc. This is "their database of what they talk about." Isolated: Jane's graph never leaks into John's. - One namespace for the company brand —
acme-co. This is the "brand in the middle" you mentioned. The team's shared themes live here. - A
_sharednamespace (optional) — cross-brand playbook knowledge: "hooks that open with a number outperform," "questions get more comments than statements." Operator-level. Deliberately does not inject into any one person's voice — it informs you, not their content.
The alias trap (learned the hard way): the same person will get
written three different ways by three different tools — jane-doe,
Jane Doe, jdoe. Pick the slug as canonical
(jane-doe) and normalize every inbound id to it on the way in.
Keep a small alias map (jdoe → jane-doe). If you don't, you wake up with a
fragmented graph — half her facts under one id, half under another — and reconciling
later is painful. Normalize at the boundary, once.
Never file a fact under a namespace that doesn't inject into that person's context. A
fact about Jane goes under jane-doe, not _shared.
5Trust tiers — the thing that keeps the graph clean
This is the single most valuable idea to steal. Three tiers:
emergent → validated → core
(proposed) (confirmed) (foundational, rarely changes)
emergent— anything auto-extracted or freshly proposed. A theme pulled from a transcript, a topic inferred from a spike in comments. Cheap to create, not trusted, does not drive output yet.validated— a human looked at it and confirmed it's real and on-voice. This tier and above is what the content generator is allowed to use.core— the person's foundational pillars / non-negotiable voice rules. Changes rarely; promotion gated to an admin.
Promotion is a human gate, always. An interview drops 40 emergent topic nodes; the person (or their strategist) skims a review queue and promotes the 12 that are actually "them." Only those steer the next interview and the content output. This is the mechanism that stops noise from compounding — without it, every scraped comment and every tangent becomes "knowledge" and the graph degrades into a transcript dump with extra steps.
A hard-won law worth internalizing: a knowledge node earns its keep only if it holds a hard, specific, ownable fact. Generic boilerplate ("Jane cares about growth") adds nothing to generated content and actively dilutes it. "Jane's 3-person team booked more meetings than a 30-person SDR floor, and she frames it as cost-per-meeting" is a node worth having. Be ruthless about the difference.
6The knowledge / metrics boundary
The graph holds knowledge, strategy, voice, themes. A normal DB holds IDs, records, and numbers. Do not put view counts and watch-through rates in the graph as nodes.
Why: metrics are high-cardinality, time-series, and change constantly. Nodes are durable facts. Mixing them bloats the graph and tempts you to inject numbers into content generation where they don't belong.
Instead: metrics live in a relational table keyed by content_id. The graph
references them by edge when useful (topic → performed_as → [content_id]). When
you want "which pillars are trending down," you join, you don't traverse.
One gotcha if you paginate reads from that metrics DB to aggregate: always sort
by a stable key (e.g. ORDER BY id). Paginated reads without a
guaranteed order silently skip and double-count rows — you'll get different totals on
every run and never know why.
7Structure: root → class → entity
Don't hang thousands of nodes directly off a root — you get an unusable hairball and the visualization melts. Instead, one structural spine:
owner root (jane-doe)
├─ class: Pillars ─┬─ pillar node ─┬─ topic ─ story
│ └─ pillar node └─ topic ─ hot_take
├─ class: Signals ─── signal ─ signal ─ signal
├─ class: Voice ─── voice_rule ─ voice_rule
└─ class: Retired ─── (tombstones — see §9)
Each entity gets exactly one belongs_to edge to its class
(its structural parent). Semantic edges (elaborates_on, contradicts,
etc.) are orthogonal — a node can have many of those. This keeps enumeration cheap
("give me every pillar" = read one class node's children) while letting meaning connect
freely across the graph.
Practical tip: if your graph engine's query is "dump everything" by default, a class node becomes a cheap named seed for a bounded neighbourhood read (start at this class, depth 1) — so you enumerate one category without pulling the whole graph.
8The emergent loop (how the graph gets smarter every cycle)
This is the engine. It's the exact flow you described, formalized:
Interview transcript ─┐
Platform signals ─────┼──▶ extract atomic candidates ──▶ EMERGENT nodes
Comment themes ──────┘ (dedup-checked) │
▼
human review queue
│
promote the real ones │ (discard the rest)
▼
VALIDATED nodes
│
┌───────────────────────────────────────┤
▼ ▼
steer NEXT interview drive content generation
(ask about under-covered pillars, (short-form scripts + written
follow up on high-signal topics) content, matched to voice)
│ │
└────────────── analytics ◀──────────────┘
(which topics/formats landed →
re-weight pillars, spawn new signals)
Every loop: new material in as emergent → human promotes → validated knowledge grows → better prompts and better output → analytics tell you what worked → that becomes new signals → next loop. The graph is the memory that makes each round build on the last instead of starting cold.
No LLM required for the parts that don't need one. If your signals already carry a label (a platform gives you comment categories, or you tag them on ingest), you can cluster them into emergent nodes with plain code — reserve the LLM for genuinely unstructured transcript extraction.
9Conventions for good nodes (and the anti-patterns to refuse)
A good node
name: concise, searchable title.description: the real, self-contained body, >15 chars, one idea.- Correct
owner(canonical slug), correctdomain,emergenttrust unless a human is promoting. - Deduped — search the graph before writing. If a near-match exists, refine it or skip; don't add a twin.
Refuse these (they're what kills a KG)
- Near-duplicates — the #1 killer. Always search first.
- Transient chatter — "user asked me to draft a post about…", session logs. Save durable knowledge only.
- Aliases as owner — always the canonical slug.
- Sub-15-char stubs — give a real description or don't write it.
- Metrics as knowledge — numbers go in the metrics DB (§6).
_sharedfor person-specific facts — they won't reach that person's content.
No hard deletes. When something is wrong or outdated,
tombstone it (move to a Retired class / set
domain: retired) rather than deleting. You keep the history, diffs stay
clean, and nothing that referenced it breaks. A wrong fact gets retired, not erased.
10Architecture shape (the moving parts)
You don't need our exact stack, but the roles are what matter:
- A graph store — holds nodes + edges. (We use a lightweight engine
called
iii-enginewrapped by an extraction/embeddings layer calledagentmemory; Neo4j or any property-graph DB works too. The embeddings layer is what gives you semantic search — "find nodes about pricing objections" without exact keywords.) - A boundary / gateway — the single chokepoint every read and write
passes through. It does three jobs: normalize identity (alias →
canonical slug), enforce scope (a per-person key can only read/write
that person's namespace), and trust-gate reads (only
validated+ flows out to content generation;emergentstays behind the wall). Put this in front of the graph on day one — retrofitting isolation later is miserable. - An access layer for the AI — expose the graph to your content tools
as a small set of verbs. Ours (via MCP, so it drops straight into Claude / Cursor / any
agent):
search— semantic search across the person's nodescontext— the curated, validated bundle for this person (their "ground truth")remember— contribute a new insight (lands asemergent, awaits promotion)whoami— confirm which namespace/scope you're bound to
contextto write in-voice; your ingestion pipeline callsrememberto deposit emergent nodes; you promote via a review UI. - Versioned snapshots — dump the whole graph to a sorted JSON file on a
schedule and commit it to git. Now
git diffbetween two days is your change log — you can see exactly what the person's knowledge grew by this week. Cheap, and surprisingly powerful for showing a client their brand database expanding over time.
11How this maps to your offer, concretely
| Your piece | In the graph |
|---|---|
| Monthly content interview | Primary ingest event → a batch of emergent topic/story/hot_take nodes under the person's namespace |
| 15–20 short-form videos | Generated from validated nodes; each output edges back to the topic it came from |
| Written content in their voice | Same validated nodes + voice_rule nodes drive a style-matched generator |
| Pulling signals from platforms | signal nodes (emergent) → reviewed → become interview questions for the next round |
| Tracking content analytics | Metrics DB (not the graph); edges link topics → performance → re-weight which pillars to mine next |
| Personal brands + company brand | One namespace per person + one for the company; _shared for your cross-client playbook |
| "As low-lift as possible for the client" | The client only touches the promotion review (skim, approve the real ones) — everything else is automated ingest → generate |
The whole thing is one emergent loop (§8) running monthly, with the graph as the memory that makes month 6 far sharper than month 1.
12If you build one thing first
Build the owner → emergent node → human-promote → validated spine before
anything fancy. Skip the fancy graph engine at first if you want — even a single table with
(id, owner, domain, trust, name, description) plus an edges table gets you 80%
of the value. The trust gate and the dedup discipline are what make it a knowledge graph;
the storage tech is swappable.
Add semantic search, the MCP access layer, and versioned snapshots once the loop is turning. Don't build the boundary/scoping after you have real client data in there — build it before.