App schema — UI Protocol property reference
App schemas of the ObjectStack UI Protocol: ActionNavItem, App, AppBranding and 12 more — each property with its type, default and a TypeScript example.
Source: packages/spec/src/ui/app.zod.ts
TypeScript Usage
import { ActionNavItemSchema, AppSchema, AppBrandingSchema, AppContextSelectorSchema, ComponentNavItemSchema, DashboardNavItemSchema, DocNavItemSchema, GroupNavItemSchema, NavigationAreaSchema, NavigationContributionSchema, NavigationItemSchema, ObjectNavItemSchema, PageNavItemSchema, ReportNavItemSchema, UrlNavItemSchema } from '@objectstack/spec/ui';
import type { ActionNavItem, App, AppBranding, AppContextSelector, ComponentNavItem, DashboardNavItem, DocNavItem, GroupNavItem, NavigationArea, NavigationContribution, NavigationItem, ObjectNavItem, PageNavItem, ReportNavItem, UrlNavItem } from '@objectstack/spec/ui';
// Validate data
const result = ActionNavItemSchema.parse(data);ActionNavItem
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'action' | ✅ | |
| actionDef | { actionName: string; params?: Record<string, any> } | ✅ | Action definition to execute when clicked |
Nested Shape: ActionNavItem.actionDef
| Property | Type | Required | Description |
|---|---|---|---|
| actionName | string | ✅ | Action machine name to execute |
| params | Record<string, any> | optional | Parameters passed to the action |
App
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | ✅ | App unique machine name (lowercase snake_case) |
| label | string | Record<string, string> | ✅ | App display label |
| version | never | optional | [REMOVED] App.version was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — no consumer in framework or objectui). An app is versioned by its owning package: use manifest.version. Delete the key. Run os migrate meta --from 16 to list the mechanical edits for existing sources; --write applies the ones it can prove, and you apply the rest by hand. |
| description | string | Record<string, string> | optional | App description |
| icon | string | optional | App icon used in the App Launcher |
| branding | { primaryColor?: string; accentColor?: string; logo?: string; favicon?: string } | optional | App-specific branding |
| active | boolean | optional (default: true) | Whether the app is enabled |
| isDefault | boolean | optional (default: false) | Is default app |
| hidden | boolean | optional | Hide from the App Switcher; the shell surfaces hidden apps via the avatar menu instead (navigation only — never an access gate) |
| _unpublished | boolean | optional | Machine-managed publish gate (ADR-0045 §3) — true = unpublished, externally unobservable. Written by AI materialization, cleared by publish-drafts. Never authored. |
| navigation | ({ id: string; label?: string | Record<string, string>; icon?: string; order?: number; … } | { type: 'separator'; id?: string; order?: number } | … +8 more)[] | optional | Full navigation tree for the app sidebar |
| areas | { id: string; label: string | Record<string, string>; icon?: string; description?: string | Record<string, string>; … }[] | optional | Navigation areas for partitioning navigation by business domain |
| contextSelectors | { id: string; label: string | Record<string, string>; icon?: string; optionsSource: object; … }[] | optional | App-level scope dropdowns whose value is injected into nav items as {<id>} template vars |
| homePageId | never | optional | [REMOVED] app.homePageId was removed in @objectstack/spec 17.0.0 (ADR-0049). objectui's console did read it before v17 (resolveLandingRoute), so this key had a consumer — it was retired because the capability is better expressed on the navigation item itself than as an ID cross-reference that silently falls back when it dangles. An app's landing page IS its first navigation item (by order), and the root landing follows isDefault routing. Delete the key; to change where an app opens, reorder navigation so the intended entry is first, and set isDefault on the app that should own the root landing. Run os migrate meta --from 16 to list the mechanical edits for existing sources; --write applies the ones it can prove, and you apply the rest by hand. |
| requiredPermissions | string[] | optional | Permissions required to access this app |
| objects | never | optional | [REMOVED] App.objects was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — never read; the spec itself labelled it "config file convenience"). Objects belong to the stack (defineStack({ objects })); an app reaches them through its navigation items. Delete the key. Run os migrate meta --from 16 to list the mechanical edits for existing sources; --write applies the ones it can prove, and you apply the rest by hand. |
| apis | never | optional | [REMOVED] App.apis was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — never read). Delete the key and declare the endpoint one level up, on the STACK: defineStack({ apis }). That surface EXECUTES from protocol 17. Before the executor landed it was refused wholesale — nothing mounted a declared path, so every key including authRequired parsed and gated nothing — and that blanket refusal is now narrowed to five per-endpoint publish gates (namespace, supported target, mapping, policy, uniqueness): an endpoint that passes them is mounted and serves traffic as soon as the stack is published. Two things to get right when you move it: the path must sit inside your own carve-out, /api/v1/apps/<manifest.namespace>/<subpath> with an explicit manifest.namespace (ADR-0121 D1/D2), and authRequired defaults to true — an explicit false is the only thing that opens anonymous access, and ADR-0121 D6 then requires an armed rateLimit: { enabled: true, windowMs, maxRequests }. Read the declarative-apis-endpoints-live entry of the protocol upgrade guide first; it is a security review, not a rename. A route that genuinely needs handler CODE is mounted imperatively instead: resolve the http.server service from your plugin context and register the route on kernel:ready (NOT the manifest contributes.routes key — removed in @objectstack/spec 17: nothing ever read it, and authoring it is now rejected with its own prescription). Run os migrate meta --from 16 to list the mechanical edits for existing sources; --write applies the ones it can prove, and you apply the rest by hand. |
| sharing | never | optional | [REMOVED] App.sharing was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit / ADR-0049 enforce-or-remove) — no public-app route ever read it, so it declared sharing that did not exist. Public access is granted per FORM VIEW (FormView.sharing, the public-data-collection surface). Delete the key. Run os migrate meta --from 16 to list the mechanical edits for existing sources; --write applies the ones it can prove, and you apply the rest by hand. |
| embed | never | optional | [REMOVED] App.embed was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit / ADR-0049) — no iframe route ever read it. Embedding is a per-form-view surface (FormView.sharing), not an app-level switch. Delete the key. Run os migrate meta --from 16 to list the mechanical edits for existing sources; --write applies the ones it can prove, and you apply the rest by hand. |
| mobileNavigation | never | optional | [REMOVED] App.mobileNavigation was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — fully unimplemented; no renderer, including packages/mobile, ever read it). Delete the key; the block returns if/when a real mobile navigation ships. Run os migrate meta --from 16 to list the mechanical edits for existing sources; --write applies the ones it can prove, and you apply the rest by hand. |
| defaultAgent | string | optional | Platform agent bound to this app's ambient chat ('ask' is the implicit default; 'build' for authoring surfaces) — ADR-0063 §1 |
| aria | never | optional | [REMOVED] App.aria was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — no renderer read app-level ARIA attributes). Declare aria on the page component that renders the DOM node instead (page.components[].aria; page.aria and the list view aria are live too). Delete the key. Run os migrate meta --from 16 to list the mechanical edits for existing sources; --write applies the ones it can prove, and you apply the rest by hand. |
| protection | { lock: Enum<'none' | 'no-overlay' | 'no-delete' | 'full'>; reason: string; docsUrl?: string } | optional | Package author protection block — lock policy for this app. |
| _lock | Enum<'none' | 'no-overlay' | 'no-delete' | 'full'> | optional | Item-level lock — controls overlay & delete (ADR-0010). |
| _lockReason | string | optional | Human-readable reason shown when a write is refused by _lock. |
| _lockSource | Enum<'artifact' | 'package' | 'env-forced'> | optional | Layer that set _lock (artifact | package | env-forced). |
| _provenance | Enum<'package' | 'org' | 'env-forced'> | optional | Origin of the item (package | org | env-forced). |
| _packageId | string | optional | Owning package machine id. |
| _packageVersion | string | optional | Owning package version. |
| _lockDocsUrl | string | optional | Optional documentation link surfaced next to _lockReason. |
Nested Shape: App.branding
| Property | Type | Required | Description |
|---|---|---|---|
| primaryColor | string | optional | Primary theme color hex code |
| accentColor | string | optional | Accent color hex code (highlights, active states). Declared to match the objectui ConsoleLayout read of branding.accentColor (inverse-drift fix, liveness audit /). |
| logo | string | optional | Custom logo URL for this app: a 1:1 square app icon, SVG preferred, at least 64 px. It is the app's one logo asset — each surface scales it to the size it needs, and there is no second size or wordmark slot. |
| favicon | string | optional | Custom favicon URL for this app |
Nested Shape: App.navigation[number][type='object']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'object' | ✅ | |
| objectName | string | ✅ | Target object name |
| viewName | string | optional | Default list view to open. When omitted, the console opens the object's default list view, else its first declared list view; all names the console's fallback tab, which exists only for an object that declares no list view. Ignored when recordId is set. |
| recordId | string | optional | Navigate directly to this record id instead of the list view. Supports template vars: {current_user_id}, {current_org_id}. |
| recordMode | Enum<'view' | 'edit'> | optional | Open the record in view (default) or edit mode. Only meaningful when recordId is set. |
| filters | Record<string, string> | optional | URL filter conditions — targets the /:objectName/data bare surface via filter[<field>]=<value> params instead of a saved view. Values support template vars {current_user_id}, {current_org_id}. Mutually exclusive with recordId/viewName. |
| runAction | string | optional | Auto-run this declared action once on arrival at the object's list surface (deep-link "navigate = run action"). Must name an action defined in the stack; validated by defineStack and lint. Not combinable with recordId. |
| children | ({ id: string; label?: string | Record<string, string>; icon?: string; order?: number; … } | { type: 'separator'; id?: string; order?: number } | … +8 more)[] | optional | Child navigation items (e.g. specific views) |
Nested Shape: App.navigation[number][type='dashboard']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'dashboard' | ✅ | |
| dashboardName | string | ✅ | Target dashboard name |
Nested Shape: App.navigation[number][type='page']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'page' | ✅ | |
| pageName | string | ✅ | Target custom page component name |
| params | Record<string, any> | optional | Parameters passed to the page context |
Nested Shape: App.navigation[number][type='url']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'url' | ✅ | |
| url | string | ✅ | Target external URL |
| target | Enum<'_self' | '_blank'> | optional (default: "_self") | Link target window |
Nested Shape: App.navigation[number][type='report']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'report' | ✅ | |
| reportName | string | ✅ | Target report name |
Nested Shape: App.navigation[number][type='action']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'action' | ✅ | |
| actionDef | { actionName: string; params?: Record<string, any> } | ✅ | Action definition to execute when clicked |
Nested Shape: App.navigation[number][type='component']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'component' | ✅ | |
| componentRef | string | ✅ | Component registry key (e.g. "metadata:directory") |
| params | Record<string, any> | optional | Props passed to the component |
Nested Shape: App.navigation[number][type='doc']
Documentation entry on the app menu (ADR-0046). Targets a book and/or a doc — at least one is required. The entry inherits the docs audience gate (ADR-0046 §6.7): a book entry renders the member's pruned subset of the book's readable pages and is not rendered for a member with no readable page in it; a doc entry the member may not read is not rendered. visible / requiredPermissions can only narrow further.
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'doc' | ✅ | |
| book | string | optional | Book to open (a declared book name, or the package id for the package's implicit book). Alone: opens the book at its first readable page with the book sidebar; membership is derived by rule, so docs added later appear under this entry with no navigation edit. With doc: that page in this book's context. At least one of book / doc is required. |
| doc | string | optional | Doc to open (the doc name = its source filename stem, lowercase snake_case). Alone: its book context is the doc's own book, else the package's implicit book. At least one of book / doc is required. |
Nested Shape: App.navigation[number][type='separator']
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'separator' | ✅ | |
| id | string | optional | Optional id for the separator |
| order | number | optional | Sort order within the same level (lower = first) |
Nested Shape: App.navigation[number][type='group']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'group' | ✅ | |
| expanded | boolean | optional (default: false) | Default expansion state in sidebar |
| children | ({ id: string; label?: string | Record<string, string>; icon?: string; order?: number; … } | { type: 'separator'; id?: string; order?: number } | … +8 more)[] | ✅ | Child navigation items |
Nested Shape: App.areas[number]
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique area identifier (lowercase snake_case) |
| label | string | Record<string, string> | ✅ | Area display label |
| icon | string | optional | Area icon name |
| description | string | Record<string, string> | optional | Area description |
| navigation | ({ id: string; label?: string | Record<string, string>; icon?: string; order?: number; … } | { type: 'separator'; id?: string; order?: number } | … +8 more)[] | ✅ | Navigation items within this area |
Nested Shape: App.contextSelectors[number]
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Selector id; selected value is exposed as the nav template var {<id>} |
| label | string | Record<string, string> | ✅ | Dropdown label |
| icon | string | optional | Icon name |
| optionsSource | { endpoint: string; valueKey?: string; labelKey?: string; filter?: object[] } | ✅ | Option data source |
| allValue | string | optional (default: "") | Sentinel value meaning "no concrete selection yet" (empty string is almost always right) |
| persist | Enum<'query' | 'session' | 'none'> | optional (default: "query") | Persist selection via URL query, sessionStorage, or not at all |
Nested Shape: App.protection
| Property | Type | Required | Description |
|---|---|---|---|
| lock | Enum<'none' | 'no-overlay' | 'no-delete' | 'full'> | ✅ | Lock policy — none | no-overlay | no-delete | full. |
| reason | string | ✅ | User-visible reason shown when the lock blocks an action. |
| docsUrl | string | optional | Optional URL the Studio banner links to for more context. |
AppBranding
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| primaryColor | string | optional | Primary theme color hex code |
| accentColor | string | optional | Accent color hex code (highlights, active states). Declared to match the objectui ConsoleLayout read of branding.accentColor (inverse-drift fix, liveness audit /). |
| logo | string | optional | Custom logo URL for this app: a 1:1 square app icon, SVG preferred, at least 64 px. It is the app's one logo asset — each surface scales it to the size it needs, and there is no second size or wordmark slot. |
| favicon | string | optional | Custom favicon URL for this app |
AppContextSelector
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Selector id; selected value is exposed as the nav template var {<id>} |
| label | string | Record<string, string> | ✅ | Dropdown label |
| icon | string | optional | Icon name |
| optionsSource | { endpoint: string; valueKey?: string; labelKey?: string; filter?: object[] } | ✅ | Option data source |
| allValue | string | optional (default: "") | Sentinel value meaning "no concrete selection yet" (empty string is almost always right) |
| persist | Enum<'query' | 'session' | 'none'> | optional (default: "query") | Persist selection via URL query, sessionStorage, or not at all |
Nested Shape: AppContextSelector.optionsSource
| Property | Type | Required | Description |
|---|---|---|---|
| endpoint | string | ✅ | REST endpoint returning the option rows (e.g. /api/v1/packages) |
| valueKey | string | optional (default: "id") | Row property used as the option value (dotted path allowed, e.g. "manifest.id") |
| labelKey | string | optional (default: "name") | Row property used as the option label (dotted path allowed, e.g. "manifest.name") |
| filter | { key: string; op?: Enum<'eq' | 'ne' | 'in' | 'nin'>; value: string | string[] }[] | optional | Predicates (AND) each option row must satisfy |
ComponentNavItem
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'component' | ✅ | |
| componentRef | string | ✅ | Component registry key (e.g. "metadata:directory") |
| params | Record<string, any> | optional | Props passed to the component |
DashboardNavItem
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'dashboard' | ✅ | |
| dashboardName | string | ✅ | Target dashboard name |
DocNavItem
Documentation entry on the app menu (ADR-0046). Targets a book and/or a doc — at least one is required. The entry inherits the docs audience gate (ADR-0046 §6.7): a book entry renders the member's pruned subset of the book's readable pages and is not rendered for a member with no readable page in it; a doc entry the member may not read is not rendered. visible / requiredPermissions can only narrow further.
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'doc' | ✅ | |
| book | string | optional | Book to open (a declared book name, or the package id for the package's implicit book). Alone: opens the book at its first readable page with the book sidebar; membership is derived by rule, so docs added later appear under this entry with no navigation edit. With doc: that page in this book's context. At least one of book / doc is required. |
| doc | string | optional | Doc to open (the doc name = its source filename stem, lowercase snake_case). Alone: its book context is the doc's own book, else the package's implicit book. At least one of book / doc is required. |
GroupNavItem
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'group' | ✅ | |
| expanded | boolean | optional (default: false) | Default expansion state in sidebar |
NavigationArea
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique area identifier (lowercase snake_case) |
| label | string | Record<string, string> | ✅ | Area display label |
| icon | string | optional | Area icon name |
| description | string | Record<string, string> | optional | Area description |
| navigation | ({ id: string; label?: string | Record<string, string>; icon?: string; order?: number; … } | { type: 'separator'; id?: string; order?: number } | … +8 more)[] | ✅ | Navigation items within this area |
Nested Shape: NavigationArea.navigation[number][type='object']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'object' | ✅ | |
| objectName | string | ✅ | Target object name |
| viewName | string | optional | Default list view to open. When omitted, the console opens the object's default list view, else its first declared list view; all names the console's fallback tab, which exists only for an object that declares no list view. Ignored when recordId is set. |
| recordId | string | optional | Navigate directly to this record id instead of the list view. Supports template vars: {current_user_id}, {current_org_id}. |
| recordMode | Enum<'view' | 'edit'> | optional | Open the record in view (default) or edit mode. Only meaningful when recordId is set. |
| filters | Record<string, string> | optional | URL filter conditions — targets the /:objectName/data bare surface via filter[<field>]=<value> params instead of a saved view. Values support template vars {current_user_id}, {current_org_id}. Mutually exclusive with recordId/viewName. |
| runAction | string | optional | Auto-run this declared action once on arrival at the object's list surface (deep-link "navigate = run action"). Must name an action defined in the stack; validated by defineStack and lint. Not combinable with recordId. |
| children | ({ id: string; label?: string | Record<string, string>; icon?: string; order?: number; … } | { type: 'separator'; id?: string; order?: number } | … +8 more)[] | optional | Child navigation items (e.g. specific views) |
Nested Shape: NavigationArea.navigation[number][type='dashboard']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'dashboard' | ✅ | |
| dashboardName | string | ✅ | Target dashboard name |
Nested Shape: NavigationArea.navigation[number][type='page']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'page' | ✅ | |
| pageName | string | ✅ | Target custom page component name |
| params | Record<string, any> | optional | Parameters passed to the page context |
Nested Shape: NavigationArea.navigation[number][type='url']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'url' | ✅ | |
| url | string | ✅ | Target external URL |
| target | Enum<'_self' | '_blank'> | optional (default: "_self") | Link target window |
Nested Shape: NavigationArea.navigation[number][type='report']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'report' | ✅ | |
| reportName | string | ✅ | Target report name |
Nested Shape: NavigationArea.navigation[number][type='action']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'action' | ✅ | |
| actionDef | { actionName: string; params?: Record<string, any> } | ✅ | Action definition to execute when clicked |
Nested Shape: NavigationArea.navigation[number][type='component']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'component' | ✅ | |
| componentRef | string | ✅ | Component registry key (e.g. "metadata:directory") |
| params | Record<string, any> | optional | Props passed to the component |
Nested Shape: NavigationArea.navigation[number][type='doc']
Documentation entry on the app menu (ADR-0046). Targets a book and/or a doc — at least one is required. The entry inherits the docs audience gate (ADR-0046 §6.7): a book entry renders the member's pruned subset of the book's readable pages and is not rendered for a member with no readable page in it; a doc entry the member may not read is not rendered. visible / requiredPermissions can only narrow further.
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'doc' | ✅ | |
| book | string | optional | Book to open (a declared book name, or the package id for the package's implicit book). Alone: opens the book at its first readable page with the book sidebar; membership is derived by rule, so docs added later appear under this entry with no navigation edit. With doc: that page in this book's context. At least one of book / doc is required. |
| doc | string | optional | Doc to open (the doc name = its source filename stem, lowercase snake_case). Alone: its book context is the doc's own book, else the package's implicit book. At least one of book / doc is required. |
Nested Shape: NavigationArea.navigation[number][type='separator']
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'separator' | ✅ | |
| id | string | optional | Optional id for the separator |
| order | number | optional | Sort order within the same level (lower = first) |
Nested Shape: NavigationArea.navigation[number][type='group']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'group' | ✅ | |
| expanded | boolean | optional (default: false) | Default expansion state in sidebar |
| children | ({ id: string; label?: string | Record<string, string>; icon?: string; order?: number; … } | { type: 'separator'; id?: string; order?: number } | … +8 more)[] | ✅ | Child navigation items |
NavigationContribution
A navigation contribution: a package injecting nav items into an app it does not own (ADR-0029 D7)
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| app | string | ✅ | Target app name to contribute navigation into (e.g. "setup") |
| group | string | optional | Target group nav-item id to append into (e.g. "group_integrations"); omit to append at the app top level. Naming a group the target app does not declare is not refused: the items are appended at the app top level anyway and a nav_contribution_group_missing diagnostic is emitted — by the runtime at warn, and by os build and os validate at compile time. |
| priority | integer | optional (default: 200) | Merge priority within the target group — lower applied first (matches object extender priority) |
| items | ({ id: string; label?: string | Record<string, string>; icon?: string; order?: number; … } | { type: 'separator'; id?: string; order?: number } | … +8 more)[] | ✅ | Navigation items contributed into the target app/group |
Nested Shape: NavigationContribution.items[number][type='object']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'object' | ✅ | |
| objectName | string | ✅ | Target object name |
| viewName | string | optional | Default list view to open. When omitted, the console opens the object's default list view, else its first declared list view; all names the console's fallback tab, which exists only for an object that declares no list view. Ignored when recordId is set. |
| recordId | string | optional | Navigate directly to this record id instead of the list view. Supports template vars: {current_user_id}, {current_org_id}. |
| recordMode | Enum<'view' | 'edit'> | optional | Open the record in view (default) or edit mode. Only meaningful when recordId is set. |
| filters | Record<string, string> | optional | URL filter conditions — targets the /:objectName/data bare surface via filter[<field>]=<value> params instead of a saved view. Values support template vars {current_user_id}, {current_org_id}. Mutually exclusive with recordId/viewName. |
| runAction | string | optional | Auto-run this declared action once on arrival at the object's list surface (deep-link "navigate = run action"). Must name an action defined in the stack; validated by defineStack and lint. Not combinable with recordId. |
| children | ({ id: string; label?: string | Record<string, string>; icon?: string; order?: number; … } | { type: 'separator'; id?: string; order?: number } | … +8 more)[] | optional | Child navigation items (e.g. specific views) |
Nested Shape: NavigationContribution.items[number][type='dashboard']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'dashboard' | ✅ | |
| dashboardName | string | ✅ | Target dashboard name |
Nested Shape: NavigationContribution.items[number][type='page']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'page' | ✅ | |
| pageName | string | ✅ | Target custom page component name |
| params | Record<string, any> | optional | Parameters passed to the page context |
Nested Shape: NavigationContribution.items[number][type='url']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'url' | ✅ | |
| url | string | ✅ | Target external URL |
| target | Enum<'_self' | '_blank'> | optional (default: "_self") | Link target window |
Nested Shape: NavigationContribution.items[number][type='report']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'report' | ✅ | |
| reportName | string | ✅ | Target report name |
Nested Shape: NavigationContribution.items[number][type='action']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'action' | ✅ | |
| actionDef | { actionName: string; params?: Record<string, any> } | ✅ | Action definition to execute when clicked |
Nested Shape: NavigationContribution.items[number][type='component']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'component' | ✅ | |
| componentRef | string | ✅ | Component registry key (e.g. "metadata:directory") |
| params | Record<string, any> | optional | Props passed to the component |
Nested Shape: NavigationContribution.items[number][type='doc']
Documentation entry on the app menu (ADR-0046). Targets a book and/or a doc — at least one is required. The entry inherits the docs audience gate (ADR-0046 §6.7): a book entry renders the member's pruned subset of the book's readable pages and is not rendered for a member with no readable page in it; a doc entry the member may not read is not rendered. visible / requiredPermissions can only narrow further.
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'doc' | ✅ | |
| book | string | optional | Book to open (a declared book name, or the package id for the package's implicit book). Alone: opens the book at its first readable page with the book sidebar; membership is derived by rule, so docs added later appear under this entry with no navigation edit. With doc: that page in this book's context. At least one of book / doc is required. |
| doc | string | optional | Doc to open (the doc name = its source filename stem, lowercase snake_case). Alone: its book context is the doc's own book, else the package's implicit book. At least one of book / doc is required. |
Nested Shape: NavigationContribution.items[number][type='separator']
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'separator' | ✅ | |
| id | string | optional | Optional id for the separator |
| order | number | optional | Sort order within the same level (lower = first) |
Nested Shape: NavigationContribution.items[number][type='group']
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'group' | ✅ | |
| expanded | boolean | optional (default: false) | Default expansion state in sidebar |
| children | ({ id: string; label?: string | Record<string, string>; icon?: string; order?: number; … } | { type: 'separator'; id?: string; order?: number } | … +8 more)[] | ✅ | Child navigation items |
NavigationItem
Union Options
This schema accepts one of the following structures:
Option 1
Type: object
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'object' | ✅ | |
| objectName | string | ✅ | Target object name |
| viewName | string | optional | Default list view to open. When omitted, the console opens the object's default list view, else its first declared list view; all names the console's fallback tab, which exists only for an object that declares no list view. Ignored when recordId is set. |
| recordId | string | optional | Navigate directly to this record id instead of the list view. Supports template vars: {current_user_id}, {current_org_id}. |
| recordMode | Enum<'view' | 'edit'> | optional | Open the record in view (default) or edit mode. Only meaningful when recordId is set. |
| filters | Record<string, string> | optional | URL filter conditions — targets the /:objectName/data bare surface via filter[<field>]=<value> params instead of a saved view. Values support template vars {current_user_id}, {current_org_id}. Mutually exclusive with recordId/viewName. |
| runAction | string | optional | Auto-run this declared action once on arrival at the object's list surface (deep-link "navigate = run action"). Must name an action defined in the stack; validated by defineStack and lint. Not combinable with recordId. |
| children | [NavigationItem](#navigationitem)[] | optional | Child navigation items (e.g. specific views) |
Option 2
Type: dashboard
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'dashboard' | ✅ | |
| dashboardName | string | ✅ | Target dashboard name |
Option 3
Type: page
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'page' | ✅ | |
| pageName | string | ✅ | Target custom page component name |
| params | Record<string, any> | optional | Parameters passed to the page context |
Option 4
Type: url
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'url' | ✅ | |
| url | string | ✅ | Target external URL |
| target | Enum<'_self' | '_blank'> | optional (default: "_self") | Link target window |
Option 5
Type: report
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'report' | ✅ | |
| reportName | string | ✅ | Target report name |
Option 6
Type: action
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'action' | ✅ | |
| actionDef | { actionName: string; params?: Record<string, any> } | ✅ | Action definition to execute when clicked |
Nested Shape: NavigationItem[type='action'].actionDef
| Property | Type | Required | Description |
|---|---|---|---|
| actionName | string | ✅ | Action machine name to execute |
| params | Record<string, any> | optional | Parameters passed to the action |
Option 7
Type: component
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'component' | ✅ | |
| componentRef | string | ✅ | Component registry key (e.g. "metadata:directory") |
| params | Record<string, any> | optional | Props passed to the component |
Option 8
Documentation entry on the app menu (ADR-0046). Targets a book and/or a doc — at least one is required. The entry inherits the docs audience gate (ADR-0046 §6.7): a book entry renders the member's pruned subset of the book's readable pages and is not rendered for a member with no readable page in it; a doc entry the member may not read is not rendered. visible / requiredPermissions can only narrow further.
Type: doc
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'doc' | ✅ | |
| book | string | optional | Book to open (a declared book name, or the package id for the package's implicit book). Alone: opens the book at its first readable page with the book sidebar; membership is derived by rule, so docs added later appear under this entry with no navigation edit. With doc: that page in this book's context. At least one of book / doc is required. |
| doc | string | optional | Doc to open (the doc name = its source filename stem, lowercase snake_case). Alone: its book context is the doc's own book, else the package's implicit book. At least one of book / doc is required. |
Option 9
Type: separator
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | 'separator' | ✅ | |
| id | string | optional | Optional id for the separator |
| order | number | optional | Sort order within the same level (lower = first) |
Option 10
Type: group
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'group' | ✅ | |
| expanded | boolean | optional (default: false) | Default expansion state in sidebar |
| children | [NavigationItem](#navigationitem)[] | ✅ | Child navigation items |
ObjectNavItem
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'object' | ✅ | |
| objectName | string | ✅ | Target object name |
| viewName | string | optional | Default list view to open. When omitted, the console opens the object's default list view, else its first declared list view; all names the console's fallback tab, which exists only for an object that declares no list view. Ignored when recordId is set. |
| recordId | string | optional | Navigate directly to this record id instead of the list view. Supports template vars: {current_user_id}, {current_org_id}. |
| recordMode | Enum<'view' | 'edit'> | optional | Open the record in view (default) or edit mode. Only meaningful when recordId is set. |
| filters | Record<string, string> | optional | URL filter conditions — targets the /:objectName/data bare surface via filter[<field>]=<value> params instead of a saved view. Values support template vars {current_user_id}, {current_org_id}. Mutually exclusive with recordId/viewName. |
| runAction | string | optional | Auto-run this declared action once on arrival at the object's list surface (deep-link "navigate = run action"). Must name an action defined in the stack; validated by defineStack and lint. Not combinable with recordId. |
PageNavItem
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'page' | ✅ | |
| pageName | string | ✅ | Target custom page component name |
| params | Record<string, any> | optional | Parameters passed to the page context |
ReportNavItem
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'report' | ✅ | |
| reportName | string | ✅ | Target report name |
UrlNavItem
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| id | string | ✅ | Unique identifier for this navigation item (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display proper label. Optional. Resolved in one order: (1) the bundle entry apps.<app>.navigation.<id>.label for the active locale chain, keyed by this entry's id — translateApp applies it at the /meta boundary, over the app's navigation tree (not areas); (2) else a present label as authored — its inline locale map's value for that locale, else its text; (3) else (absent) the CURRENT label of what the entry opens, at render time — the view's label when it names a labelled view, else the object's / dashboard's label — localized by the target's own translation. A present label is never replaced by its target's label and never translated by matching its text. Every real destination must have identity and text: identity is the target, text is inherited at render. No stored inherited flag; nothing is materialised for the absent case. |
| icon | string | optional | Icon name |
| order | number | optional | Sort order within the same level (lower = first) |
| badge | string | number | optional | Badge text or count displayed on the item |
| badgeVariant | Enum<'default' | 'secondary' | 'destructive' | 'outline'> | optional | Visual variant of the nav badge. Declared to match the objectui NavigationRenderer read (inverse-drift fix, liveness audit /). |
| visible | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL). e.g. P'org_admin' in current_user.positions |
| requiredPermissions | string[] | optional | Permissions required to access this item |
| requiresObject | string | optional | Hide/disable this entry unless the named object is registered in the runtime |
| requiresService | string | optional | Hide/disable this entry unless the named kernel service is registered |
| type | 'url' | ✅ | |
| url | string | ✅ | Target external URL |
| target | Enum<'_self' | '_blank'> | optional (default: "_self") | Link target window |