Architecture

One rule above all: the kernel stays small. Complexity lives in services around it — never inside it.

The map#

                    KHAELOR TUI ──── khaelord (daemon)
                          │               │
                          ▼               ▼
                     Session Engine (JSONL event log)
                          │
                          ▼
                     Agent Kernel  ←  deriveNext(state) — a pure fold
          ┌───────────────┼───────────────────┐
          ▼               ▼                   ▼
    Context Engine   Tool Runtime        Model Runtime
     (tiers, cache,   (permissions,       (Anthropic SDK,
      compaction)      phase gate,         streaming)
          │            verify loop)
          ▼               ▼
    RepoGraph        Workspace ── the ONLY fs/process seam
    Memory                │
    Phases           Files · Processes · Git worktrees

The kernel is a fold#

Each iteration, the kernel re-derives “what next” from the recorded event log — not from loop-local flags. foldTurnState(events)deriveNext(state) → dispatch to a service. Interruption, steering injection, compaction, verification, completion: all are positions in the log, which is why resume, fork, and replay are cheap and exact.

Services around the kernel#

ServiceOwns
PhaseServiceThe gate: per-phase capability policy, design approval, phase events. Consulted by the Tool Runtime — the kernel never sees it.
VerifyRunnerNative checks after edit batches, the bounded repair loop.
PermissionServiceCapability evaluation (deny > ask > allow), grants, the panel seam.
ContextEngineTiers, byte-stable history projection, prune/compact decisions.
RepoGraphServiceThe incremental semantic index behind symbols/refs/skeletons.
SubtaskManagerWorktree lifecycle, child engines, supervised merges.
GoalStore / BudgetGuard / ApprovalQueueThe daemon's persistence: goals, ledgers, pending approvals — plain files under .khaelor/daemon/.

The seams that matter#

  • Workspace — four methods (cwd, readFile, writeFile, exec); the only module allowed to import node:fs/child_process. Everything above it is testable and portable.
  • ModelClient — one streaming interface over the Anthropic SDK. Not a multi-provider framework; just a clean wall.
  • ChannelAdapter — daemon notifications (webhook, command today; richer channels later without touching the core).

House rules#

  • Every displayed number comes from real data — usage metadata, exit codes, git diffs. No fabricated progress, ever.
  • Baseline git state is recorded before edits; KHAELOR never assumes an existing diff is its own, and never commits unless asked.
  • Whenever something is tempted into the kernel, the question is asked: can this be a service around it? The answer so far has always been yes.