Skip to main content

CoreProtocol — The Coordinator

The core is the bus. It connects stacks, plugins, and the model. It has an ID. It routes operations. It manages the composition. The core is not “the entity.” The entity is the composition. But the core is what holds the composition together.
The core_id persists across reconfigurations. Swap the model, change the stacks, add or remove plugins — the core_id stays the same.

CoreProtocol Interface

The default implementation is kernle.entity.Entity.

Properties

Model Management

Stack Management

Plugin Management

Routed Memory Operations

Upsert Semantics (v0.13.12)

drive() and relationship() use get-then-atomic-update-or-create:
  • drive() — Looks up an existing drive by drive_type. If found, updates intensity, focus_areas, and other fields in place. The original id, created_at, and version chain are preserved. Only explicitly provided optional fields are overwritten.
  • relationship() — Looks up an existing relationship by entity_name (other_stack_id). If found, updates fields in place and increments interaction_count. If not found, creates a new relationship.
Both methods use atomic updates with optimistic locking. VersionConflictError propagates if the record was modified between read and write.

Routed Search, Load, and Status

Trust Operations

Checkpoint & Binding

Stack Management

The core manages multiple stacks with one active at a time. All routed operations go to the active stack.
When a stack is attached, the core calls stack.on_attach(core_id, inference_service) so the stack can pass the inference service to its components. When detached, stack.on_detach(core_id) clears inference access.

Plugin Lifecycle

Plugins follow a strict lifecycle managed by the core.

Protocol Version Enforcement

The core checks the plugin’s protocol_version property on load:
This ensures that a plugin built for a newer protocol cannot silently break on an older core. Older plugins are loaded with a warning since the core is expected to maintain backward compatibility.

Operation Routing

When you call entity.episode(...), the core does not just forward to the stack. It enforces provenance first. The provenance step populates:
  • id: New UUID
  • stack_id: From the active stack
  • source_entity: "core:{core_id}" or a custom source (plugins use "plugin:{name}")
  • source_type: Explicit on all write paths. Accepts a string or SourceType enum value. Defaults to "direct_experience" when not specified. Invalid strings raise ValueError. Internal subsystems pass explicit values: checkpoint uses "observation", sync uses "external" with source_entity="kernle:sync", doctor uses "observation" with source_entity="kernle:doctor".
  • created_at: Current UTC timestamp
  • derived_from: Optional lineage chain
  • context / context_tags: Optional grouping
This is why writing through the core matters. Direct stack.save_*() calls skip provenance, producing memories with incomplete attribution.

Checkpoint Save and Restore

The checkpoint() method saves the current composition to a timestamped JSON file. from_checkpoint() restores an Entity from a saved checkpoint.
Checkpoint files include:
  • schema_version — format version (currently 1) for forward compatibility
  • checkpoint_id — unique identifier for this checkpoint
  • message — human-readable description
  • binding — the composition snapshot (core_id, model_config, stacks, plugins)
  • created_at — UTC timestamp
Schema versioning policy:
  • Missing schema_version is treated as version 1 with a warning (backward compat for checkpoints created before this change)
  • schema_version > 1 raises ValueError (forward compat — prevents loading newer formats with older code)
Restore semantics: Restore is best-effort. Individual stack, plugin, or model failures during rehydration are logged at WARNING level but do not abort the restore. A partially restored entity is better than no entity in alpha. Retention: Each checkpoint() call retains the 10 most recent checkpoints per core_id, removing older ones automatically.