Skip to content

Enrichment & the Knowledge Graph

A chapter that mentions React, Go, or Linus Torvalds is more useful when the reader — or an AI assistant answering a question about it — can pull up what React actually is, how many people star it this week, or which language a repository is mostly written in. Enrichment is how the platform adds that context. It links the things a piece of content talks about to a shared, living record of what those things are, without copying any of it into the text.

That shared record is the Knowledge Graph — a global registry of real-world things: people (authors, maintainers, speakers), code repositories, programming languages, technologies, and many more types over time. The graph knows what React is exactly once, for the whole platform. Your tenant simply knows where in your content React is mentioned. Those two facts are kept deliberately apart, and that split is the single most important idea on this page.

The other important idea is that enrichment never disturbs the content it enriches. When a repository gains ten thousand stars overnight, nothing about your chapter changes — no new version, no re-processing, no cache to invalidate wholesale. The link between content and the graph lives in a separate layer, the entity overlay, that points at the content by position rather than being woven into it. This page explains what the graph holds, why the overlay design keeps content stable, how links are made (automatically and by hand), and how to cache the result safely.

What the Knowledge Graph is

The Knowledge Graph is a registry of real-world entities. Each entry — a knowledge-graph entity — has a stable, system-generated identity (a kg_ ID such as kg_lang_go), a canonical name, a set of aliases, and type-specific metadata that the platform keeps fresh from external sources: GitHub statistics, public profiles, release histories, and so on.

The standard entity types today are:

Type Represents Example metadata
person A notable person relevant to content biography, professional profiles, associated languages
github A GitHub repository description, licence, stars/contributors/commits, language breakdown
language A programming language paradigms, year first appeared, official website
technology A framework, library, or tool category, website, related technologies

The set grows over time — community, organisation, conference, package, protocol, licence and more are anticipated — and it grows without a breaking change. New types simply appear; consumers that do not recognise a type fall back to its name and carry on. See the Roadmap below.

An entity is a real-world thing, not your content

A knowledge-graph entity is React the framework, not the paragraph in your book that mentions React. The graph is a map of the world content refers to. What links your content to that map is the overlay, described next. The word "entity" is overloaded on the platform — see the Glossary for the three distinct meanings.

Global registry, tenant references

The graph is global by design. kg_gh_chi names the same GitHub repository for every tenant, and refreshing its metadata refreshes it once, for everyone. This is a deliberate carve-out from the platform's normal rule that everything belongs to exactly one Tenant — and it is safe because of a strict division of what lives where:

  • The registry holds public-world facts only. Entity names, aliases, and metadata such as GitHub stats and published profiles. Nothing in the registry records which tenants, Resources, or blocks mention an entity.
  • References are tenant-scoped and live with your content. Which Resource mentions which entity, and exactly where, sits inside your tenant's partition of the Content Lake. It is never visible across tenants — or even to the registry itself.

The one-liner worth remembering: the graph knows what React is once; your tenant knows where you mention it.

flowchart TD
    subgraph tenant [Your tenant]
        C["Content (PCF)<br/>Chapter 3"]
        O["Entity overlay<br/>block b2, chars 56–66 → chi"]
        C -.->|annotated by| O
    end
    subgraph global [Global — no tenant]
        KG["Knowledge Graph registry<br/>kg_gh_chi · kg_lang_go · kg_person_…"]
    end
    O -->|references by kg_id| KG

Global events carry no tenant

Because the registry is global, the Knowledge Graph's events (a new entity registered, metadata refreshed, two duplicates merged) carry no tenant_id — the one documented exception to the platform's event convention. Consumers that care about a change apply their own per-tenant fan-out. The Content Lake, for instance, works out which of your Resources reference a refreshed entity and updates their overlays; the registry never learns which those were.

Why content never re-versions

The link between your content and the graph is the entity overlay: a separate JSON layer, sitting alongside the content, that pins each entity to the exact place it appears. It addresses content by position, not by editing the content itself:

  • Block key — which block of the content the mention sits in, by the block's stable _key.
  • Character range — a zero-based, half-open range within that block's plain text, measured in Unicode code points.

