Skip to content
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/93 lessons0/18 achievements
0/100 XP to next level100 XP to go0% complete

Orchestration above the adapter boundary

The framework was designed never to touch the brain stem, and it barely does: backend/adapters/claude.py gained the MCP wiring that exposes StatefulTask and the checkpointed web tools, plus one call inside its receive loop that persists a show_widget render as it streams. Everything else 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 by the brains as a tool — StatefulTask, through Claude's MCP server and every variant's local tool bridge — not as a REST API. The only REST surface is a read-only status list for the frontend's progress panels. 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, and its whole decision is two functions: next_unfinished_step(task) picks the first step that is neither done nor failed, and resume_decision(step) says run it, block it for a side effect, fail it on an exhausted attempt cap, or leave a terminal step alone. The records and the artifact classes sit beside it in models.py. No FastAPI, no chat, no council, no provider SDK. Around it, three ports — TaskStore (which also owns the atomic lease), ArtifactStore, and 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 the tool executors

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 the result to the model, unchanged, with a footer naming the checkpoint so the model moves on instead of repeating the call. 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 once the result arrives, rather than dropping it on the floor. That covers Connector, WebSearch, WebFetch, the Firecrawl tools, and show_widget, and covers Bash when its output declares an artifact file; ordinary local tools (Read, Write, Edit) keep the fast path untouched. Second, the replay-skip guard: before re-running a reusable tool, the executor checks the same conversation for a completed checkpoint with the same effective tool name and exact input, no older than an hour (a day for a step labeled Class 2). If it finds one, it returns the saved artifact and skips the provider call. The reusable set is Connector, WebSearch, WebFetch, Firecrawl's scrape, map, and crawl-start, and Bash; a show_widget render and a crawl-status poll are checkpointed but never reused, because they are supposed to change. Past the window, read_artifact still reads any saved snapshot with no age limit: resume is the sanctioned path, and the reuse guard is only a replay shield. Identical replay is an executor concern, not a model judgment call, and this guard is what made the Claude mid-turn-cut auto-retry worth turning back on (three attempts by default) — a retry 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 while the brain stem changes by a few wiring lines and one checkpoint call, 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):  StatefulTask tool (Claude MCP · variant tool bridges)
                             executor checkpoints (Connector · Web · Firecrawl
                               · Bash · show_widget) · Cron / heartbeat sweeps
                                   |  ports (interfaces)
   backend/stateful/  -- PURE KERNEL
     next_unfinished_step(task) -> step
     resume_decision(step) -> run | block_side_effect
                              | fail_attempts_exhausted | already_terminal
     No FastAPI · no chat · no council · no provider SDK
                                   |  ports: TaskStore (+ atomic lease)
                                   |         ArtifactStore · ToolRunner
 driven adapters (called OUT):  SQLite-WAL store · content-addressed file store

# existing code calls adapters; adapters call the kernel;
# the kernel never imports a surface.
Executor checkpoint contract (per volatile tool call)·text
1. run the existing executor exactly once
2. error -> log it; an active step keeps running, its lease released
            (the resume policy retries it or hits the cap)
3. success -> locate the active running stateful step for this
   conversation + executor
4. no matching step? local tool (Read/Write/Edit) -> untouched fast path
   volatile tool (Connector/WebSearch/WebFetch/Firecrawl/show_widget,
   or Bash that declares STATEFUL_ARTIFACT_PATH) ->
     auto-create a single-step checkpoint now, around the result
     already in hand (don't drop it)
5. persist raw result as artifact, mark step done, release lease
6. return original result + a short checkpoint footer
7. before a reusable re-run (Connector/WebSearch/WebFetch/Firecrawl
   scrape, map, crawl-start/Bash): an identical completed checkpoint in
   this conversation, younger than 1 h (24 h for a Class-2 step)?
   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 Pippa— warm

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.