← the Atlas

Electricity — identified, and their progress

Analysis·evergreen·

A tracker for kolu's electricities — infrastructure pulled out from beneath the app into its own thing — and where each stands.

“Decompose based on volatility” — Löwy’s directive: encapsulate each area likely to change behind a stable interface, rather than split a system by what it does. “Electricity” is his own example, and the source of our term: “the electricity that powers a house … is highly volatile: power can be AC or DC; 110 volts or 220 volts … produced by solar panels … a generator … or plain grid connectivity … All that volatility is encapsulated behind a receptacle … all the user sees is an opaque receptacle.” The body does the same — blood-pressure, salinity, and pulse volatility “encapsulated behind the service called the heart.” An electricity, in kolu, is one such volatility lifted into its own @kolu/* package; a receptacle is the socket a consumer plugs into. — Juval Löwy, Software System Decomposition, ch. 2 of Righting Software.

The electricities

Electricity Owns (volatility) PR Progress
@kolu/surface Live client↔server state — Cell/Collection/Stream/Event over oRPC, reconnect, fine-grained reconcile. #805 done · 2nd consumer: drishti
@kolu/surface-app The app shell for surface apps — fresh delivery + server/build identity + the connection/update lifecycle model + desktop-install. Owns the stale-tab handshake gate (#1231) and now the connection plumbing (#1234) — the pid-echo, the partysocket construction, and the upgrade gate, lifted from both consumers into three composable primitives (see archived notes). The restart axis already lived here, so each leak plugs into a receptacle the package had. #1154 · #1231 · #1234 done · 2nd consumer: drishti
@kolu/surface-nix-host HostSessionnix copy a closure to a host, realise, run --stdio over ssh. #984 done · also in drishti
@kolu/artifact-sdk Two volatilities under one roof — the agnostic anchoring core (W3C quote re-find; speaks only Range/Document/ShadowRoot) and the sandboxed-iframe parent↔frame bridge (opaque-origin postMessage, now carrying comments + in-frame navigation + back/forward input). See the re-eval note below. #922 done re-eval
@kolu/transcript-core + transcript-html Transcript model + rendering. #744 done
@kolu/solid-pierre SolidJS adapters for Pierre tree/diff. #823 done
persistedPref Validated localStorage (validate-on-read; closed the zoom-NaN + maximize bugs). #1089 done
@kolu/log · @kolu/html-escape Zero-dep leaf types every package can import without dragging the domain tree. #1089 done
dom/ + injectable isMac walkShadowRoots relocated to a neutral wall; keybind core no longer reads the UA singleton. #1089 done
createSharedRoot Lazy app-scoped reactive singleton (7 consumers). 100% agnostic SolidJS. #974 done publish?
@kolu/serve-dir Fetch-native file serving from an absolute root — streaming byte-range (206/416), content-type, lexical traversal guard; a pure (root, relPath, request) → Response. Its own package, zero workspace deps (node:fs/path/stream + the focused mrmime MIME table) — the dependency arrow points out (kolu-server → @kolu/serve-dir). Agnostic of terminals/git/kolu; the consumer injects the root and composes the artifact-sdk <script> decorator downstream. A 20-agent prior-art survey found no static-serve library fits the serving shape (all pipe to a Node res, breaking the Fetch-Response + decorator composition; none takes a per-request absolute root or does a realpath guard), so the serving is owned here — but the MIME table leans on mrmime (the separable commodity the survey explicitly didn’t cover). That’s load-bearing for decomposition: a complete table means adding a format to kolu’s *_EXTENSIONS classifier needs no edit here (mrmime already types it), so the ext↔MIME shared-volatility the lens debated is dissolved for every mrmime-known format. For the mrmime gap set (.m4v/.ico, and any future classifier entry mrmime doesn’t know) the coupling is instead contained-by-test: a 2-entry OVERRIDES in serve-dir supplies the MIME, and the coverage invariant in iframePreviewRoute.test.ts is load-bearing, not a thin sanity check — delete an OVERRIDES row and the classifier still routes the file to a <video>/<img> appliance while serve-dir answers application/octet-stream, so only that test catches the silent download regression. Path safety is two-stage by volatility: the lexical guard (decode-then-split + path.relative containment) is built in (pure, universal), while the realpath/symlink guard is an injected realpathGuard the consumer supplies (fs-touching, threat-model-specific) — kolu-server wires kolu-git’s assertRealpathUnder, so the package stays agnostic without dropping the security boundary. A leaf (bounded algorithm, not a transport-grade volatility). #1225 done ②/③ proof-pending
@kolu/terminal-protocol The VT/device-query protocol policy both terminal clients and the server must agree on — the query-reply suppression grammars (whole-payload predicate for the browser’s onData, streaming boundary-aware stripper for kolu-tui’s raw tty), the headless forward/drop rule, the answered/silent device-query matrix as data (executed against a real headless by @kolu/pty-host’s contract tests, so policy and implementation can’t drift), the bracketed-paste delimiters, and the snapshot-reciprocal TTY reset. Born when the second terminal client (kolu-tui attach, #1255) made the fragmentation visible: the same concept lived in kolu-common, pty-host, and pty-tui, held in lockstep by prose — and the browser may not depend on @kolu/pty-host, so a leaf both sides import is the only receptacle that dissolves the cross-references. Hashed into the pty-host staleKey (a protocol change is observable daemon behaviour; pinned by buildId.closure.test.ts). A leaf (bounded protocol tables, not a transport-grade volatility) — the serve-dir tier, not the surface tier. #1255 done
@kolu/xterm-kit The accumulated high-level xterm.js machinery — pinned _core internals with two failure philosophies, in-place scrollback surgery + seam-token write path, the mirror anchoring lifted from kaval, and the SolidJS lifecycle (WebGL single-owner + context-loss recovery, owner-correct async dispose across await) — as a runtime-neutral core + /solid adapter; kaval and the client as two consumers. (archived plan). #1795 (PR 1)
#1808 (PR 2)
core graduated <Xterm> wrapper
osfacts + osfacts-client How an OS answers “which processes in this subtree hold listening TCP sockets, and on what addresses?” — one Rust binary on both platforms; TypeScript client is osfacts-client (no @kolu scope; exactly one npm runtime dep, effect, pinned to the same version both consumers already pin — its spawning verbs hand back Effects, so an abandoned read kills its child instead of running out a five-second deadline). The former @kolu/port-scan package dissolved: OS volatility lives in osfacts; kolu policy (bind judge, U-row blindness) in padi; browser-safe PortInfo + fold in @kolu/terminal-vocab. Test ② measured: darwin’s mechanism changed three times before settling on osfacts. Consumers call scanSubtreePorts (padi) / snapshotSubtree (client) and learn none of the OS detail. Test ①: pid → identity join is the CALLER’s. Test ③ closed: drishti shipped as the second consumer of osfacts-client (#122), retiring its own hand-rolled readers. #1982 · #1996 extracted ③ two consumers
@kolu/port-forward How a port that answers only on some other machine’s loopback is made to answer here — an ssh -L child on a connection of its own for a remote target, an in-process TCP relay for this machine’s own loopback, behind one ForwardManager receptacle (create idempotent by target · cancel · list · dispose · onLost). Test ② is the strong one and it is measured: the mechanism was rebuilt mid-PRT0 when a shared ssh master was proved unable to give the one property the whole feature rests on — a live sshd showed -O forward listeners outliving their requester by the full ControlPersist window, with no -O list to re-adopt them — so lifetime won and each forward took its own connection. Consumers call create(target) and learn none of it. Test ① passes by construction: a target is (host, port) where host is any ssh destination, so nothing of terminals, tiles or kolu’s host model crosses the boundary. Test ③ is PROVEN, not pending — PRT0 shipped a standalone TUI consumer (vazhi; since removed) beside the library with no kolu running, and PRT2’s Inspector embed was the second genuinely independent app: embedding it changed the library’s mechanism API by exactly one field (lastLocalPort, so a restarted dev server comes back on the URL you already have), and BOTH of the shape changes the plan predicted a second consumer would force — a list() subscription, a tagged error union — turned out unwanted when that second consumer actually arrived. Production consumer today is kolu’s Inspector only. #1975 (PR0) · #1991 (PRT2) done · consumer: kolu’s Inspector
holdOneLink (candidate — recorded, not extracted) One live connection to a dialed surface — memoized across concurrent callers, dropped the instant the transport announces its close (identity-guarded, so a late announcement from a disposed predecessor cannot stomp the successor a redial already published), re-dialed on demand, disposed under a teardown latch. Test ② is measured, not asserted: the axis has moved twice in this tree — #1719 split dead-vs-transient transport tags, and #2117 moved discovery→announcement. Test ① passes by construction: nothing of terminals, padi or MCP crosses it. Test ③ is where it stands: three hand-rolled implementations todaysurface-mcp’s shared connection slot and its ResourcePusher attachment (packages/surface-mcp/src/{server,pusher}.ts), and surface-daemon-supervisor’s holdConnection (endpoint.ts, which already does the identity-guarded onClose→drop in almost the same words); @kolu/port-forward publishes the same verb as a required member (onLost). odu’s redialingAClient is deliberately not counted, and the reason cuts against this row rather than for it: it opens a fresh .ci/odu.sock for every upstream call and holds nothing, so it has no slot to invalidate and pays a dial per call to avoid needing one. That is a real alternative to this receptacle, not an instance of it — a consumer can buy the same freshness by making dials cheap enough not to memoize. The evidence it is one concept and not three: koluCliConnectionOf (kolu-cli/src/connect.ts) exists only because two packages declare the same handle, so the boundary can only be crossed by carrying each wire over by hand — under a shared HeldLink<C> it collapses to a client-narrowing wrapper with no per-field carry and no drift class. Home would be @kolu/surface beside links/ + isDeadTransportErrornot a new package: a parallel receptacle for an axis the supervisor already encapsulates is the duplicated-receptacle trap. Extraction is deliberately deferred (prove-then-extract); this row exists so the candidate cannot evaporate. #2117 candidate · ③ population 3 in-tree, extraction unproven
@kolu/solid-browser The Code tab is a browser — location/address model, back-forward history, cross-content-type link interception, GitHub-relative resolution, sandboxed-iframe lifecycle. git is an injected resolver; the renderer packages plug in. (archived plan). #1191 phases 1+2 primitives + createBrowser history shipped · <Browser>/gitResolver deferred, ③ proof-pending

Plus external electricity correctly leaned on instead of hand-rolled: Corvu (dialog/drawer/focus-trap/scroll-lock), @solid-primitives/* (resize-observer, media). Origin: a 41-agent Hickey/Lowy audit (16 candidates) → its “ship now” tier landed in #1089; a framework-scale re-test + adversarial skeptic surfaced the missed solid-xterm.

Built: @kolu/xterm-kit

Considered — not electricity

Looked framework-sized (the audit’s biggest braids), but fail the bar — recorded so they don’t get re-proposed.

Candidate Verdict Why
defineMutation (optimisticOverlay) helper One module, one domain (canvas layouts); the write echo is already owned by surface’s metadata subscription. Pending is a UI cache, not a transport axis.
@kolu/fs-watch helper Owns a refcount/debounce lifecycle, not a streaming transport — no wire contract, Node-bound. A @kolu/shared helper, not a socket.
@kolu/geometry domain-coupled TileLayout binds it to a server-persisted domain type; a Rect package re-adapts at every boundary — moves the braid, doesn’t dissolve it.
@kolu/surface-publish already-covered Surface’s cellHandlers/collectionHandlers/pollOnEvent already own server snapshot+delta. Only terminal.attach is a raw escape hatch.
@kolu/commands (palette) domain-coupled Palette engine is already agnostic; all coupling is isolated in createCommands, which must stay in the app. Extracting deletes ~0 kolu lines.
God-procedure split refactor Its biggest dissolvable chunk is xterm-kit (above); the rest is kolu orchestration — a refactor, not a receptacle.

Bar from Juval Löwy, Righting Software (receptacle/volatility) + Rich Hickey, Simple Made Easy (complecting); one-socket-not-a-topic-bundle is .agency/lowy.md §6.5. file:line verified against the codebase; ③ demonstrated by drishti — a second consumer (kolu is the first) that vendors @kolu/surface via npins.