Reference
Admin Shell Conventions
Extension admin routes render inside the same authenticated shell used by core admin screens. The shell gives extension pages the utility bar, navigation rail, workspace container, shared CSS, breadcrumbs, and document title behavior.
The conventions below describe what an extension route may rely on today.
Route File Shape
A route file should start with the system bootstrap and an administration access gate:
require_once dirname(__DIR__, 4) . '/system/bootstrap.php';
$currentUser = myronRequireAdministrationAccess();
$sdk = new MyronExtensionSDK('my_vendor');
Then wrap page markup with:
myronRenderAdminShellStart($currentUser, [
'title' => 'My Vendor Settings',
'titleContext' => 'Extensions',
'activeItem' => 'settings',
]);
and close with:
myronRenderAdminShellEnd();
Shell Options
| Option | Use |
|---|---|
title | The page title used in the browser document title and workspace context. |
titleContext | A broader context label. Extension pages should usually use Extensions. |
activeItem | The current route key for shell active-state checks. |
headStyles | Optional extension-owned stylesheet URLs. |
headScripts | Optional extension-owned script URLs. |
utilityPrimary | Optional override for the utility primary action. |
Keep route pages conservative. The current shell contract is for rendering workspace content, not for replacing global shell behavior.
Workspace Header
Use a standard workspace header:
<div class="mc-workspace__header">
<?php myronRenderAdminBreadcrumbs([
['label' => 'Extensions', 'href' => myronBuildAdminUrl('extensions.installed')],
['label' => 'My Vendor Settings'],
]); ?>
<div class="mc-workspace__title-row">
<h1 class="mc-workspace__title">My Vendor Settings</h1>
</div>
<p class="mc-workspace__subtitle">Manage settings owned by this extension.</p>
</div>
Breadcrumbs should lead back to the Installed Extensions surface unless the extension has a stronger local parent route.
Content Canvas
Use the existing admin content wrappers:
<div class="mc-page-canvas mc-page-canvas--site">
<div class="sg-main">
<section class="sg-section">
<h2 class="sg-section__title">Settings</h2>
...
</section>
</div>
</div>
This keeps extension UI visually aligned with existing admin pages. It does not grant permission to add global shell groups, replace core navigation, or change public-site styling.
Route Keys And Active State
The manifest route key controls the mounted route tail. The route file should use the same local key for activeItem:
{
"adminRoutes": [
{
"key": "settings",
"path": "admin/routes/settings.php"
}
]
}
'activeItem' => 'settings'
The core shell has a built-in Extensions rail section for administrators with extensions-register and extensions-installed. The reference sample includes sample-hello in the shell's active keys, but that is not a general dynamic rail-injection contract for arbitrary extensions.
Human Path
A developer authors a route file and manifest route entry. An administrator registers and enables the extension, then opens the route in the browser under /x/{vendor}/{route-tail}.
AI Path
An AI coding agent can author the local files and verify the route registration contract. It should not claim that a running MCP client can render or operate the admin route as a tool.
If AI-callable behavior is needed, author a scoped action in addition to the admin UI route.
Scopes
Shell rendering does not define an action scope. Route access is controlled by the route guard, and extension loadability is controlled by the manifest grant.
For privileged extension settings pages, use:
$currentUser = myronRequireAdministrationAccess();
and declare appropriate manifest scopes for the extension's broader runtime behavior.
Artifacts
Authoring artifacts:
app/extensions/{vendor}/manifest.jsonapp/extensions/{vendor}/admin/routes/{route}.php
Runtime helpers:
myronRenderAdminShellStart()myronRenderAdminShellEnd()myronRenderAdminBreadcrumbs()myronBuildAdminUrl()
Safety Boundary
Do not use extension route files to:
- skip administrator access checks,
- inject new core rail groups,
- change global shell chrome,
- mutate public render state outside documented extension APIs,
- present admin UI as MCP-callable.
The current extension admin route contract is route isolation plus shell rendering. Core shell extension points beyond that require a future contract.
Verification
Run:
php app/tests/verify-extension-system-foundation.php
Then inspect the route in a browser as an administrator. Confirm the page has:
- the authenticated utility bar,
- the admin rail,
- breadcrumbs,
- one workspace title,
- content inside the workspace canvas,
- no duplicate shell wrappers.
Failure Modes
| Failure | What it means | Safe response |
|---|---|---|
| Route renders without admin access | The guard is missing or too weak. | Add myronRequireAdministrationAccess() before rendering. |
| Route is not mounted | Manifest route failed, extension is not loaded, or handler file is missing. | Fix manifest/path/load state; do not bypass the loader. |
| Active rail state is wrong | activeItem does not match a known active key. | Use the manifest route key; avoid relying on unsupported rail injection. |
| Shell appears twice | The route included its own HTML shell around myronRenderAdminShellStart(). | Let AdminShell own document chrome. |
| MCP cannot discover route | Expected behavior. | Admin shell routes are browser UI, not tools. |