Quick Start Guide

Get started with Agent Orcha in minutes using Docker (recommended). Follow these steps to set up your first multi-agent system.

Agent Orcha Studio

Agent Orcha includes a built-in web dashboard accessible at http://localhost:3000 when the server is running. The Studio provides a visual interface for managing and testing your entire instance. When AUTH_PASSWORD is set, the Studio will prompt for the password before granting access.

Studio Tabs

Tab Description
Agents Browse all agents, invoke with custom input, stream responses, manage conversation sessions
Knowledge Browse and search knowledge stores, view entities and graph structure for stores with direct mapping
MCP Browse MCP servers, view available tools per server, call tools directly
Workflows Browse and execute workflows (step-based and ReAct), stream execution progress, respond to Human-in-the-Loop prompts
Skills Browse and inspect available skills attached to agents
Monitor View LLM call logs with context size, token estimates, and duration metrics
IDE Full in-browser file editor with file tree, syntax highlighting (YAML, JSON, JS), hot-reload on save

Docker Reference

Docker is the recommended way to run Agent Orcha. The ddalcu/agent-orcha image includes everything you need — no Node.js installation required.

Initialize a Project via Docker

Bash
docker run -v ./my-agent-orcha-project:/data ddalcu/agent-orcha init

Start the Server via Docker

Bash
docker run -p 3000:3000 -e AUTH_PASSWORD=mypass -v ./my-agent-orcha-project:/data ddalcu/agent-orcha start

Docker Compose

For a more manageable setup, use a docker-compose.yaml file:

YAML
services:
  agent-orcha:
    image: ddalcu/agent-orcha
    ports:
      - "3000:3000"
    volumes:
      - ./my-agent-orcha-project:/data
    environment:
      AUTH_PASSWORD: mypass

Environment Variables

