Skip to content

Setup & the metadata-type registry

Everything an app is made of — its objects, fields, layouts, picklists, permissions, roles, tabs, and apps — is itself metadata: definitions described by a small, bounded catalog of metadata types the kernel interprets. The kernel is a pure engine over that catalog. It never hard-codes “Invoice” or “Account”; it knows only these types, and every org is some combination of instances of them.

Setup is the collection of editors over that catalog — the analogue of Salesforce Setup (Object Manager, Permission Sets, Sharing Settings, …). But Setup is not part of the engine. The kernel ships no application UI of its own beyond a sign-in screen and an empty-workspace landing (see How the platform works); the Setup app and every editor in it are metadata. The setup package delivers the app itself — it masters the setup capability and exposes injection points so other packages can contribute their own setup pages — but it does not deliver the editors mounted into it. Each of those ships with the package that defines the type it edits, which for almost all of them is the package that surfaces the kernel; see which package owns an administrative page below. This page documents the metadata-type registry Setup edits, and how each Setup surface maps onto it.

The kernel is generic over a fixed catalog of metadata types. Each row below is itself described by a schema (“an Object has a key, a label, a table, and a list of Fields”), and each Setup editor is a typed view over one authoritative definition rather than a bespoke form. The full model and its lanes live on the architecture object-model reference; the working set is:

Metadata type Shape (key fields) Salesforce analogue
App key, label, tabs[], landingTab, settingsPage (CAOS-694 — this app’s own setup-kind settings surface, reached from the account menu, not from tabs), navStyle (standard / console), icon, brand, logo CustomApplication
Tab key, label, target (an object or a page), defaultListView, icon CustomTab
Object key, label, pluralLabel, nameField, nameTemplate (CAOS-1585 — optional; how a record titles itself, as a {field} template over the record’s own fields, with {id} for the record’s short id and {label} for the object’s translated label. Absent means the renderer’s default: the label in front of an auto-number, the label plus the short id when the name is blank, and the bare value otherwise — which {label} {nameField} and {label} {id} express exactly), sharingModel (private / publicRead / publicReadWrite / controlledByParent), optional recordTypes, lifecycle CustomObject
Field three axes — a storageType (Text, Number, Boolean, Date, DateTime, Select, MultiSelect, Reference, Formula, Rollup, AutoNumber, JSON, File, Overridable, Localizable), a format modifier, and reference.composition for master-detail — see the field model CustomField
Record Type A variant of an object that shows/hides fields and selects a layout. Every object has one real default; variants layer on top RecordType
Page Layout two artifacts: a simple layout (object, sections[] of {label, columns, fields[]}) and a richer page manifest (template, sections → field/component items, related lists, actions) Layout / FlexiPage
List View A saved, filtered, columned view of an object’s records ListView
Value Set / Picklist key, label, values[] (value + label), with per-value retire/restore GlobalValueSet
Page Template A named-region blueprint pages are built from — see pages & components Lightning page template
Page A composed screen — a template plus components placed in its regions FlexiPage
Permission Set objectPermissions[], fieldPermissions[], userPermissions[], appVisibility[], tabVisibility[], appPermissions[] (CAOS-694 — per-app { app, administer } rows: does this person administer this app, distinct from appVisibility and from the global setup.access system permission), optional sessionRequired PermissionSet
Permission-Set Group sets[] + one optional mute PermissionSetGroup
Role key, label, parent — a node in the record-visibility hierarchy; grants no permission, only inherited visibility of records owned below it in the tree (CAOS-509) — see Roles & record sharing Role
Package A versioned distribution of metadata plus its capability registrations — see Packaging Managed / Unlocked Package
Capability Registration A package’s claim to master a capability (the shell, setup) or to extend one via an injection point; enforces one-master-per-capability (no direct analogue)
Guidance Recipe + Anchor Intent-based guidance steps referencing UI anchors by capability role, never by pixels (no direct analogue)

Beyond these, the registry also carries formula and roll-up fields, validation rules, list views, lifecycles, automations, calc functions, custom metadata, the design system, AI config, and the org itself — so the platform describes itself in the same typed metadata every app is built from. The Package, Capability Registration, and Guidance types are the newest additions: they exist precisely because UI is now installed rather than compiled into the engine, so a shell, a setup app, or an app arrives and claims its role as metadata the kernel reads.

Setup is a package, not a privileged surface

Section titled “Setup is a package, not a privileged surface”

The setup package masters the setup capability. Under the capability model, the kernel exposes a fixed set of capability slots and enforces one master per capability; the package that masters setup owns the Setup app’s frame — its navigation, its landing surface, its search, its entry points. It holds that role by satisfying the setup capability contract, not by being special-cased in the engine. In principle it is replaceable: a conforming package could claim setup instead, and swapping it changes the frame around administration with no change to the engine and no change to the editors mounted inside it. Remove it and the org falls back to the empty-workspace landing.

