ContractSpec docs

OSS-first docs

These docs teach the open system first: contracts, generated surfaces, runtimes, governance, and incremental adoption. Studio shows up as the operating layer on top, not as the source of truth.

NavSurfaceItemSpec

Detail view for a single contract reference.

field.key.label
NavSurfaceItemSpec
field.version.label
field.type.label
field.title.label
NavSurfaceItemSpec
field.description.label
field.tags.label
field.owners.label
field.stability.label
public

Single navigation entry contract that binds a capability to a web route with persona and grouping semantics. Includes optional mobile-extension fields for Expo Router native navigation (Phase D.0).

Overview

`NavSurfaceItemSpec` mirrors the `PresentationSpec.capability` pattern and defines a hard binding between:

A registered **capability** that provides the navigation surface (validated against CapabilityRegistry)

A **route** (web path + optional API root)

**Persona visibility** (which personas can see this entry)

**Grouping** (sidebar/nav section)

**Icon** (logical key resolved at render time)

Key Semantics

**Capability Binding**: Every nav item MUST reference a `CapabilityRef` so the host can validate at build time that every navigation surface is backed by a real capability registered with `surface: 'navigation'`.

**Persona Visibility**: The `personaVisibility` array lists personas allowed to see the entry. An empty array means hidden from all personas.

**Optional Policy**: The `policy` field adds an additional gate on top of persona visibility (e.g., require a feature flag or explicit permission).

**Optional Density Hint**: The `densityHint` field suggests UI density ('compact' | 'comfortable') applied to the rendered entry.

Mobile Extension Fields (additive, Phase D.0)

Three optional fields enable native Expo Router navigation without app-level hard-coding:

**`tabBarIcon?`**: Logical icon key for native tab bar rendering, separate from the web sidebar `iconKey`. When absent the host may fall back to `iconKey` or a platform default. Only meaningful on tab-root items (`parentGroupKey` absent).

**`gestureHint?`** (`NativeGestureHint`): Declares the primary gesture affordance for this screen. Use `'none'` to explicitly disable back/dismiss gestures (e.g. auditor audit-log where accidental swipe-dismiss would lose evidence context).

**`parentGroupKey?`**: Expresses the tab-vs-stack hierarchy. Absent = item IS a tab-bar root. Present = item is a stack-child pushed onto the named tab's navigator and does NOT appear in the tab bar.

Tab/stack hierarchy example:

`cockpit` → `parentGroupKey: undefined` → tab bar root

`work-graph` → `parentGroupKey: 'cockpit'` → stack child under cockpit tab

`inbox` → `parentGroupKey: undefined` → tab bar root

`threads/[id]` → `parentGroupKey: 'inbox'` → stack child under inbox tab

Web shells ignore these fields (absent optional fields produce no effect).

Usage in NavRegistry

The `NavRegistry` consumes `NavSurfaceItemSpec` entries and provides:

`indexByPersona(persona)`: Get all entries visible to a persona

`indexByGroup(groupKey)`: Get all entries in a nav group

`resolveForRoleMorph(roleMorph, preferences)`: Resolve visible entries for a role-morph projection (filtered by persona + hidden groups)

Example

const inboxNav = defineNavSurfaceItem({
  meta: {
    key: 'inbox',
    version: '1.0.0',
    description: 'Inbox navigation entry',
    goal: 'Direct users to their messages and notifications',
    context: 'Core workflow entry point for all personas',
    owners: ['team-platform'],
    tags: ['core', 'workflow'],
  },
  capability: { key: 'inbox.read' },
  route: { web: '/companyos/inbox', api: '/api/companyos/inbox' },
  personaVisibility: ['founder_approver', 'operations_manager', 'frontline_staff'],
  groupKey: 'workflow',
  iconKey: 'icon.inbox',
  densityHint: 'comfortable',
  // Mobile extension fields (optional — web shell ignores these)
  tabBarIcon: 'tab.inbox',
  gestureHint: 'swipe-back',
});