Skip to content

API Reference

This document describes the public API exposed by the Canonical Knowledge Structure (CKS) Python reference implementation.

Applications should use the functions documented here instead of importing implementation modules directly.

The public API is defined by the Canonical Knowledge Interface (CKS-007).


The recommended import style is:

from cks import (
construct,
parse,
serialize,
validate,
validate_all,
diagnose,
inspect,
compare,
extract,
project,
evolve,
merge,
MergeConflictError,
)
from cks.evolution import (
AddObject,
AddRelation,
RemoveObject,
RemoveRelation,
compose,
)

All public operations are:

  • deterministic;
  • observationally pure;
  • implementation-independent.

Construct a canonical Knowledge Structure from an iterable of Knowledge Objects.

construct(
objects: Iterable[KnowledgeObject],
) -> KnowledgeStructure
structure = construct(
[
object1,
object2,
relation,
]
)

Parse canonical JSON into a Knowledge Structure.

parse(
source: str | dict,
) -> KnowledgeStructure
Parameter Description
source Canonical JSON string or decoded JSON object
structure = parse(json_text)

Serialize a Knowledge Structure into canonical JSON.

serialize(
structure: KnowledgeStructure,
) -> str
json_text = serialize(structure)

The reference implementation guarantees canonical round-trip behaviour.


Execute the complete canonical validation pipeline.

validate(
structure: KnowledgeStructure,
*,
min_severity: DiagnosticSeverity = DiagnosticSeverity.ERROR,
) -> ValidationResult
  1. Structural Validation
  2. Semantic Validation
  3. Constraint Evaluation
result = validate(structure)
print(result.is_valid)

Validate multiple Knowledge Structures and return individual results.

validate_all(
structures: Iterable[KnowledgeStructure],
*,
min_severity: DiagnosticSeverity = DiagnosticSeverity.ERROR,
) -> list[ValidationResult]
results = validate_all(
[
structure1,
structure2,
],
min_severity=DiagnosticSeverity.WARNING,
)

Return diagnostics without exposing the complete ValidationResult.

diagnose(
structure: KnowledgeStructure,
) -> DiagnosticCollection
diagnostics = diagnose(structure)

Return an implementation-independent summary of a Knowledge Structure.

inspect(
structure: KnowledgeStructure,
) -> Mapping[str, object]
summary = inspect(structure)

Typical summary information includes:

  • object count;
  • relation count;
  • structural metadata.

Compare two Knowledge Structures.

compare(
left: KnowledgeStructure,
right: KnowledgeStructure,
) -> Mapping[str, object]
comparison = compare(
structure1,
structure2,
)

The comparison is based on observable structure rather than implementation details.


Extract a single Knowledge Object.

extract(
structure: KnowledgeStructure,
identity: str,
) -> KnowledgeObject | None
obj = extract(
structure,
"definition-001",
)

Returns None when the requested object does not exist.


Create a new Knowledge Structure containing only selected objects.

project(
structure: KnowledgeStructure,
identities: Iterable[str],
) -> KnowledgeStructure
subset = project(
structure,
[
"definition-001",
"theorem-003",
],
)

Projection never modifies the original structure.


CKS provides optional constraints that are not active by default. They can be registered explicitly to extend the validation pipeline with domain‑specific rules.

For example, the EmbeddingProjectionIntegrityConstraint (available in cks.constraints.projection) enforces that an EmbeddingProjection object points to a valid source object and references its vector payload externally.

Other optional constraints, available via OPTIONAL_CONSTRAINTS_BY_NAME:

Name Module Checks
temporal_validity cks.constraints.temporal An object’s structure.valid_until, if present, has not passed (WARNING)
layering_rule cks.constraints.layering depends_on relations between recognized ecosystem components respect cks-core < cks-runtime < cks-mcp (ERROR)
inference_confidence_conflict cks.constraints.reasoning Active InferenceSteps sharing a conclusion but disagreeing on confidence (WARNING)
stale_premise cks.constraints.reasoning An active InferenceStep citing a premise that has itself been superseded (WARNING)

To activate an optional constraint, register it in the global registry or in a scoped ConstraintRegistry:

from cks.constraints.builtin import OPTIONAL_CONSTRAINTS
from cks.constraints.registry import registry
for constraint in OPTIONAL_CONSTRAINTS:
registry.register(constraint)
# Or activate a single named constraint:
from cks.constraints.builtin import OPTIONAL_CONSTRAINTS_BY_NAME
registry.register(OPTIONAL_CONSTRAINTS_BY_NAME["temporal_validity"])

See the Plugin Development Guide for more details.


Apply a sequence of admissible structural operators (Genesis/Decay/Mutation) to a Knowledge Structure.

evolve(
structure: KnowledgeStructure,
operators: Iterable[StructuralOperator],
) -> KnowledgeStructure
Operator Class Description
AddObject Genesis Introduce a new KnowledgeObject
AddRelation Genesis Introduce a new CanonicalRelation
RecordInference Genesis Append a new InferenceStep (conclusion + premises)
RemoveObject Decay Remove a KnowledgeObject (and related relations)
RemoveRelation Decay Remove a CanonicalRelation
UpdateObject Mutation Update an object’s structure in place (merge/replace modes)
RenameObject Mutation Change identity.name without invalidating relations
ResolveInferenceConflict Mutation Supersede every losing InferenceStep in favor of a chosen winner

