---
title: Add an OM-Backed System
description: Add a system through the Organization Model, runtime resource descriptors, UI wiring, and alignment tests.
---
<!-- @generated by packages/sdk/scripts/copy-reference-docs.mjs -- DO NOT EDIT -->
<!-- Regenerate: pnpm scaffold:sync -->


# Add an OM-Backed System

Use this recipe when a project needs a new bounded system with semantic model entries, executable resources, and optional UI presence. The correct shape is model-first: define the Organization Model boundary, then attach workflows, agents, routes, and tests to the same IDs.

Do not create a second identity catalog in operations or UI code. System IDs, resource IDs, and ontology IDs should come from the Organization Model.

## 1. Add the System

Edit `core/config/organization-model.ts` and add the system to the `systems` override. Use nested `systems` plus dotted IDs for hierarchy.

```ts
const organizationOverride = defineOrganizationModel({
  systems: {
    operations: {
      id: 'operations',
      order: 10,
      label: 'Operations',
      description: 'Operational work orchestration.',
      kind: 'operational',
      lifecycle: 'active',
      ui: {
        path: '/operations',
        surfaces: []
      },
      systems: {
        review: {
          id: 'operations.review',
          order: 20,
          label: 'Review',
          description: 'Human review and approval work.',
          kind: 'operational',
          parentSystemId: 'operations',
          lifecycle: 'active',
          ui: {
            path: '/operations/review',
            surfaces: []
          }
        }
      }
    }
  }
})
```

If the local project already uses recursive `subsystems`, treat that as compatibility authoring. Do not mix `systems` and `subsystems` in the same branch; prefer moving new examples to `systems`.

## 2. Add Ontology Object Types for Durable Business Nouns

Add ontology object types only for stable business objects the system owns. Object types are semantic contracts; they are not every DTO, provider payload, or workflow step shape.

```ts
systems: {
  operations: {
    id: 'operations',
    order: 10,
    label: 'Operations',
    lifecycle: 'active',
    systems: {
      review: {
        id: 'operations.review',
        order: 20,
        label: 'Review',
        lifecycle: 'active',
        ontology: {
          objectTypes: {
            'operations.review:object/review-item': {
              id: 'operations.review:object/review-item',
              label: 'Review Item',
              description: 'A human-reviewable work item produced by an automation.',
              ownerSystemId: 'operations.review',
              storage: { kind: 'table', table: 'review_items' }
            }
          }
        }
      }
    }
  }
}
```

Use ontology `linkTypes` when the object has durable relationships to other modeled object types. Top-level `entities` still work for existing consumers, but they are compatibility inputs that compile into object and link types. New authoring belongs in `System.ontology.objectTypes` and `System.ontology.linkTypes`.

## 3. Add Ontology Action Types for Stable Business Verbs

Add ontology action types for verbs that operators, policies, Command View, or agents should reason about.

```ts
systems: {
  operations: {
    id: 'operations',
    order: 10,
    label: 'Operations',
    lifecycle: 'active',
    systems: {
      review: {
        id: 'operations.review',
        order: 20,
        label: 'Review',
        lifecycle: 'active',
        ontology: {
          actionTypes: {
            'operations.review:action/review-item.approve': {
              id: 'operations.review:action/review-item.approve',
              label: 'Approve Review Item',
              description: 'Approve a pending human review item.',
              ownerSystemId: 'operations.review',
              actsOn: ['operations.review:object/review-item'],
              effects: [{ kind: 'emitEvent', eventType: 'operations.review:event/review-item.approved' }]
            }
          }
        }
      }
    }
  }
}
```

Runtime availability, payload schemas, prioritization, and side effects stay in runtime code. The action type is the stable semantic verb. Top-level `actions` still work for existing consumers, but they are compatibility inputs. New authoring belongs in `System.ontology.actionTypes`.

## 4. Add Ontology Catalog Types for Local Catalogs

