Apps & extension
The kernel changes globally or not at all. That sounds restrictive until you see what it buys: your instance takes upgrades forever, because there is nothing of yours in the part that upgrades.
Everything specific to you lives in one of four places outside the kernel. Which one is not a matter of taste — each answers a different question.
| You need… | It goes in |
|---|---|
| New behaviour | An app |
| New data on an existing thing | Custom fields |
| The kernel to ask you something before it decides | A decision |
| A different look, layout or flow | Your storefront |
An app is code that runs beside the kernel and drives it through the same port you do. It declares what it needs in a manifest: the scopes it wants consent for, the slots it renders into, the events it listens to.
Two properties make apps safe to install:
- Consent is explicit and scoped. An app asks for scopes by name; installing it is granting them. It
reaches exactly what it was granted and gets a named
forbiddenfor anything else — the kernel’s check, not the app’s honesty. - Its data is its own. When an app has data that belongs to it, it gets its own isolated storage. It does not add columns to the kernel’s tables, so uninstalling it does not leave a wound.
An app is also how tooling gets written here. A seed script, a demo-data generator, an importer — anything that drives the port — is born as an app rather than a loose script, because the app model already gives it install, consent, scope and isolated storage.
Custom fields
Section titled “Custom fields”For data that belongs to an existing thing — an extra attribute on a product, a field the checkout must collect — you define a custom field rather than adding a column.
The value rides in a JSONB metadata bag on the item, the definition is declared through the port, and the
admin and storefront render it. No migration, no kernel change, and the field travels with the order snapshot
like everything else.
Decisions
Section titled “Decisions”Sometimes the kernel needs an answer only you have: which warehouse should serve this order, is this customer allowed this price, should this cart get free shipping.
A decision is the kernel asking — a declared question, with a declared shape, that your code answers during the transaction. It is not a webhook fired into the void; it is a synchronous seam the kernel is designed around. See decisions.
Your storefront
Section titled “Your storefront”Design, layout, flow and copy are not kernel concerns. The storefront that ships with Forge is a reference implementation — you can restyle it with theme tokens, replace pieces of it, or replace the whole thing.
⚠️ “Theme” is only the visual-identity layer: colours, typography, logo, spacing tokens. Rebuilding the checkout flow is not theming, it is owning the storefront — which is supported, and which means you own it. See own your storefront.
The ruler, when it is not obvious
Section titled “The ruler, when it is not obvious”Ask: should every instance of Forge get this?
- Specific to one business, one vertical, one integration → app, custom field, decision, or storefront.
- A neutral primitive, generic and atomic, that several unrelated integrations would use → arguably kernel.
If it is the second, ask for it. Kernel requests are reviewed and, when accepted, ship to everyone — the kernel never learns one customer’s vocabulary.
What forking costs
Section titled “What forking costs”You can fork. The kernel is source-available, and nothing stops you.
What you give up is every upgrade after that day. The four seams above exist so that you never have to: they are wide enough for real work, and they sit outside the part that moves.