Variable Description Default
WORKSPACE Base directory for the project inside the container /data
PORT Port for the server to listen on 3000
AUTH_PASSWORD When set, all API routes and the Studio UI require this password to access. When unset, no authentication is required. unset (no auth)
CORS_ORIGIN Controls cross-origin request policy. When unset, only same-origin requests are allowed. Set to * to allow all origins, or a specific URL (e.g. https://your-frontend.com) to allow that origin. unset (same-origin only)
BROWSER_SANDBOX When true, starts Chromium + Xvfb + VNC inside the container for browser sandbox tools. The VNC viewer is accessible through the Studio UI at /vnc. true

CLI Commands (npx alternative)

If you prefer not to use Docker, you can run Agent Orcha directly via npx (requires Node.js 24+).

Command Description Options
npx agent-orcha init [dir] Initialize a new project with example configs dir - Target directory (default: current)
npx agent-orcha start Start the agent orchestrator server Environment variables: PORT, HOST, WORKSPACE
npx agent-orcha help Show help information -

Core Concepts

The diagram below shows how the major components fit together — from input sources through the orchestrator to tool execution.

Agent Orcha Architecture

Agents

Agents are AI-powered units that can use tools and respond to queries. Each agent is defined in a YAML file with its configuration.

Agent Schema

YAML
name: string                    # Unique identifier (required)
description: string             # Human-readable description (required)
version: string                 # Semantic version (default: "1.0.0")

llm: string | object            # Reference to LLM config in llm.json
  # Simple: llm: default
  # With override: llm: { name: default, temperature: 0.3 }

prompt:                         # Prompt configuration (required)
  system: string                # System message/instructions
  inputVariables: [string]      # Variables to interpolate

tools:                          # Tools available to agent (optional)
  - mcp:<server-name>           # MCP server tools
  - knowledge:<store-name>      # Knowledge store search
  - function:<function-name>    # Custom functions
  - builtin:<tool-name>         # Built-in tools (e.g., ask_user)
  - sandbox:<tool-name>         # Sandbox tools (exec, shell, browser, web)

skills:                         # Skills to inject into system prompt (optional)
  - skill-name                  # Array of skill names
  # Or: skills: { mode: all }   # Attach all available skills

memory: boolean | object        # Persistent memory across sessions (optional)
  # Simple: memory: true
  # With options: memory: { enabled: true, maxLines: 100 }

output:                         # Output formatting (optional)
  format: text | structured
  schema:                       # Required when format is "structured"
    type: object
    properties: { ... }
    required: [string]

triggers:                       # Automatic execution triggers (optional)
  - type: cron
    schedule: "0 9 * * *"       # Cron expression
    input: { key: value }       # Input for the agent
  - type: webhook
    path: /api/triggers/webhooks/my-hook
    input: { key: value }       # Base input (merged with request body)

integrations:                   # External connectors (optional)
  - type: collabnook            # Chat platform connector
    url: https://collabnook.example.com
    channel: general
    botName: orcha-bot
  - type: email                 # Email connector (IMAP + SMTP)
    imap: { host: imap.gmail.com, port: 993, secure: true }
    smtp: { host: smtp.gmail.com, port: 587, secure: false }
    auth: { user: agent@example.com, pass: app-password }

publish: boolean | object       # Standalone chat page (optional)
  # Simple: publish: true
  # With password: publish: { enabled: true, password: "secret" }

Example Agent with Tools

YAML
name: researcher
description: Researches topics using knowledge search and web fetch
version: "1.0.0"

llm:
  name: default
  temperature: 0.5

prompt:
  system: |
    You are a thorough researcher. Use available tools
    to gather information before responding.
  inputVariables:
    - topic

tools:
  - mcp:fetch
  - knowledge:docs
  - function:fibonacci

output:
  format: text

Structured Output

Agents can return validated, structured JSON output by specifying an output.schema. This ensures responses match your schema with automatic validation.

YAML
name: sentiment-structured
description: Sentiment analysis with structured output

llm:
  name: default
  temperature: 0

prompt:
  system: |
    Analyze the sentiment of the provided text.
  inputVariables:
    - text

output:
  format: structured
  schema:
    type: object
    properties:
      sentiment:
        type: string
        enum: [positive, negative, neutral]
      confidence:
        type: number
        minimum: 0
        maximum: 1
      keywords:
        type: array
        items:
          type: string
    required:
      - sentiment
      - confidence

Conversation Memory

Agents support session-based conversation memory for multi-turn dialogues. Pass a sessionId in API calls to maintain context across interactions.

  • In-memory session storage with custom message types
  • Automatic FIFO message limit (default: 50 messages per session)
  • Optional TTL-based session cleanup
  • Session management API endpoints for stats and cleanup
Bash
# First message with sessionId
curl -X POST http://localhost:3000/api/agents/chatbot/invoke \
  -H "Content-Type: application/json" \
  -d '{"input": {"message": "My name is Alice"}, "sessionId": "user-123"}'

# Second message - agent remembers context
curl -X POST http://localhost:3000/api/agents/chatbot/invoke \
  -H "Content-Type: application/json" \
  -d '{"input": {"message": "What is my name?"}, "sessionId": "user-123"}'

Workflows

Workflows orchestrate multiple agents. Agent Orcha supports two workflow types: step-based (sequential/parallel with explicit steps) and ReAct (autonomous, prompt-driven).

Step-Based Workflow Schema

YAML
name: string                    # Unique identifier (required)
description: string             # Human-readable description (required)
version: string                 # Semantic version (default: "1.0.0")
type: steps                     # Optional (steps is default)

input:                          # Input schema (required)
  schema:
    <field_name>:
      type: string | number | boolean | array | object
      required: boolean
      default: any
      description: string

steps:                          # Workflow steps (required)
  - id: string                  # Unique step identifier
    agent: string               # Agent name to execute
    input:                      # Input mapping using templates
      <key>: "{{input.field}}"
      <key>: "{{steps.stepId.output}}"
    condition: string           # Optional conditional execution
    retry:                      # Optional retry configuration
      maxAttempts: number
      delay: number
    output:
      key: string

  # Parallel execution block
  - parallel:
      - id: step-a
        agent: agent-a
        input: { ... }

config:                         # Workflow configuration (optional)
  timeout: number               # Total timeout ms (default: 300000)
  onError: stop | continue | retry

output:                         # Output mapping (required)
  <key>: "{{steps.stepId.output}}"

Template Syntax

Access data within workflows using double curly braces:

Template Description
{{input.fieldName}} Access workflow input field
{{steps.stepId.output}} Access step output
{{steps.stepId.output.nested.path}} Access nested output
{{steps.stepId.metadata.duration}} Access step metadata

ReAct Workflows

ReAct workflows use autonomous agents that discover and call tools/agents based on your prompt, without explicit step definitions.

ReAct Schema

YAML
name: string
type: react                     # Required for ReAct

input:
  schema:
    <field>:
      type: string
      required: true

prompt:
  system: string                # System instructions
  goal: string                  # Goal template (supports {{input.*}})

graph:
  model: string                 # LLM config name from llm.json
  executionMode: react | single-turn  # Default: react
  tools:
    mode: all | include | exclude | none
    sources: [mcp, knowledge, function, builtin]
    include: [string]           # For mode: include
    exclude: [string]           # For mode: exclude
  agents:
    mode: all | include | exclude | none
  maxIterations: number         # Default: 10
  timeout: number               # Default: 300000

output:
  <key>: "{{state.messages[-1].content}}"

Execution Modes

Mode Behavior Best For
single-turn Calls tools once, then returns Research, data gathering, straightforward tasks
react Multiple rounds of tool calls with analysis Complex problems, iterative refinement

Human-in-the-Loop

ReAct workflows support the builtin:ask_user tool. When called, the workflow pauses and waits for user input. In the Studio Workflows tab, an inline input prompt appears automatically — type your response and the workflow resumes. You can also respond via the Monitor tab or the Tasks API (POST /api/tasks/:id/respond).

Functions

Functions are custom JavaScript tools that extend agent capabilities. They're simple to create and require no dependencies.

Function Schema

JavaScript
export default {
  name: 'function-name',
  description: 'What it does',

  parameters: {
    param1: {
      type: 'number',  // string | number | boolean | array | object | enum
      description: 'Parameter description',
      required: true,
      default: 0,
    },
  },

  execute: async ({ param1 }) => {
    // Your logic here
    return `Result: ${param1}`;
  },
};

export const metadata = {
  name: 'function-name',
  version: '1.0.0',
  author: 'Your Name',
  tags: ['category'],
};

Example Function

JavaScript
export default {
  name: 'fibonacci',
  description: 'Returns the nth Fibonacci number (0-based indexing)',

  parameters: {
    n: {
      type: 'number',
      description: 'The index (0-based, max 100)',
    },
  },

  execute: async ({ n }) => {
    if (n < 0 || !Number.isInteger(n)) {
      throw new Error('Index must be a non-negative integer');
    }
    if (n > 100) {
      throw new Error('Index too large (max 100)');
    }

    if (n === 0) return 'Fibonacci(0) = 0';
    if (n === 1) return 'Fibonacci(1) = 1';

    let prev = 0, curr = 1;
    for (let i = 2; i <= n; i++) {
      [prev, curr] = [curr, prev + curr];
    }

    return `Fibonacci(${n}) = ${curr}`;
  },
};

MCP Servers

Model Context Protocol (MCP) servers provide external tools to agents. Configure them in mcp.json.

MCP Configuration

JSON
{
  "version": "1.0.0",
  "servers": {
    "fetch": {
      "transport": "streamable-http",
      "url": "https://remote.mcpservers.org/fetch/mcp",
      "description": "Web fetch capabilities",
      "timeout": 30000,
      "enabled": true
    },
    "filesystem": {
      "transport": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    }
  },
  "globalOptions": {
    "throwOnLoadError": false,
    "prefixToolNameWithServerName": true,
    "defaultToolTimeout": 30000
  }
}

Skills

Skills are prompt augmentation units that expand what an agent knows how to do. Unlike tools or functions, skills are not executable code — they are knowledge and instruction bundles (Markdown files) that get injected into an agent's system prompt at runtime.

Directory Structure

Each skill lives in its own directory under skills/:

Bash
skills/
  orcha-builder/
    SKILL.md
  pii-guard/
    SKILL.md
  sandbox/
    SKILL.md
  web-pilot/
    SKILL.md

SKILL.md Format

A SKILL.md file has optional YAML frontmatter followed by Markdown content:

Markdown
---
name: pii-guard
description: PII and OWASP security filtering rules
---

# PII Guard

## Sensitive Data Categories (NEVER include in responses)

- SSN, tax IDs, government identifiers
- Salary, compensation, financial data
- Home addresses, personal phone numbers
- Dates of birth, ages
- Full email addresses (mask as j***@company.com)

The frontmatter fields:

  • name — Unique skill identifier. If omitted, the directory name is used.
  • description — Human-readable description shown in the UI and API.

Agent Configuration

Attach skills to agents in their YAML definition file:

YAML
# Specific skills by name
name: corporate
description: Friendly corporate assistant
llm: default
prompt:
  system: You are a friendly corporate assistant.
  inputVariables:
    - query
skills:
  - pii-guard

# Or attach all available skills
skills:
  mode: all

How It Works

When an agent with skills is invoked, the skill content is appended to the agent's system prompt before the LLM call. Each skill is wrapped in <skill name="..."> delimiters so the LLM can distinguish between different skill instructions.

Creating Custom Skills

  1. Create a directory under skills/ with your skill name.
  2. Add a SKILL.md file with frontmatter and instructions.
  3. Reference the skill name in your agent's skills array.
  4. Restart the server or use hot-reload to pick up changes.

Community Skills Registry

Community-contributed skills that you can copy into your project:

Name Description Author
orcha-builder Documentation for creating and modifying ORCHA resources Agent Orcha
pii-guard PII and OWASP security filtering rules Agent Orcha
sandbox JavaScript sandbox, shell, web fetch, and browser tools Agent Orcha
web-pilot Browser automation via observe-act loop with element refs Agent Orcha

Want to contribute a skill? Add it to templates/skills/ and submit a pull request to the repository.

Tasks

Tasks provide async execution for agents and workflows. Submit a task, poll its status, stream updates via SSE, or cancel it. Tasks are managed in-memory with automatic cleanup.

Task Lifecycle

Tasks progress through these statuses:

submittedworkingcompleted | failed | canceled

ReAct workflows may also reach input-required when the builtin:ask_user tool is called, pausing until you respond via the API.

Submit a Task

Bash
# Submit an agent task
curl -X POST http://localhost:3000/api/tasks/agent \
  -H "Content-Type: application/json" \
  -d '{
    "agent": "researcher",
    "input": {"topic": "AI trends"},
    "sessionId": "optional-session-id"
  }'

