Skip to main content
The Knowledge Catalog stores domain knowledge as Open Knowledge Format (OKF) bundles and grounds a model call on them at request time. A bundle is a set of markdown files with YAML frontmatter; on an opted-in request the gateway picks the concepts that match the user’s turn and injects them as one system message before the provider is called, so GPT, Claude, and Gemini all answer from your knowledge without the client resending it. Grounding is opt-in per request through a single metadata field, so a call is only ever touched when you ask for it
OKF is markdown plus YAML frontmatter under an Apache-2.0 spec, so a bundle you author here is portable to any other OKF tool. ForceAI adds the catalog, the governed store, and the injection hook that makes an agent actually use it

How it fits together

Import and grounding run on two planes. The catalog API runs on the control plane, the grounding hook runs on the data plane, and both read and write one shared context store. That is why a bundle you import through the dashboard is available to every model call the gateway serves
The shared store is not optional. Import writes on the control plane and grounding reads on the data plane, so both must point at the same store or the gateway never sees your bundles and grounding silently does nothing (it fails open). In production set FORCEAI_CONTEXT_BACKEND=s3 plus the bucket and endpoint on both the backend and the gateway

The real-time flow

This is what happens on every grounded request, in the few milliseconds before the provider is called
1

The caller opts in

The request carries metadata.forceai_okf. Without it the hook returns immediately and the call is untouched
2

The hook loads the bundle

It reads the named bundle, and a pinned version if you gave one, from the shared context store
3

Access groups are applied

A concept whose frontmatter lists access_groups is dropped unless the caller’s access groups intersect it, so a caller is only grounded on knowledge it is entitled to
4

The best concepts are selected

Every remaining concept is scored against the user’s last message, tags counting double and prose once. The top three are kept; index.md and log.md are never injected
5

Knowledge is injected and audited

The selected concepts are prepended as one system message and a summary is written to spend_logs_metadata.forceai_okf, then the provider call proceeds with the knowledge in context

Author a bundle

A bundle is a directory of .md files, one concept per file. A type in the frontmatter is required; everything else is optional but improves how well a concept is retrieved and governed. Relative markdown links between files become edges in the concept graph
tags is the strongest lever on retrieval because it is weighted twice as heavily as prose, so tag a concept with the words a user would actually say. access_groups gates who can be grounded on the concept. index.md and log.md are reserved names and are never injected into a prompt

Import a bundle

Open the dashboard Knowledge Catalog page (admin only), give the bundle an id, add your .md files, and click Import. Valid files become concepts; invalid files are reported, not silently dropped. Select the bundle to browse its concepts and the concept graph. The same thing over the API:
You can also post a gzip tarball with Content-Type: application/gzip, which is exactly what GET /forceai/okf/bundles/{id}/export returns, so bundles round-trip cleanly. Each import is a new version, so a re-import never overwrites the old one

Ground a request in real time

This is the part an agent or app does on every turn. Add metadata.forceai_okf to the chat completion and the gateway does the rest. The value is a bundle id, or an object that pins a version:
Streaming works the same way; injection happens before the first token, so "stream": true needs no extra handling. Without forceai_okf in the request the model runs ungrounded, which is the point: you decide per call

How an agent uses it

Grounding keys off the request body, so whatever builds the model call sets the metadata. For a direct API or SDK client, set metadata.forceai_okf as above; this is the supported path today for any OpenAI-compatible caller. Agent, A2A, and orchestrator turns all pass through the gateway, so grounding fires as soon as the metadata is present on the turn
Attaching a bundle to an agent so its runtime stamps forceai_okf on every turn automatically, with no caller involvement, is a planned per-agent setting rather than a current option. Until then, ground an agent by setting the metadata wherever its turns originate

Tune what gets selected

Selection is lexical and deterministic, so you shape it by shaping the concepts. If the right concept is not being pulled in, add the user’s vocabulary to that concept’s tags, since tags outweigh prose. At most three concepts are injected per turn, which keeps the added tokens small and predictable. Split a sprawling document into several focused concepts rather than one large file, so the matcher can pick the relevant piece

See what a request used

Open the request in Logs and expand it to see which concepts were injected, or read it back from the spend log. The summary is stamped into spend_logs_metadata.forceai_okf:
available is how many concepts the caller was allowed to see, loaded is how many were injected, and loaded_paths names them exactly

Scope and safety

A caller is only ever grounded on concepts it could see, since access_groups filtering runs before selection. The hook fails open, so a store hiccup leaves the request untouched rather than blocking it. Injected knowledge is system context the model reads, so treat a bundle as content any grounded caller may see and keep secrets out of it
Grounding only happens on requests that opt in, so a request without metadata.forceai_okf is never modified. A concept with no access_groups is visible to every caller of the bundle; add access_groups to restrict it

API reference

Catalog routes are admin-gated and served on the control plane; chat completions are served on the data plane. Behind the dashboard both are the same origin, proxied by nginx, which is why the examples above use http://localhost:3000 for catalog calls and http://localhost:4000 for chat