Build an AI Agent
An AI Agent is an application that talks to a language model. It receives messages, reasons about them, calls tools (like reading data or triggering actions), and responds. Under the hood, it is a standard RootCX Application with one extra configuration file: agent.json.
It inherits everything a regular application has -- Authentication, RBAC, Audit Logs -- plus session memory, supervision policies, and streaming responses.

Create an Agent with Forge
Open the AI Forge in Studio. Describe your agent, its purpose, and what tools it should access.
Example prompt:
"Create a customer support agent. It should be polite and concise. Give it read access to the Orders app and the ability to send Slack notifications. Enable session memory."
The Forge generates everything: the agent.json configuration, a Markdown system prompt, the manifest with permission keys, and the backend logic.
What Gets Generated
After the Forge builds your agent, review the key files:
agent.json-- configures the agent's name, system prompt path, memory settings, turn limits, and supervision policies.agent/system.md-- the instructions your agent follows. Plain Markdown, editable at any time.manifest.json-- declares the agent's entities, permission keys, and actions.backend/index.ts-- the LLM invocation logic.
agent.json
This is the file that turns a regular application into an AI Agent:
{
"name": "Support Agent",
"description": "Handles customer queries about orders and shipping",
"systemPrompt": "./agent/system.md",
"memory": { "enabled": true },
"limits": {
"maxTurns": 20,
"maxContextTokens": 100000,
"keepRecentMessages": 10
},
"supervision": {
"mode": "supervised",
"policies": [
{
"action": "mutate",
"entity": "orders",
"requires": "approval"
}
]
}
}
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | required | Agent display name. |
description |
string | — | Short description of what the agent does. |
systemPrompt |
string | — | Path to the Markdown system prompt file. |
memory.enabled |
boolean | false |
Retain conversation history across messages. |
limits.maxTurns |
number | 50 |
Maximum reasoning turns per invocation. |
limits.maxContextTokens |
number | 100000 |
Context window budget for history. |
limits.keepRecentMessages |
number | 10 |
Messages preserved when context is compacted. |
supervision.mode |
string | — | "autonomous", "supervised", or "strict". |
system.md prompt. Edit it directly in the Studio editor at any time to change the agent's behavior.Tools and RBAC
Your agent uses the platform's built-in tools, governed by the same RBAC policies as human users:
query_data-- read records from any entity. Supports cross-app reads with theappparameter.mutate_data-- create, update, delete, or bulk_create records. Supports cross-app writes with theappparameter.describe_app-- inspect the data model of an app.list_apps-- discover all installed applications.list_integrations-- browse available integrations and their actions.invoke_agent-- delegate a task to another agent in the fleet.

Each tool is gated by RBAC. If the agent lacks a permission, the Core blocks the call instantly. Permission keys follow the app:<appId>:<entity>.<action> format for data operations, or tool:<toolName> for tool access.
Cross-app tools
The query_data and mutate_data tools accept an optional app parameter to read/write data in other applications:
// query_data — read contacts from the CRM app
{ "entity": "contacts", "app": "crm", "where": { "stage": "lead" } }
// mutate_data — create a task in another app
{ "entity": "tasks", "app": "task_manager", "action": "create", "data": { "title": "Follow up" } }
The permission check uses app:{target_app}:{entity}.{action}. Grant the agent's role access to the target app's entities.
invoke_agent
Delegate tasks to other agents in the fleet:
{ "app_id": "finance_agent", "message": "Summarize Q4 revenue" }
Returns the sub-agent's full response. Sub-agents cannot spawn further sub-agents (single-level delegation). Approval requests from sub-agents propagate to the parent agent's session.
Session Memory
When memory is enabled, the agent retains conversation history across messages within a session. A user can ask follow-up questions without repeating context.
| Setting | Description |
|---|---|
maxContextTokens |
How much history fits in the context window. |
keepRecentMessages |
Number of recent messages preserved when context is compacted. |
Sessions and messages are persisted in the database. When the context window fills up, older messages are compacted into a summary while preserving the most recent messages.
Supervision
Supervision controls how much freedom the agent has before acting:
| Mode | Behavior |
|---|---|
autonomous |
The agent executes all tool calls freely within its RBAC permissions. |
supervised |
Certain actions require explicit human approval before execution. |
strict |
Every tool call requires human approval. |
In supervised mode, you define granular policies per action or entity:
{
"action": "mutate",
"entity": "orders",
"requires": "approval"
}
The action field maps tool names to policy actions: query_data maps to "query", mutate_data maps to "mutate", other tools use their name directly. Use "*" to match all tools.
Rate Limits
Policies can include rate limits:
{
"action": "mutate",
"rateLimit": { "max": 20, "window": "1h" }
}
Window values: "60s", "30m", "1h", "1d".
Approval Flow
When approval is required:
- The agent pauses execution and broadcasts an
approval_requiredSSE event. - The approval request appears in Studio and via
GET /api/v1/apps/{appId}/agent/approvals. - A human approves or rejects via
POST /api/v1/apps/{appId}/agent/approvals/{approvalId}with{ "action": "approve" }or{ "action": "reject", "reason": "..." }. - The agent resumes or adapts based on the decision.
Hooks (Entity Triggers)
Agents can be automatically invoked when data changes in other apps. Define a trigger in the manifest:
{
"trigger": {
"app_id": "crm",
"entity": "contacts",
"on": ["INSERT", "UPDATE"]
}
}
When a matching database operation occurs, the Core automatically invokes the agent with the change details (entity, operation, record data, old record).
Deploy and Test
Hit Run (F5). The Core installs the manifest, syncs the schema, and starts the backend -- same flow as any application. The agent gets its own system identity (agent+<appId>@localhost) with a role (agent:<appId>) that has app:<appId>:* and tool:* by default.
Test it by sending a message and observing the streamed response in Studio.
Invoke and Monitor
Send a message to the agent:
POST /api/v1/apps/{appId}/agent/invoke
{ "message": "What are the open orders?", "session_id": "optional-uuid" }
The response is streamed via SSE with events for text chunks, tool calls, approvals, and the final response. Sessions can be listed, inspected, and replayed via the API.
See the REST API Reference for the full list of agent endpoints (invoke, sessions, approvals, fleet stream).
Full agent.json Example
{
"name": "Finance Agent",
"description": "Automates invoice processing and payment reconciliation",
"systemPrompt": "./agent/system.md",
"memory": { "enabled": true },
"limits": {
"maxTurns": 15,
"maxContextTokens": 100000,
"keepRecentMessages": 10
},
"supervision": {
"mode": "supervised",
"policies": [
{ "action": "mutate", "entity": "invoices", "requires": "approval" },
{ "action": "mutate", "rateLimit": { "max": 20, "window": "1h" } },
{ "action": "query", "rateLimit": { "max": 200, "window": "1h" } },
{ "action": "*", "rateLimit": { "max": 500, "window": "1d" } }
]
}
}
Next Steps
- Build an Application -- understand the foundation every agent inherits.
- RBAC -- how to assign permissions to your agent's role.
- REST API -- full endpoint reference.
