Skip to content

Core Concepts

Vocabulary

Kando term What it is
Ledger The append-only event log for a single agent run. One ledger per run. The source of truth.
World The live projected state: all objects, relations, and their current data. Deterministically derived from the ledger. Never stored directly — always reconstructable.
Responder A function (plain, LLM-backed, or tool-calling) that subscribes to event patterns, reads the world, and emits new events back to the ledger. Responders do not call each other.
Edge logic Semantic behavior attached to a typed relation (contradicts, depends_on, supports, blocks). When the relation is created, its edge logic fires. Coordination without orchestration.
Snapshot A materialized checkpoint of the world at a ledger position. Optimization for fast startup — the ledger remains authoritative.
Branch A fork of a ledger at a specific position. The prefix before the branch point is shared (zero-copy, no re-execution). Each branch diverges independently.
Diff A structural comparison of two worlds (typically parent vs. branch) showing which objects, relations, and responder outputs diverged.
Cache Content-addressed store of LLM responses keyed by normalized request hash. On replay or branch, cached responses are served instead of making new API calls.
Kit A domain bundle: object types, responders, tools, prompts, and policies packaged for a specific use case (diligence, research, planning).
Trace The causal chain from any event back to the originating goal. Every event records its parent event and the responder that emitted it.
Budget Per-run resource limits: max events, max LLM cost, max wall-clock seconds, max recursion depth. Enforced by the runtime, not by individual responders.

Design Principles

The ledger is the agent

There is no separate "memory," no mutable state store, no conversation context that outlives its events. If it didn't happen in the ledger, it didn't happen.

The world is derived, never stored

Object data, relation graphs, responder state — all of it is a deterministic function of the ledger. Snapshots are a performance optimization. The ledger can always reconstruct the world from scratch.

Responders are physics, not control flow

A responder subscribes to a pattern. When the pattern matches, the responder fires. There is no orchestrator deciding what runs next. Chaining happens because one responder's output event matches another responder's subscription. The execution order is an emergent property of the event stream.

Edge logic carries meaning

A contradicts relation is not just data — it's a trigger. When evidence contradicts a belief, the contradiction-resolution responder fires automatically. Logic lives where the semantic meaning is, not in a central router.

Branches are cheap

Forking a 500-event run at position 250 replays the first 250 events from cache (zero LLM calls, sub-second) and executes only the divergent tail. This makes hypothesis testing, A/B comparison, and self-improvement loops economically viable.

Traces are not observability

The causal chain from goal to artifact is not a debugging tool bolted on after the fact. It is the structural output of every run, queryable at any time, and it falls out of the architecture for free.


Event model

Every KandoEvent carries:

@dataclass
class KandoEvent:
    id: str           # unique within the ledger
    type: str         # e.g. "object.created", "relation.created"
    source: str       # ledger identity — "run:{id}" or "branch:{id}"
    actor: str        # which responder emitted this event
    cause: list[str]  # parent event IDs — the causal chain
    timestamp: datetime
    data: dict        # type-specific payload

Built-in event types

Type Meaning
object.created A WorldObject was created
object.patched A WorldObject's data was partially updated
relation.created A typed relation between two objects was created
relation.removed A relation was removed
branch.created A branch was forked from a parent run
budget.exhausted A budget limit was hit; the run stops
llm.request / llm.response LLM call lifecycle (for cost tracking)
tool.called / tool.returned Tool invocation lifecycle
responder.fired / responder.completed / responder.failed Responder lifecycle
kit.loaded A kit module was loaded by the runtime

The event loop

seed events
┌───────────────────────────────────┐
│           Runtime loop            │
│                                   │
│  dequeue event                    │
│     → append to ledger            │
│     → apply to world              │
│     → check budget                │
│     → dispatch edge logic         │
│     → fire matching responders    │
│     → enqueue output events       │
│                                   │
│  repeat until queue empty         │
└───────────────────────────────────┘
projected World

The loop is synchronous and deterministic. The same seed events through the same responders always produce the same world.