# Submit a workflow task
curl -X POST http://localhost:3000/api/tasks/workflow \
  -H "Content-Type: application/json" \
  -d '{
    "workflow": "research-paper",
    "input": {"topic": "AI trends"}
  }'

Stream Task Status (SSE)

Bash
curl -N http://localhost:3000/api/tasks/TASK_ID/stream

Respond to Input Request

When a ReAct workflow reaches input-required, respond to continue execution:

Bash
curl -X POST http://localhost:3000/api/tasks/TASK_ID/respond \
  -H "Content-Type: application/json" \
  -d '{"response": "Yes, proceed with option A"}'

Sandbox

The sandbox system provides isolated execution environments for agents. It includes tools for JavaScript execution, shell commands, web interaction, and browser automation.

Configuration

Configure sandbox behavior in sandbox.json (optional — defaults to enabled):

JSON
{
  "enabled": true,
  "commandTimeout": 30000,
  "maxOutputChars": 50000,
  "browserCdpUrl": "http://localhost:9222"
}

Sandbox Tools

Tool Description Parameters
sandbox:exec Execute JavaScript code in a sandboxed VM code (string), timeout (number, optional)
sandbox:shell Execute shell commands as a non-root sandbox user command (string), timeout (number, optional)
sandbox:web_fetch Fetch a web page and convert HTML to Markdown url (string), raw (boolean, optional)
sandbox:web_search Search the web via DuckDuckGo query (string), num_results (number, optional)
sandbox:browser_navigate Navigate the browser to a URL and wait for page load url (string)
sandbox:browser_observe Get a text snapshot of the current page (accessibility tree)
sandbox:browser_click Click an element by CSS selector selector (string)
sandbox:browser_type Type text into a focused element selector (string), text (string)
sandbox:browser_screenshot Take a screenshot (returns image to the LLM as a multimodal content part)
sandbox:browser_evaluate Execute JavaScript in the browser page context expression (string)

Browser Sandbox (Docker)

Browser tools require Chromium running inside the Docker container. Set BROWSER_SANDBOX=true (enabled by default in the Docker image) to start Xvfb + Chromium + VNC automatically. The VNC viewer is accessible through the Studio UI at /vnc (protected by AUTH_PASSWORD when set).

