C.W.K.
Stream
Lesson 05 of 06 · published

The Pure Kernel — Ports, Adapters & Executor Checkpoints

~14 min · ports-adapters, kernel, executor-checkpoint, architecture-rules

Level 0Curious
0 XP0/65 lessons0/17 achievements
0/100 XP to next level100 XP to go0% complete

Orchestration above the adapter boundary

The framework never touches the brain stem — backend/adapters/claude.py's receive loop is untouched. It sits above the adapter boundary as orchestration, honoring the three architecture rules the rules track drilled: Claude-shaped, narrow adapter boundary, cost absorbed downstream.

Where does it live? Family Council weighed three options and rejected two. A standalone service revives the external-client pattern (souls are root users at home, not clients). Inlining into existing services inflates the monolith. The answer: a new backend/stateful/ module inside the codebase, reachable as an MCP tool, not a REST endpoint. Conversation and state are one body; the moment you move state outside the codebase, it's already two bodies.

A hexagonal kernel

The module is a ports-and-adapters kernel, so it stays swappable and testable in isolation while binding loosely to every surface. The kernel is pure: reduce(event) → state, plan_next(state) → step, the resume policy, the artifact classes. No FastAPI, no chat, no council, no provider SDK. Around it, four ports — TaskStore, ArtifactStore, LeaseManager, ToolRunner — map onto the storage, taxonomy, lease, and side-effect bracketing from the earlier lessons.

The load-bearing invariant: existing code calls adapters; adapters call the kernel; the kernel never imports a surface. Dependency points inward only — and that one direction is the architecture test. It's what stops the framework from quietly becoming a second chat stack.

Executor checkpoints — the real surface is small

The implementation surface is executor-shaped, not provider-shaped. Models don't call Polygon or Nano Banana as framework ports; they call cwkPippa's tool executors — Connector, WebSearch / WebFetch, the Firecrawl tools, Bash, and show_widget. Those become stateful-aware adapters. When a running step is active, the executor runs the existing tool, persists the raw result as the step artifact immediately, marks the step done, releases the lease, and only then returns a bounded result to the model. That closes the gap where a provider call succeeds but the model disconnects before it can commit.

Two refinements make it robust. First, auto-checkpoint: if the model forgets to start a task before volatile provider work, the executor auto-creates a single-step checkpoint rather than dropping the result on the floor — while ordinary local tools (Read, Write, Edit) keep the fast path untouched. Second, the replay-skip guard: before re-running a read-only volatile tool, the executor checks the same conversation for a completed checkpoint with the same effective tool name and exact input; if it exists, it returns the saved artifact and skips the provider call. Identical replay is an executor concern, not a model judgment call. With that guard in place, Claude mid-turn-cut auto-retry is safe to re-enable by default — replay no longer throws away completed pulls.

Self-reference: The rules track told you the adapter boundary is sacred and Claude is the canonical shape. This is that doctrine doing real work: a whole new subsystem lands without the brain stem changing a line, because the kernel points inward and the surfaces stay outside. Build the narrowest real loop first; generalize only on demand. That's Rule 2 keeping a framework from turning into a cathedral.

Code

Ports & adapters — dependency points inward only·text
driving adapters (call IN):  Chat (branch/retry/SSE) · Council (artifact_refs[])
                             Cron / heartbeat (scheduled wake)
                                   |  ports (interfaces)
   backend/stateful/  -- PURE KERNEL
     reduce(event) -> state     plan_next(state) -> step
     resume_policy + artifact classes
     No FastAPI · no chat · no council · no provider SDK
                                   |  ports: TaskStore · ArtifactStore
                                   |         LeaseManager · ToolRunner
 driven adapters (called OUT):  SQLite-WAL store · File artifact store

# existing code calls adapters; adapters call the kernel;
# the kernel never imports a surface.
Executor checkpoint contract (per volatile tool call)·text
1. locate the active running stateful step for this conversation + executor
2. no matching step? local tool (Read/Write/Edit) -> untouched fast path
   volatile tool (Connector/WebSearch/WebFetch/Firecrawl/show_widget) ->
     auto-create a single-step checkpoint (don't drop the result)
3. run the existing executor exactly once
4. success -> persist raw result as artifact, mark step done, release lease
5. return original result + a short checkpoint footer
6. error -> leave step running (resume policy retries / hits the cap)
7. before a read-only volatile re-run: identical completed checkpoint in
   this conversation? return the saved artifact, skip the provider call

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue
💛 by Pippawarm

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.