informer.yaml Reference
The informer.yaml file is the central configuration file for your Magic App. It declares which APIs the app can access and defines custom roles for role-based UIs.
Place it in your project root. It's uploaded to the app's library on deploy and enforced at runtime by the Informer server.
Basic Structure
# informer.yaml
access:
datasets:
- admin:sales-data
queries:
- admin:monthly-summary
integrations:
- salesforce
roles:
- id: viewer
name: Viewer
description: Read-only access
Access Section
The access section controls which Informer APIs your app can call. Without this section, all API access is blocked when the app runs in Informer (secure by default).
In dev mode, the Vite proxy uses your admin credentials directly, so access restrictions are not enforced locally. They only apply when the app is deployed and viewed by users.
Datasets
Grants access to dataset search and field metadata.
access:
datasets:
- admin:sales-data
- admin:customers
Each entry grants:
POST /api/datasets/{id}/_search— Elasticsearch queriesGET /api/datasets/{id}/fields— Field metadata
Row-Level Security
Restrict data based on the viewing user's profile:
access:
datasets:
- id: admin:orders
filter:
region: $user.custom.region # User only sees their region
sales_rep: $user.username # User only sees their own records
Filters are injected server-side into every search request. The app code doesn't need to handle filtering — it's automatic and tamper-proof.
Queries
Grants access to execute saved queries:
access:
queries:
- admin:daily-summary
- admin:monthly-report
Each entry grants:
POST /api/queries/{id}/_execute
Integrations
Grants access to make requests through integrations (Salesforce, REST APIs, etc.):
access:
integrations:
- salesforce
- quickbooks
Each entry grants:
POST /api/integrations/{id}/request
Credential Injection
Pass user-specific credentials to external APIs:
access:
integrations:
- id: partner-api
headers:
Authorization: Bearer $user.custom.partnerToken
X-Client-ID: $tenant.id
params:
user_id: $user.custom.externalId
Headers and params are expanded server-side — sensitive values are never exposed to client JavaScript.
Path Restrictions
Limit which endpoints the app can call on an integration:
access:
integrations:
- id: salesforce
paths:
- /data/*/query
- /data/*/sobjects/*
Datasources
Grants access to run SQL queries against datasources:
access:
datasources:
- postgres-main
- mysql-analytics
Each entry grants:
POST /api/datasources/{id}/_query
Libraries
Grants access to read files from other libraries:
access:
libraries:
- admin:shared-assets
- admin:common-templates
Each entry grants:
GET /api/libraries/{id}/contents/*
Raw API Paths
For edge cases not covered by resource types:
access:
apis:
- POST /api/custom/endpoint
- GET /api/special/resource
- POST /api/models/go_everyday/_chat
- POST /api/models/go_everyday/_completion
- POST /api/models/go_everyday/_object
- /api/read-only/resource # METHOD defaults to GET if omitted
Each entry is a string in the format METHOD /api/path. If the HTTP method is omitted, it defaults to GET.
Roles Section
Define custom roles that publishers assign when sharing the app:
roles:
- id: viewer
name: Viewer
description: Can view reports but not take actions
- id: approver
name: Approver
description: Can approve or reject requests
- id: manager
name: Manager
description: Full management access
| Field | Required | Description |
|---|---|---|
id | Yes | String identifier used in code |
name | Yes | Display name shown in share dialogs |
description | No | Help text shown in share dialogs |
Reading Roles
Client-side:
const roles = window.__INFORMER__?.roles || [];
if (roles.includes('approver')) {
showApprovalPanel();
}
Server-side (route handlers):
// Automatic enforcement via config
export const config = {
roles: ['admin', 'manager'] // 403 if user lacks these roles
};
// Manual checking
export async function GET({ request }) {
if (request.roles.includes('manager')) {
// show admin data
}
}
How Roles Are Assigned
- Internal shares — Publisher selects roles in the share dialog
- External links — Publisher selects roles when creating the link; roles are baked into the token
- Publisher+ on owning team — Automatically receives all defined roles
- No roles defined —
window.__INFORMER__.rolesis[]
Variable Reference
Variables are expanded server-side, keeping sensitive values secure.
| Variable | Description |
|---|---|
$user.username | Login name |
$user.email | Email address |
$user.displayName | Full name |
$user.custom.xxx | Custom user field value |
$tenant.id | Tenant identifier |
$tenant.<setting> | Tenant setting value (from system settings) |
$report.id | App UUID |
$report.name | App display name |
If a variable references a custom user field that doesn't exist (e.g., $user.custom.region when the user has no region field), it resolves to an empty string. For dataset filters, this means the filter matches records where that field is empty — not all records. Ensure all referenced custom fields exist for your users.
Agents Section
Define AI agents that execute autonomously in response to events, cron schedules, or manual triggers. See the Agents API docs for full details.
agents:
order-processor:
description: Processes new orders and sends confirmations
instructions: |
You are an order processing agent. When triggered by an order_created event,
verify the order details, update inventory, and send a confirmation email.
tools:
- send-email
- update-inventory
on: order_created
model: go_everyday
daily-report:
description: Generates a daily summary email
instructions: Summarize today's orders and email the report to the team.
tools:
- send-email
cron: "0 17 * * 1-5"
crm-agent:
description: Customer support with CRM tools
instructions: Help customers using CRM data and web search.
toolkits:
- admin:crm-toolkit
assistants:
- admin:support-persona
on: support_request
webSearch: true
Agent Fields
| Field | Type | Description |
|---|---|---|
description | string | Human-readable description |
instructions | string | System prompt for the AI model |
tools | string[] | App tool names (from tools/ directory) |
toolkits | string[] | Toolkit natural IDs to attach |
assistants | string[] | Assistant natural IDs — instructions merge into the agent's system prompt |
on | string | string[] | Event name(s) that trigger this agent |
cron | string | Cron schedule (5-field: min hour dom mon dow) |
webSearch | boolean | Enable web search tool |
model | string | AI model slug (default: go_everyday) |
Toolkits
Agents can reference external toolkits that provide additional tools. Toolkit references are resolved at deploy — if a referenced toolkit doesn't exist, deploy fails with a clear error.
agents:
my-agent:
instructions: Use CRM tools to look up customer data.
toolkits:
- admin:crm-toolkit # Resolved by naturalId at deploy
on: customer_inquiry
At execution time, the agent receives all tools from its referenced toolkits alongside its app tools. Toolkit system instructions are appended to the agent's prompt.
Assistants
Agents can reference Informer assistants to inherit their instructions. Each assistant's system prompt is merged into the agent's own instructions at execution time.
agents:
support-bot:
instructions: Handle customer inquiries.
assistants:
- admin:support-persona # Assistant instructions merged into prompt
on: support_request
Assistant references are validated at deploy time — if a referenced assistant doesn't exist, deploy fails with a clear error. At runtime, assistant instructions are prepended to the system prompt before toolkit instructions.
Cron Schedules
Standard 5-field cron format: minute hour day-of-month month day-of-week
agents:
nightly-sync:
instructions: Sync data from external system.
cron: "0 3 * * *" # 3:00 AM daily
weekly-report:
instructions: Generate weekly report.
cron: "0 9 * * 1" # 9:00 AM every Monday
frequent-check:
instructions: Check for new items.
cron: "*/15 * * * *" # Every 15 minutes
Events Section
Declare event types that agents can listen for. Events are emitted from server route handlers via the emit() callback.
events:
order_created:
description: Fired when a new order is submitted
order_shipped:
description: Fired when an order ships
support_request:
description: Fired when a customer opens a support ticket
agents:
order-processor:
on: order_created
instructions: Process the new order.
support-bot:
on: support_request
instructions: Respond to the support ticket.
Event types are stored in app.defn.events on deploy. To emit an event from a server route:
export async function POST({ query, emit, request }) {
const [order] = await query(
'INSERT INTO orders (customer, total) VALUES ($1, $2) RETURNING *',
[request.body.customer, request.body.total]
);
await emit('order_created', { orderId: order.id });
return { status: 201, body: order };
}
Widgets Section
Declare dashboard widgets that render inside Informer's widget gallery. Widgets are static HTML files served in iframes at fixed grid sizes.
widgets:
cash-balance:
entry: widgets/cash-balance.html
label: Cash Balance
size: { w: 2, h: 1 }
refresh: 300
sales-trend:
entry: widgets/sales-trend.html
label: Sales Trend
size: { w: 2, h: 2 }
refresh: 300
Widget Fields
| Field | Type | Description |
|---|---|---|
entry | string | Path to HTML file relative to public/ |
label | string | Display name in the widget gallery |
size | object | Grid dimensions: w (width) and h (height) in grid units |
refresh | number | Auto-refresh interval in seconds |
Widget HTML files go in public/widgets/ and are self-contained (inline CSS/JS, no external dependencies). They use the same API access as the main app.
Complete Example
# informer.yaml
access:
datasets:
- admin:sales-data
- id: admin:orders
filter:
region: $user.custom.region
queries:
- admin:monthly-summary
integrations:
- salesforce
- sendgrid
datasources:
- postgres-analytics
roles:
- id: viewer
name: Viewer
description: Read-only access
- id: manager
name: Manager
description: Full management access
events:
order_created:
description: New order submitted
order_shipped:
description: Order has shipped
agents:
order-processor:
description: Processes new orders
instructions: Verify order details and update inventory.
tools:
- update-inventory
- send-email
on: order_created
daily-digest:
description: Daily order summary
instructions: Summarize today's orders and email to managers.
tools:
- send-email
cron: "0 17 * * 1-5"
widgets:
order-count:
entry: widgets/order-count.html
label: Today's Orders
size: { w: 2, h: 1 }
refresh: 60