Using Sandbox Tools in Agents

YAML
name: code-runner
description: Agent that can execute code and search the web
llm: default

prompt:
  system: |
    You can execute JavaScript code and search the web.
  inputVariables:
    - task

tools:
  - sandbox:exec
  - sandbox:shell
  - sandbox:web_fetch
  - sandbox:web_search
  - sandbox:browser_navigate
  - sandbox:browser_observe
  - sandbox:browser_click
  - sandbox:browser_type
  - sandbox:browser_screenshot
  - sandbox:browser_evaluate

Persistent Memory

Agent Orcha has two memory layers. Conversation memory (session-based, in-memory) tracks multi-turn dialogues. Persistent memory saves facts to disk so agents remember across sessions and server restarts.

Agent Configuration

YAML
name: assistant
description: Agent with persistent memory
llm: default

prompt:
  system: |
    You are a helpful assistant. Save important facts
    about the user to your memory for future sessions.
  inputVariables:
    - message

memory: true        # Enable persistent memory

How It Works

  • When memory: true, the agent gets a save_memory built-in tool
  • Memory is stored as Markdown files in .memory/{agentName}.md
  • On each invocation, prior memory is loaded and injected into the system prompt
  • The agent decides what to remember by calling save_memory

Triggers

Triggers allow agents to run automatically on a schedule (cron) or in response to external events (webhook).

Cron Trigger

YAML
name: daily-reporter
description: Runs every morning at 9am
llm: default

prompt:
  system: Generate a daily summary report.
  inputVariables:
    - task

triggers:
  - type: cron
    schedule: "0 9 * * *"
    input:
      task: "Generate the daily report"

Webhook Trigger

YAML
name: webhook-handler
description: Responds to external webhook events
llm: default

prompt:
  system: Process the incoming webhook payload.
  inputVariables:
    - data

triggers:
  - type: webhook
    path: /api/triggers/webhooks/webhook-handler
    input:
      data: "default context"

Webhook triggers register a POST endpoint at the specified path. The request body is merged with the base input and the agent is invoked immediately.

Integrations

Integrations connect agents to external communication platforms. When configured, agents can receive messages from external sources and respond back through the same channel. Agent Orcha currently supports two integration types: Collabnook (real-time chat) and Email (IMAP/SMTP).

Integrations are added to agents via the integrations field in the agent YAML. Each integration type injects its own input variables and tools into the agent automatically.

Collabnook

Collabnook is a minimalistic anonymous chat with audio and video calls — no sign-up required. The Collabnook integration connects to it via WebSocket. When active, the agent joins a channel and responds to @mentions in real time.

How It Works
  • The agent connects to the Collabnook server via WebSocket and joins the specified channel
  • When a user @mentions the bot name, the agent is invoked with the message
  • Recent channel messages and member lists are automatically injected as input variables (channelContext, channelMembers)
  • The agent's response is posted back to the channel
  • Combined with cron triggers, agents can also proactively monitor and respond to channel activity on a schedule
Schema
Field Type Description
type string "collabnook" (required)
url string Collabnook server URL (required)
channel string Channel to join (required)
botName string Display name for the bot in the channel (required)
password string Server password if authentication is required (optional)
replyDelay number Delay in ms before posting the reply (optional)
Example
YAML
name: channel-bot
description: Bot connected to a chat channel
llm: default

prompt:
  system: |
    You are a channel assistant.
    Use the channel context to respond to messages.
  inputVariables:
    - message
    - channelContext
    - channelMembers

integrations:
  - type: collabnook
    url: https://collabnook.example.com
    channel: general
    botName: orcha-bot
Injected Input Variables
Variable Description
channelContext Recent channel messages formatted as text
channelMembers List of channel members with userId and name

Email

Connect agents to email via IMAP polling (inbound) and SMTP (outbound). The agent polls a mailbox folder for new emails and is automatically invoked when one arrives. The agent's response is sent back to the original sender as a reply. Agents also receive an email_send tool for composing new outbound emails to any address.

How It Works
  • The agent connects to the IMAP server and polls the configured folder at a regular interval
  • New (unseen) emails trigger the agent with the email content as input
  • The agent's response is automatically sent back to the original sender via SMTP
  • The agent also gets an email_send built-in tool for composing new emails to arbitrary recipients
Schema
Field Type Description
type string "email" (required)
imap.host string IMAP server hostname (required)
imap.port number IMAP port (default: 993)
imap.secure boolean Use TLS for IMAP (default: true)
smtp.host string SMTP server hostname (required)
smtp.port number SMTP port (default: 587)
smtp.secure boolean Use TLS for SMTP (default: false)
auth.user string Email account username (optional)
auth.pass string Email account password or app password (optional)
fromName string Display name for outbound emails (optional)
fromAddress string From address override — defaults to auth.user (optional)
pollInterval number Seconds between mailbox checks (default: 60)
folder string IMAP folder to monitor (default: INBOX)
Example
YAML
name: support-agent
description: Handles inbound support emails
llm: default

prompt:
  system: |
    You are a customer support agent.
    Reply helpfully to inbound emails.
    Use the email_send tool if you need to
    contact other departments.
  inputVariables:
    - message

integrations:
  - type: email
    imap:
      host: imap.gmail.com
      port: 993
      secure: true
    smtp:
      host: smtp.gmail.com
      port: 587
      secure: false
    auth:
      user: support@example.com
      pass: app-password
    fromName: "Support Agent"
    pollInterval: 30
    folder: INBOX
Injected Tools
Tool Description Parameters
email_send Compose and send a new email to (string), subject (string), body (string)

Published Agents

