AI Miniapps With Navigation
The generation pipeline now targets a bundle format: multiple React Native screen artifacts, one portable navigation manifest, and version metadata that keeps the runtime and KV publisher aligned.
Generated Artifact Shape
JSON
{
"components": [
{
"key": "support/HomePage",
"name": "HomePage",
"fileName": "HomePage.tsx",
"code": "export default function HomePage() { return null; }"
},
{
"key": "support/DetailsPage",
"name": "DetailsPage",
"fileName": "DetailsPage.tsx",
"code": "export default function DetailsPage() { return null; }"
}
],
"navigation": {
"version": 1,
"rootId": "root-stack",
"nodes": [
{
"kind": "stack",
"id": "root-stack",
"name": "Root",
"route": { "path": "/" },
"initialRouteId": "home-page",
"children": [
{
"kind": "page",
"id": "home-page",
"name": "HomePage",
"componentKey": "support/HomePage",
"route": { "path": "/" }
},
{
"kind": "page",
"id": "details-page",
"name": "DetailsPage",
"componentKey": "support/DetailsPage",
"route": { "path": "/details" }
}
]
}
]
}
}Publishing Flow
- Validate every generated screen component independently.
- Validate the navigation graph against the generated component keys and the effective
targetNavigationEngine. - Store navigation and the resolved engine in version metadata.
- Write every screen artifact to Cloudflare KV.
- Save one miniapp index payload containing
components[]andnavigation.
Target Navigation Engine
Every codegen request resolves a targetNavigationEngine so the generator and validator speak the same language as the runtime that will render the miniapp. Resolution order (first match wins):
targetNavigationEnginein thePOST /api/codegen/generaterequest body..dpage/project.jsonfromdpage linkin the workspace that issued the request.- The project's server-side default from
Project Settings → Navigation Engine. "manifest"(built-in fallback).
When the effective engine is:
- manifest - No react-navigation-specific constraints. Icons on bottom tabs stay optional.
- react-navigation - Every visible child of a
bottomTabsnavigator must declare a non-emptytabItem.icon(stack children must carry it on the initial page). Hidden tabs (tabItem.hidden: true) are exempt. Bundles that omit a required icon fail server validation and trigger the refinement loop. New bundles should also includetabItem.iconLibraryso the host can resolve the correct icon set. - auto - Let the host pick at runtime; non-strict validation. Icons are encouraged but not enforced.
JSON
{
"navigation": {
"version": 1,
"rootId": "root-tabs",
"nodes": [
{
"kind": "tabs",
"id": "root-tabs",
"variant": "bottomTabs",
"initialRouteId": "home-page",
"children": [
{
"kind": "page",
"id": "home-page",
"name": "Home",
"componentKey": "bookhub/HomeScreen",
"route": { "path": "/home" },
"tabItem": {
"icon": "home",
"iconLibrary": "feather",
"label": "Home"
}
},
{
"kind": "page",
"id": "clubs-page",
"name": "Clubs",
"componentKey": "bookhub/BookClubsScreen",
"route": { "path": "/clubs" },
"tabItem": {
"icon": "account-group",
"iconLibrary": "material-community",
"label": "Clubs"
}
}
]
}
]
}
}Changing the engine later
Update the project-wide default from
Project Settings → Navigation Engine, re-run dpage link to change a workspace's value, or pass targetNavigationEngine explicitly on a one-off codegen request.Runtime Contract
The mobile runtime fetches the miniapp index from /m/:id. Each component entry still carries its fetched code in value, while the optional navigation field tells the runtime how to assemble those screens into a full app flow.
If the AI returns a single screen or the stored version predates portable navigation, the server falls back to a synthesized one-screen manifest so older miniapps remain valid.