Every operator exposes read-only introspection properties (.obj, .object_id, .relation_id, .structure_patch, .mode, .new_name) so callers can inspect a pending operator without depending on private attributes.

from cks.evolution import AddObject, AddRelation, RenameObject, compose
ops = [
AddObject(new_object),
AddRelation(new_relation),
RenameObject("obj-1", "New Name"),
]
evolved = evolve(structure, ops)

All operators are observationally pure — the original structure is never modified.


Two pure query functions in cks.constraints.reasoning support reasoning over InferenceStep objects without mutating the structure. Neither produces a Diagnostic.

Ranks the active InferenceSteps sharing a conclusion by confidence (descending).

rank_by_entrenchment(structure: KnowledgeStructure, conclusion_id: str) -> list[KnowledgeObject]

Walks every active InferenceStep chain concluding object_id back through its premises to base facts, reporting operator, confidence, justification, alternatives considered, and supersession history per step.

explain_inference(
structure: KnowledgeStructure,
object_id: str,
*,
max_depth: int = 25,
) -> dict

To resolve a detected conflict, apply ResolveInferenceConflict through evolve():

from cks.evolution import ResolveInferenceConflict
winner = rank_by_entrenchment(structure, "concl-1")[0]
resolved = evolve(structure, [ResolveInferenceConflict("concl-1", winner.identity.id)])

k-hop subgraph extraction around a starting object, with an optional traversal budget and type-weighted ranking of candidates.

query_subgraph(
structure: KnowledgeStructure,
start_id: str,
*,
k: int = 2,
budget: int | None = None,
) -> SubgraphResult

Three-way merge of independently evolved Knowledge Structures.

merge(
base: KnowledgeStructure,
branch_a: KnowledgeStructure,
branch_b: KnowledgeStructure,
*,
resolutions: dict[str, str] | None = None,
) -> KnowledgeStructure

resolutions maps a conflicting object_id to "branch_a" or "branch_b", resolving that conflict instead of raising. Any conflict not covered by resolutions still raises MergeConflictError.

from cks import merge, MergeConflictError
base = KnowledgeStructure([obj1, obj2])
branch_a = KnowledgeStructure([obj1, obj3]) # evolved independently
branch_b = KnowledgeStructure([obj2, obj4]) # evolved independently
try:
merged = merge(base, branch_a, branch_b)
except MergeConflictError as e:
for conflict in e.conflicts:
print(f"Conflict on {conflict.object_id}")
# Or resolve specific conflicts explicitly:
merged = merge(base, branch_a, branch_b, resolutions={"obj-1": "branch_a"})

Raised when branch_a and branch_b changed the same identity to different results and no resolutions entry covers it. The conflicts attribute is a list of MergeConflict objects, each containing:

Field Description
object_id The identity that both branches changed
base The object in the common ancestor (or None)
branch_a The object in branch A (or None if removed)
branch_b The object in branch B (or None if removed)

The public interface internally delegates every operation to the Reference Engine.

Applications normally do not need to instantiate the engine directly.

However, it remains available:

from cks import ReferenceEngine
engine = ReferenceEngine()

The engine provides the same canonical operations exposed by the module-level API.


Raised when canonical serialization cannot be parsed.

Example:

from cks import SerializationError
try:
structure = parse(text)
except SerializationError:
...

The validator returns an immutable ValidationResult.

Useful properties include:

Property Description
is_valid Overall validation status
diagnostics Complete diagnostic collection
error_count Number of errors
warning_count Number of warnings
information_count Number of informational diagnostics
metadata Validation metadata

Convenience methods include:

  • has_errors()
  • has_warnings()
  • has_information()
  • summary()

The following classes are part of the supported public API.

Class Purpose
ObjectIdentity Canonical identity
KnowledgeObject Semantic object
CanonicalRelation Semantic relation
KnowledgeStructure Immutable knowledge structure
ValidationResult Validation outcome
Diagnostic Validation diagnostic
DiagnosticCollection Immutable diagnostic collection
ReferenceEngine Reference implementation engine
SerializationError Serialization exception
StructuralOperator Abstract base for evolution operators
AddObject Genesis – add a KnowledgeObject
AddRelation Genesis – add a CanonicalRelation
RemoveObject Decay – remove a KnowledgeObject
RemoveRelation Decay – remove a CanonicalRelation
MergeConflict Describes a single merge conflict
MergeConflictError Exception raised when merge conflicts occur

KnowledgeObject, CanonicalRelation and KnowledgeStructure are deeply immutable by contract. When used with copy.copy or copy.deepcopy they return the same object (self) rather than creating a new copy. This is safe and intentional – no observable state can be changed, so sharing the reference is indistinguishable from cloning the object.

You can safely pass these objects to any library or store them in containers that rely on deepcopy (for example cks-runtime’s in‑memory storage).


The public API follows semantic versioning.

Within a major version:

  • public function names remain stable;
  • observable behaviour remains stable;
  • canonical semantics remain stable.

Internal implementation details may evolve without affecting user code.


For additional information, see:

  • Getting Started — installation and first steps.
  • Concepts — semantic foundations.
  • Architecture — implementation design.
  • Examples — practical usage patterns.
  • Core Specifications — formal normative definitions.