Published agents get standalone chat pages accessible at /chat/<agent-name>, independent of the Studio UI. This is useful for sharing agents with end-users who don't need access to the full Studio interface.

Configuration

Add the publish field to any agent YAML file:

YAML
# Simple — publish with no password
name: my-chatbot
description: A helpful assistant
llm: default
prompt:
  system: You are a helpful assistant.
  inputVariables:
    - message
publish: true
YAML
# With password protection
publish:
  enabled: true
  password: "secret123"

How It Works

  • Visit /chat/<agent-name> to open the standalone chat page
  • If password-protected, users must authenticate before chatting
  • The password is per-agent and independent of the global AUTH_PASSWORD
  • The standalone page supports markdown rendering, code highlighting, thinking blocks, tool call visualization, and file attachments
  • Sessions are ephemeral (per browser tab) and use sessionStorage
  • Unpublished agents and non-existent agents return a 404

Knowledge Stores

Agent Orcha Knowledge Architecture

Knowledge stores are one of the most powerful features of Agent Orcha and a key differentiator from other agentic frameworks. They combine semantic vector search, knowledge graphs, and direct SQL querying in a single unified system — all from a simple YAML definition.

Most frameworks stop at basic RAG (embed chunks, search by similarity). Agent Orcha goes further:

  • Vector search — Semantic similarity search powered by SQLite + sqlite-vec. No external vector databases (Chroma, Pinecone, etc.) required.
  • Knowledge graphs — Build entity graphs from structured data via directMapping. Deterministic extraction from columns — no LLM calls, 100% data preservation.
  • Direct SQL querying — For database-backed stores (PostgreSQL, MySQL, SQLite), agents automatically get a readonly SQL tool to query the source data directly. This means agents can do precise filtering, aggregation, joins, and counts that semantic search alone cannot provide.
  • Zero-config persistence — All data is persisted to SQLite. On restart, unchanged stores restore instantly without re-indexing.

Knowledge Store Schema

All knowledge stores share a single unified schema. A store without graph does vector-only search; adding graph.directMapping enables entity extraction and graph traversal.

Schema

YAML
name: string                    # Unique identifier (required)
description: string             # Human-readable description (required)

source:                         # Data source (required)
  type: directory | file | database | web
  # Web-specific options:
  selector: string              # CSS selector for html loader (optional)
  headers: { key: value }       # Custom/auth headers (optional)
  jsonPath: string              # Dot-notation path to extract nested array from JSON (optional)

loader:                         # Document loader (optional)
  type: text | pdf | csv | json | markdown | html
  # Defaults: html for web sources, text for file/directory
  # Not used for database sources (has its own row-to-document logic)

splitter:                       # Text chunking (required)
  type: character | recursive | token | markdown
  chunkSize: number             # Characters per chunk (default: 1000)
  chunkOverlap: number          # Overlap between chunks (default: 200)

embedding: string               # Reference to embedding config in llm.json (default: "default")

graph:                          # Optional - enables entity graph
  directMapping:                # Maps structured data to entities and relationships
    entities:
      - type: string            # Entity type name
        idColumn: string        # Column used as unique ID
        nameColumn: string      # Column used as display name (optional)
        properties: [string]    # Columns to include as entity properties
    relationships:              # Optional
      - type: string            # Relationship type name
        source: string          # Source entity type
        target: string          # Target entity type
        sourceIdColumn: string  # Column linking to source entity
        targetIdColumn: string  # Column linking to target entity

search:                         # Search configuration (optional)
  defaultK: number              # Results per search (default: 4)
  scoreThreshold: number        # Minimum similarity score (0-1)

reindex:                        # Periodic re-indexing (optional)
  schedule: string              # Cron expression (e.g., "0 * * * *" for hourly)

Example: Vector-Only Store

YAML
name: docs
description: Documentation for semantic search

source:
  type: directory
  path: knowledge/sample-data
  pattern: "*.txt"

loader:
  type: text

splitter:
  type: character
  chunkSize: 1000
  chunkOverlap: 200

embedding: default

search:
  defaultK: 4
  scoreThreshold: 0.2

Direct Mapping (Graph)

Add a graph.directMapping section to build a knowledge graph from structured data (database, CSV, or JSON sources). Entities and relationships are mapped deterministically from columns/keys — no LLM calls during extraction, 100% data preservation.

Example: Blog Posts with Authors

YAML
name: blog-posts
description: Blog posts with authors as a knowledge graph

source:
  type: database
  connectionString: postgresql://user:pass@localhost:5432/blog
  query: |
    SELECT p.id, p.title, p.slug, p.html AS content,
           u.name AS author_name, u.email AS author_email
    FROM posts p
    LEFT JOIN users u ON p.author_id = u.id
    WHERE p.status = 'published'
  contentColumn: content
  metadataColumns: [id, title, slug, author_name, author_email]

splitter:
  type: recursive
  chunkSize: 2000
  chunkOverlap: 300

embedding: default

graph:
  directMapping:
    entities:
      - type: Post
        idColumn: id
        nameColumn: title
        properties: [title, slug, content]

      - type: Author
        idColumn: author_email
        nameColumn: author_name
        properties: [author_name, author_email]

    relationships:
      - type: WROTE
        source: Author
        target: Post
        sourceIdColumn: author_email
        targetIdColumn: id

search:
  defaultK: 10

Each entity definition maps a row's columns to a graph node. The idColumn determines uniqueness (duplicate IDs are merged), nameColumn sets the display name, and properties lists which columns to attach as node properties. Relationships connect entities via their ID columns.

Example: Web JSON API with Graph

You can also build knowledge graphs from JSON API endpoints. When a JSON source contains an array of objects, each object is treated as a row with keys mapped to columns — just like database and CSV sources.