This positional addressing is what makes enrichment free of side effects. Entity metadata is computed and volatile — detection improves, new types are added, a repository's star count changes daily — and none of that is authorial intent. Keeping it in a companion document rather than as marks inside the content buys four things:

  1. The content is the source of truth. It renders, edits, and versions with no awareness of entities at all.
  2. Entities evolve independently. Metadata can be refreshed and detection re-run without touching a single byte of content — so refreshing stars, releases or profiles never creates a new content version.
  3. Overlapping mentions are trivial. Two entities can reference the same or crossing character ranges in one block with no structural conflict — impossible if entities were span-level marks, which demand identical boundaries.
  4. Consumers opt in. A pipeline that does not need context simply ignores the overlay.

Because the overlay is keyed by position and the graph is referenced by kg_id, a metadata refresh updates the registry entry and, at most, the copy of metadata cached in your overlay — never the content. A block's entities are computed once per block and reused across every version that shares that block, so identical content is never re-enriched.

How it works under the hood

The overlay is a JSON document with a contentRef (a cl:// URI naming the content and version it was computed against), a generation timestamp, and an entities array. Each entity carries _type, _id, an optional kg_id (null until resolved in the graph), a name, confidence and salience scores, its cached metadata, and a mentions array. Each mention gives a blockKey plus a startChar/endChar range (both omitted for a whole-block reference, e.g. tagging an image). Character offsets are measured in Unicode code points against the block's plain text — the ordered concatenation of its span text values — which is what keeps them stable across producers. See the JSON below for the full shape.

Two paths put entities into the overlay.

Enrichment runs on every content change. It reads the text, spots mentions of things it recognises, resolves each against the graph, and writes them into the overlay. Detection runs a quick first pass at ingestion, then richer passes follow as more of the content is understood — which is exactly why the caching rules below treat freshly ingested content with caution. Detection quality varies by type: github entities, for instance, are currently detected reliably only where a full repository URL appears (printed or linked); recognition of looser textual references improves over time. Automatically detected entities carry a confidence score.

Editors can add an entity reference in the Content Lake editor where automatic detection missed one — a repository named in prose without a link, say. Manually tagged entities omit the confidence score, since a human vouched for them.

Whichever path adds a mention, resolution against the graph is the same step. A confident, previously unseen thing is registered as a new entity; a low-confidence mention stays in the overlay unresolved (kg_id: null) and never creates a registry entry. When a mention resolves to a real-world thing already in the graph, it simply points at the existing kg_id — this is how deduplication happens, so the graph holds one entry per real-world thing rather than one per mention.

Person entities are discovered, not decided

Not everyone has a person entity, and having one — or not — is never an editorial judgement. Person entities are discovered and created as the Content Lake grows. Traits that make inclusion likely: being an author, a contributor (particularly on GitHub), a speaker, a reviewer, or someone referenced across multiple published works.

Reading and consuming entities

Entities reach you through the Public API as the overlay for a Resource, or as filters in search. The common needs:

Need How
Entities in one Resource Request the Resource's overlay, or ask for the entities field inline.
Content mentioning an entity, across your tenant Search with an entity filter — the graph knows the kg_id, your search index knows where it appears.
Entity-aware relevance Hybrid search resolves entities in the query and merges entity-filtered results automatically.
Live entity metadata Read the overlay's metadata; treat it as eventually consistent.

When you build a consumer, prefer a Packt client library where one exists — they track new entity types as they ship. Whatever you use, handle unknown types by falling back to name and the mention's text; both are always present, so a type you have never seen still renders as readable text rather than breaking your parser. You can also make parsers leaner by enabling only the entity types you care about.

An entity overlay (JSON)

A chapter titled Building APIs with Go and Chi enriched with a language, a repository, and two people. Note the two entities referencing independent ranges in the same block (b1), and the unresolved-until-linked kg_id.

{
  "$schema": "https://schema.packt.com/pcf/entity-overlay/v1.0.0",
  "contentRef": "cl://packt/document/res_go_tooling/latest",
  "version": "2026-03-23T10:30:00Z",
  "entities": [
    {
      "_type": "language",
      "_id": "ent-lang-go",
      "kg_id": "kg_lang_go",
      "name": "Go",
      "confidence": 0.96,
      "salience": 0.85,
      "mentions": [
        { "blockKey": "b1", "startChar": 19, "endChar": 21, "text": "Go" },
        { "blockKey": "b2", "startChar": 0, "endChar": 2, "text": "Go" }
      ],
      "metadata": {
        "about": "An open-source programming language supported by Google",
        "paradigm": ["concurrent", "imperative", "compiled"],
        "firstAppeared": 2009,
        "website": "https://go.dev"
      }
    },
    {
      "_type": "github",
      "_id": "ent-gh-chi",
      "kg_id": "kg_gh_chi",
      "name": "chi",
      "confidence": 0.94,
      "salience": 0.70,
      "mentions": [
        { "blockKey": "b1", "startChar": 26, "endChar": 29, "text": "Chi" },
        { "blockKey": "b2", "startChar": 56, "endChar": 66, "text": "Chi router" }
      ],
      "metadata": {
        "href": "https://github.com/go-chi/chi",
        "about": "Lightweight, idiomatic and composable router for building Go HTTP services",
        "license": "MIT",
        "stats": { "stars": 18900, "contributors": 120, "commits": 1450 },
        "languages": [
          { "name": "Go", "proportion": 0.98, "kg_id": "kg_lang_go" }
        ]
      }
    },
    {
      "_type": "person",
      "_id": "ent-person-peter",
      "kg_id": "kg_person_peter_kieltyka",
      "name": "Peter Kieltyka",
      "confidence": 0.88,
      "salience": 0.30,
      "mentions": [
        { "blockKey": "b2", "startChar": 70, "endChar": 84, "text": "Peter Kieltyka" }
      ],
      "metadata": {
        "about": "Creator of the Chi router for Go",
        "profiles": [
          { "name": "github", "url": "https://github.com/pkieltyka" }
        ]
      }
    }
  ]
}
A new entity type a consumer has never seen (JSON)

Adding a type needs no schema change. A consumer that does not understand community skips it, using name and text, and keeps going.

{
  "_type": "community",
  "_id": "ent-comm-golang",
  "kg_id": "kg_comm_r_golang",
  "name": "r/golang",
  "confidence": 0.91,
  "salience": 0.35,
  "mentions": [
    { "blockKey": "b6", "startChar": 22, "endChar": 30, "text": "r/golang" }
  ],
  "metadata": {
    "platform": "reddit",
    "url": "https://www.reddit.com/r/golang",
    "subscribers": 245000
  }
}

Caching

Overlays are recomputed as the Knowledge Graph evolves and as detection improves, so cache them with care. Freshly ingested content is the case to watch: its first-pass enrichment is deliberately quick, with richer passes still to come, so an overlay read minutes after ingestion may be incomplete.

Consumer Guidance
Editing applications Do not cache overlays.
Internal tools Short-lived caches only (under 60 seconds).
End-user applications Up to 1 hour — and only for content ingested more than 24 hours ago. Newer content may still be undergoing enrichment; use short caches until the 24-hour mark.

Enrichment is never in an end state

Entities are constantly evolving — new types, new attributes, refreshed metadata. Content you consume today may carry richer context tomorrow. Design for that: treat overlay metadata as eventually consistent, and never assume the set of entities on a Resource is final.

Roadmap

The four standard types are the start. Planned additions, grouped — tell the Packt tech team if you need one of these or a type not listed, as prioritisation follows demand:

  • Communities and organisations — community (Reddit boards, Discord servers, Slack workspaces, mailing lists), organisation (companies, foundations, standards bodies), conference (KubeCon, PyCon, GopherCon).
  • Content and learning — book (with ISBN/edition metadata), course, paper (DOI, authors, venue), RFC/specification, dataset, blog post, tutorial, newsletter, podcast, documentation, Q&A, conference talk, slide deck, workshop, changelog/release notes.
  • Software and infrastructure — package (npm, PyPI, Go modules, crates.io), API, cloud service, platform, CLI tool, and code repositories beyond GitHub (GitLab, Bitbucket, self-hosted).
  • Concepts — design pattern, algorithm, protocol, licence.
  • Content Lake overview — the estate this enrichment layers onto.
  • Content format — the block-and-span structure the overlay addresses by _key and character range.
  • Resources & versions — why an unchanged block is never re-enriched across versions.
  • Search — finding content by the entities it mentions.
  • Glossary — one-line definitions for Knowledge Graph, entity, and overlay.
  • Explorer — Chapter V — enrichment and the Knowledge Graph, visualised.