The Knowledge Graph
On this page
This page is generated from docs/source/concepts-knowledge-graph/ — each section below links to its own source.
Everything this harness knows about itself is one graph: the Schemas that describe its content, the Skills an agent reads, the Workflows those Skills are invoked from, the Roles that own a lane, the Tools and Tests that exercise a Skill, and the running record of what is being worked on. That graph is the Knowledge Graph, bootstrap’s own term for it (called the KGraph until 2026-09-30).
Two sentences fix the whole model, and the rest of this page elaborates them.
An Agent utilizes Skills to execute one or more Tasks in a Workflow, with an associated Knowledge Graph of Static Context (Skills, User Stories) and Dynamic Context. Zero or more Tools may be associated with a Skill, for Test execution on an agentic-to-deterministic spectrum.
Knowledge Graphs are managed in git repositories, comprised of self-documenting JSON-LD. Content is rendered into various formats for consumption by downstream knowledge products, and by public-health, clinical-health and personal-health applications.
Three definitions come straight out of the first sentence and are used unchanged throughout:
- A Role is a swimlane, played by a human, agentic or mechanical Actor.
- A Task is a step in a Workflow — a node in the BPMN.
- A Skill is a Capability with defined inputs and outputs.
The Knowledge Graph is not one directory, and not one repository. An instance declares
the directories it scans and the kind of graph each holds, in its
<name>.json root declaration; a dependent instance inherits those and may add
its own. So the Knowledge Graph of a checkout is the union of what every instance in it
declares — which is why “where is the Knowledge Graph” has no filesystem answer, and why
a consumer asks for a kind rather than opening a path.
This page says what the subgraphs are, which way the references between them
run, how repositories divide the work, and how much of it is declared today. It
does not restate the declaration mechanism: that is
directory-conventions,
and the schema is
schemas/cat-harness.ts.
Two axes, and a word that already means a third thing
Two independent questions get asked about every subgraph, and reading either answer as the other is the mistake this section exists to prevent.
What is it about? Schemas, Skills, Workflows, Roles, Tools, Tests, Context, running state. This is the topical axis, and it is what the next section describes.
Does it change while a Workflow runs? This is the Static Context /
Dynamic Context split from the anchor sentence above, and the declaration
already answers it mechanically in the holds field of each kind: a graph is
content (a process produces it), context (a process reads it and never
writes it), state (a process writes it as it runs), or derived (something
else computes it).
holds | examples | |
|---|---|---|
| Static Context | content, context, derived | Skills, User Stories, Schemas, Workflows, methodologies, memories |
| Dynamic Context | state | beans, todos, Workflow instances, QA sidecars |
A step that writes to a context graph is a defect rather than an update,
which is the whole reason the field is REQUIRED — a kind that has not decided
does not compile.
The two axes are orthogonal. Skills and Schemas are both Static and are nothing like each other topically; memories and methodologies are both Static for entirely different reasons. Asking “is this a Skill?” tells you nothing about whether a Workflow may write to it, and asking “may a Workflow write to it?” tells you nothing about what it is for.
A third meaning of subgraph is already in circulation, and it is worth pinning before it spreads. Subgraph viewers uses it for one declared directory — the thing a visualiser draws and a Skill governs. This page uses it for a branch of the topical taxonomy. One topical subgraph is usually several declared directories across several instances, so the two readings are related but do not count the same things. Where the number matters, this page says declared directory or graph typology and leaves subgraph for the taxonomy.
The subgraphs
Schema
Every managed node has a definition — Zod authoritative, JSON Schema and JSON-LD generated from it — saying what shape it takes and what its fields mean. The Schema subgraph holds those definitions.
It arrives empty except for what is self-describing. A bare harness knows
how to describe a declaration, a directory and a kind; everything else is
contributed by the layer that introduces it. A harness that adds a content kind
adds its Schema in the same change, or the kind is unvalidated and its documents
are told apart by shape — which is the failure
directory-conventions
names when it says the files declare what they are.
Used for: validation at read time, the generated schema reference, and the
@context a published Knowledge Graph is parsed against.
Content
Instances of knowledge assets — the authored material a Schema describes and a Skill governs. Catalogues, documentation pages, themes, boards, translation sources, artefact indexes. Four subgraphs below are kinds of Content, listed separately because they are referenced differently, not because they are something else.
Used for: everything a reader or a renderer consumes.
Scenarios
Actors, the Roles they can take, and the User Stories those Roles are there to serve.
An Actor is a concrete participant — person, agentic or mechanical — and persists across Workflows. A Role is the swimlane: a persona an Actor takes on because of the lane it is acting in, carrying the Skills that lane needs. Nothing is a reviewer; somebody acts as reviewer for the duration of a lane, and the same Actor is a different Role in the next diagram.
Used for: binding a lane to what its occupant is expected to know, and auditing whether a Role’s Skills actually cover its lanes.
Workflows
Business process as BPMN, with DMN for the decisions. Prefer Workflow over process throughout: they were used interchangeably, and the inconsistency cost more than the synonym bought.
The diagrams are executable rather than illustrative. A lane binds a Role, an activity names the Skill to run, and a gateway MAY compute its branch from a DMN table. Instance state is committed, so a sibling session reads the same position rather than inferring one.
Used for: running the work, and being the single answer to “where are we”.
Skills
A Capability with defined inputs and outputs — the instruction body an Actor needs to perform a Task, stated generically so that it is portable across forges, binaries and machines by construction. A Content repository MUST constrain those inputs and outputs with a Schema; the consequence of not doing so is in Repositories below, and it is not a small one.
A Skill MAY be designated mechanical, human, or either. That is a property of the Capability, not of whoever happens to run it today.
Tools
The concrete mechanisms. A Tool names the Skills it satisfies through its
satisfies field, and one Skill MAY be satisfied by several Tools — which
is the point of the separation rather than an allowance. Several Tools for one
Skill is what lets the same Capability be exercised at different points on the
spectrum from fully deterministic to fully agentic, and compared.
Used for: keeping the mechanism out of the instruction. A Skill that names a vendor, a CLI or an endpoint has swallowed a Tool, and the swallowing is what makes a layer un-portable.
Tests
What adjudicates whether a Skill was performed, and how well. A Test exercises a Skill; the Tools associated with that Skill are what a Test runs it through. So the chain reads Test → Skill → Task, and a Test that names a Tool directly has jumped the Skill and measures a mechanism rather than a Capability.
Used for: quality control, compliance testing, and comparing model performance across modalities. Tests are the third repository class below.
Context
README files, memories, methodologies, recorded confirmations: what changes the conditions a Workflow executes in, without changing during execution. Applying a set of it deliberately — a Context Overlay — is what lets the same Workflow be run twice and the difference attributed to the context rather than to chance.
Used for: repeatable testing across conditions. Covered in full by Managing agent context.
Harness
The layer that renders the rest: the JSON-LD export, the visualisers, and the documentation. Its obligation is stated as three separate requirements because they fail differently — nothing draws it, nothing says what it is for, nothing an agent can invoke against it.
Used for: making a declared directory something a person can actually look at. A directory nobody can see is one nobody checks.
Dynamic Context
What is being worked on and how far it got. Written by processes as they run, committed so it survives a fresh container. It splits by who the state is for, which is a sharper line than what the state holds:
- beans — agentic state management. Used by Agents to coordinate and track internal state within a Workflow. “Changes to the vaccination schedule are ready for review at staging.”
- todos — human state management. Attached to a step in a Workflow or to a knowledge asset, for human Actors. “Please review this change in medication.”
A todo attaching to a knowledge asset and not only to a step is what makes the two stores genuinely different rather than one store with an audience field: a bean without a Workflow position is incomplete, and a todo on a chapter has no Workflow position to be missing.
Workflow instances, QA sidecars and health results are Dynamic Context too, written by the process that produces them.
Used for: the work plan, and the evidence that a claim about the corpus was measured rather than remembered.
Which way the arrows flow
A reference has a direction, and the direction is what makes the graph answerable. Every edge below is carried by a named field in a schema, so it can be followed mechanically rather than inferred:
| from | field | to |
|---|---|---|
| Actor | roles | Role |
| Role | skills | Skill |
| Voice | activeIn.roles | Role |
| User Story | role | Role |
| Workflow activity | <bootstrap.processes:skill ref> | Skill |
| Workflow lane | partitionElementRef → <bpmn:resource> | Role |
| Workflow activity | <cat-harness.processes:bean op> | a work-plan operation |
| Tool | satisfies | Skill |
| Skill, Capability | satisfies | Requirement statement |
| Skill | graph-typologies | Graph typology |
| Skill | input, output | Schema (its contract) |
| Test run | skill | Skill |
| any content node | $schema | Schema |
| Folio | the board layer | Board, then Position, then Note |
Three properties of that table are worth stating, because each one is a decision that could have gone the other way.
Skill is a sink. Roles point at Skills, Workflow activities point at Skills, Tools point at Skills, Tests point at Skills — and a Skill points at none of them. It names a Capability and does not know who holds it, what runs it, or what measures it. That is what lets one Skill serve several Roles, be satisfied by several Tools and be exercised by several Tests without editing the Skill.
It is also why the chain reads Test → Skill → Task rather than Test → Tool. A Test that names a Tool directly has jumped the sink and is measuring a mechanism instead of a Capability — which is exactly the comparison the several Tools per Skill allowance exists to make possible.
The Harness points at everything and nothing points back. A board is a
diagram of a folio in the OMG sense that a BPMNDiagram is a diagram of a
bpmn:process: the folio carries what is true, the layout layer carries where
it was drawn, and the arrow runs folio → board → position → note and never
back. A folio is complete with no board. The same asymmetry holds for every
visualiser: removing the rendering layer loses the picture and no content.
Workflows reference Context and never write it. The holds field makes
that enforceable rather than conventional — a step writing into a context
graph is a defect, not an update. This is the edge that makes a Context Overlay
possible at all: if a run could mutate its own conditions, replaying it under
the same conditions would not be a thing you could ask for.
User Story works this way too, as of #1168. CRDM produces Workflows, User
Stories and Roles, and Scenarios is where the User Stories belong. Until then a
Role carried its stories as useCases, free-text strings that could not be
pointed at, counted, or traced to a Workflow. Each story is now a node in
scenarios/stories.json that names its role, and the role names none — the
same direction as a voice, which points at the role it addresses.
Repositories — four classes, three relations
A Knowledge Graph is managed in git repositories, comprised of self-documenting JSON-LD, and rendered into whatever formats a downstream knowledge product, public-health system, clinical system or personal-health application needs. That makes a repository the unit of distribution, and repositories come in four classes. A class is defined by what it is ALLOWED to do, not by what it happens to contain.
Content repositories
Where the Knowledge Graph itself lives. A Content repository:
- MAY define Schemas for the Content types of a Knowledge Graph’s nodes.
- MAY instantiate instances of those Content types.
- MAY define the Skills needed to publish and consume those instances.
- MAY designate a Skill as mechanical, as human, or as either.
- MUST constrain a Skill’s inputs and outputs with Schemas.
That last clause is the only absolute requirement in the whole four-class model, and it is what makes the rest of it hold together. A Skill is a Capability with defined inputs and outputs; a Tool claims to satisfy a Skill; a Test claims to exercise one. If the Skill’s boundary is not written down as a Schema, “does this Tool satisfy that Skill?” has no answer anyone can check, and the agentic-to-deterministic comparison the Tool and Test classes exist for cannot be run at all.
Tool repositories
Where the mechanisms live, out of the Content repository on purpose. A Tool repository:
- MAY implement a Skill through coordinated use of Tools — scripts, retrieving and running software, remote or local services, containers.
- MAY expose Tools to agents as MCP services.
- MAY expose a Tool for local execution.
- MAY configure Tools for a test harness.
- MAY define more than one Tool for one Skill.
The last one is the point of the separation rather than an allowance. Several Tools for one Skill is what lets the same Capability be exercised at different points on the spectrum from fully deterministic to fully agentic, and compared.
Test repositories
Where adjudication, quality control and compliance testing live. A Test repository:
- MAY contain test data.
- MAY contain test-data generation templates and configuration data.
- MAY define Test Plans.
- MAY define test-language dialects such as Gherkin.
- MAY make test data available to a test harness, or to a subject-matter expert or author for review.
Consumer applications
The downstream end. A consumer application:
- MAY use a Knowledge Graph’s Schemas and instance data from a Content repository.
- MAY execute decision logic or indicator calculation from a Content repository.
- MAY use Test and Tool repositories when building, preparing for a connectathon, or compliance-testing.
Three relations run between repositories
The edges are not interchangeable, and each already has a carrier in the declaration — they had simply never been named as one set of three:
| relation | runs | carried by |
|---|---|---|
| depends | Content → Content | needs in the declaration — the layer stack, foundation first |
| references | Tool → Content, Test → Content | remoteGraphs — a graph this instance knows about and does not hold |
| utilizes | Tool → Tool, Test → Tool, App → Content, App → Test | dependencies in the config — what this instance USES, overlaid |
| associated | any harness ↔ any harness | associatedHarnesses — a harness this one knows, and where it is published; never loaded or materialized (issue #1146, skill associate-harness) |
Associated is a fourth, and it fixes no order: it is how a folio in another repository, such as ihris, is listed without being built here.
The three answer different questions, which is why collapsing them loses information a consumer needs. Depends is about layering: it fixes an order, so a cycle in it is a defect. References is about knowing a graph exists without holding it, so it crosses a repository boundary by definition. Utilizes is about consumption at run time, and a consumer application may utilize a Content repository it has no dependency on whatsoever.
What is declared today, measured
The taxonomy above is what the Knowledge Graph is for. What the registry can actually produce is narrower, and the gap is worth stating plainly: a reader who takes the taxonomy for an inventory will go looking for directories that are not there.
Measured on this instance, 2026-09-21, by reading the registry and every
instance declaration rather than by counting prose. Re-derive rather than
quote: bun run cat kg:export dumps the graph, and instanceRootsIn plus
readDeclaration give the directory census directly.
layer (holds) | registered kinds |
|---|---|
content | 13 |
state | 12 |
context | 5 |
derived | 1 |
Thirty-one kinds in total, of which exactly one — docs — is
renderable. Renderability is what wires a graph to the site build, so the
number being one is not an oversight: every other graph reaches a reader
through a visualiser the Harness layer builds over it, never by being
published directly.
Three of those kinds were one until 2026-09-21. cat-harness was declared
by 22 directories that between them held Skills, Workflows, Scenarios and
methodologies — four branches of the taxonomy above, indistinguishable to any
consumer filtering on kind. “Give me the Workflows” was not a query anybody
could write; it could only be approximated by matching a path, which is the
fragility the graph exists to remove. skills, workflows and scenarios are
now their own kinds and the query works.
cat-harness survives and is not deprecated, which surprises people twice
over. An alias cannot express a split — GRAPH_TYPOLOGY_ALIASES maps one name to
one name, and this would have to become three. And the kind had a fifth job the
split does not name: on an entry declaring ["schemas", "cat-harness"] it means
a schema IS a knowledge-graph node, which is why the skill scanner tests for
the kind exactly rather than for its presence. That job is still real, so
the umbrella stays, now meaning harness knowledge-graph content whose directory
holds more than one part of it — the eight mixed schema entries. A downstream
declaration still saying ["cat-harness"] keeps parsing and keeps being scanned
for Skills; what it loses is the finer query, which it never had.
What the split cost, and where it nearly went wrong. Two directories that
had been reached by convention stopped being reached the moment their parent
changed kind: processes/ and methodologies/crdm/processes/ both sat
inside a cat-harness directory and were found by walking it. Each declared
workflows in its own right. (CRDM’s eight diagrams moved into processes/ on
2026-09-22 and that second declaration is gone, so only the first survives —
the episode is recorded here in the past tense because it is what the orphan
report caught, not a description of today’s layout.) The second was caught only because the generated
process index reported it as an orphan rather than quietly indexing eight
fewer diagrams — which is the whole argument for a generator that names what it
pruned.
One gap remains, already named above:
fsh-gutsis registeredcontext, though it is topically Dynamic State. Both readings are defensible — it is read by processes and not written by them, which is whatcontextasserts — but the two axes disagree here, and a disagreement nobody has written down is one that gets rediscovered.
How a dependent contributes into a shared body of knowledge. Through the
kind, and that is the mechanism rather than a stopgap — settled by the
owner, 2026-09-21. Three instances — agent-skills, cat-harness and
who-style-guide (since folded into the IRIS replica, bean qsx4) — each declared their own voices/ directory of kind
voices, and the overlay resolves all three together. A fourth instance
wanting to contribute a Voice declares a directory, names the kind, and is
done: no nesting, no subgraph declaration, nothing added to the schema.
The alternative considered and set aside was letting a directory entry declare
nested subgraph directories, so that a shared body would live at a path such as
skills/voices/ and dependents would add under the same path. It buys a
hierarchy that nothing currently needs, at the cost of a schema change, a
migration of every in-tree declaration, and an alias carried for downstream
ones. The overlay already delivers the outcome, and it is already proven by
three instances.
Where the rules live
This page is a map. The discipline is in the Skills, and where a Skill and this page disagree, the Skill wins and this page is wrong.
| question | where it is answered |
|---|---|
| How an instance declares its directories, and every graph typology | directory-conventions |
What content, context, state and derived each promise a consumer | content-context-and-state-graphs |
| Actors, Roles, Permissions, and why a Role is a swimlane | role-model |
| Authoring a Workflow activity, and what a bean-marked step performs | bpmn-processes |
| Which store answers which question about a running Workflow | workflow-state |
| Why a Skill states a capability and a Tool the mechanism | skills-and-tools |
| Context Overlays, and the several ways context is generated | Managing agent context |
| What a visualiser owes a declared directory | Subgraph viewers |
The schema behind every declaration on this page is
schemas/cat-harness.ts;
the Role and Actor shapes are in
scenarios/roles.json
and cat-harness/scenarios/actors/; the Tool shape is
schemas/tool.ts.
The audit that checks these joins actually resolve is bun run cat kg:audit, one
criterion per join, written as committed QA sidecars so that “unbound since it
was drawn” and “broken in the commit under review” stay distinguishable.