Absent, not disabled
Commercial capabilities — identity-provider login, multi-factor authentication, token accounting and quotas, billing, B2B prospecting, agent evaluation, the administration panel — are not present in the open-source build. There is no feature flag to flip and no dead code in the image. Two of them are recent, and worth naming because the core keeps a hook where the brick used to be the whole answer:- Agent evaluation left the core in
0.2.0. The eval routes and the judge logic belong to the evaluation brick; the core no longer serves the ADKeval_sets/eval_resultsroutes. - Supervision across accounts stays in the core, but who may cross accounts is answered by a brick. With none registered, each person sees only their own sessions — see Supervision.
A missing key and a key set to
false do not say the same thing. The first says
the capability does not exist in this edition. Client code should treat an absent key
as “not in this edition”, never as “disabled”.The extension mechanism
Bricks are plugged in by naming their Python module inTH2_EXTENSIONS, as a
comma-separated list. Each module exposes a register(registry) function — or,
historically, init_overlay(registry). Both entry-point names are accepted.
TH2_OVERLAY_MODULE is the older single-module form. It is still honoured and is
loaded after everything listed in TH2_EXTENSIONS.
With neither variable set, no extension loads and the core stays generic and complete
in itself. That property is what makes publishing the core alone possible.
Failures are loud
Any error while loading an extension propagates and stops startup. A broken extension must be visible to the healthcheck, never degrade the service silently. An extension that exposes neitherregister nor init_overlay raises at load time.
Writing an extension
Interface slots
The web interface has the same arrangement, in JavaScript. The core declares named slots and never imports what fills them; a brick registers a component for a slot at startup. With no brick, a slot rendersnull — that is the open-source product, not a
degraded mode.
Three slots exist today:
A brick is an object with a
name and a register(registry) function, listed in
src/extensions/installed.js:
AuthScreen.legalPrefix, AuthScreen.privacyPolicy,
AuthScreen.legalAnd and AuthScreen.termsOfUse stay in the core for a brick that
wants the translated wording rather than its own.
A flag would not have been enough.
NEXT_PUBLIC_OAUTH_EXCLUDE_PROVIDERS hides sign-in
buttons, and the code for them still ships in the published bundle. An empty slot has
nothing to hide — the component was never imported.