knowledge global exposes the knowledge features and items that have been attached to a document family. Scripts can read what the knowledge engine has resolved for a family without re-running resolution, then dispatch downstream behaviour from a single source of truth.
knowledge is available in script steps only — not in intake scripts, event subscriptions, or selection-option formulas. It is read-only: every returned object is Object.freeze-d, and there is no setter or mutate API.How to think about it
Knowledge in Kodexa is a declarative way to describe what a document is and what should happen to it — kept separate from the script’s runtime state. Two pieces work together:- Knowledge features are facts about a document family (vendor ID, language, document classification). They are attached to the family early in processing — typically by an upstream script step that reads upstream metadata, or by an intake module.
- Knowledge sets are org-level rules that match on features and produce knowledge items with rich, type-checked properties: configuration, prompts, validation rules, processing models, anything you want a downstream script to consume.
knowledge global — it does not re-implement the matching logic.
The mental model is declare configuration as knowledge, dispatch in the script:
Why we built it this way
Withoutknowledge, a script that needs vendor- or document-type-specific behaviour has to do one of:
- Hard-code lookup tables inside the script body.
- Round-trip to a service bridge for every document.
- Stash configuration in environment variables or module options.
- Re-implement set-matching logic by reading raw features and writing JS conditionals.
knowledge global is designed so you can keep configuration in org metadata (versioned, reviewable, separately deployed) and keep the script thin enough that it rarely changes.
What knowledge is and isn’t
If the answer to “where does this value come from?” is “an org admin configures it in the UI”, knowledge is probably the right home. If the answer is “this script computes it for this document”, keep it in the script.
API surface
The global has four explicit accessors and four bare-form conveniences.Bare accessors (single-family scripts)
When exactly one document family is in scope, scripts can use the bare forms. These are the 80% path for activity-plan script steps that operate on one family at a time.Explicit accessors (always available)
The explicit forms are required when the script’s
families slice has anything other than exactly one entry. The familyId you pass MUST be in the script’s families slice (see Family-access scoping).
Object shapes
Annotations below use TypeScript-style notation. Each returned array element is a frozen plain JS object with exactly these properties.KnowledgeFeature
KnowledgeFeatureType (sub-record on each feature)
KnowledgeItem
KnowledgeItemType (sub-record on each item)
KnowledgeOption (schema entries inside options / extendedOptions)
Single-family rule
The bare accessors (knowledge.features, knowledge.items, knowledge.featuresByType, knowledge.itemsByType) auto-bind to families[0] when exactly one family is in scope. Anything else throws:
families and use the explicit forms:
Family-access scoping
Even with the explicit accessors, thefamilyId you pass must be present in the script’s families slice (the families attached to the script’s task). Calling with a foreign family throws:
document_family_id only, so this check prevents a script from reading another tenant’s data by guessing UUIDs.
Write protection
Every object returned byknowledge.* is Object.freeze-d, recursively. Nested arrays and sub-records (e.g. featureType, itemType, properties) are also frozen.
In both cases
Object.isFrozen(obj) returns true. The contract is: knowledge is read-only from scripts. If you need to compute a derived value, build a new object instead of mutating the returned one:
Performance characteristics
Per-script-execution caches keyed by family ID make repeated calls cheap.
Calling
knowledge.featuresByType("vendor") ten times in the same script runs one query.
The KDDB load behind
knowledge.items is a separate loader from loadDocument(familyId). If a script calls both, the KDDB is loaded twice (once for each cache). This is acceptable today but may be consolidated in a future revision.Item ordering
knowledge.items and knowledge.itemsByType always return items sorted by:
sequenceOrderASC- ties broken by
slugASC
items[0]) may rely on it. Without this, scripts would be at the mercy of whatever order the KDDB happens to return.
Features have no documented ordering — they come back in whatever order the SQL join returns them.
Active-features policy
The bindings return all features and items regardless of theactive flag, with the boolean exposed on each instance. If you want only-active records, filter in JS:
Empty-result handling
Filtered accessors return[] when nothing matches. Indexing [0] on an empty array yields undefined, and any property access after that throws. Always guard:
Null featureType / itemType
In pathological cases (e.g. the type was deleted via direct DB access despite the immutability claims) the enrichment lookup returns no row. The binding surfaces this as featureType: null (or itemType: null) on the affected instance rather than throwing. Null-check before accessing nested fields:
itemType may also be null when a knowledge item references a type from a different organisation than the script’s context, since the type lookup is org-scoped.
Type-slug case sensitivity
featuresByType / itemsByType perform an exact string match against the type’s slug. Slugs are lowercase by convention — featuresByType("Vendor") will not match a type whose slug is "vendor".
Kill switch
There is no runtime feature flag for theknowledge global. Emergency disable requires commenting out the registration in kodexa-orchestrator/internal/service/planner_script_adapters.go (the kb.Register(vm) call near the bottom of plannerContextBindings.Register) and redeploying.
What’s NOT here (deferred to v2)
The following are not available in v1:- Resolution metadata (
knowledge.matches,ResolutionMatchobjects). The engine does not currently persist per-set resolution decisions; surfacing them requires engine changes. - Per-item source / clauses. Which knowledge clause produced an item is not exposed.
- Attachment-fetch accessors.
itemType.supportsAttachmentis exposed, but there is no accessor to fetch the underlying attachment (presigned URL, content, etc.). - Mid-script re-resolution. The bindings read what is already attached to the family; they do not re-run the knowledge engine. If you need fresh resolution, run a separate engine invocation upstream of the script.
- Feature provenance read fields (
feature.attachedAt,feature.attachedBy). The schema and write-side population land in v1’s parallel track so the data accumulates; the read API ships in v2.
Worked example: vendor routing
A common cass-analysis pattern: a single document family carries avendor feature emitted upstream, the knowledge engine resolves the family’s processing-model knowledge set, and a downstream script step dispatches based on the resolved item’s properties.
Common patterns
Pattern 1: Two-step feature emission then read
The canonical use ofknowledge is a two-step activity-plan flow: an upstream script step emits a feature using the planner’s {features: [...]} return contract; the orchestrator runs AssessAndEnrich between steps; a downstream script reads the resolved items via knowledge.itemsByType(...).
Pattern 2: Per-vendor configuration without a lookup table
Older code commonly contains hard-coded tables like:Pattern 3: Conditional behaviour gated on feature presence
Sometimes you don’t need a knowledge item at all — just the existence of a feature. UsefeaturesByType:
Pattern 4: Multi-vendor / batch script steps
When the step’sfamilies slice has more than one entry, the bare accessors throw. Loop and use the explicit forms:
Pattern 5: Audit / inspection
A read-only inspection script can summarise what the engine has done:Choosing knowledge vs. alternatives
A short decision guide for “where should this configuration live?”:
The recurring test: if the org admin needs to change this value tomorrow, do they have to redeploy code, redeploy the project template, or just edit a knowledge item? The last is the cheapest — favour it when the value is genuinely org-scoped.
See also
- Scripting Reference — core globals, document/data-object/attribute APIs, and execution-context details.
- Service Bridges — calling external systems from scripts.
