# A2A Protocol
Source: https://docs.crewform.tech/a2a-protocol
Agent-to-Agent interoperability — expose CrewForm agents to external AI systems and delegate tasks to remote agents
## Overview
CrewForm supports the **A2A (Agent-to-Agent) protocol**, enabling your agents to communicate with external AI systems. This is the open standard for agent-to-agent interoperability.
A2A complements MCP (tools) and AG-UI (frontend) — together they form the **three agentic protocols** that CrewForm supports.
## How It Works
A2A provides two capabilities:
### A2A Server — Expose Your Agents
External platforms can discover and call your CrewForm agents via standard A2A endpoints:
| Endpoint | Method | Description |
| ------------------------- | ------ | ----------------------------------------------------------------------- |
| `/.well-known/agent.json` | GET | Agent Card discovery — returns agent capabilities, skills, and metadata |
| `/a2a/:agentId` | POST | JSON-RPC endpoint — accepts `message/send`, `tasks/get`, `tasks/cancel` |
**Agent Card example:**
```json theme={null}
{
"name": "Research Agent",
"description": "Performs web research and summarization",
"version": "1.0.0",
"skills": [
{
"id": "web_research",
"name": "Web Research",
"description": "Search the web and compile findings"
}
]
}
```
### A2A Client — Delegate to External Agents
CrewForm agents can delegate tasks to any external A2A-compliant agent using the built-in `a2a_delegate` tool.
**How to enable:**
1. Go to **Settings → A2A Protocol**
2. Enter the base URL of the external agent (e.g. `https://agent.example.com`)
3. Click **Discover** — CrewForm fetches the Agent Card and registers the agent
4. Toggle the agent to **Enabled**
5. Add `a2a_delegate` to any agent's tool list
The agent can then call:
```
a2a_delegate(agent_id: "remote-agent-uuid", message: "Research the latest AI trends")
```
## Authentication
A2A endpoints require a **Bearer token** matching an API key in your workspace:
```bash theme={null}
curl -X POST https://your-task-runner/a2a/AGENT_ID \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"message/send","params":{"message":{"role":"user","parts":[{"text":"Hello"}]}},"id":"1"}'
```
## Managing Remote Agents
Navigate to **Settings → A2A Protocol** to:
* **Discover** — Register external agents by URL
* **Toggle** — Enable/disable remote agents
* **Refresh** — Update cached Agent Cards
* **Delete** — Remove remote agent registrations
## Database
A2A uses two tables:
* `a2a_remote_agents` — Registered external agents and cached Agent Cards
* `a2a_task_log` — Inbound and outbound A2A interaction history
# AG-UI Protocol
Source: https://docs.crewform.tech/ag-ui-protocol
Real-time SSE streaming for frontend integration — the open standard for agent-to-UI communication
## Overview
CrewForm supports the **AG-UI (Agent-User Interaction) protocol**, enabling real-time streaming of agent execution events to any compatible frontend via Server-Sent Events (SSE).
AG-UI complements MCP (tools) and A2A (agents) — together they form the **three agentic protocols** that CrewForm supports.
## How It Works
When a CrewForm agent executes a task, the task runner emits structured AG-UI events through an SSE endpoint. Any frontend — CrewForm's dashboard, a custom app, or a CopilotKit integration — can subscribe and display execution in real-time.
```
Agent Executor → AG-UI Event Bus → SSE Endpoint → Your Frontend
```
### Event Types
| Event | Description |
| ---------------------- | ------------------------------------------ |
| `RUN_STARTED` | Task execution begins |
| `TEXT_MESSAGE_START` | LLM response stream begins |
| `TEXT_MESSAGE_CONTENT` | LLM response token chunk |
| `TEXT_MESSAGE_END` | LLM response stream ends |
| `TOOL_CALL_START` | Tool execution begins (includes tool name) |
| `TOOL_CALL_ARGS` | Tool call arguments |
| `TOOL_CALL_END` | Tool execution completes (includes result) |
| `RUN_FINISHED` | Task completes successfully |
| `RUN_ERROR` | Task fails with error message |
| `INTERACTION_REQUEST` | Agent pauses and requests user input |
| `INTERACTION_RESPONSE` | User submitted their response |
| `INTERACTION_TIMEOUT` | Interaction timed out without response |
## Rich Interactions
AG-UI supports **bidirectional communication** — agents can pause execution, present choices to the user, and resume based on user input.
### Interaction Types
| Type | When to use | User sees |
| -------------- | ------------------------------------------- | --------------------------------------- |
| `approval` | Agent needs permission before proceeding | Approve / Reject buttons |
| `confirm_data` | Agent wants the user to verify or edit data | Data table with Confirm / Edit / Reject |
| `choice` | Agent needs the user to pick from options | Radio button list with Select |
### How It Works
```
Agent executes → INTERACTION_REQUEST → Agent pauses
↓
User sees modal, makes decision
↓
POST /respond → INTERACTION_RESPONSE → Agent resumes
```
### INTERACTION\_REQUEST Event
When an agent requests input, the SSE stream emits:
```json theme={null}
{
"type": "INTERACTION_REQUEST",
"timestamp": 1711000010,
"threadId": "task-uuid",
"interactionId": "uuid",
"interactionType": "approval",
"title": "Deploy to production?",
"description": "The agent wants to deploy version 2.4.1 to production.",
"timeoutMs": 300000
}
```
For `confirm_data`, includes a `data` object. For `choice`, includes a `choices` array.
### Submitting a Response
```
POST /ag-ui/:agentId/respond
```
**Body:**
```json theme={null}
{
"threadId": "task-uuid",
"interactionId": "uuid",
"approved": true
}
```
For `confirm_data`, include `data` with modified values. For `choice`, include `selectedOptionId`.
### React Hook Usage
The `useAgentStream` hook handles interactions automatically:
```typescript theme={null}
const { status, textContent, pendingInteraction, respond } = useAgentStream(
'https://your-task-runner-url',
agentId,
taskId,
apiKey,
true
)
// When an interaction is pending, show the modal
if (pendingInteraction) {
return (
)
}
```
### Timeout Behavior
* Default timeout: **5 minutes** per interaction
* When the timeout expires, the agent emits `INTERACTION_TIMEOUT` and the task fails
* The task status transitions: `running` → `waiting_for_input` → `failed`
* Timeout duration is included in the `INTERACTION_REQUEST` event
## Authentication
AG-UI uses the same Bearer token auth as A2A — provide an API key from your workspace's `api_keys` table (provider: `ag-ui` or `a2a`).
## Important Notes
* The SSE stream is **real-time only** — connect before or during task execution
* Events stream for the duration of task execution and close on completion
* The `threadId` maps to a CrewForm task ID
* Works with any AG-UI-compatible client, including CopilotKit
* Rich interactions require a connected SSE client to display the modal — if no client is connected, the interaction will time out
### Request
```
POST /ag-ui/:agentId/sse
```
**Headers:**
```
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
```
**Body** (RunAgentInput):
```json theme={null}
{
"threadId": "task-uuid",
"runId": "task-uuid"
}
```
### Response
The endpoint returns `text/event-stream` with AG-UI events:
```
data: {"type":"RUN_STARTED","timestamp":1711000000,"threadId":"abc","runId":"abc"}
data: {"type":"TEXT_MESSAGE_START","timestamp":1711000001,"messageId":"msg_1","role":"assistant"}
data: {"type":"TEXT_MESSAGE_CONTENT","timestamp":1711000002,"messageId":"msg_1","delta":"Here is "}
data: {"type":"TEXT_MESSAGE_CONTENT","timestamp":1711000003,"messageId":"msg_1","delta":"the result..."}
data: {"type":"TEXT_MESSAGE_END","timestamp":1711000004,"messageId":"msg_1"}
data: {"type":"RUN_FINISHED","timestamp":1711000005,"threadId":"abc","runId":"abc","result":"Here is the result..."}
```
## Quick Test
### Health Check
```bash theme={null}
curl http://localhost:3001/ag-ui/health
# → {"status":"ok","protocol":"ag-ui","version":"1.1"}
```
### Stream Events
```bash theme={null}
# In terminal 1: Connect to SSE stream
curl -N -X POST http://localhost:3001/ag-ui/AGENT_ID/sse \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"threadId":"TASK_ID","runId":"TASK_ID"}'
# In terminal 2: Trigger the task via API or dashboard
```
## React Hook
CrewForm includes a `useAgentStream` React hook for consuming AG-UI events:
```typescript theme={null}
import { useAgentStream } from '@/hooks/useAgentStream'
function TaskStreamView({ taskId, agentId, apiKey }) {
const { status, textContent, toolCalls, error } = useAgentStream(
'https://your-task-runner-url',
agentId,
taskId,
apiKey,
true // enabled
)
return (
Status: {status}
{textContent}
{toolCalls.map(tc => (
🔧 {tc.name}: {tc.status === 'done' ? tc.result : 'running...'}
))}
)
}
```
### Hook Return Values
| Field | Type | Description |
| -------------------- | ----------------------------------------------------------------- | ------------------------------------------ |
| `status` | `'idle' \| 'connecting' \| 'streaming' \| 'completed' \| 'error'` | Connection state |
| `textContent` | `string` | Accumulated LLM response text |
| `toolCalls` | `AgUiToolCall[]` | Tool calls with name, args, result, status |
| `pendingInteraction` | `AgUiInteractionRequest \| null` | Current interaction awaiting user response |
| `events` | `AgUiEvent[]` | All raw AG-UI events received |
| `error` | `string \| null` | Error message if status is `'error'` |
| `respond` | `(response) => Promise` | Submit a response to a pending interaction |
# Agents
Source: https://docs.crewform.tech/agents
# Agents Guide
Agents are the core building blocks of CrewForm. Each agent is an AI worker configured with a specific model, system prompt, and capabilities.
## Creating an Agent
Navigate to **Agents → New Agent** or use the `+` button.
### Required Fields
| Field | Description |
| ----------------- | ------------------------------------------------------------ |
| **Name** | Human-readable identifier (e.g., "Code Reviewer") |
| **Model** | LLM model to use (see [Supported Models](#supported-models)) |
| **System Prompt** | Instructions that define the agent's behavior |
### Optional Fields
| Field | Description |
| --------------- | ------------------------------------------------------ |
| **Description** | What the agent does (shown in marketplace) |
| **Temperature** | Creativity level (0.0 = deterministic, 1.0 = creative) |
| **Max Tokens** | Maximum response length |
| **Tags** | Categorization for search and marketplace |
## Supported Models
CrewForm supports three LLM providers. You must add your API key in **Settings → API Keys** before using a provider.
### Anthropic (Claude)
| Model | Best For |
| --------------------------- | -------------------------------------- |
| `claude-sonnet-4-20250514` | General-purpose, balanced cost/quality |
| `claude-3-5-haiku-20241022` | Fast, cost-effective tasks |
| `claude-3-opus-20240229` | Complex reasoning, analysis |
### Google (Gemini)
| Model | Best For |
| ------------------ | --------------------------- |
| `gemini-2.0-flash` | Fast, multimodal tasks |
| `gemini-1.5-pro` | Long-context, complex tasks |
### OpenAI (GPT)
| Model | Best For |
| --------------- | ------------------------- |
| `gpt-4o` | General-purpose, fast |
| `gpt-4-turbo` | Complex reasoning |
| `gpt-3.5-turbo` | Simple, high-volume tasks |
## Writing System Prompts
The system prompt defines your agent's personality, expertise, and output format. Tips:
### Be Specific
```
❌ "You are a helpful assistant."
✅ "You are a senior code reviewer specializing in TypeScript and React.
You review code for bugs, performance issues, and best practices.
Output your review as a numbered list with severity (HIGH/MEDIUM/LOW)."
```
### Define Output Format
```
You must respond in the following JSON format:
{
"summary": "one-line summary",
"findings": [{ "severity": "HIGH|MEDIUM|LOW", "description": "..." }],
"recommendation": "overall recommendation"
}
```
### Set Boundaries
```
You ONLY review code. If asked to write new code, respond with:
"I'm configured as a reviewer. Please create a separate coding agent."
```
## Agent Lifecycle
```
Created → Idle → Running (task assigned) → Idle
↓
Failed (error)
```
* **Idle**: Ready to accept tasks
* **Running**: Actively processing a task
* **Failed**: Task errored — check the task detail for the error message
## Output Routes
By default, when an agent completes a task, the result is broadcast to **all** active output routes (HTTP webhooks, Slack, Discord, Telegram, Teams, Asana, Trello) in your workspace. See the [Output Routes guide](./output-routes.md) for how to configure destinations.
You can restrict an agent to deliver results to specific channels only:
1. Open the agent in **Agents → \[Agent Name] → Settings**
2. Scroll to **Output Routes**
3. Select one or more channels from the dropdown — or leave blank to send to all
> **Leave blank (default)** = broadcast to all active routes. Select specific channels to narrow delivery.
This is useful when you have multiple output routes (e.g., a `#dev-alerts` Slack channel and a Telegram group) and only want certain agents to send to specific ones.
### How it works
Under the hood, the agent stores a list of route UUIDs in `output_route_ids`:
| Value | Behaviour |
| ------------------ | -------------------------------------- |
| `null` (default) | Dispatch to all active output routes |
| `[]` (empty array) | Dispatch to no routes |
| `[uuid, ...]` | Dispatch to only those specific routes |
## Voice Profiles
Voice profiles let you control how an agent communicates — its tone, style, and formatting preferences. When a voice profile is configured, it's injected into the system prompt as a `## Voice & Tone` section before each execution.
### Configuring a Voice Profile
1. Open an agent → click the **Voice Profile** tab
2. Select a **Tone Preset** — Formal, Casual, Technical, Creative, Empathetic, or Custom
3. Add **Custom Voice Instructions** — e.g. *"Always refer to customers as 'members'. Use active voice. Avoid jargon."*
4. Add **Output Format Hints** (optional) — e.g. *"Use numbered lists for steps. Keep responses under 200 words."*
5. Click **Save Voice Profile**
### Tone Presets
| Preset | Style |
| -------------- | --------------------------------------- |
| **Formal** | Professional, structured, precise |
| **Casual** | Friendly, conversational, approachable |
| **Technical** | Detailed, accurate, documentation-style |
| **Creative** | Expressive, engaging, vivid language |
| **Empathetic** | Warm, supportive, understanding |
| **Custom** | Define your own tone |
### Brand Voice Templates
You can save a voice profile as a reusable **Brand Voice Template** that other agents can share:
1. Configure the tone, instructions, and format hints
2. Click **Save as Template** → give it a name (e.g. "Acme Brand Voice")
3. On any other agent, select the template from the **Brand Voice Template** dropdown
This ensures all customer-facing agents (or all internal agents) use the same voice consistently.
### How It Works at Runtime
When the agent runs a task, the system prompt is constructed as:
```
[Agent's base system prompt]
## Voice & Tone
Tone: formal
Always refer to customers as 'members'. Use active voice. Avoid jargon.
Output format: Use numbered lists for steps. Keep responses under 200 words.
[Task instructions]
```
Voice profiles work across **all execution modes** — standalone tasks, pipeline steps, orchestrator delegations, and collaboration discussions.
## Output Templates
Output templates let you format agent output consistently using `{{variable}}` placeholders. Instead of raw LLM text, results are wrapped in a structured template.
### Configuring an Output Template
1. Open an agent → click the **Output Template** tab
2. Select a **Template Type** — Markdown, JSON, HTML, CSV, or Custom
3. Write the **Template Body** using `{{variable}}` syntax:
```markdown theme={null}
# {{task_title}}
> Generated by **{{agent_name}}** on {{timestamp}}
{{task_result}}
---
*Tokens used: {{tokens_used}} · Model: {{model}}*
```
4. Click **Preview** to see it rendered with sample data
5. Click **Save Template**
### Available Variables
| Variable | Description |
| ----------------- | ----------------------------------- |
| `{{task_title}}` | Title of the task |
| `{{task_result}}` | Full output from the agent |
| `{{agent_name}}` | Name of the agent that ran the task |
| `{{timestamp}}` | ISO 8601 timestamp of completion |
| `{{tokens_used}}` | Total tokens used during execution |
| `{{model}}` | Model ID used for execution |
### How It Works at Runtime
After the LLM generates its response, the output template is applied:
```
LLM raw output → {{task_result}} slot in template → Final formatted result
```
Missing variables are left as `{{variable_name}}` in the output, so templates degrade gracefully.
## MCP Server Publishing
You can expose any agent as an **MCP tool** that Claude Desktop, Cursor, or any MCP-compatible client can call directly.
### Publishing an Agent
1. Open the agent in **Agents → \[Agent Name]**
2. Click the **MCP Publish** button in the header bar
3. The button changes to **MCP Published** (green) — the agent is now exposed as an MCP tool
Click again to unpublish. The agent immediately appears/disappears from the MCP tool list.
### What Happens
When published, the agent becomes callable via the MCP protocol:
| Property | Value |
| --------------- | ----------------------------------------------------------------------------------------------------------------- |
| **Tool Name** | Lowercase agent name, alphanumeric + underscores (e.g., "Code Reviewer" → `code_reviewer`) |
| **Description** | Agent's description field |
| **Input** | A `message` string — the prompt or task to send |
| **Execution** | Full agent execution — same model, system prompt, tools, knowledge base, and voice profile as running from the UI |
### Connecting External Clients
1. Go to **Settings → MCP Servers**
2. Click **Generate MCP API Key** to create a `cf_mcp_` prefixed key
3. Copy the auto-generated config snippet into your client:
```json theme={null}
{
"mcpServers": {
"crewform": {
"url": "https://runner.crewform.tech/mcp",
"headers": {
"Authorization": "Bearer cf_mcp_your_key_here"
}
}
}
}
```
Each API key is scoped to a single workspace — only that workspace's published agents are visible.
See the full [MCP Server Publishing Guide](./mcp-server-publishing.md) for detailed setup instructions.
## Export & Import
### Exporting an Agent
1. Open the agent in **Agents → \[Agent Name]**
2. Click the **Export** button in the header bar
3. A `crewform-agent-{name}.json` file downloads automatically
The export includes: model, system prompt, temperature, max tokens, tags, tools, voice profile, and config. It does **not** include workspace-specific data like API keys, task history, or custom tools.
### Importing an Agent
1. Navigate to **Agents** list page
2. Click the **Import** button in the top-right
3. Select a `.json` file (CrewForm export format)
4. The agent is created with an `(imported)` suffix
Importing a team export file from the Agents page will import the team **and** all its member agents.
### Export Format
Exports use a versioned `crewform-export` format (v1) for forward compatibility:
```json theme={null}
{
"format": "crewform-export",
"version": 1,
"type": "agent",
"exported_at": "2026-04-08T12:00:00.000Z",
"data": {
"name": "Code Reviewer",
"model": "claude-sonnet-4-20250514",
"system_prompt": "You are an expert code reviewer...",
"tools": ["web_search", "knowledge_search"],
...
}
}
```
## Using Agents in Teams
Agents become more powerful when combined into teams. See the [Pipeline Teams Guide](./pipeline-teams.md) for multi-agent workflows.
## API Key Security
All API keys are encrypted with **AES-256-GCM** before storage. Keys are:
* Encrypted client-side before being sent to the database
* Never stored in plaintext
* Only decrypted by the task runner at execution time
* Scoped to your workspace via Row-Level Security
See \[Settings → API Keys] in the app to manage your provider keys.
# Api reference
Source: https://docs.crewform.tech/api-reference
# REST API Reference
CrewForm provides two API layers:
* **[API v2](#api-v2-recommended)** — Edge Functions API with versioned envelopes, rate limiting, and pagination *(recommended)*
* **[API v1 (Legacy)](#api-v1-legacy)** — Direct Supabase PostgREST access *(still supported)*
***
# API v2 (Recommended)
> **Base URL:** `https://.supabase.co/functions/v1`
The v2 API uses CrewForm Edge Functions with structured responses, per-tier rate limiting, and cursor-based pagination.
## Authentication
All requests require one of:
| Method | Header | Use case |
| ----------- | ------------------------------- | ---------------------------------- |
| **API Key** | `X-API-Key: cf_your_key` | Zapier, scripts, third-party tools |
| **JWT** | `Authorization: Bearer ` | Frontend, authenticated clients |
Generate API keys in **Settings → API Keys**.
## Versioning
Set `X-API-Version: 2` to opt into v2 response format. Omitting the header defaults to v1 (raw data, no envelope).
```bash theme={null}
curl -H "X-API-Key: cf_..." \
-H "X-API-Version: 2" \
https://your-project.supabase.co/functions/v1/api-agents
```
## Response Format
**v2 Success:**
```json theme={null}
{
"data": { ... },
"meta": {
"api_version": 2,
"request_id": "req_abc123def456",
"timestamp": "2026-03-13T10:00:00.000Z"
}
}
```
**v2 List (paginated):**
```json theme={null}
{
"data": {
"items": [ ... ],
"next_cursor": "2026-03-12T08:00:00.000Z",
"has_more": true
},
"meta": { ... }
}
```
**v2 Error:**
```json theme={null}
{
"error": {
"code": "not_found",
"message": "Agent not found"
},
"meta": { ... }
}
```
## Rate Limits
Enforced per workspace per minute:
| Plan | Requests/min |
| ---------- | ------------ |
| Free | 30 |
| Pro | 120 |
| Team | 300 |
| Enterprise | 600 |
Every response includes:
```
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1710324360
```
Exceeding the limit returns `429 Too Many Requests` with a `Retry-After` header.
## Pagination
List endpoints support cursor-based pagination:
| Param | Type | Default | Description |
| -------- | ------ | ------- | ---------------------------------------------- |
| `limit` | int | 50 | Items per page |
| `cursor` | string | — | Cursor from `next_cursor` of previous response |
```bash theme={null}
# First page
curl -H "X-API-Key: cf_..." -H "X-API-Version: 2" \
"https://.../functions/v1/api-agents?limit=10"
# Next page
curl -H "X-API-Key: cf_..." -H "X-API-Version: 2" \
"https://.../functions/v1/api-agents?limit=10&cursor=2026-03-12T08:00:00.000Z"
```
***
## Endpoints
### Agents — `/functions/v1/api-agents`
| Method | Params | Description |
| -------- | ------------------- | ---------------- |
| `GET` | — | List all agents |
| `GET` | `?id=` | Get single agent |
| `POST` | body | Create agent |
| `PATCH` | `?id=` + body | Update agent |
| `DELETE` | `?id=` | Delete agent |
**Create body:**
```json theme={null}
{
"name": "Code Reviewer",
"model": "claude-sonnet-4-20250514",
"description": "Reviews code for bugs and best practices",
"system_prompt": "You are a senior code reviewer...",
"temperature": 0.3,
"tools": [],
"status": "idle"
}
```
### Tasks — `/functions/v1/api-tasks`
| Method | Params | Description |
| -------- | ------------------- | ---------------------------------------------------- |
| `GET` | — | List all tasks |
| `GET` | `?status=running` | Filter by status |
| `GET` | `?id=` | Get single task |
| `POST` | body | Create task (auto-dispatches if agent/team assigned) |
| `PATCH` | `?id=` + body | Update task |
| `DELETE` | `?id=` | Delete task |
**Create body:**
```json theme={null}
{
"title": "Review PR #42",
"description": "Review the authentication changes",
"priority": "high",
"assigned_agent_id": "",
"metadata": {}
}
```
**Task statuses:** `pending`, `dispatched`, `running`, `waiting_for_input`, `completed`, `failed`, `cancelled`
**Task priorities:** `low`, `medium`, `high`, `urgent`
### Teams — `/functions/v1/api-teams`
| Method | Params | Description |
| -------- | ------------------- | --------------------------------- |
| `GET` | — | List all teams (includes members) |
| `GET` | `?id=` | Get single team |
| `POST` | body | Create team |
| `PATCH` | `?id=` + body | Update team |
| `DELETE` | `?id=` | Delete team |
**Create body:**
```json theme={null}
{
"name": "Content Pipeline",
"description": "Research → Write → Edit",
"mode": "pipeline",
"config": {
"steps": [
{
"agent_id": "",
"step_name": "Research",
"instructions": "Research the topic thoroughly",
"expected_output": "Detailed research notes",
"on_failure": "retry",
"max_retries": 2
}
],
"auto_handoff": true
}
}
```
**Team modes:** `pipeline`, `orchestrator`, `collaboration`
### Team Runs — `/functions/v1/api-runs`
| Method | Params | Description |
| ------ | ----------------- | ---------------------------------- |
| `GET` | — | List all runs |
| `GET` | `?team_id=` | Filter by team |
| `GET` | `?id=` | Get single run (includes messages) |
| `POST` | body | Start a new team run |
**Create body:**
```json theme={null}
{
"team_id": "",
"input_task": "Research the latest trends in AI agent frameworks"
}
```
### Webhook Hooks — `/functions/v1/api-hooks`
| Method | Params | Description |
| -------- | ------------ | --------------------------------- |
| `GET` | — | List active webhook subscriptions |
| `POST` | body | Subscribe (Zapier REST Hook) |
| `DELETE` | `?id=` | Unsubscribe |
**Subscribe body:**
```json theme={null}
{
"target_url": "https://hooks.zapier.com/...",
"event": "task_completed"
}
```
### Identity — `/functions/v1/api-me`
| Method | Description |
| ------ | ------------------------------------------------------ |
| `GET` | Returns current user, workspace, plan, and API version |
**Response:**
```json theme={null}
{
"id": "",
"email": "user@example.com",
"name": "Vince",
"workspace_id": "",
"workspace_name": "My Workspace",
"plan": "pro",
"api_version": 2
}
```
***
## Error Codes (v2)
| Code | HTTP Status | Description |
| --------------------- | ----------- | ---------------------------------- |
| `bad_request` | 400 | Invalid request body or parameters |
| `unauthorized` | 401 | Missing or invalid authentication |
| `not_found` | 404 | Resource not found |
| `method_not_allowed` | 405 | HTTP method not supported |
| `rate_limit_exceeded` | 429 | Too many requests |
| `internal_error` | 500 | Server error |
***
## Example: cURL
```bash theme={null}
# List agents (v2 with envelope)
curl -s \
-H "X-API-Key: cf_abc123..." \
-H "X-API-Version: 2" \
"https://your-project.supabase.co/functions/v1/api-agents"
# Create a task and auto-dispatch to an agent
curl -s -X POST \
-H "X-API-Key: cf_abc123..." \
-H "Content-Type: application/json" \
-d '{"title":"Review PR","description":"...","assigned_agent_id":""}' \
"https://your-project.supabase.co/functions/v1/api-tasks"
# Start a team run
curl -s -X POST \
-H "X-API-Key: cf_abc123..." \
-H "Content-Type: application/json" \
-d '{"team_id":"","input_task":"Research AI trends"}' \
"https://your-project.supabase.co/functions/v1/api-runs"
```
***
### AG-UI Protocol — Task Runner Endpoints
> **Base URL:** `https:///ag-ui`
These endpoints are served by the task runner (not Edge Functions). They handle real-time agent streaming and user interactions.
#### SSE Stream — `POST /ag-ui/:agentId/sse`
Open an SSE connection to stream AG-UI events for a task execution.
**Headers:**
```
Authorization: Bearer
Content-Type: application/json
```
**Body:**
```json theme={null}
{
"threadId": "",
"runId": "optional-run-id"
}
```
**Response:** Server-Sent Events stream with AG-UI events:
```
data: {"type":"RUN_STARTED","timestamp":1711000000,"threadId":"..."}
data: {"type":"TEXT_MESSAGE_CONTENT","timestamp":1711000001,"content":"Hello..."}
data: {"type":"INTERACTION_REQUEST","interactionId":"uuid","interactionType":"approval",...}
data: {"type":"RUN_FINISHED","timestamp":1711000010}
```
See [AG-UI Protocol](/ag-ui-protocol) for the full event type reference.
#### Submit Interaction Response — `POST /ag-ui/:agentId/respond`
Submit a user response to a pending interaction request. The task must be in `waiting_for_input` status.
**Headers:**
```
Authorization: Bearer
Content-Type: application/json
```
**Body (approval):**
```json theme={null}
{
"threadId": "",
"interactionId": "",
"approved": true
}
```
**Body (data confirmation):**
```json theme={null}
{
"threadId": "",
"interactionId": "",
"approved": true,
"data": { "name": "Corrected Name", "email": "updated@example.com" }
}
```
**Body (choice):**
```json theme={null}
{
"threadId": "",
"interactionId": "",
"selectedOptionId": "option-2"
}
```
**Success Response:**
```json theme={null}
{ "ok": true, "interactionId": "" }
```
**Error Responses:**
| Status | Error |
| ------ | --------------------------------------------- |
| 400 | `threadId and interactionId are required` |
| 401 | `Unauthorized — provide Bearer token` |
| 404 | `Task not found` |
| 409 | `Task is not waiting for input (status: ...)` |
#### Health Check — `GET /ag-ui/health`
```json theme={null}
{ "status": "ok", "protocol": "ag-ui", "version": "1.1" }
```
***
***
# API v1 (Legacy)
> **Base URL:** `https://.supabase.co/rest/v1`
The v1 API provides direct Supabase PostgREST access. It is still supported but we recommend migrating to [API v2](#api-v2-recommended) for rate limiting, structured responses, and pagination.
## Authentication
All API requests require a REST API key in the `Authorization` header:
```bash theme={null}
curl -H "Authorization: Bearer crfm_your_api_key" \
-H "Content-Type: application/json" \
https://your-project.supabase.co/rest/v1/agents
```
### Creating API Keys
1. Go to **Settings → API Keys**
2. Click **Generate Key**
3. Copy the key — it's only shown once
4. The key is hashed (SHA-256) before storage for security
## Endpoints
All endpoints are accessed via the Supabase REST API at:
```
https://.supabase.co/rest/v1/
```
You also need the `apikey` header with your Supabase anon key:
```bash theme={null}
curl -H "Authorization: Bearer crfm_your_api_key" \
-H "apikey: your-supabase-anon-key" \
https://your-project.supabase.co/rest/v1/agents
```
***
## Agents
### List Agents
```http theme={null}
GET /rest/v1/agents?select=*
```
**Response:**
```json theme={null}
[
{
"id": "uuid",
"name": "Code Reviewer",
"description": "Reviews code for bugs and best practices",
"model": "claude-sonnet-4-20250514",
"provider": "anthropic",
"system_prompt": "You are a senior code reviewer...",
"temperature": 0.3,
"max_tokens": 4096,
"tags": ["code", "review"],
"workspace_id": "uuid",
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-01-15T10:00:00Z"
}
]
```
### Create Agent
```http theme={null}
POST /rest/v1/agents
Content-Type: application/json
{
"name": "Code Reviewer",
"model": "claude-sonnet-4-20250514",
"provider": "anthropic",
"system_prompt": "You are a senior code reviewer...",
"workspace_id": "your-workspace-id"
}
```
### Update Agent
```http theme={null}
PATCH /rest/v1/agents?id=eq.{agent_id}
Content-Type: application/json
{
"name": "Updated Name",
"temperature": 0.5
}
```
### Delete Agent
```http theme={null}
DELETE /rest/v1/agents?id=eq.{agent_id}
```
***
## Tasks
### List Tasks
```http theme={null}
GET /rest/v1/tasks?select=*&order=created_at.desc
```
**Query parameters for filtering:**
| Parameter | Example | Description |
| ---------- | ------------ | ------------------------ |
| `status` | `eq.running` | Filter by status |
| `priority` | `eq.high` | Filter by priority |
| `agent_id` | `eq.{uuid}` | Filter by assigned agent |
### Create Task
```http theme={null}
POST /rest/v1/tasks
Content-Type: application/json
{
"title": "Review PR #42",
"description": "Review the authentication changes",
"agent_id": "uuid",
"priority": "high",
"workspace_id": "your-workspace-id"
}
```
**Task statuses:** `pending`, `dispatched`, `running`, `waiting_for_input`, `completed`, `failed`, `cancelled`
**Task priorities:** `low`, `medium`, `high`, `urgent`
### Get Task Detail
```http theme={null}
GET /rest/v1/tasks?id=eq.{task_id}&select=*
```
***
## Teams
### List Teams
```http theme={null}
GET /rest/v1/teams?select=*
```
### Create Team
```http theme={null}
POST /rest/v1/teams
Content-Type: application/json
{
"name": "Content Pipeline",
"description": "Research → Write → Edit",
"mode": "pipeline",
"workspace_id": "your-workspace-id"
}
```
### Team Runs
```http theme={null}
GET /rest/v1/team_runs?team_id=eq.{team_id}&select=*&order=created_at.desc
```
***
## Usage Records
### Query Usage
```http theme={null}
GET /rest/v1/usage_records?select=*&created_at=gte.2026-01-01&order=created_at.desc
```
**Response fields:**
| Field | Type | Description |
| -------------------- | ------- | ----------------------------------- |
| `task_id` | uuid | Associated task |
| `agent_id` | uuid | Agent that ran |
| `provider` | string | LLM provider |
| `model` | string | Model used |
| `prompt_tokens` | integer | Input tokens |
| `completion_tokens` | integer | Output tokens |
| `estimated_cost_usd` | decimal | Estimated cost |
| `billing_model` | string | `per-token` or `subscription-quota` |
***
## Marketplace
### Browse Agents
```http theme={null}
GET /rest/v1/agents?is_marketplace=eq.true&select=*
```
### Install Agent (RPC)
```http theme={null}
POST /rest/v1/rpc/increment_install_count
Content-Type: application/json
{
"agent_row_id": "uuid"
}
```
***
## Rate Limits (v1)
The Supabase free tier includes:
* **500 requests/minute** per API key
* **50,000 requests/month** total
For higher limits, upgrade your Supabase plan.
## Error Handling (v1)
All errors follow the standard Supabase/PostgREST format:
```json theme={null}
{
"code": "PGRST301",
"message": "Row not found",
"details": null,
"hint": null
}
```
Common error codes:
| HTTP Status | Meaning |
| ----------- | -------------------------------- |
| `401` | Missing or invalid API key |
| `403` | Row-Level Security denied access |
| `404` | Resource not found |
| `409` | Conflict (duplicate key) |
| `422` | Validation error |
# Changelog
Source: https://docs.crewform.tech/changelog
All notable changes to CrewForm.
# Changelog
All notable changes to CrewForm will be documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## \[1.9.3] — 2026-05-14
### Added
* **CrewForm CLI (`npx crewform`)** — Standalone command-line tool for running AI agents locally without the web platform:
* **12 Commands** — `run`, `chat`, `init`, `validate`, `tools`, `login`, `logout`, `whoami`, `agents`, `teams`, `pull`, `push`
* **Local Agent Execution** — Run agents from JSON config files with streaming output, Ollama auto-detection, and 16 LLM provider support
* **Pipeline Teams** — Multi-agent pipeline execution with sequential steps, fan-out (parallel branches), merge agents, and configurable failure handling
* **MCP Client Integration** — Connect to MCP servers via `stdio`, `sse`, or `streamable-http` transports (`--mcp` flag)
* **Interactive Chat** — REPL with conversation history, token/cost tracking, and `/clear`, `/history`, `/stats`, `/exit` commands
* **Platform API Mode** — `crewform login` to authenticate, browse workspace agents/teams, `pull` configs locally, and `push` tasks remotely
* **Config Compatibility** — Accepts inline JSON and full `crewform-export` v1 format from the web app
* **Built-in Tools** — `web_search`, `http_request`, `code_interpreter`, `read_file`, `grammar_check`
* **Zero-Config Start** — `crewform init` scaffolds agent or team configs with Ollama model auto-detection
* **CI/CD Friendly** — `--json`, `--quiet`, stdin/stdout piping, and `CREWFORM_API_KEY` env var support
### Documentation
* New [CLI Tool](/cli) guide added to docs
## \[1.9.2] — 2026-05-08
### Added
* **Google Workspace Gateway** — OAuth 2.0 integration with 4 output destinations: Google Sheets (row append), Gmail (send from your account), Google Docs (auto-create documents), Google Calendar (create review events)
* **Notion Output Route** — Create pages in a Notion database with task results
* **GitHub Issues Output Route** — Create issues with labels and assignees
* **Email (Resend) Output Route** — Managed email delivery with HTML templates
* **SMTP Email Output Route** — Self-hosted email via nodemailer
* **Linear Output Route** — Create issues via GraphQL with team label resolution
* **Serverless Cron Evaluation** — Edge Function + pg\_cron replaces always-on task runner for trigger scheduling (runs every 30 min)
* **Canvas Logic Nodes** — Conditional (If-Else) and HTTP Request nodes with branching edges
* **Human-Readable Cron Labels** — Friendly labels like "Every weekday at 9:00 AM" across all UIs
* **Stale Model Validation** — Warning badge on deprecated model IDs
* **Docker Research Crew** — Compose edition for research workflows
### Fixed
* Dependency vulnerabilities, canvas logic connections, bypass edge suppression, ESLint compliance
### Documentation
* Output Routes docs updated with 9 new destination types
* Total output destinations: **16** (HTTP, Slack, Discord, Telegram, Teams, Asana, Trello, Notion, GitHub, Email, SMTP, Linear, Google Sheets, Gmail, Google Docs, Google Calendar)
## \[1.9.1] — 2026-04-23
### Added
* **7-Day Team Trial** — Every new signup gets full Team-tier access for 7 days with dashboard trial banner
* **Coolify Deployment Guide** — Step-by-step docs for Coolify v4 deployment
* **Cloudflare Turnstile** — Bot protection on login and signup forms
### Fixed
* Trial feature gating with `useEELicense` hook fallback
* Auth callback PKCE timeout handling
## \[1.9.0] — 2026-04-22
### Added
* **Workflow Templates** — Reusable workflow blueprints that bundle agents, teams, and triggers into single installable packages with `{{variable}}` placeholders
* **Template Marketplace** — Browse, filter, and install published templates by category from the Marketplace → Templates tab
* **One-Click Install** — Fill in variables and CrewForm auto-creates all agents, team config, and pipeline steps
* **Create Template Wizard** — 4-step wizard (Select → Variables → Metadata → Publish) from the Marketplace header or Agent Detail page
* **Variable Auto-Detection** — Wizard scans agent prompts for `{{variable}}` patterns and generates variable definitions
* **5 Starter Templates** — Weekly Sports Coach, Content Research Pipeline, Daily News Digest, Code Review Assistant, Weekly Report Generator
* **Template Triggers** — Templates can include CRON schedules or webhook triggers
### Documentation
* New **Workflow Templates** guide added to docs
## \[1.8.2] — 2026-04-11
### Added
* **AG-UI Multi-Step Wizards** — Agents can orchestrate complex, stateful, branching user interactions with 5 input types (approval, confirm\_data, choice, text\_input, form), conditional branching, and cancellation support
* **Marketplace: Creator Analytics** — Comprehensive usage dashboard for template authors: install trend charts (30-day), rating distribution, per-agent performance table, and recent reviews feed
* **Navigation: Settings Sub-Navigation** — 14 settings tabs migrated to collapsible sidebar groups with URL-based routing (`/settings/:tab`)
* **Navigation: Admin Panel Sub-Navigation** — 8 admin tabs migrated to collapsible sidebar group with URL-based routing (`/admin/:tab`)
### Changed
* Settings and Admin pages now use sidebar sub-navigation instead of horizontal tab bars
* TopBar shows per-section titles for all Settings and Admin sub-pages
## \[1.8.1] — 2026-04-10
### Added
* **Canvas: Copy/Paste Nodes** — `Ctrl+C` / `Ctrl+V` to duplicate agent nodes with auto-connection
* **Canvas: Sticky Notes** — Right-click annotations with 5 color presets and persistence
* **Canvas: Node I/O Inspector** — Click any agent node to inspect input/output data
* **Canvas: Autosave Infrastructure** — Draft config support for Save vs. Publish workflow
### Fixed
* Canvas node blur, copy/paste reliability, sticky note persistence across navigation
* Orchestrator final answer aggregation and webhook output consistency
## \[1.8.0] — 2026-04-08
### Added
* **Embeddable Chat Widget** — Drop-in `
```
Place this snippet just before the closing `