Use `System.ontology.catalogTypes` for pipelines, stages, templates, template steps, status flows, status entries, and small config vocabularies owned by the system.

```ts
systems: {
  operations: {
    id: 'operations',
    order: 10,
    label: 'Operations',
    lifecycle: 'active',
    systems: {
      review: {
        id: 'operations.review',
        order: 20,
        label: 'Review',
        lifecycle: 'active',
        parentSystemId: 'operations',
        ontology: {
          catalogTypes: {
            'operations.review:catalog/review-flow': {
              id: 'operations.review:catalog/review-flow',
              kind: 'status-flow',
              label: 'Review Statuses',
              ownerSystemId: 'operations.review',
              appliesTo: 'operations.review:object/review-item',
              entries: {
                pending: { label: 'Pending', semanticClass: 'open', order: 10 },
                approved: { label: 'Approved', semanticClass: 'completed', order: 20 }
              }
            }
          }
        }
      }
    }
  }
}
```

Do not use catalog entries as an action registry. If a template step invokes a canonical action, store the action ID in the catalog entry metadata and keep the action contract in `actionTypes`.

`System.content kind: "schema"` still works for existing consumers and projects into ontology catalog types. Use it only when maintaining code that has not moved yet; new authoring belongs in `System.ontology.catalogTypes`.

## 5. Add Resource Descriptors

Resources are governed descriptors for executable workflows, agents, integrations, and scripts. Operations imports them and derives runtime identity from them.

```ts
import { defineResources } from '@elevasis/core/organization-model'

export const resourceDescriptors = defineResources({
  approveReviewItem: {
    id: 'approve-review-item-workflow',
    title: 'Approve review item',
    description: 'Routes a review item through the operations approval workflow.',
    order: 10,
    kind: 'workflow',
    systemPath: 'operations.review',
    ownerRoleId: 'role-ops-lead',
    status: 'active',
    codeRefs: [
      {
        path: 'operations/src/review/approve-review-item/index.ts',
        role: 'entrypoint',
        symbol: 'approveReviewItemWorkflow'
      },
      {
        path: 'operations/src/review/approve-review-item/approve-review-item.test.ts',
        role: 'test'
      }
    ],
    ontology: {
      actions: ['operations.review:action/review-item.approve'],
      primaryAction: 'operations.review:action/review-item.approve',
      reads: ['operations.review:object/review-item'],
      writes: ['operations.review:object/review-item'],
      emits: ['operations.review:event/review-item.approved']
    }
  }
})
```

Use descriptor `title` and `description` for executable display metadata.

Use nested `resource.ontology` bindings for the semantic actions, objects, catalogs, and events a Resource performs, reads, writes, uses, or emits. `resource.ontology.primaryAction` is the default/selectable ontology action and must be included in `resource.ontology.actions`. Top-level resource `emits` remains readable for bridge-era descriptors, but new descriptors should keep event bindings in `resource.ontology.emits`.

Use `codeRefs` as repo-relative breadcrumbs for agents and operators. They point from the governed Resource descriptor to implementation files; they do not define resource identity, System membership, runtime topology, or graph links.

## 6. Bind Runtime to the Descriptor

Workflow and agent code owns schemas, handlers, steps, and runtime behavior. It should import the descriptor and derive `resourceId`, `type`, and display metadata from it.

```ts
import type { WorkflowDefinition } from '@elevasis/sdk'
import { organizationModel, resourceDescriptors } from '@core/config/organization-model'

export const approveReviewItemWorkflow: WorkflowDefinition = {
  config: {
    resource: resourceDescriptors.approveReviewItem,
    resourceId: resourceDescriptors.approveReviewItem.id,
    name: resourceDescriptors.approveReviewItem.title,
    description: resourceDescriptors.approveReviewItem.description,
    type: resourceDescriptors.approveReviewItem.kind,
    version: '1.0.0',
    status: 'dev',
    category: 'production'
  },
  contract: {
    inputSchema,
    outputSchema
  },
  steps,
  entryPoint: 'approve'
}
```

