RootCX
Docs
Pricing
RootCX/RootCXSource Available
Introduction
What is RootCX?Getting StartedHow it Works
Build
ApplicationAI AgentIntegrationDeploying
Platform
CoreAuthenticationRBACData APISecret VaultJob QueueScheduled Jobs (Crons)Audit LogReal-time LogsChannels
Developers
React SDKBackend & RPCManifest ReferenceREST APICLIClaude CodeSelf-Hosting
DocsDevelopersManifest Reference

Manifest Reference

The manifest.json is the single source of truth for your application. It declares your entities, fields, permissions, and actions. Everything else — tables, CRUD API, constraints — is derived from it automatically.

Top-level fields

Field Type Required Default Description
appId string Yes Unique identifier. Becomes the PostgreSQL schema name. Immutable after first deploy.
name string Yes Display name shown in the Studio.
type string No "app" Application type: "app", "integration", or "agent".
version string No "0.0.1" Semantic version for deployment history.
description string No "" Short description shown in the Studio.
dataContract array No [] Array of entity definitions.
permissions object No Object with a permissions array of permission keys.
actions array No [] Array of RPC action declarations.
configSchema object No JSON Schema for the app's configuration structure.
webhooks string[] No [] Webhook event names the app can receive.
instructions string No Usage instructions for AI agents interacting with this app.
trigger object No Entity trigger for auto-invoking agents on data changes.
appId must be lowercase snake_case (letters, digits, underscores). Hyphens are not allowed. It is immutable after first deploy and becomes the PostgreSQL schema name directly (e.g. appId: "crm" creates schema crm).

dataContract[]

Each entry becomes a PostgreSQL table. System columns (id, created_at, updated_at) are added automatically. You can override id with a custom primary key, but created_at and updated_at are always managed by the system and cannot be overridden.

Field Type Required Description
entityName string Yes Table name. Used in API routes (/api/v1/apps/{appId}/collections/{entityName}).
fields array Yes Array of field definitions.
identityKind string No Federates records across apps (e.g. "contact"). Must be snake_case.
identityKey string No Field name used for identity lookup. Must reference an existing field. Required if identityKind is set.
"dataContract": [
  {
    "entityName": "contacts",
    "fields": [
      { "name": "first_name", "type": "text", "required": true },
      { "name": "last_name",  "type": "text", "required": true },
      { "name": "email",      "type": "text" },
      { "name": "phone",      "type": "text" }
    ]
  }
]

Identity Federation

Multiple apps can declare the same identityKind with different data. The SDK's useIdentity hook queries across all apps that share the same identity kind:

{
  "entityName": "contacts",
  "identityKind": "contact",
  "identityKey": "email",
  "fields": [...]
}

dataContract[].fields[]

Field Type Required Default Description
name string Yes Column name. created_at and updated_at are reserved (system-managed).
type string Yes One of the field types.
required boolean No false Adds a NOT NULL constraint.
defaultValue any No Default on insert. Accepts JSON values: "draft", 0, false, {"key": "val"}.
enumValues string[] No Allowed values. Generates a CHECK constraint.
references object No For entity_link only. Generates a FOREIGN KEY. See references.
isPrimaryKey boolean No false Custom primary key. Rarely needed.

Field types

Fields map directly to PostgreSQL types:

Type PostgreSQL Description
text TEXT Variable-length string.
number DOUBLE PRECISION 64-bit floating-point.
boolean BOOLEAN True/false.
date DATE Calendar date (YYYY-MM-DD).
timestamp TIMESTAMPTZ Date and time in UTC.
json JSONB Arbitrary JSON. Supports GIN indexing.
file TEXT File reference from the upload endpoint.
entity_link UUID REFERENCES Foreign key. Requires references.
[text] TEXT[] Array of strings.
[number] DOUBLE PRECISION[] Array of numbers.

Relationships and constraints

Use entity_link to create foreign keys. The references object supports three reference types:

Local references

Reference an entity within the same app:

{
  "name": "contact_id",
  "type": "entity_link",
  "references": { "entity": "contacts", "field": "id" }
}

Core references

Reference system entities using the core: prefix. Currently only core:users is supported:

{
  "name": "assigned_to",
  "type": "entity_link",
  "references": { "entity": "core:users", "field": "id" }
}

This creates a foreign key to rootcx_system.users(id) with ON DELETE SET NULL.

Cross-app references (e.g. crm:contacts) are not yet supported and will return a validation error.

Constrained values

Use enumValues to restrict text field values:

{
  "name": "stage",
  "type": "text",
  "enumValues": ["lead", "qualified", "proposal", "won", "lost"],
  "defaultValue": "lead"
}

actions[]

Actions are RPC methods declared in the manifest. Declaring them makes them discoverable by the Studio, integrations, and AI agents.

