# Your app as a data layer for AI

Every app Fayz generates is born **agent-ready**. It isn't a feature you switch on later: the same manifest that describes screens, routes and data also describes, as a typed contract, **what an AI is allowed to read and do** in that app. An agent that understands the contract can check the calendar, summarize the books or adjust inventory — without you writing an AI endpoint from scratch.

This page covers the `aiTools` contract, what you get for free, how the chat shell connects to an LLM, and how your own plugin joins this layer.

## The `aiTools` contract

Any plugin can declare an `aiTools` field in its manifest (`PluginManifest.aiTools?: PluginAITool[]`, in `@fayz-ai/core`). Each tool is a **function an agent can call**, described in a format LLMs understand natively — the same _function calling_ shape OpenAI and Anthropic use:

```ts
type PluginAITool = {
  id: string            // 'agenda.create-appointment'
  name: string          // 'createAppointment' — the name the LLM calls
  description: string    // what the tool does, in natural language
  mode: 'read' | 'persist'   // does it only read data, or write/change state?
  parameters?: {         // JSON Schema: type:'object', properties, required
    type: 'object'
    properties: Record<string, { type: string; description?: string }>
    required?: string[]
  }
  permission?: { feature: string; action: 'read' | 'create' | ... }
  suggestions?: { label: string }[]   // suggestion chips in the chat
  category?: string
}
```

Two details matter:

- **`mode` separates reads from writes.** `read` queries; `persist` creates or changes state. The shell uses this to filter tools, and so you can require confirmation before any `persist`.
- **`permission` binds the tool to access control.** The same feature and permission that guards the screen guards the tool. An agent running as a given user only sees the tools that user could use.

{% callout type="tip" %}
**14 of the 22 plugins already declare `aiTools`** today — agenda, conversations, crm, dashboard, financial, forms, inventory, marketing, menu, orders, shop, tables, tasks and admin. Enable the plugin and you get its tools in the contract.
{% /callout %}

## Real examples from the SDK

These are tools that exist in plugin code today — not invented examples:

| Plugin | Tool | `mode` | What it does |
| --- | --- | --- | --- |
| `agenda` | `listAppointments` | `read` | Lists appointments for a date or period, filterable by professional. |
| `agenda` | `createAppointment` | `persist` | Creates an appointment for a client with a professional and a service. |
| `agenda` | `checkAvailability` | `read` | Checks a professional's free slots on a given date. |
| `menu` | `toggleMenuItemAvailability` | `persist` | Marks a menu item as available or sold out. |
| `financial` | `getRevenue` | `read` | Returns revenue for a period. |
| `orders` | `createOrder` | `persist` | Opens a new order. |
| `inventory` | `getLowStock` | `read` | Lists items below the reorder point. |
| `conversations` | `sendMessage` | `persist` | Sends a message in a conversation. |
| `dashboard` | `getKpiSummary` | `read` | Summarizes the business KPIs. |

## What you get for free: core tools + registries

On top of what each plugin declares, the Fayz shell (`@fayz-ai/saas`) injects **three core tools that are always present**, defined in `core-ai-tools.ts`:

- `getBusinessSummary` (`read`) — the business at a glance.
- `getTeamMembers` (`read`) — who's on the team.
- `navigateTo` (`read`) — takes the user to a screen.

And there's a multiplier: **every non-readonly registry (entity) in your app automatically becomes a `list<Entity>` tool**. Register `products` and you get `listProducts` without writing anything — the comment in the code says it literally: _"Each registry gets a basic 'list' tool so plugins get AI capabilities for free."_ Your entities become queryable by an agent just by existing.

## The chat shell — and the honest boundary

The shell ships the UI: a **chat FAB** and a **panel** (`ChatFab`, `ChatPanel`), with suggestion chips sourced from `aiTools` and filtering by permission and vertical via the `useAITools` hook. Users see the right tools and ready-made suggestions.

But `useChat` is **bring-your-own-endpoint** (_BYO endpoint_). It `POST`s the conversation history to an `apiEndpoint` in OpenAI format that you configure. With no endpoint, the response is a demo mock.

{% callout type="warn" %}
**The SDK does not execute tools.** `PluginAITool` has no handler — it is a **schema**, not an implementation. Receiving the `tool_call` from the LLM, running the action against Supabase (honoring RLS) and returning the result is the job of the **app owner's backend**. The SDK gives you the contract and the UI; the execution loop is yours. Never assume Fayz "runs the agent" for you.
{% /callout %}

The target architecture, honest about what exists:

```
┌──────────────┐   history (tools stay in your backend)   ┌────────────────────┐
│  ChatPanel   │ ───────────────────────────────────────▶ │  your apiEndpoint  │
│  (shell UI)  │                                          │   (your backend)   │
│  useAITools  │ ◀─────────────────────────────────────── │  + LLM (Claude/…)  │
└──────────────┘        response / tool_call              └─────────┬──────────┘
       ▲                                                            │ runs the tool
       │ aiTools schemas                                            ▼
       │ (from the manifest)                              ┌────────────────────┐
       └───────────────────────────────────────────────── │  Supabase + RLS    │
                                                          │  (tenant data)     │
                                                          └────────────────────┘
```

The shell supplies the **schemas** (what exists) and the **UI**. Your endpoint supplies the **LLM** and the **execution**. RLS guarantees the agent only touches the right tenant's data.

## Practical scenarios

Written as **target architecture on top of what already exists** — the schemas are ready; you just need to plug in the endpoint:

- **An assistant that checks the calendar and books.** The LLM receives `listAppointments`, `checkAvailability` and `createAppointment`. "Can you fit Sarah in tomorrow morning?" → it calls `checkAvailability`, picks a slot and proposes `createAppointment` (which is `persist` — so you ask for confirmation).
- **Financial summaries over chat.** `getRevenue` + `getKpiSummary` answer "how was this week?" with real tenant numbers, not estimates.
- **An inventory agent.** `getLowStock` finds what's running out; a restock `persist` (once you declare one) closes the loop.

## A real `aiTool`, in JSON

The schema your endpoint hands to the LLM — adapted from the real `createAppointment` in plugin-agenda:

```json
{
  "name": "createAppointment",
  "description": "Creates a new appointment for a client with a specific professional and service.",
  "parameters": {
    "type": "object",
    "properties": {
      "client":       { "type": "string", "description": "Client name" },
      "professional": { "type": "string", "description": "Professional name" },
      "service":      { "type": "string", "description": "Service name" },
      "date":         { "type": "string", "description": "Date (YYYY-MM-DD)" },
      "time":         { "type": "string", "description": "Time (HH:MM)" }
    },
    "required": ["client", "professional", "service", "date", "time"]
  }
}
```

`mode: 'persist'` and `permission` stay in the manifest (they never reach the LLM) — they're what the shell and your backend use for gating and confirmation.

## How your own plugin joins this layer

It's simple: **declare `aiTools` in the manifest.** `fayz create plugin` already emits the (empty) array — you just fill it in. A well-built tool:

1. Has a clear verb-noun `name` (`listLeads`, `createOrder`).
2. Declares an honest `mode` — `persist` for anything that changes state.
3. Describes `parameters` with a `description` on every field (the LLM reads them).
4. Ties `permission` to the same feature as the screen.

Once that's done, your plugin shows up in the chat, in the suggestions and in the contract the agent reads. For the full field list, see the [Plugin manifest reference](/en/docs/reference/plugin-manifest). To connect an agent to this Dev Center, see [Connect your agent](/en/docs/ai/connect-your-agent).
