This section covers the two foundational pieces of the render-hook system:
- naming
- slot declaration
If those are not clear, everything else becomes fragile very quickly.
Relative Names vs Fully Qualified Names¶
Render-hook names are treated as module-scoped contract keys.
If your module is auth and you talk about login.form.after_fields, the fully qualified hook key is usually:
auth.login.form.after_fieldsThis is why the facade exposes qualify_render_hook_name(...).
The slot owner often wants to work with a short relative name inside its own module, while downstream providers should target the fully qualified key explicitly.
qualify_render_hook_name(name: str) -> str¶
This method returns the fully qualified hook name for the current module.
Example:
qualified = module_sdk.hooks.qualify_render_hook_name(
"dashboard.after_stats"
)
# -> "my_module.dashboard.after_stats"What It Is For¶
Use this when you need the canonical hook name rather than the short module-local form.
Typical cases:
- logging
- documenting slot contracts
- checking that provider registration is targeting the exact expected key
- generating references to hook names in config or developer tooling
How It Works¶
The rule is simple:
- if the current module is
core, the name is left unchanged - if the name is already prefixed with the current module, the name is left unchanged
- otherwise the current module name is prefixed automatically
Why It Matters¶
Without this normalization, slot owners and providers drift very easily.
One module thinks the hook is dashboard.after_stats, another registers analytics.dashboard.after_stats, and now the extension point silently stops working.
qualify_render_hook_name(...) keeps the slot owner side deterministic.
@render_hook_slot(...) And Slot Contracts¶
Although the decorator is documented under the decorators domain, it is part of the practical hooks mental model and should be understood together with this facade.
A render-hook slot declares:
- the public hook key
- whether providers are optional
- a human-readable description
Example:
@render_hook_slot(
"login.form.after_fields",
optional=True,
description="Inject additional UI after the login form fields.",
)
def register_login_after_fields_hook():
return NoneIf this is declared inside the auth module, the public slot key becomes:
auth.login.form.after_fieldsWhy Slot Declarations Matter¶
Slots are what turn a render hook from a hidden convention into a public extension contract.
If a slot is resolved without being declared, the runtime logs a warning that the hook was resolved without being declared as a public hook API.
That warning is telling you something real:
- undeclared hooks can still work
- declared hooks are easier to discover, document, and maintain
If a hook is meant to be extended by other modules, declare the slot.
get_render_hook_slots(module_name: str | None = None)¶
This method returns the declared render-hook slot definitions from the runtime registry.
Example:
all_slots = module_sdk.hooks.get_render_hook_slots()
auth_slots = module_sdk.hooks.get_render_hook_slots("auth")What It Is For¶
Use this method when your module wants to inspect which public hook slots have been declared across the application.
Typical use cases:
- developer documentation pages
- extension browser/debug screens
- validation tooling
- module admin UIs that explain available UI extension points
What It Returns¶
Each slot definition contains metadata such as:
namemodule_nameoptionaldescription
This is the runtime-visible declaration of the public hook contract.
Filtering By Module¶
Pass module_name when you only want hooks declared by a specific owner module.
Omit it when you want the full global list.
Why This Method Is Useful¶
Render hooks are much easier to build against when the extension surface is inspectable.
get_render_hook_slots(...) is what makes that possible.
Without it, hook contracts become tribal knowledge hidden in source files.
Safe Naming Guidance¶
Render-hook names work best when they describe a stable UI position owned by a specific module.
Good examples:
auth.login.form.after_fieldscrm.dashboard.after_statsbilling.invoice.view.sidebar
Weak examples:
extraslot1hook
The name should tell another developer where the injected UI will appear.