YAML
name: team-directory
description: Team members from internal API

source:
  type: web
  url: https://api.internal.com/v1/employees
  jsonPath: data.employees
  headers:
    Authorization: "Bearer ${EMPLOYEE_API_TOKEN}"

loader:
  type: json

splitter:
  type: character
  chunkSize: 500

embedding: default

graph:
  directMapping:
    entities:
      - type: Employee
        idColumn: id
        nameColumn: name
        properties: [name, email, role]
      - type: Department
        idColumn: department
        nameColumn: department
        properties: [department]
    relationships:
      - type: BELONGS_TO
        source: Employee
        target: Department
        sourceIdColumn: id
        targetIdColumn: department

How It Works

  • All stores persist to SQLite via .knowledge-data/{name}.db
  • On startup, source hashes are compared — if unchanged, data is restored from SQLite without re-indexing
  • Stores with graph.directMapping also store entities and relationships in SQLite, with vector embeddings for entity similarity search
  • Agents get additional graph tools (traverse, entity_lookup, graph_schema) when entities exist

Source Types

All knowledge stores support the same source types for loading documents.

Type Description Key Options
directory Load files from a local directory path, pattern (glob), recursive
file Load a single file path
database Query PostgreSQL, MySQL, or SQLite. Agents also get a readonly SQL tool for direct querying. connectionString, query, contentColumn, metadataColumns, batchSize
web Fetch content from a URL (HTML, JSON, text, CSV) url, selector (CSS, html only), headers (auth/custom), jsonPath (dot-notation for nested arrays)

Paths for directory and file sources are relative to the project root.

Loader Types

The loader.type determines how fetched content is parsed. It is optional — defaults to html for web sources and text for file/directory sources. Not used for database sources.

Type Description Graph Support
html Parse HTML with Cheerio, optional CSS selector. Default for web sources. No
text / markdown Raw text as a single document. Default for file/directory sources. No
json Array of objects: each object becomes a row with _rawRow metadata. Other JSON: extracts all string values. Yes (array of objects)
csv One document per row, formatted as "column: value" pairs with _rawRow metadata. Yes
pdf Extract text from PDF files (requires pdf-parse package). File/directory only. No

Search Configuration

All stores use the same unified search pipeline:

  1. Embed the query using the configured embedding model
  2. Run KNN cosine similarity search against chunk vectors in SQLite
  3. If entities exist: also search entity vectors, then expand neighborhoods via graph traversal
  4. Merge all results by score, return top-K
YAML
search:
  defaultK: 4                   # Results per search (default: 4)
  scoreThreshold: 0.2           # Minimum similarity score (optional)

Scheduled Re-indexing

Knowledge stores can be configured to automatically re-index on a cron schedule. The cron checks source hashes and only re-indexes when the underlying data has changed.

YAML
reindex:
  schedule: "0 * * * *"         # Cron expression (e.g., every hour)

Persistence

All data is persisted to SQLite at .knowledge-data/{name}.db. On server restart, source file hashes are compared — if nothing changed, the store is restored instantly from SQLite without re-embedding or re-extracting. To force a full rebuild, use the Re-index button in the Studio or call POST /api/knowledge/:name/index.

Direct SQL Querying

For knowledge stores backed by a database source, agents automatically receive a readonly SQL tool (knowledge_sql_{name}) in addition to the semantic search tool. This lets agents query the source database directly using SQL — enabling precise filtering, aggregation, joins, and counts that vector search alone cannot provide.

How It Works

  • The SQL tool is auto-generated from the knowledge store's source.query — the agent sees the available tables and columns
  • Only SELECT queries are allowed — INSERT, UPDATE, DELETE, and DDL statements are blocked
  • Results are automatically limited (default 25 rows, max 100) to prevent runaway queries
  • Supported databases: PostgreSQL, MySQL, and SQLite

When to Use SQL vs Semantic Search

Use Case Best Tool
"Find documents about customer satisfaction" Semantic search — meaning-based matching
"How many orders were placed last month?" SQL — precise aggregation
"Show me all calls handled by agent John" SQL — exact filtering
"What topics come up most in support tickets?" Both — SQL for counts, semantic for themes

The agent decides which tool to use based on the question. Having both available means agents can combine the precision of SQL with the flexibility of semantic search in a single conversation.

Example: SQLite Knowledge Store

YAML
name: music-store
description: Music catalog with artists, albums, and tracks

source:
  type: database
  connectionString: sqlite://knowledge/music-store/musicstore.sqlite
  query: |
    SELECT t.TrackId, t.Name AS track, a.Title AS album,
           ar.Name AS artist, g.Name AS genre, t.UnitPrice
    FROM tracks t
    JOIN albums a ON t.AlbumId = a.AlbumId
    JOIN artists ar ON a.ArtistId = ar.ArtistId
    JOIN genres g ON t.GenreId = g.GenreId
  contentColumn: track
  metadataColumns: [TrackId, album, artist, genre, UnitPrice]

splitter:
  type: character
  chunkSize: 500

embedding: default

graph:
  directMapping:
    entities:
      - type: Artist
        idColumn: artist
        nameColumn: artist
        properties: [artist]
      - type: Genre
        idColumn: genre
        nameColumn: genre
        properties: [genre]
    relationships:
      - type: PLAYS
        source: Artist
        target: Genre
        sourceIdColumn: artist
        targetIdColumn: genre

With this configuration, an agent can semantically search for "upbeat jazz tracks", run SELECT artist, COUNT(*) FROM tracks GROUP BY artist ORDER BY COUNT(*) DESC LIMIT 5 to find the most prolific artists, and traverse the knowledge graph to discover genre relationships — all from the same knowledge store.

