Manifest Reference
The manifest.json is the single source of truth for your application. It declares entities, fields, permissions, actions, webhooks, crons, and public access. Everything else (database tables, CRUD API, constraints, RBAC policies) is derived from it automatically.
All field names use camelCase (the manifest is parsed with serde(rename_all = "camelCase")).
Top-level fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
appId |
string | Yes | Unique identifier. Lowercase snake_case (letters, digits, underscores). Immutable after first deploy. Becomes the PostgreSQL schema name. | |
name |
string | Yes | Display name. | |
version |
string | No | "0.0.1" |
Semantic version. |
description |
string | No | "" |
Short description. |
type |
string | No | "app" |
"app", "integration", or "agent". |
icon |
string | No | Icon path (relative to project root). Stored in platform storage on deploy. | |
dataContract |
array | No | [] |
Array of entity definitions. |
permissions |
object | No | Object with a permissions array of permission key declarations. |
|
actions |
array | No | [] |
Array of RPC action declarations. |
webhooks |
array | No | [] |
Array of webhook definitions. |
crons |
array | No | [] |
Array of declarative cron schedules. |
public |
object | No | Public-access surface (RPCs and collections that bypass auth). | |
configSchema |
object | No | JSON Schema for app-level configuration. | |
userAuth |
object | No | User authentication mode (for integrations). | |
instructions |
string | No | Usage instructions surfaced to AI agents via list_integrations. |
|
trigger |
object | No | Auto-invoke this agent on entity changes in another app. |
dataContract
Each entry becomes a PostgreSQL table. System columns (id, created_at, updated_at) are added automatically.
| Field | Type | Required | Description |
|---|---|---|---|
entityName |
string | Yes | Table name. Used in API routes. Lowercase snake_case. |
fields |
array | Yes | Array of field definitions. |
identityKind |
string | No | Federates records across apps (e.g., "contact"). |
identityKey |
string | No | Field name used for identity lookup. Required if identityKind is set. |
indexes |
array | No | Declarative secondary indexes. See indexes. |
checks |
array | No | Declarative CHECK constraints. See checks. |
fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | Yes | Column name. Lowercase snake_case. created_at and updated_at are reserved. |
|
type |
string | Yes | One of the field types below. | |
required |
boolean | No | false |
Adds NOT NULL constraint. |
default_value |
any | No | Default on insert. Accepts JSON values. | |
enum_values |
string[] | No | Allowed values. Generates a CHECK constraint automatically. | |
references |
object | No | For entity_link only. { "entity": "...", "field": "id" }. |
|
is_primary_key |
boolean | No | false |
Custom primary key. Rarely needed. |
on_delete |
string | No | For entity_link. "cascade", "restrict", or "set_null". Default: "restrict" if required, "set_null" if optional. |
Field 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. |
uuid |
UUID | UUID value. |
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. |
References
Local entity:
{ "entity": "contacts", "field": "id" }
System users (creates FK to rootcx_system.users(id) with ON DELETE SET NULL):
{ "entity": "core:users", "field": "id" }
permissions
"permissions": {
"permissions": [
{ "key": "contacts.create", "description": "Create contacts" },
{ "key": "contacts.read", "description": "View contacts" }
]
}
Keys follow entity.action convention. On deploy, they are prefixed with app:{appId}:. If not declared, CRUD keys are auto-generated from entities + cron keys (cron.read, cron.write, cron.trigger).
actions
"actions": [
{
"id": "pipeline",
"name": "Pipeline Summary",
"description": "Returns deal counts per stage",
"inputSchema": { "type": "object", "properties": {...} },
"outputSchema": { "type": "object", "properties": {...} }
}
]
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Must match a key in serve() rpc handlers. |
name |
string | Yes | Display name for 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. |
Each action gets an RBAC permission: app:{appId}:action:{actionId}.
webhooks
"webhooks": [
{ "name": "stripe", "method": "onStripePayment" },
"github"
]
Two formats: full object { "name", "method" } or simple string (name only, method defaults to "POST"). For applications, always use the full format with an explicit method name.
See Webhooks for full reference.
crons
"crons": [
{
"name": "daily-check",
"schedule": "0 9 * * *",
"timezone": "America/New_York",
"method": "onDailyCheck",
"payload": { "task": "check_replies" },
"overlapPolicy": "skip"
}
]
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | Yes | 1-64 chars, alphanumeric + dash + underscore. | |
schedule |
string | Yes | 5-field cron expression or "N seconds" (1-59). |
|
timezone |
string | No | GMT | Timezone for the schedule. |
method |
string | No | If set, added to payload as payload.method. |
|
payload |
object | No | {} |
JSON object passed to the worker. |
overlapPolicy |
string | No | "skip" |
"skip" or "queue". |
See Scheduled Jobs for full reference.
public
"public": {
"rpcs": [
{ "name": "submitForm", "scope": [] },
{ "name": "checkStatus", "scope": ["orderId"] }
],
"collections": [
{ "entity": "announcements", "actions": ["list", "read"] }
]
}
rpcs
| Field | Type | Description |
|---|---|---|
name |
string | RPC method name to expose publicly. |
scope |
string[] | Keys to enforce-match between share token context and request body. Empty = anonymous access (no token needed). Non-empty = share token required. |
collections
| Field | Type | Description |
|---|---|---|
entity |
string | Entity name to expose. |
actions |
string[] | Subset of CRUD actions: "list", "read", "create", "update", "delete". |
trigger
For agent apps. Auto-invoke the agent when data changes in another app:
"trigger": {
"appId": "crm",
"entity": "contacts",
"on": ["INSERT", "UPDATE"]
}
| Field | Type | Description |
|---|---|---|
appId |
string | Target app whose entity to watch. |
entity |
string | Entity name to watch. |
on |
string[] | Operations: "INSERT", "UPDATE", "DELETE". |
configSchema
JSON Schema for app-level configuration. For integrations, fields with platformSecret store values in the encrypted vault:
"configSchema": {
"properties": {
"botToken": { "type": "string", "platformSecret": "SLACK_BOT_TOKEN" }
},
"required": ["botToken"]
}
indexes
Declare secondary indexes on an entity. Reconciled at every deploy: the core creates, replaces, or drops only the indexes it owns (tagged with a hash comment). Manually-created indexes are never touched.
"indexes": [
{ "name": "deal_stage_idx", "columns": ["stage"] },
{ "columns": ["company_id", "created_at"], "unique": true },
{ "columns": [{ "column": "amount", "sort": "desc" }], "where": "amount > 0" }
]
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | No | Auto-derived | Index name. Auto-generated if omitted. |
columns |
array | Yes | Column names (strings) or specs ({ column, expr, sort, nulls, ops }). |
|
unique |
boolean | No | false |
Create a UNIQUE index. |
using |
string | No | "btree" |
Index method: btree, hash, gin, gist, spgist, brin. |
where |
string | No | Partial-index predicate (SQL fragment). | |
with |
object | No | Storage parameters (e.g. {"fillfactor": "70"}). |
checks
Declare table-level CHECK constraints with arbitrary SQL boolean expressions. Same ownership model as indexes: the core reconciles only the checks it owns, and never drops manually-created constraints.
Enum-derived CHECKs (from enum_values) are generated automatically. Use checks for business rules that span multiple columns or express conditions beyond simple value membership.
"checks": [
{ "name": "dates_valid", "expr": "end_date IS NULL OR end_date >= start_date" },
{ "expr": "quantity > 0" }
]
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | No | Constraint name. Auto-derived if omitted. |
expr |
string | Yes | SQL boolean expression. Can reference any column on the table. |
Schema sync
Every deploy diffs dataContract against the live PostgreSQL schema and applies the minimum DDL:
| Change | DDL |
|---|---|
| New entity | CREATE TABLE |
| New field | ALTER TABLE ADD COLUMN |
| Field type changed | ALTER COLUMN TYPE with USING cast |
required changed |
SET / DROP NOT NULL |
default_value changed |
SET / DROP DEFAULT |
on_delete changed |
Replace foreign key constraint |
| Field removed | DROP COLUMN CASCADE |
| Entity removed | DROP TABLE CASCADE |
indexes changed |
Drop + recreate (tag-owned, no churn if unchanged) |
checks / enum_values changed |
Drop + recreate (tag-owned, no churn if unchanged) |
Column DDL runs in a single transaction per table. Indexes and checks are reconciled in a separate pass. If any statement fails, the transaction rolls back. Unchanged objects are left untouched (no drop/recreate churn).
id, created_at, and updated_at are protected.Full example
{
"appId": "sales_crm",
"name": "Sales CRM",
"version": "1.0.0",
"description": "Manage contacts, companies, and deals.",
"dataContract": [
{
"entityName": "contacts",
"identityKind": "contact",
"identityKey": "email",
"fields": [
{ "name": "first_name", "type": "text", "required": true },
{ "name": "last_name", "type": "text", "required": true },
{ "name": "email", "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" } },
{ "name": "stage", "type": "text", "enum_values": ["lead", "qualified", "proposal", "won", "lost"], "default_value": "lead" }
]
},
{
"entityName": "companies",
"fields": [
{ "name": "name", "type": "text", "required": true },
{ "name": "industry", "type": "text" },
{ "name": "website", "type": "text" }
]
}
],
"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" }
]
},
"webhooks": [
{ "name": "stripe", "method": "onStripePayment" }
],
"crons": [
{ "name": "daily-sync", "schedule": "0 9 * * *", "overlapPolicy": "skip" }
]
}