Two consequences follow, and both are load-bearing:

  • Setup exposes injection points. A master owns the frame but not everything mounted into it. Other packages contribute their own setup pages through named injection seams without claiming the capability — the same mechanism a billing package uses to add a rates page under its own group. One convention the tooling relies on: a package that injects setup pages brings at least one group, and each group contains at least one page, so the Setup navigation is never left with a dangling or empty entry.
  • Enforcement stays in the kernel. Every Setup screen edits metadata the kernel interprets — an object definition, a permission set, a layout, a capability registration. Mastering setup lets a package own the editor and the presentation; it does not move any enforcement into the package. The access engine that checks every read and write, the interpreter that renders metadata, and the deploy primitive that commits a change all stay in the kernel and cannot be swapped. Owning the administration UI is not the same as deciding who is allowed to administer.

Mastering setup does not make the setup package the owner of everything shown inside it. Ownership is decided by one rule, applied without exception:

A page that administers a thing belongs to the package that defines that thing — not the one that displays it, not the one that needs it first, and not the administrative application by default.

For anything that is a security boundary the definer must be the kernel, because nothing above the kernel can guarantee anything: a guarantee that lives in an installable package can be uninstalled, replaced, or simply never installed, and any of those removes it silently. That is not a second rule — it is the first one plus the observation that a guarantee cannot be delegated upward.

The test to apply, so this is decidable rather than a matter of taste:

If the capability this page administers were uninstalled, should the page disappear? If yes, it ships in that package. If the page still makes sense on a platform with nothing installed, it belongs with whoever ships what it edits.

Two consequences catch most people out:

  • The administrative application owns no domain pages. It holds its landing surface, its navigation, its search, and its frame — and nothing domain-specific, ever. A page is shown there; it does not live there. Everything else arrives through the injection seams above.
  • A page can be core while its contents are not. The pricing-and-calculations surface edits calcFunction, which the kernel defines, so the page is core — while every calculation function it edits arrives with whichever package defines that function.

Applying this across the reference application’s twenty administrative entries puts eighteen with the package that surfaces the kernel, one with the package that defines the object it lists, and leaves one deliberately unowned rather than assigned to make the table look complete. The per-page table, with the reason for each row and the ticket carrying it, is the CAOS-447 ownership record.

Each Setup editor is a typed surface over one metadata type (or, for assignments, over a control-plane record). Every change to a metadata definition goes through the same metadata deploy pipeline — validated against its schemas and referential integrity, then applied in one transaction or rejected whole; a role’s tree shape (parent) is one such definition, projected into the enforced hierarchy at activation (CAOS-509). The surfaces that write records (permission-set assignment and per-user role assignment) write directly instead — a role’s own tree shape and a user’s assignment to one are deliberately drawn apart the same way a permission set and its assignment are.

Setup surface What it edits Write path Salesforce Setup area
Object Manager / catalog Objects, their fields, and nav (tabs → targets) metadata deploy Object Manager
App builder Apps and their tabs/objects metadata deploy App Manager / Lightning App Builder
Page-layout editor Layouts and page manifests (regions, sections, placements) metadata deploy Page Layouts / Lightning Record Pages
Value-set editor Retire / restore a value of a picklist guarded metadata deploy Picklist Value Sets
Permission-set editor Object / field / system grants + group muting metadata deploy Permission Sets / Permission Set Groups
Field-level security matrix Field read/edit per permission set, as a field × set grid metadata deploy (as permission-set metadata) Field Accessibility / FLS
Assignment editor User → permission-set / group assignments writes control-plane records directly Permission Set Assignments
Roles editor The role hierarchy (create / rename / reparent) metadata deploy (CAOS-509) Roles (Role Hierarchy)
Role assignment Per-user role (zero or one) writes control-plane records directly Roles (Role Hierarchy)
Sharing editor Org-wide defaults + sharing rules metadata deploy / rules Sharing Settings

Read-and-explain surfaces sit alongside the editors. An access-explain view answers “why can / can’t this user see this record or field?” across permission sets, roles, sharing, and FLS — the resolved access, not a source’s raw flag (see Permissions & FLS and Roles & record sharing). These read from the describe layer and the effective-access resolver rather than reconstructing access by hand. The access-explain view lives at Setup → Platform → Access Explain: it asks the access noun’s explain and check verbs and shows the clause that decided, including the clauses that did not — what would have granted access is the half an administrator acts on. Both verbs require security.manage, because explaining another person’s access is introspection over the access model itself.

Every editable definition is simultaneously reflected as a read-only describe row — a queryable record that reports what the metadata universe currently contains (object_definition, field_definition, permission_set, capability_registration, and the rest). Describe rows are never authored directly; the kernel projects them from the deployed metadata and serves them through the same query surface as data. They are how a Setup surface, or an integration, asks “what objects, fields, and permissions does this org have?” — and the capability_registration rows are how “which package masters setup, and which packages inject into it?” becomes a query rather than an inspection of package internals. Describe reads pass through the same access engine as any other read; describing the org is not a privileged side channel.

  • How the platform works — the engine/UI separation, capabilities, and injection points in one page.
  • The developer surface — the full map of what you author, including the setup surface.
  • Packaging — how a package claims or extends a capability, and how each editor arrives from the package that defines what it edits.
  • Field model and Permissions & FLS — the storage and access planes Setup edits.

For the settled architecture behind the catalog and the engine — the full metadata universe, the describe layer, the capability registry, and the shell contract — see the object-model, kernel, and shell references on the architecture site.