2026-09-23·by Sijie Wang#software

external-means-fully-external

Parent: structure · Kin: owner-facade-from-registry · mcp-capability-plugins · convergence-inbound-and-outbound

An externalized capability owns its own storage too. If the kernel still holds the table, the capability was relocated, not externalized — and a tidier address passes every gate while changing nothing.

The failure mode this names

Moving a capability out of the kernel is easy to do halfway, and the halfway state is comfortable: the code lives in capabilities/<id>/, the import graph is green, the arch-lint passes, the diff looks like progress. What stayed behind is the data — a table in the shared schema, a repo in a shared data module, a field on a shared config struct. The kernel still knows this capability exists, and adding the next one still means editing the middle.

The diagnostic question is not "where does the code live" but "if I delete this capability, what is left behind in the kernel?" If the answer is a table, a column, a struct field, or a case in a switch, it is not external.

What fully external looks like

  • Its own storage. Each capability gets an isolated store, provisioned from its own declaration — never a shared data module that every capability reaches into. Isolated storage is what makes the outbound convergence (a field on an invite code), the inbound reach-back (a sandbox reading and writing), and the usage gate all read from one place per capability.
  • Its own declaration, as data. Identity, which host ops it orders, which field it occupies on an invite code, its config defaults — in backend/capabilities/<id>/manifest.yaml, not as a Go literal at the assembly root. Written where the capability is described, not where the program is wired (convergence-inbound-and-outbound).
  • Its own instructions. Strategy and phrasing ship with the capability's MCP instructions, so a session not granted it never reads them. The kernel states facts; capabilities give instructions.
  • Its edges move with it. The thing that rots a move is not the code — it is the error table, the lint exemption, the testid, the 'use client' boundary. None of those follow automatically, and when one fails to follow nothing errors; the system simply does one less thing than before.

Why the kernel must be able to forget

The test of externalization is the ratchet in check-core-agnostic: no concrete capability name may appear in a kernel package at all. Not "may not import" — may not be named. Import-graph checking cannot see a kernel file that wrote a capability's logic in its own package, because every arrow stays green. So the guard reads strings, and it runs with an empty baseline: nothing grandfathered.

The canonical catch was not a table but a sentence: the kernel's always-on datetime context mentioned the owner's calendar, delivering scheduling advice to visitors who had no booking tool. The capability had been externalized; one sentence about it had not.

read next
about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →