Build Guide

Knowledge Graph Framework for Content Creation

A growing, per-person knowledge graph that captures what someone talks about, feeds on interviews + platform signals + analytics, and steers the next round of content. Distilled from a production system running the same pattern in a different domain — the concepts transfer directly.

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:

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:

Edge

The relationship. Directed, typed. Examples for a content graph:

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:

domainmeaningfeeds…
pillara core theme the person ownsinterview prompts, series planning
topica specific subject under a pillarindividual pieces
hot_takean opinion / contrarian stancehigh-engagement short-form
storya personal anecdote / examplehooks, B-roll narration
claima factual assertion they makecredibility, citations
voice_rulehow they phrase things / what they avoidstyle-matching the generator
signalsomething surfaced from a platform (comment theme, trending question)next interview questions
personawho they're talking toangle 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:

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)

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

Refuse these (they're what kills a KG)

  1. Near-duplicates — the #1 killer. Always search first.
  2. Transient chatter — "user asked me to draft a post about…", session logs. Save durable knowledge only.
  3. Aliases as owner — always the canonical slug.
  4. Sub-15-char stubs — give a real description or don't write it.
  5. Metrics as knowledge — numbers go in the metrics DB (§6).
  6. _shared for 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:

  1. A graph store — holds nodes + edges. (We use a lightweight engine called iii-engine wrapped by an extraction/embeddings layer called agentmemory; 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.)
  2. 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; emergent stays behind the wall). Put this in front of the graph on day one — retrofitting isolation later is miserable.
  3. 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 nodes
    • context — the curated, validated bundle for this person (their "ground truth")
    • remember — contribute a new insight (lands as emergent, awaits promotion)
    • whoami — confirm which namespace/scope you're bound to
    A person's content generator calls context to write in-voice; your ingestion pipeline calls remember to deposit emergent nodes; you promote via a review UI.
  4. Versioned snapshots — dump the whole graph to a sorted JSON file on a schedule and commit it to git. Now git diff between 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 pieceIn the graph
Monthly content interviewPrimary ingest event → a batch of emergent topic/story/hot_take nodes under the person's namespace
15–20 short-form videosGenerated from validated nodes; each output edges back to the topic it came from
Written content in their voiceSame validated nodes + voice_rule nodes drive a style-matched generator
Pulling signals from platformssignal nodes (emergent) → reviewed → become interview questions for the next round
Tracking content analyticsMetrics DB (not the graph); edges link topics → performance → re-weight which pillars to mine next
Personal brands + company brandOne 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.