Use this skill when creating or updating routed modules, deciding where files belong, or wiring a feature into the authenticated app shell.
If the user wants a reusable app surface, tool UI, settings panel, or workflow screen, prefer a custom routed page module over a space. Spaces are for persisted user-authored widget canvases; custom pages are for feature-owned interfaces.
First-Party Module Placement
- Browser modules are namespaced as
mod/<author>/<repo>/.... - Repo-owned first-party modules should normally live under
app/L0/_all/mod/_core/<feature>/. - A routed feature should usually own its own
view.htmlunder that module root. - Keep the module root as the real implementation location and use
ext/html/...files only as thin adapters into existing seams.
Custom Pages Instead Of Spaces
- Build a custom routed page when the extension should behave like a first-class feature screen instead of a widget on a persisted space canvas.
- Use spaces when the user wants a configurable board of widgets that lives under
~/spaces/.... - Use a routed page when the feature owns its own layout, state, and navigation flow.
- To make a custom page appear in the dashboard
Panelssection, addext/panels/<name>.yamlin the owning module. - Panel manifests should define
name,path, optionaldescription, optionalicon, and optionalcolor. - For first-party
_coreroutes, the manifestpathmay use shorthand such asuserinstead of a full/mod/...path. - Panel manifest
pathvalues may use shorthand route paths such asuser, prefixed hash paths such as#/user, or direct/mod/...HTML paths such as/mod/_core/user/view.html.
Router Resolution
- The main app is hash-routed.
#/dashboardresolves to/mod/_core/dashboard/view.html.#/time_travelresolves to/mod/_core/time_travel/view.html.- A multi-segment route such as
#/author/repo/pathresolves to/mod/author/repo/path/view.html. - If the final route segment already ends in
.html, the router resolves directly to that file under/mod/.... - Query parameters stay attached to the resolved route target.
Router-Owned Seams
Current routed shell anchors are:
_core/router/shell_start_core/router/shell_endpage/router/route/startpage/router/route/endpage/router/overlay/startpage/router/overlay/end
Use those anchors before editing router shell markup directly. Floating UI such as the onscreen agent belongs in the routed overlay anchors.
Common Module Shape
For a new first-party routed feature, the normal home is:
app/L0/_all/mod/_core/<feature>/
view.html
<feature>.css
store.js
panel.html or supporting components
ext/panels/<feature>.yaml when the page should be discoverable from the dashboard
ext/html/... only when the feature mounts into an existing seam
Minimal first-party custom page example:
app/L0/_all/mod/_core/my_tool/
view.html
my-tool.css
store.js
ext/panels/my-tool.yaml
Example panel manifest:
name: My Tool
path: my_tool
description: A custom routed tool page.
icon: build
color: "#94bcff"
Panel Helper Script
Reusable helper script:
const panelTools = await import("/mod/_core/skillset/ext/skills/development/modules-routing/panel-tools.js");
Available helpers:
await panelTools.listPanels()returns the normalized dashboard panel entries discovered fromext/panels/*.yaml, each withroutePathand ready-to-usehrefawait panelTools.findPanel("user")resolves a panel by visible name, route path, hash route, direct/mod/...HTML path, or a panel object returned bylistPanels()await panelTools.resolvePanelRoutePath("/mod/_core/user/view.html")normalizes a panel target into its router route pathawait panelTools.createPanelHref("#/user")returns the routed hrefawait panelTools.goToPanel("User")navigates throughspace.routerwith a hash fallbackawait panelTools.openPanel(panelEntry)is an alias forgoToPanel(...)
Use those helpers when you need to inspect the registered panels before wiring new links or when the user asks to navigate to one of them.
Example:
const panelTools = await import("/mod/_core/skillset/ext/skills/development/modules-routing/panel-tools.js");
const panels = await panelTools.listPanels();
const userPanel = await panelTools.findPanel("/mod/_core/user/view.html");
await panelTools.goToPanel(userPanel ?? "user");
Shell Rules
/is the authenticated app shell and mounts_core/router./adminis separate and firmware-clamped toL0; do not treat it as the default home for user-facing routed features.- Keep page-shell concerns in the router or page shells and keep feature logic inside the owning module.
Mandatory Doc Follow-Up
- If route resolution, stable router seams, or the first-party module placement rules change, update the router docs and the
developmentskill subtree in the same session.