Register runtime resources in the deployment assembly, usually `operations/src/index.ts`:

```ts
export const org = {
  version: '0.1.0',
  organizationModel,
  workflows: [approveReviewItemWorkflow],
  agents: [],
  relationships: {
    'approve-review-item-workflow': {
      uses: { integrations: ['email'] }
    }
  }
}
```

Use `organizationModel.topology.relationships` for durable execution topology. The initial topology relationship kinds are `triggers`, `uses`, and `approval`; use `systemPath` and `resource.ontology` for semantic binding. Existing compatibility graph links can stay readable while old consumers migrate.

## 7. Add UI Wiring

If the system needs UI, add shell wiring after the OM IDs are stable.

1. Create a `SystemModule` manifest with `systemId` equal to the OM System ID.
2. Register the manifest in the project manifest array.
3. Add TanStack routes whose paths match the system or sidebar surface path.
4. Wrap pages in the existing auth guard and `SystemGuard`.
5. Query OM resources, compiled ontology indexes, compatibility actions, and graph data where possible instead of hardcoding a page-local registry.

```tsx
import type { SystemModule } from '@elevasis/ui/provider'
import { IconClipboardCheck } from '@tabler/icons-react'
import { ReviewSidebar } from './sidebar'

export const reviewManifest: SystemModule = {
  key: 'operations.review',
  systemId: 'operations.review',
  icon: IconClipboardCheck,
  sidebar: ReviewSidebar
}
```

```tsx
import { createFileRoute, Outlet } from '@tanstack/react-router'
import { ProtectedRoute, SystemGuard } from '@elevasis/ui/features/auth'

export const Route = createFileRoute('/operations/review')({
  component: ReviewLayout
})

function ReviewLayout() {
  return (
    <ProtectedRoute>
      <SystemGuard systemKey="operations.review">
        <Outlet />
      </SystemGuard>
    </ProtectedRoute>
  )
}
```

## 8. Test Alignment

Add tests for the boundaries you changed:

- OM config tests for systems, ontology object/action/catalog records, resources, and any compatibility `System.content`.
- Runtime registry tests that deployed workflows import descriptors and keep `resourceId`, `type`, title, description, and `resource.ontology.primaryAction` aligned.
- UI tests or type checks for route, manifest, and guard wiring.
- Graph or knowledge tests when new ontology records, resources, compatibility content nodes, or emitted events should appear in Command View.
- Scaffold sync when new docs or generated scaffold references are affected.

```bash
pnpm -C core test
pnpm -C operations check-types
pnpm -C ui check-types
pnpm knowledge:generate
pnpm scaffold:sync
pnpm scaffold:verify
pnpm verify:scaffold-reference
```

## Finish Checklist

- The System exists once in the OM.
- Ontology object types represent durable business nouns, not transient data shapes.
- Ontology action types represent stable business verbs.
- Ontology catalog types contain local vocabularies such as pipelines, stages, templates, and status flows.
- Compatibility `System.content` is used only for existing bridge-era local catalogs or schemas.
- Each executable workflow or agent has an OM Resource descriptor with `systemPath`.
- Executable Resources use descriptor `title` / `description`, `resource.ontology.actions`, and `resource.ontology.primaryAction`.
- `codeRefs` point to useful entrypoints, handlers, schemas, tests, docs, or config.
- Runtime assembly imports descriptors and derives identity from them.
- UI routes, manifests, and guards use the same System ID.
- Tests prove OM, runtime, and UI stay aligned.

## Related References

- [Add a Resource](add-a-resource.md)
- [Customize organization-model.ts](customize-organization-model.md)
- [Gate by System or Admin](gate-by-feature-or-admin.md)
- [Organization Model](../core/organization-model.mdx)
- [System Shell and Provider](../ui/feature-shell.mdx)
