This section covers the most privileged part of the domain:
module_sdk.system.setup.is_enabled()module_sdk.system.setup.finalize(admin_user, admin_pass, admin_email=None)module_sdk.system.setup.request_finalize(admin_user, admin_pass, admin_email=None, stream_id=None, session_key=None)
This subdomain is not general operational sugar. It is specifically about the application setup flow.
setup.is_enabled() -> bool¶
This method returns whether setup mode is currently enabled.
Example:
if module_sdk.system.setup.is_enabled():
module_sdk.system.log("Application still in setup mode")What It Is For¶
Use it when UI or action logic needs to branch on whether the application has already completed setup.
That is how it is used in setup pages and some guarded UI flows.
What It Actually Does¶
The method checks app_ctx().setup_mode and returns False if even that lookup fails.
So it is intentionally forgiving and safe for normal UI logic.
Important Detail¶
This helper reads the same setup-mode flag used by the setup finalization path. It is intentionally a simple runtime-state check, not a full validation of whether a submitted setup payload is complete.
setup.finalize(admin_user, admin_pass, admin_email=None) -> None¶
This method finalizes setup mode, bootstraps the runtime around the chosen configuration, runs migrations, seeds the admin user, and then disables setup mode.
Example:
module_sdk.system.setup.finalize("admin", "change-me", admin_email="admin@example.com")What It Is For¶
Use this only in the actual setup-completion flow, after configuration has already been written and validated.
The system module setup helper is the reference pattern around this operation:
- build or validate the config payload
- apply it to the config provider
- save the config
- ensure setup storage is writable
- log setup progress
- request setup finalization through
module_sdk.system.setup.request_finalize(...)
Direct finalize(...) is the low-level finalization routine behind that flow.
What It Actually Does¶
The method performs a lot of runtime work.
At a high level, it:
- checks that
context.setup_modeis truthy - tears down and resets existing database/data-engine globals
- rebuilds the persistence, media, KG, vector, data, and observability providers from config
- resets the network session store when available
- runs database and storage migrations
- seeds the administrator user
- tries to apply process restrictions such as seccomp/Landlock if enabled
- finally sets
context.setup_mode = False
This is much more than “mark setup as complete”.
Important Preconditions¶
If the application is not in setup mode, the method raises:
PermissionError("APPLICATION NOT IN SETUP MODE")That means it is intentionally protected from accidental use in normal runtime flows.
Why This Matters¶
This is an orchestration API, not just a flag flip.
If you call it from the wrong place or at the wrong time, you are not merely making a harmless state change. You are reinitializing core runtime providers and executing migrations.
So the right way to document and use it is:
- setup flow only
- after config persistence and validation
- with clear operator intent
setup.request_finalize(...) -> dict[str, Any]¶
This method queues setup finalization through the core runtime consumer.
Example:
result = await module_sdk.system.setup.request_finalize(
"admin",
"change-me",
admin_email="admin@example.com",
stream_id=ctx.get("stream_id"),
session_key=ctx.get("session_key"),
)What It Is For¶
Use it when setup completion should be requested asynchronously and tracked by the runtime instead of running the full finalization inline inside the action.
The optional stream_id and session_key let the runtime associate setup progress and follow-up messages with the active client/session.
Relationship To finalize(...)¶
request_finalize(...) does not replace finalize(...) as the low-level finalization routine.
It publishes a setup-finalize request that the core runtime consumes, and the consumer eventually runs the same setup-finalization path.
Real Usage Pattern¶
The existing setup helper does roughly this:
cfg = app_ctx().config
apply_config_payload(cfg, payload)
cfg.save()
ensure_setup_storage_writable(cfg)
module_sdk.system.log("[Setup] Configuration saved. Bootstrapping providers...", "info")
await module_sdk.system.setup.request_finalize(
admin_user,
admin_pass,
admin_email=admin_email,
stream_id=stream_id,
session_key=session_key,
)
module_sdk.system.log("[Setup] Finalization requested.", "info")That is the pattern module authors should follow if they are touching the setup flow itself.
Practical Guidance¶
Treat setup.finalize(...) as one of the most privileged SDK methods in the project.
For normal module development, you will almost never need it.
For setup-flow work, you should document and structure the surrounding code so it is obvious that configuration save, storage checks, and setup finalization happen in the correct order.