Field Type Required Description
id string Yes Must match a key in serve().
name string Yes Display name for Studio and AI agents.
description string No What the action does.
inputSchema object No JSON Schema for input parameters.
outputSchema object No JSON Schema for the return value.

permissions

Add permission keys to control access. Keys follow the entity.action convention in the manifest. On deploy, they are automatically prefixed with app:<appId>: to form the full namespaced key.

"permissions": {
  "permissions": [
    { "key": "contacts.create", "description": "Create contacts" },
    { "key": "contacts.read",   "description": "View contacts" },
    { "key": "contacts.update", "description": "Edit contacts" },
    { "key": "contacts.delete", "description": "Delete contacts" }
  ]
}

These become app:sales_crm:contacts.create, app:sales_crm:contacts.read, etc. If you don't declare explicit permissions, the system auto-generates CRUD keys from your dataContract entities.

configSchema

An optional JSON Schema that defines the structure of app-level configuration:

"configSchema": {
  "type": "object",
  "properties": {
    "defaultCurrency": { "type": "string", "default": "USD" },
    "enableNotifications": { "type": "boolean", "default": true }
  }
}

Triggers

For agent apps, define a trigger to auto-invoke the agent on entity changes:

"trigger": {
  "app_id": "crm",
  "entity": "contacts",
  "on": ["INSERT", "UPDATE", "DELETE"]
}

When a matching database operation occurs in the target app, the agent is invoked via the hook system with the change details (entity, operation, record data, old record).

Schema sync

Every manifest install diffs your dataContract against the live PostgreSQL schema and applies the minimum DDL in a single transaction per table. Schema sync runs automatically on install and deploy — there are no manual migration files to manage.

Change DDL
New entity CREATE TABLE
New field ALTER TABLE ... ADD COLUMN
Field type changed ALTER TABLE ... ALTER COLUMN ... TYPE with USING cast
required changed SET / DROP NOT NULL
defaultValue changed SET / DROP DEFAULT
enumValues updated DROP CONSTRAINT + ADD CONSTRAINT CHECK
Field removed DROP COLUMN ... CASCADE
Entity removed DROP TABLE ... CASCADE

Changes are applied in a safe order within a single transaction. Type conversions use appropriate USING clauses where possible.

The Schema Sync Engine drops columns removed from the manifest and can drop orphaned tables. Only id, created_at, and updated_at are protected.

Full example manifest

{
  "appId": "sales_crm",
  "name": "Sales CRM",
  "version": "1.0.0",
  "description": "Manage contacts, companies, and deals with a sales pipeline.",
  "dataContract": [
    {
      "entityName": "contacts",
      "fields": [
        { "name": "first_name", "type": "text", "required": true },
        { "name": "last_name",  "type": "text", "required": true },
        { "name": "email",      "type": "text" },
        { "name": "phone",      "type": "text" },
        { "name": "company_id", "type": "entity_link", "references": { "entity": "companies", "field": "id" } },
        { "name": "assigned_to", "type": "entity_link", "references": { "entity": "core:users", "field": "id" } }
      ]
    },
    {
      "entityName": "companies",
      "fields": [
        { "name": "name",     "type": "text", "required": true },
        { "name": "industry", "type": "text" },
        { "name": "website",  "type": "text" }
      ]
    },
    {
      "entityName": "deals",
      "fields": [
        { "name": "title",      "type": "text", "required": true },
        { "name": "value",      "type": "number" },
        { "name": "stage",      "type": "text", "enumValues": ["lead", "qualified", "proposal", "won", "lost"], "defaultValue": "lead" },
        { "name": "contact_id", "type": "entity_link", "references": { "entity": "contacts", "field": "id" } },
        { "name": "company_id", "type": "entity_link", "references": { "entity": "companies", "field": "id" } },
        { "name": "notes",      "type": "json" }
      ]
    }
  ],
  "actions": [
    {
      "id": "pipeline",
      "name": "Pipeline Summary",
      "description": "Returns deal counts per stage"
    }
  ],
  "permissions": {
    "permissions": [
      { "key": "contacts.create", "description": "Create contacts" },
      { "key": "contacts.read",   "description": "View contacts" },
      { "key": "contacts.update", "description": "Edit contacts" },
      { "key": "contacts.delete", "description": "Delete contacts" },
      { "key": "companies.read",  "description": "View companies" },
      { "key": "deals.create",    "description": "Create deals" },
      { "key": "deals.read",      "description": "View deals" },
      { "key": "deals.update",    "description": "Edit deals" },
      { "key": "deals.delete",    "description": "Delete deals" }
    ]
  }
}
PreviousBackend & RPCNextREST API

On this page

Top-level fields
dataContract[]
dataContract[].fields[]
Field types
Relationships and constraints
actions[]
permissions
configSchema
Triggers
Schema sync
Full example manifest