Kernel
The kernel is the engine and nothing else. It is a set of platform services and an exposed API surface whose single responsibility is to interpret metadata — to turn an org’s authored content into a running application — and to let authoring tools write that metadata in. It has no interface of its own beyond a login screen and a blank canvas, and it holds no opinion about how anything should look.
Everything on this page is written to one discipline: if a thing is user interface or user experience, it does not belong in the kernel. The previous generation of the platform violated this repeatedly — a login layout, a shell, theme tokens, whole components compiled into the engine — and every one of those was a place a customer’s flexibility ended. This kernel is re-derived from that working system with the interface deliberately removed. The exercise is subtractive: keep the proven engine logic, exclude everything that was really metadata wearing an engine’s clothes.
The one job
Section titled “The one job”Given an org and an authenticated user, the kernel:
- resolves the org and the user’s access,
- loads the org’s UI metadata,
- interprets it into a rendered result, and
- serves the read/write APIs that the running application and the authoring tools call.
If step 2 finds no UI metadata, step 3 produces the empty-workspace landing — a designed “no apps installed” page painted in the kernel’s baked-in default design system. That is not an error state; it is the correct output of an engine that has nothing to interpret.
The boundary — what is and is not the kernel
Section titled “The boundary — what is and is not the kernel”| In the kernel (engine) | Not in the kernel (metadata / packages) |
|---|---|
| Metadata store and the interpreter that renders it | The shell, headers, navigation, record tabs |
| The object/data engine (records over metadata-defined objects) | Any theme beyond the bare default signature |
| The access engine (permission sets, grants, field-level security, sharing) | Component libraries and component definitions |
| Local authentication + the login surface + a dev user | App definitions, page/layout definitions, list views |
| The capability registry and injection mechanism | Guidance Center, Report a Bug, AI, Setup, Sales Atlas |
| The package manager (install / version / namespace / lock) | Branding, wordmarks, accent colors |
| The read-only metadata-of-metadata (describe) layer | Anything a customer should be able to make look different |
| Org provisioning and lifecycle | — |
| The API surface and the CLI command surface | — |
The deliberate exception on the interface side is the pair of surfaces an org needs before any package exists: the kernel ships a default sign-in screen and a default empty-workspace landing (the “no apps installed” state), plus a local development user, because an org must be reachable and legible before anything is installed. These two are the only screens the engine renders that a package did not put there, and both are rendered in the kernel’s baked-in default design system (below). Everything past them is metadata, and the moment a shell and apps install they take over.
The services the kernel provides
Section titled “The services the kernel provides”The kernel is a small set of cooperating services, each with engine logic and none rendering a designed interface. They are decomposed by reasons to change, not by feature: two pieces of logic share a service only if they would change for the same reason, and the moment they would change for different reasons they become separate services with a hard boundary. That is why, for example, the logic that renders a page and the logic that decides access are two different services — a new component type and a new sharing rule are unrelated changes, and neither should be able to disturb the other. Each service has exactly one owner-concern, and nothing else may own it.
The services fall into dependency layers. Dependencies point downward only — a lower layer never knows a higher one exists.
Foundation — persistence and truth-of-shape
Section titled “Foundation — persistence and truth-of-shape”Metadata Store. Durable storage and retrieval of metadata documents, scoped by org and API version. Pure persistence. Owns: the metadata rows. Leans on: nothing — it is the floor.
Schema Registry. Holds the type schemas — the bounded catalog of metadata types (Object, Field, Page, Package, …) — and validates any document against its type. This is the service that makes the kernel generic: every other service that interprets or validates asks it “what shape is this type?” Adding a genuinely new kind of thing to the platform is a new schema plus an interpreter, nothing more. Owns: the type definitions. Leans on: nothing.
Security — the universal chokepoint
Section titled “Security — the universal chokepoint”Authentication. Establishes and validates sessions and maps an IdP claim to an org-scoped user. Local login is the default method plus the local dev user; pluggable methods (SSO and the like) attach here. This is the kernel’s one interface concession. Owns: who you are. Leans on: Metadata Store (IdP config, users).
Access Engine. Permission sets, grants, business roles, platform roles, field-level security, and sharing — the settled security model, carried forward. Every read and write, including every metadata read, is access-checked here. It is deliberately separate from Authentication (who ≠ what) and sits in front of everything above it. Owns: what you may do. Its rules live in the security documentation and are not restated here.
Engines — the interpreters (the dynamic code)
Section titled “Engines — the interpreters (the dynamic code)”Metadata Interpreter. Reads UI metadata (a shell registration, an app, a page, a component instance, a layout) and produces what the browser renders. It knows the shapes of metadata and how to compose them; it knows nothing about any specific shell, app, or brand. Owns: metadata → interface. Leans on: Metadata Store, Schema Registry, Describe Layer, Access Engine.
Object & Data Engine. Create/read/update/delete of records over objects that are themselves defined in metadata. Standard and custom objects are the same machinery; the only difference is whether the object’s definition is a standard describe row or a customer-authored one. Owns: data rows over a metadata-defined shape. Leans on: Metadata Store (for the shape), Schema Registry, Access Engine.
The split between these two is the heart of the engine layer: the Interpreter turns metadata into interface; the Object & Data Engine turns a metadata-defined shape into record operations. Different jobs, different services — and neither decides access. Both call the Access Engine.
Platform management — services that manage the metadata set itself
Section titled “Platform management — services that manage the metadata set itself”Deploy primitive (validate-and-commit). The one true write path for metadata: diff against the target, validate against the schemas, check referential integrity, commit transactionally. This is the single door behind all three authoring surfaces (CLI, API, package install). Owns: the only way metadata mutates. Leans on: Metadata Store, Schema Registry, Access Engine.
Capability Registry. The mechanism by which a package claims a platform capability (the shell, the setup app, …) or extends one (inject an avatar-menu item, register a setup page). It enforces one master per capability, validates that a claimant satisfies the capability’s contract, and exposes the injection points that let non-master packages contribute. Crucially it holds policy hooks rather than policy: whether a second package may replace an existing master is a setting the master package surfaces, not a rule compiled here. Owns: who is the shell / setup / etc. Leans on: Metadata Store, Schema Registry.
Package Manager. Install, version, namespace, and lock packages. A package is a bundle of metadata plus its capability registrations; the manager resolves its namespace and dependencies, hands the bundle to the deploy primitive, and registers its claims with the Capability Registry. It records what is installed — itself exposed through the describe layer, so an org can be asked “what packages do I have?” It is a client of the deploy primitive, not a second write path. Owns: distribution units. Leans on: Deploy primitive, Capability Registry, Metadata Store.
Self-description and lifecycle
Section titled “Self-description and lifecycle”Metadata-of-metadata (describe) layer. Read-only, queryable descriptions of the org’s own metadata — objects, fields, permission sets, which are standard vs custom, which packages are installed. Queryable like any object, never editable, never shown in the Object Manager, and deliberately with no write path — that absence is what keeps it query-only. Owns: the org describing itself. Leans on: Metadata Store, Access Engine. Specified in the Object Model.
Provisioning & Org Lifecycle. Standing up an org, tearing one down, and installing a feature set into it. What kinds of orgs exist and what a provisioning request must capture is foundational and is designed alongside the object model, not bolted on later. Owns: orgs exist. Leans on: Metadata Store, Package Manager, Access Engine.
How the services cooperate — the four invariants
Section titled “How the services cooperate — the four invariants”The decomposition holds together because of four rules that make the services cooperate rather than tangle:
- The Access Engine is a chokepoint, not a helper. Every service that touches data or metadata routes through it — even the describe layer’s reads are access-checked. There is no back door. This one rule is what makes multi-tenancy safe.
- Dependencies point one way — downward. Interpreters depend on the store, the schemas, and the access engine; none of those knows an interpreter exists. The whole Interpreter could be replaced and the Metadata Store would not notice.
- One write path per domain. Metadata mutates only through the deploy primitive; data mutates only through the Object & Data Engine. Two write paths total, each singular for its domain — so “how does anything change an org?” always has exactly one answer.
- The Schema Registry is the generic core. Because every validate-or-interpret step asks it for the shape, the kernel never hard-codes “Quote.” A new metadata type is a new schema plus an interpreter; no existing service is rewritten.
Performance — two clocks, and what is cached
Section titled “Performance — two clocks, and what is cached”A fully dynamic engine invites an obvious worry: since each request is stateless, does every request re-run the whole resolve → fetch → validate → hydrate → interpret chain from scratch? The design answer is no, and it falls out of a single observation.
Every step in the chain runs on one of two clocks. Metadata changes on deploy cadence — rarely; the objects, the installed packages, the page shapes, and the permission sets do not change between two requests a second apart. Data changes on request cadence — constantly. The design rule follows directly: nothing that depends only on metadata is recomputed per request. It is computed once per deploy and reused until the next one; only the record data on the current page is fetched fresh.
Concretely, three things are cached:
- The compiled metadata registry — the validated, hydrated “known universe” for an org. Built once and shared across every user and every request of that org. Keyed by
(org, metadataVersion). Validation and hydration are the expensive steps and are identical for every user, so this single cache removes most of the per-request cost. - The resolved access set — a user’s effective permissions, pre-flattened so “can they?” is a lookup rather than a re-evaluation of raw permission-set documents. Keyed by
(role / permission-set-group, metadataVersion), so users who share a role share the entry. - The resolved page shape — a route interpreted into a render plan (template + components + which fields), minus the data. Keyed by
(route, layout, metadataVersion, accessProfile); the data is slotted into the pre-resolved shape at request time.
The key to correctness is a single monotonic metadataVersion stamp per org that bumps atomically on every deploy or install. Every metadata-derived cache key contains it, so invalidation is a non-event: on a change the version moves, old keys are simply never looked up again and age out on their own — no cache is ever hunted down and purged. This is exactly why invariant #3 (one write path for metadata) matters beyond tidiness: because all metadata changes funnel through the deploy primitive, there is exactly one place that bumps the stamp, so metadata cannot be mutated without invalidating the cache. The single write path is what makes aggressive caching safe.
This is also why the metadata ≠ data separation is load-bearing for performance, not only for multi-tenancy: because shape and contents are cleanly separated, the engine caches all of the shape and streams only the contents — which is how a wildly dynamic platform still feels static.
The honest weak spot is cold start: the first request after a deploy, or on a cold worker, still pays the full validate-and-compile cost. The mitigations are standard — compile to a durable artifact at deploy time so a cold worker rehydrates from a pre-validated blob rather than re-validating raw documents, and warm the cache on deploy — and, because the platform runs at the edge, the compiled registry can live close to the user, versioned so a deploy rolls it forward. This section is design intent; the cold-start numbers are the part that needs real benchmarking once the kernel exists.
What the kernel exposes
Section titled “What the kernel exposes”The kernel’s outward surface is two things that are really one: an API and a CLI over that API. Anything the CLI can do, the API can do; the CLI is the ergonomic developer front-end, the API is the programmatic one. Both are the only ways to change an org.
That surface separates into distinct API families, each individually documentable, and is significant enough to have its own document — The API Surface. The families the platform builds first:
- Data API — record create, read, update, delete, plus query and describe over metadata-defined objects. This is the headless workhorse: the way a customer operates on their data with none of the platform’s UI. (Absent from earlier drafts of this list, and the most important one — a headless customer needs CRUD, not only metadata deploy.)
- Metadata API — write authored metadata into an org and read it back out; the unit is source-format metadata, transactional and access-checked (the deploy primitive above).
- Tooling API — fine-grained, synchronous, per-component metadata operations for the CLI, the VS Code extension, and dev tools — the interactive sibling of the Metadata API.
- Event API — one modern streaming API to subscribe and publish over the platform’s event system, with durable replay and flow control.
Plus the platform-management families already described as services: capability registration, authentication, package management, and provisioning. Additive families (Bulk, UI, GraphQL, Composite, custom endpoints) and the deliberate exclusions (no SOAP, no legacy streaming twin, no per-industry API catalog) are covered in The API Surface.
The precise commands, the source/project format, and the local VS Code tooling that drives all of this are specified in CAOS CLI. This page’s claim is only structural: the kernel exposes these as APIs and CLI commands, and nothing authors an org except through them.
The default design system
Section titled “The default design system”To paint any pixel — the sign-in screen, the empty-workspace landing — the engine needs a design system: colors, type, spacing, a mark. Rather than a bare unbranded signature, the kernel bakes in a complete default design system: the platform’s own first-generation (v1) look. This is the one design system compiled into the engine, and it exists so that a freshly provisioned org is polished and on-brand from its very first screen, not blank-on-blank.
Two properties keep this consistent with the metadata-first rule:
- It is a fixed default generation, not a privileged one. Any installed brand — Dragon, or a customer’s own — is a design system delivered as metadata that overrides the default on every surface past provisioning. The baked-in default shows only on the two pre-install surfaces (sign-in and empty workspace).
- It is frozen against rebrands. If the platform’s own marketing brand later changes, the baked-in v1 default can stay exactly as it is — it is the engine’s provisioning-time signature, not the company’s living brand. Decoupling the two means a rebrand never touches the kernel.
This is the single, bounded place the engine carries a designed look. It buys a finished first impression for a brand-new org, at the cost of exactly two compiled-in surfaces — and it costs nothing thereafter, because installed metadata supersedes it everywhere else.
The provisioning-time experience
Section titled “The provisioning-time experience”The two default surfaces exist to make the first minutes of a new org feel immediate and finished rather than empty and confusing. The intended sequence when someone signs up:
- Spin up the tenant and hand over credentials fast. Provisioning stands up the org and returns sign-in credentials right away, so the user can log in almost immediately rather than waiting on a long setup.
- Log in to the designed sign-in screen. The first surface is the baked-in sign-in page — finished and on-brand, not a bare form.
- Land on the empty-workspace page. With nothing installed yet, the user sees the designed “no apps installed” landing — a deliberate moment that shows what the platform looks like with nothing on it, and makes the model tangible: the kernel is running; a shell and apps are what fill it.
- Default apps install in the background, then appear. While the user takes in the empty state, the standard packages install; the workspace populates without a jarring reload. The empty landing is the honest before-picture, not a dead end.
The wide-open org — a playground shape
Section titled “The wide-open org — a playground shape”The empty-workspace landing’s install actions also enable a deliberately bare org shape: an environment provisioned with nothing installed, offered as a hands-on trial. From it, a prospective customer can install different shells, design systems, and org shapes and watch the same kernel become visibly different systems — a tactile way to experience the platform’s whole premise before committing. It is the platform’s answer to a scratch org, but visual and self-serve rather than a developer artifact: the empty workspace is the doorway, and installing packages is the demonstration.
Boot and interpret order — what happens when the platform loads
Section titled “Boot and interpret order — what happens when the platform loads”There are two questions worth answering separately: the order of events from a cold request to a painted screen, and the order the interpreter resolves metadata once it has a session. The first is the lifecycle; the second is the dependency order within the metadata universe.
The lifecycle — cold request to painted screen
Section titled “The lifecycle — cold request to painted screen”- Resolve the org. The tenant is identified from the domain (each org has its own subdomain or custom domain) and confirmed by the signed-in user’s authoritative org claim — domain first for speed and login branding, the claim final. One request always resolves to exactly one org.
- Require a session. If there is no authenticated session, the kernel serves the default local login (its one interface concession) and stops here until identity is established.
- Fetch this org’s metadata set. With a session, the kernel pulls the org’s metadata — capability registrations, apps, objects, fields, layouts, list views, permissions, design system — scoped to this org, from the metadata store.
- Validate against the type schemas. Every metadata document is checked against its type’s schema before anything renders. Invalid metadata never reaches the screen; it fails loudly, it does not render half a UI.
- Hydrate the runtime registry. The validated metadata becomes the in-memory “known universe” for this org — the kernel’s map of what exists and what claims which capability.
- Interpret and render (the resolution order below), every read passing through the access engine.
The resolution order — how the interpreter walks the metadata universe
Section titled “The resolution order — how the interpreter walks the metadata universe”Once the registry is hydrated, the interpreter resolves metadata outermost-first, each layer establishing the context the next is interpreted inside:
- Capabilities first — is there a shell? The interpreter looks for a package that has registered as the shell. If none is registered, it renders the empty-workspace landing in the default design system — a designed “no apps installed” page (kernel online, workspace awaiting a shell) with actions to install a shell or deploy an app. Interpretation stops here; the org is reachable and clearly not broken. This is why the shell resolves before anything else: it is the frame everything else renders inside.
- Design system. The org’s design system (or the default one Core carries) is applied as tokens, so every surface below paints in the right brand before it appears.
- The shell’s own surfaces. The registered shell’s global header, navigation, app switcher, and edge-anchored injection points are rendered from its metadata — plus any surfaces other packages injected into it.
- Route → app → tab → object. The current URL resolves to an app, the app to a tab, the tab to what it opens — a list view or a record page — which is bound to an object. The interpreter asks the registry “what is object X?” and gets its fields, record types, layout, list views, and permissions.
- Page → template → components. The resolved page selects a page template (its named regions) and places its components into those regions — the generic list-view renderer, the generic record-page renderer, custom web components — each parameterized by metadata, none written per object.
- Data rows, never shape. Finally the rendered surface reads and writes the object’s data. The shape stayed in metadata; the contents live in data tables; the two are never confused.
No step consults a hard-coded interface. The shell in step 1 is metadata the engine was handed — swap the shell package and the whole frame changes with no change to the kernel — and the same is true at every layer below it.
What installing a package does at boot vs. at install time
Section titled “What installing a package does at boot vs. at install time”Two moments are easy to conflate. At install time, the package manager validates the package’s metadata, resolves its namespace and dependencies, records its capability claims (enforcing one-master), and commits the bundle — the same validate-and-commit primitive a deploy uses. Nothing renders; the org’s metadata set simply grows. At boot, the interpreter finds those already-committed registrations in the registry (step 5 of the lifecycle) and resolves them in the order above. So “installing the shell package” and “the shell appears” are two separate events: install writes the registration; the next load interprets it. A package is inert metadata until the interpreter walks it.
Default surfaces — the conditions only the kernel can catch
Section titled “Default surfaces — the conditions only the kernel can catch”The empty-workspace landing is not a special case; it is one member of a family. There is a set of conditions that occur before or outside any successfully-resolved page — so no installed metadata can be responsible for them, and the kernel is the only thing positioned to catch them. A user typing a nonexistent URL is the obvious one, but it is not alone.
The catchable conditions
Section titled “The catchable conditions”Before a session, or before an org even resolves:
- Org not resolvable — the domain or subdomain maps to no org. There is no tenant to load, so nothing downstream can respond.
- Org unavailable — the org exists but is suspended, not yet provisioned, in maintenance, or outside the supported API-version window. A lifecycle state, not a metadata state.
- Not authenticated — no valid session. The kernel serves the default local login (already its one interface concession).
After a session, inside a resolved org:
- Empty workspace — a valid session, but no shell/UI metadata to interpret. The kernel renders its designed “no apps installed” landing in the default design system (not a blank page): a legitimate empty state, not an error, carrying actions to install a shell or deploy an app.
- Route not found — the URL resolves to no app, tab, object, or page in this org’s metadata. The shell exists; the specific destination does not.
- Record not found — the route is valid (the object exists) but the specific record does not, whether deleted, mistyped, or invisible to this user under sharing.
- Not authorized — the access engine denies the requested app, object, or record. The thing exists, but this user may not see it.
- Metadata fault — the interpreter is handed metadata that fails validation at render time, or a component throws. The engine must fail loud and legible, never a silent white screen.
- Capability unsatisfied — a package registered as a capability master (the shell, say) but fails its contract at render, or a required capability the current route depends on is claimed-but-broken. The registry is a kernel service, so keeping this from becoming a blank frame is a kernel duty: it falls back to the next legible level (a broken shell degrades toward the empty-workspace landing rather than a dead page) and says so.
The rule — detect in the kernel, present in a package
Section titled “The rule — detect in the kernel, present in a package”Every one of these follows the same two-layer shape as the empty workspace:
- The kernel detects the condition and guarantees a minimal, legible fallback — painted in the default design system, stating in plain words what happened and offering the one obvious way out (a link home, a sign-in prompt). This guarantee is what makes the platform never a broken void: even with nothing installed and something gone wrong, the user gets a legible sentence, not a dead page.
- A shell or package presents the branded version by registering a handler for the condition — a fallback capability, resolved exactly like any other. When a shell has registered a not-found handler, the kernel routes the condition into it so the branded “page doesn’t exist” renders inside the shell chrome. When nothing is registered, the kernel’s bare fallback still answers. Branded error surfaces are therefore installed metadata, not compiled UI — the same discipline as everything else.
Blank is correct for empty, never for error
Section titled “Blank is correct for empty, never for error”The distinction the empty workspace raises is worth stating outright, because it decides how each fallback should look:
- An intentionally empty surface — the empty-workspace landing, or a list view with zero records — states plainly that nothing is there yet. The empty-workspace landing is designed and calm rather than raw-blank, because “nothing installed” is a normal starting state, not a failure.
- An error surface — not found, not authorized, faulted — must never be a silent void, because a blank page on an error is indistinguishable from a crash. The kernel’s fallback for every error condition therefore always says something: what happened, and what to do next.
(One policy call worth stating explicitly: for a record the user isn’t allowed to see, the kernel can answer either not authorized or not found — the latter avoids leaking that the record exists at all. This is a per-org security posture exposed as a setting, not welded into the engine, and it defaults to the most secure behavior: answer not found, so existence is never disclosed. An org may relax it to not authorized where showing “you can’t see this, but it’s here” is acceptable.)
Why this belongs in the kernel
Section titled “Why this belongs in the kernel”Every condition here shares one trait: it happens where there is no successfully-resolved page metadata to hand to a shell. The org can’t be found, the session isn’t there, the route matches nothing, the access check failed, the metadata itself is bad. In each, the only actor guaranteed to exist is the engine. So detection and the guaranteed-minimal fallback are kernel responsibilities by necessity, while the branded presentation stays installed metadata — mirroring the open-canvas/shell split precisely. The kernel owns that a fallback happens and that it is legible; a package owns what it looks like.
Bootstrapping and the no-deadlock guarantee
Section titled “Bootstrapping and the no-deadlock guarantee”An empty org must always be able to pull itself up. Two deadlocks could trap it, and the architecture closes both by construction.
The UI deadlock — closed because the API is the floor. Every UI surface (a Setup page, a capability toggle, the shell itself) is a projection of something the kernel API can already do. The API — and the CLI over it — is exposed by the kernel and depends on no package being installed. So there is no configuration, policy, or capability that is reachable only through a UI: whatever a Setup page could flip, the API can flip directly. An org with nothing installed is never a dead end, because the kernel’s authoring API is always the open door.
Claiming a vacant capability is not a takeover. Two operations look similar and are governed differently:
- Claiming a vacant slot. An empty org with no shell can install a shell package, which claims the unoccupied shell capability. Allowed by default — one-master-per-capability forbids a second master, not a first one. No package (not even CAOS Core) is a prerequisite; requiring one would privilege it, which the kernel does not do. Any shell can be the first shell.
- Taking over an occupied capability. Replacing an existing master (installing a second shell over CAOS Core) is a takeover, gated by a policy the incumbent surfaces. Its default is deny, so an installed package can never silently seize the shell. The policy value lives in the kernel, so it is settable through the incumbent’s Setup UI or directly through the API/CLI — the takeover path never depends on a UI existing.
The kernel API sits above every package. The one state we must never permit is a package creating a condition only that same package can undo. The rule that prevents it: an org admin acting through the kernel API is the ultimate authority. A package may surface a policy and default it, but it can never override the admin’s ability to change it. So a buggy or hostile package can never permanently lock an org out of its own shell — the API is the escape hatch above every package, because it belongs to the kernel, not to any package.
Headless orgs are a first-class mode, not an edge case. An org may install none of the standard UI packages, drive everything from its own frontend on its own site, and use the API for all configuration. This is a direct consequence of the engine/UI separation, not a special path: the kernel exposes the same API whether the caller is CAOS Core or a customer’s own application. “Bring your own UI, hit the API” is simply what a headless org is.
Provisioning seeds a bootstrap admin. The permissions twin of the UI deadlock: the default provisioned user must arrive with enough privilege to install packages and set policy, or an empty org would be a dead end for lack of rights rather than lack of UI. Provisioning therefore seeds a bootstrap admin grant — the minimum the org needs to pull itself up.
The abstraction mandate
Section titled “The abstraction mandate”This kernel is built from scratch architecturally, but it is not invented from nothing. The prior platform is a working reference: its engine logic — the interpreter, the object engine, the access engine, provisioning — is proven and is borrowed deliberately. What is not carried over is everything that was interface hiding inside the engine. The value of re-deriving the kernel with hindsight is exactly this: we already know what the finished product needs to do, so we can draw the engine/interface line precisely and keep the line clean this time.