API Reference

Complete REST API documentation for interacting with agents, workflows, knowledge stores, functions, MCP servers, files, and LLMs.

Health Check

HTTP
GET /health

Response:
{
  "status": "ok",
  "timestamp": "2026-01-21T12:00:00.000Z"
}

Authentication API

When the AUTH_PASSWORD environment variable is set, all /api/* routes require a valid session cookie. The /health endpoint is always public. When AUTH_PASSWORD is not set, authentication is disabled and all routes are open.

Method Endpoint Description
GET /api/auth/check Check authentication status (never returns 401)
POST /api/auth/login Authenticate with password, returns session cookie
POST /api/auth/logout Invalidate session and clear cookie

Login

HTTP
POST /api/auth/login
Content-Type: application/json

Request:
{
  "password": "your-secret-password"
}

Response (success — sets HttpOnly session cookie):
{
  "authenticated": true
}

Response (wrong password):
HTTP 401
{
  "error": "Invalid password"
}

Check Auth Status

HTTP
GET /api/auth/check

Response (auth enabled, not logged in):
{
  "authenticated": false,
  "required": true
}

Response (auth disabled):
{
  "authenticated": true,
  "required": false
}

Agents API

Method Endpoint Description
GET /api/agents List all agents
GET /api/agents/:name Get agent details
POST /api/agents/:name/invoke Run agent
POST /api/agents/:name/stream Stream agent response (SSE)
GET /api/agents/sessions/stats Get session statistics
GET /api/agents/sessions/:sessionId Get session details
DELETE /api/agents/sessions/:sessionId Clear session messages

Invoke Agent

Bash
curl -X POST http://localhost:3000/api/agents/researcher/invoke \
  -H "Content-Type: application/json" \
  -d '{
    "input": {
      "topic": "your topic"
    },
    "sessionId": "optional-session-id"
  }'

Response

JSON
{
  "output": "Agent response text",
  "metadata": {
    "tokensUsed": 150,
    "toolCalls": [],
    "duration": 1234,
    "sessionId": "optional-session-id",
    "messagesInSession": 4,
    "structuredOutputValid": true
  }
}

Chat API (Published Agents)

These endpoints power the standalone chat pages for published agents. They are exempt from global AUTH_PASSWORD authentication and handle their own per-agent auth.

Method Endpoint Description
GET /chat/:agentName Serve standalone chat page (HTML)
GET /api/chat/:agentName/config Get published agent config (name, description, requiresPassword)
POST /api/chat/:agentName/auth Authenticate with agent password, returns token
POST /api/chat/:agentName/stream Stream agent response (SSE), requires X-Chat-Token header if password-protected

Authenticate

Bash
curl -X POST http://localhost:3000/api/chat/my-agent/auth \
  -H "Content-Type: application/json" \
  -d '{ "password": "secret123" }'

# Response: { "token": "abc123..." }

Stream (with token)

Bash
curl -N -X POST http://localhost:3000/api/chat/my-agent/stream \
  -H "Content-Type: application/json" \
  -H "X-Chat-Token: abc123..." \
  -d '{
    "input": { "message": "Hello!" },
    "sessionId": "optional-session-id"
  }'

Workflows API

Method Endpoint Description
GET /api/workflows List all workflows
GET /api/workflows/:name Get workflow details
POST /api/workflows/:name/run Execute workflow
POST /api/workflows/:name/stream Stream workflow execution (SSE)

Run Workflow

Bash
curl -X POST http://localhost:3000/api/workflows/research-paper/run \
  -H "Content-Type: application/json" \
  -d '{
    "input": {
      "topic": "research topic",
      "style": "professional"
    }
  }'

Knowledge API

Method Endpoint Description
GET /api/knowledge List all knowledge stores
GET /api/knowledge/:name Get knowledge store config
POST /api/knowledge/:name/search Search knowledge store
POST /api/knowledge/:name/refresh Reload documents
POST /api/knowledge/:name/add Add documents
GET /api/knowledge/:name/entities Get graph entities
GET /api/knowledge/:name/edges Get graph edges

Search Knowledge Store

Bash

Add Documents to Knowledge Store

Dynamically add documents to a knowledge store without restarting the server. If the store isn't initialized, it will be created automatically.

Bash
curl -X POST http://localhost:3000/api/knowledge/docs/add \
  -H "Content-Type: application/json" \
  -d '{
    "documents": [
      {
        "content": "Your document content here",
        "metadata": {
          "source": "api",
          "category": "example",
          "timestamp": "2026-01-29"
        }
      }
    ]
  }'

Response:

JSON
{
  "success": true,
  "added": 1
}

Use cases:

  • Building knowledge stores incrementally from external sources
  • Real-time ingestion of generated content
  • Integrating with webhooks or external APIs
  • Dynamic document addition without server restarts

Functions API

Method Endpoint Description
GET /api/functions List all functions
GET /api/functions/:name Get function details and schema
POST /api/functions/:name/call Call a function

Skills API

Method Endpoint Description
GET /api/skills List all skills (name, description)
GET /api/skills/:name Get skill details (name, description, content)

Tasks API

Method Endpoint Description
GET /api/tasks List all tasks (filter by ?status=, ?kind=, ?target=)
GET /api/tasks/:id Get task status and result
POST /api/tasks/agent Submit an agent task
POST /api/tasks/workflow Submit a workflow task
POST /api/tasks/:id/cancel Cancel a running task
POST /api/tasks/:id/respond Respond to an input-required task (ReAct human-in-the-loop)
GET /api/tasks/:id/stream Stream task status updates (SSE)

MCP API

Method Endpoint Description
GET /api/mcp List all MCP servers
GET /api/mcp/:name Get MCP server config
GET /api/mcp/:name/tools List tools from server
POST /api/mcp/:name/call Call a tool on server

Files API

Method Endpoint Description
GET /api/files/tree Get project directory tree
GET /api/files/read?path=... Read file contents
PUT /api/files/write Write file contents (hot-reload)

LLM API

Method Endpoint Description
GET /api/llm List all LLM configurations
GET /api/llm/:name Get LLM config details
POST /api/llm/:name/chat Chat with LLM
POST /api/llm/:name/stream Stream chat with LLM (SSE)

Examples

Real-world examples to help you get started with common use cases.

Example 1: Corporate Assistant with Knowledge Graph

This example shows an agent using a knowledge store for org chart queries with PII protection.

YAML - agents/corporate.agent.yaml
name: corporate
description: Friendly corporate assistant — answers questions about the org, people, departments
version: "1.0.0"

llm:
  name: default
  temperature: 0.3

prompt:
  system: |
    You are Orcha, a friendly corporate assistant. You help employees find information
    about teams, people, projects, and the organization.
  inputVariables:
    - query

tools:
  - knowledge:org-chart

publish:
  enabled: true

memory:
  enabled: true
  maxLines: 50

output:
  format: text

Example 2: Multi-Step Workflow

Orchestrating multiple agents to complete a complex task.

YAML - workflows/example.workflow.yaml
name: example-workflow
description: A workflow demonstrating multi-agent orchestration
version: "1.0.0"

input:
  schema:
    topic:
      type: string
      required: true
      description: The topic to process

steps:
  - id: get-time
    agent: time
    input:
      timezone: "America/New_York"
    output:
      key: current_time

  - id: search-knowledge
    agent: knowledge
    input:
      query: "{{input.topic}}"
    output:
      key: knowledge_result

  - id: summarize
    agent: example
    input:
      query: |
        Summarize: {{steps.get-time.output}}
        Topic: {{input.topic}}
        Knowledge: {{steps.search-knowledge.output}}
    output:
      key: final_summary

config:
  timeout: 300000
  onError: stop

output:
  timestamp: "{{steps.get-time.output}}"
  knowledge: "{{steps.search-knowledge.output}}"
  summary: "{{steps.summarize.output}}"

Example 3: Knowledge Store for RAG

Setting up semantic search with a knowledge store. All data is persisted to SQLite automatically.

YAML - knowledge/docs.knowledge.yaml
name: docs
description: Knowledge base for semantic search

source:
  type: directory
  path: knowledge/sample-data
  pattern: "*.txt"

loader:
  type: text

splitter:
  type: character
  chunkSize: 1000
  chunkOverlap: 200

embedding: default

search:
  defaultK: 4
  scoreThreshold: 0.2

Example 4: ReAct Workflow

An autonomous workflow using the ReAct pattern with automatic tool and agent discovery.

YAML - workflows/research.workflow.yaml
name: react-research
description: Autonomous research using tool discovery
version: "1.0.0"
type: react

input:
  schema:
    topic:
      type: string
      required: true

prompt:
  system: |
    You are a research assistant with access to tools and agents.
    Identify all tools you need, call them in parallel,
    then synthesize results into a comprehensive report.
  goal: "Research and analyze: {{input.topic}}"

graph:
  model: default
  executionMode: single-turn
  tools:
    mode: all
    sources: [mcp, knowledge, function, builtin]
  agents:
    mode: all
  maxIterations: 10
  timeout: 300000

output:
  analysis: "{{state.messages[-1].content}}"

Example 5: Knowledge Store with Graph

Building a knowledge graph from a CSV file using direct mapping. Entities and relationships are extracted deterministically from columns.

YAML - knowledge/org-chart.knowledge.yaml
name: org-chart
description: Company org chart with personnel directory and performance reviews

source:
  type: file
  path: knowledge/org-chart/personnel.csv

loader:
  type: csv

splitter:
  type: character
  chunkSize: 800
  chunkOverlap: 0

embedding: default

search:
  defaultK: 5

graph:
  directMapping:
    entities:
      - type: Department
        idColumn: department_id
        nameColumn: department_name
        properties: []

      - type: Employee
        idColumn: employee_id
        nameColumn: employee_name
        properties:
          - title
          - location
          - hire_date
          - status
          - rating

    relationships:
      - type: WORKS_IN
        source: Employee
        target: Department
        sourceIdColumn: employee_id
        targetIdColumn: department_id

      - type: REPORTS_TO
        source: Employee
        target: Employee
        sourceIdColumn: employee_id
        targetIdColumn: manager_id

Example 6: Music Librarian with Knowledge Graph and Email

An agent that explores a music catalog via knowledge graph and handles email inquiries.

YAML - agents/music-librarian.agent.yaml
name: music-librarian
description: Music store expert — explore the catalog, discover artists, and analyze customer listening patterns
version: "1.0.0"

llm:
  name: default
  temperature: 0.6

prompt:
  system: |
    You are a Music Librarian for a digital music store. You have deep access to the store's
    full catalog and purchase history through a knowledge graph.
    Use semantic search, entity lookup, and graph traversal to answer questions.
  inputVariables:
    - query

tools:
  - knowledge:music-store

integrations:
  - type: email
    imap:
      host: mail.example.com
      port: 993
      secure: true
    smtp:
      host: mail.example.com
      port: 587
      secure: false
    auth:
      user: librarian
      pass: secret
    fromName: "Music Librarian"
    fromAddress: librarian@example.com
    pollInterval: 20

memory:
  enabled: true
  maxLines: 50

publish:
  enabled: true