Configuration Schema

Defining what settings agents can configure when using your graph.

Overview

Configuration schema defines agent settings:

  • What agents can configure - Prompts, models, tools, etc.
  • UI generation - How settings appear in console
  • Validation - Allowed values and constraints
  • Defaults - Starting values

Location: src/versions/{version}/config-schema.json

Each version can have different configuration options.

Basic Schema

Minimal Example

json
{
  "version": "1.0.0",
  "schema": {
    "type": "object",
    "properties": {
      "systemPrompt": {
        "type": "string",
        "title": "System Prompt",
        "default": "You are a helpful assistant."
      }
    }
  }
}

This creates one text field in the console UI where agents can set their system prompt.

Schema Structure

json
{
  "version": "1.0.0",           // Must match version folder
  "schema": {                    // JSON Schema v7
    "type": "object",
    "properties": {              // Available settings
      "fieldName": {
        "type": "...",
        "title": "...",          // UI label
        "description": "...",    // Help text
        "default": ...           // Default value
      }
    },
    "required": ["fieldName"]    // Required fields
  }
}

Field Types

String

Text input field.

json
{
  "userName": {
    "type": "string",
    "title": "User Name",
    "description": "Name shown in conversations",
    "default": "Assistant",
    "minLength": 1,
    "maxLength": 50
  }
}

Options:

  • minLength - Minimum characters
  • maxLength - Maximum characters
  • pattern - Regex validation (e.g., "^[a-zA-Z]+$")
  • enum - Allowed values (see Enums)

Number

Numeric input (integers or decimals).

json
{
  "temperature": {
    "type": "number",
    "title": "Temperature",
    "description": "Controls randomness (0 = focused, 1 = creative)",
    "default": 0.7,
    "minimum": 0,
    "maximum": 2,
    "multipleOf": 0.1
  }
}

Options:

  • minimum - Minimum value
  • maximum - Maximum value
  • exclusiveMinimum - Value must be greater than (not equal)
  • exclusiveMaximum - Value must be less than (not equal)
  • multipleOf - Value must be multiple of (e.g., 0.1 for one decimal)

Integer

Whole numbers only.

json
{
  "maxRetries": {
    "type": "integer",
    "title": "Max Retries",
    "default": 3,
    "minimum": 1,
    "maximum": 10
  }
}

Same options as number, but rejects decimals.

Boolean

Checkbox for true/false.

json
{
  "enableLogging": {
    "type": "boolean",
    "title": "Enable Logging",
    "description": "Log all conversations for debugging",
    "default": true
  }
}

Object

Nested configuration group.

json
{
  "modelSettings": {
    "type": "object",
    "title": "Model Settings",
    "description": "Configuration for AI model",
    "properties": {
      "modelId": {
        "type": "string",
        "title": "Model",
        "enum": ["gpt-4", "gpt-3.5-turbo", "claude-3-opus"]
      },
      "temperature": {
        "type": "number",
        "title": "Temperature",
        "default": 0.7
      }
    },
    "required": ["modelId"]
  }
}

Objects create collapsible sections in UI.

Array

List of values.

json
{
  "keywords": {
    "type": "array",
    "title": "Keywords",
    "description": "Keywords to watch for",
    "items": {
      "type": "string"
    },
    "minItems": 1,
    "maxItems": 10,
    "uniqueItems": true
  }
}

Options:

  • items - Schema for each array item
  • minItems - Minimum array length
  • maxItems - Maximum array length
  • uniqueItems - Prevent duplicates

Array of objects:

json
{
  "escalationRules": {
    "type": "array",
    "title": "Escalation Rules",
    "items": {
      "type": "object",
      "properties": {
        "keyword": { "type": "string" },
        "action": { "type": "string", "enum": ["email", "slack"] }
      }
    }
  }
}

modelSelector

UI for choosing AI model.

json
{
  "modelId": {
    "type": "modelSelector",
    "title": "AI Model",
    "params": {
      "modelType": "chat"
    },
    "default": "gpt-4o"
  }
}

params.modelType: "chat", "rerank", "embedding"

Returns model ID string: "gpt-4o", "claude-4-5-sonnet"

toolSelector

UI for selecting tools from catalog.

json
{
  "allowedTools": {
    "type": "toolSelector",
    "title": "Available Tools",
    "params": {
      "isMulti": true
    }
  }
}

params.isMulti: Allow multiple selection (default: true)

Returns array of tool IDs: ["web-search", "calculator"]

kbSelector

UI for selecting knowledge bases.

json
{
  "knowledgeBases": {
    "type": "kbSelector",
    "title": "Knowledge Bases",
    "params": {
      "isMulti": true
    }
  }
}

params.isMulti: Allow multiple selection (default: true)

Returns array of KB IDs: ["docs-kb", "support-kb"]

Format Hints

Format hints control UI rendering without changing validation.

textarea

Multi-line text input.

json
{
  "systemPrompt": {
    "type": "string",
    "format": "textarea",
    "title": "System Prompt",
    "default": "You are a helpful assistant."
  }
}

Use for long text like prompts, instructions, templates.

password

Hidden input field.

json
{
  "apiKey": {
    "type": "string",
    "format": "password",
    "title": "API Key",
    "description": "Your secret API key"
  }
}

Value is masked in UI and logs.

email

Email validation and appropriate keyboard on mobile.

json
{
  "contactEmail": {
    "type": "string",
    "format": "email",
    "title": "Contact Email"
  }
}

uri

URL validation.

json
{
  "webhookUrl": {
    "type": "string",
    "format": "uri",
    "title": "Webhook URL",
    "description": "URL to send notifications"
  }
}

date / time

Date or time picker.

json
{
  "startDate": {
    "type": "string",
    "format": "date",
    "title": "Start Date"
  },
  "startTime": {
    "type": "string",
    "format": "time",
    "title": "Start Time"
  }
}

Validation

Required Fields

Mark fields as required.

json
{
  "schema": {
    "type": "object",
    "properties": {
      "systemPrompt": { "type": "string" },
      "modelId": { "type": "string" }
    },
    "required": ["systemPrompt", "modelId"]
  }
}

Console UI shows error if required fields are empty.

Enums

Restrict to specific values.

json
{
  "logLevel": {
    "type": "string",
    "title": "Log Level",
    "enum": ["debug", "info", "warn", "error"],
    "default": "info"
  }
}

Renders as dropdown in UI.

With labels:

json
{
  "logLevel": {
    "type": "string",
    "title": "Log Level",
    "enum": ["debug", "info", "warn", "error"],
    "enumLabels": ["Debug (verbose)", "Info", "Warning", "Error only"],
    "default": "info"
  }
}

Pattern (Regex)

Validate string format.

json
{
  "agentId": {
    "type": "string",
    "title": "Agent ID",
    "pattern": "^[a-z0-9-]+$",
    "description": "Lowercase letters, numbers, and hyphens only"
  }
}

Shows error message if pattern doesn't match.

Min/Max

Number and string length constraints.

json
{
  "temperature": {
    "type": "number",
    "minimum": 0,
    "maximum": 2
  },
  "userName": {
    "type": "string",
    "minLength": 3,
    "maxLength": 50
  }
}

Using Configuration

Configuration is passed to your graph builder function at runtime.

TypeScript

typescript
// src/versions/v1.0.0/builder.ts

import { GraphConfig } from '@flutch/sdk';

export function buildGraph(config: GraphConfig) {
  const {
    systemPrompt,
    modelSettings,
    availableTools,
    enableLogging
  } = config;

  // Use config to build graph
  const llm = new ChatOpenAI({
    model: modelSettings.modelId,
    temperature: modelSettings.temperature,
    maxTokens: modelSettings.maxTokens,
  });

  if (enableLogging) {
    flutch.logger.info('Graph initialized', { config });
  }

  // Build and return graph using config
  return graph;
}

Python

python
# src/versions/v1.0.0/builder.py

def build_graph(config: dict):
    system_prompt = config["systemPrompt"]
    model_settings = config["modelSettings"]
    tools = config.get("availableTools", [])
    enable_logging = config.get("enableLogging", False)

    # Use config to build graph
    llm = ChatOpenAI(
        model=model_settings["modelId"],
        temperature=model_settings["temperature"],
        max_tokens=model_settings["maxTokens"],
    )

    if enable_logging:
        flutch.logger.info("Graph initialized", extra={"config": config})

    # Build and return graph using config
    return graph

SDK Helper

typescript
import { flutch } from '@flutch/sdk';

export function buildGraph() {
  // Get config from SDK
  const config = flutch.config.get();

  const systemPrompt = config.systemPrompt;
  const temperature = config.modelSettings.temperature;

  // Use config...
}

Complete Examples

Customer Support Bot

json
{
  "version": "1.0.0",
  "schema": {
    "type": "object",
    "properties": {
      "systemPrompt": {
        "type": "promptTemplate",
        "title": "System Prompt",
        "default": "You are a helpful customer support agent for {{companyName}}.",
        "params": {
          "variables": ["companyName", "agentName"]
        }
      },
      "model": {
        "type": "modelSelector",
        "title": "AI Model",
        "params": {
          "providers": ["openai", "anthropic"],
          "showPricing": true
        }
      },
      "temperature": {
        "type": "number",
        "title": "Temperature",
        "default": 0.7,
        "minimum": 0,
        "maximum": 1,
        "ui:widget": "slider"
      },
      "availableTools": {
        "type": "toolSelector",
        "title": "Tools",
        "params": {
          "isMulti": true,
          "categories": ["knowledge-base", "crm"]
        }
      },
      "escalationSettings": {
        "type": "object",
        "title": "Escalation",
        "properties": {
          "enableEscalation": {
            "type": "boolean",
            "title": "Enable Escalation to Humans",
            "default": true
          },
          "escalationKeywords": {
            "type": "array",
            "title": "Escalation Keywords",
            "items": { "type": "string" },
            "default": ["refund", "manager", "cancel"],
            "visibleWhen": {
              "field": "enableEscalation",
              "equals": true
            }
          },
          "notificationMethod": {
            "type": "string",
            "title": "Notification Method",
            "enum": ["email", "slack"],
            "default": "email",
            "visibleWhen": {
              "field": "enableEscalation",
              "equals": true
            }
          }
        }
      }
    },
    "required": ["systemPrompt", "model"]
  }
}

RAG Research Assistant

json
{
  "version": "1.0.0",
  "schema": {
    "type": "object",
    "properties": {
      "systemPrompt": {
        "type": "string",
        "format": "textarea",
        "title": "System Prompt",
        "default": "You are a research assistant that helps users find information."
      },
      "vectorStore": {
        "type": "object",
        "title": "Vector Store",
        "properties": {
          "provider": {
            "type": "string",
            "title": "Provider",
            "enum": ["pinecone", "weaviate", "qdrant"],
            "default": "pinecone"
          },
          "indexName": {
            "type": "string",
            "title": "Index Name"
          },
          "topK": {
            "type": "integer",
            "title": "Top K Results",
            "default": 5,
            "minimum": 1,
            "maximum": 20
          }
        },
        "required": ["provider", "indexName"]
      },
      "rerankSettings": {
        "type": "object",
        "title": "Reranking",
        "properties": {
          "enableRerank": {
            "type": "boolean",
            "title": "Enable Reranking",
            "default": false
          },
          "rerankModel": {
            "type": "string",
            "title": "Rerank Model",
            "enum": ["cohere-rerank-v3", "cross-encoder"],
            "visibleWhen": {
              "field": "enableRerank",
              "equals": true
            }
          },
          "topN": {
            "type": "integer",
            "title": "Top N After Rerank",
            "default": 3,
            "minimum": 1,
            "maximum": 10,
            "visibleWhen": {
              "field": "enableRerank",
              "equals": true
            }
          }
        }
      },
      "citationStyle": {
        "type": "string",
        "title": "Citation Style",
        "enum": ["inline", "footnotes", "none"],
        "enumLabels": ["Inline [1]", "Footnotes ¹", "No Citations"],
        "default": "inline"
      }
    },
    "required": ["systemPrompt", "vectorStore"]
  }
}

Multi-Agent Workflow (Node-Based)

Real-world example from a production support graph with routing and specialized agents.

json
{
  "version": "1.0.0",
  "schema": {
    "type": "object",
    "properties": {
      "conversationRouter": {
        "type": "object",
        "title": "Conversation Router",
        "description": "Routes queries to the right agent",
        "properties": {
          "model": {
            "type": "modelSelector",
            "title": "Model",
            "modelType": "chat",
            "default": "gpt-4o-mini"
          },
          "temperature": {
            "type": "number",
            "title": "Temperature",
            "default": 0.2,
            "minimum": 0,
            "maximum": 2
          },
          "systemPrompt": {
            "type": "string",
            "title": "System Prompt",
            "format": "textarea",
            "default": "You are an intelligent query router..."
          }
        }
      },
      "authoritativeAgent": {
        "type": "object",
        "title": "Authoritative Agent",
        "description": "High-precision KB answers with CoRAG",
        "properties": {
          "model": {
            "type": "modelSelector",
            "title": "Model",
            "modelType": "chat",
            "default": "gpt-4o"
          },
          "temperature": { "type": "number", "default": 0.3 },
          "coragRetrieval": {
            "type": "object",
            "title": "CoRAG Retrieval",
            "properties": {
              "maxIterations": {
                "type": "number",
                "default": 3,
                "minimum": 1,
                "maximum": 10
              },
              "topK": {
                "type": "number",
                "default": 8,
                "minimum": 3,
                "maximum": 20
              }
            }
          },
          "knowledgeReranker": {
            "type": "object",
            "title": "Knowledge Reranker",
            "properties": {
              "model": {
                "type": "modelSelector",
                "title": "Rerank Model",
                "modelType": "rerank",
                "default": "cohere-rerank-v3"
              },
              "topK": { "type": "number", "default": 8 }
            }
          }
        }
      },
      "researchAgent": {
        "type": "object",
        "title": "Research Agent",
        "description": "Deep analysis with query decomposition",
        "properties": {
          "model": {
            "type": "modelSelector",
            "modelType": "chat",
            "default": "gpt-4o"
          },
          "temperature": { "type": "number", "default": 0.7 },
          "queryDecomposer": {
            "type": "object",
            "title": "Query Decomposer",
            "properties": {
              "maxSubQueries": { "type": "number", "default": 5 }
            }
          }
        }
      }
    }
  }
}

Key features:

  • Each major node has its own configuration object
  • Nested settings (e.g., coragRetrieval inside authoritativeAgent)
  • Specialized selectors (modelSelector with modelType: "rerank")
  • Clear descriptions for each node's purpose
  • UI renders as collapsible sections per node

Simple ReAct Graph

Example from production ReAct implementation.

json
{
  "title": "ReAct Graph v1.0.0",
  "type": "object",
  "properties": {
    "stepBudget": {
      "type": "integer",
      "minimum": 1,
      "maximum": 15,
      "default": 6,
      "description": "Maximum number of ReAct cycles"
    },
    "allowedTools": {
      "type": "toolSelector",
      "title": "Available Tools",
      "params": {
        "isMulti": true,
        "showDescriptions": true
      }
    },
    "reactNode": {
      "type": "object",
      "title": "ReAct Node Configuration",
      "properties": {
        "modelId": {
          "type": "modelSelector",
          "modelType": "chat",
          "default": "gpt-4o"
        },
        "temperature": {
          "type": "number",
          "default": 0.7,
          "minimum": 0,
          "maximum": 2
        },
        "systemPrompt": {
          "type": "string",
          "format": "textarea",
          "default": "You are a reasoning AI assistant..."
        }
      }
    },
    "answerNode": {
      "type": "object",
      "title": "Answer Node Configuration",
      "properties": {
        "modelId": {
          "type": "modelSelector",
          "modelType": "chat",
          "default": "claude-3-5-sonnet"
        },
        "temperature": { "type": "number", "default": 0.6 }
      }
    }
  },
  "required": ["allowedTools"]
}

Note: Global settings like stepBudget and allowedTools at top level, node-specific settings grouped by node.

Best Practices

1. Provide Good Defaults

Every field should have a sensible default value.

json
// ✅ Good
{
  "temperature": {
    "type": "number",
    "default": 0.7,
    "description": "Recommended: 0.7 for balanced responses"
  }
}

// ❌ Bad
{
  "temperature": {
    "type": "number",
    "description": "Set temperature"
  }
}

2. Use Clear Descriptions

Help users understand what each field does.

json
// ✅ Good
{
  "maxTokens": {
    "type": "integer",
    "title": "Max Tokens",
    "description": "Maximum length of AI responses. Higher = longer answers but higher cost.",
    "helpText": "GPT-4: ~750 words = 1000 tokens. Recommended: 2000 for conversations."
  }
}

// ❌ Bad
{
  "maxTokens": {
    "type": "integer",
    "title": "Tokens"
  }
}

Recommended: Organize configuration by graph nodes for better UI and maintainability.

json
// ✅ Good - organized by nodes
{
  "reactNode": {
    "type": "object",
    "title": "ReAct Node Configuration",
    "description": "Settings for the reasoning and tool selection node",
    "properties": {
      "modelId": { "type": "modelSelector", "default": "gpt-4o" },
      "temperature": { "type": "number", "default": 0.7 },
      "systemPrompt": { "type": "string", "format": "textarea" }
    }
  },
  "answerNode": {
    "type": "object",
    "title": "Answer Node Configuration",
    "description": "Settings for the final answer generation node",
    "properties": {
      "modelId": { "type": "modelSelector", "default": "claude-3-5-sonnet" },
      "temperature": { "type": "number", "default": 0.6 },
      "systemPrompt": { "type": "string", "format": "textarea" }
    }
  }
}

// ❌ Bad - flat structure without grouping
{
  "reactModel": {...},
  "reactTemperature": {...},
  "answerModel": {...},
  "answerTemperature": {...}
}

Benefits:

  • UI renders each node as collapsible section
  • Easy to understand which settings affect which part of the graph
  • Easier to maintain and update
  • Matches code structure (one config per node)

4. Validate Appropriately

Use validation to prevent errors, not to frustrate users.

json
// ✅ Good - reasonable constraints
{
  "userName": {
    "type": "string",
    "minLength": 1,
    "maxLength": 100
  }
}

// ❌ Too strict
{
  "userName": {
    "type": "string",
    "pattern": "^[a-z]{3,10}$",
    "minLength": 3,
    "maxLength": 10
  }
}

5. Use Conditional Fields Wisely

Hide complexity until needed.

json
// ✅ Good
{
  "enableAdvanced": {
    "type": "boolean",
    "title": "Enable Advanced Settings",
    "default": false
  },
  "advancedSettings": {
    "type": "object",
    "visibleWhen": { "field": "enableAdvanced", "equals": true },
    "properties": {
      "timeout": {...},
      "retryStrategy": {...}
    }
  }
}

6. Keep It Simple

Start with essential settings, add more as needed.

json
// ✅ Good for v1.0.0
{
  "systemPrompt": {...},
  "model": {...},
  "temperature": {...}
}

// Can expand in v2.0.0 with more advanced options

7. Use Enums for Fixed Choices

Prevent typos and show available options.

json
// ✅ Good
{
  "logLevel": {
    "type": "string",
    "enum": ["debug", "info", "warn", "error"]
  }
}

// ❌ Bad - allows any string
{
  "logLevel": {
    "type": "string"
  }
}

Troubleshooting

Schema Validation Failed

Error: Invalid schema: properties.temperature.type must be 'number'

Fix: Check JSON Schema syntax. Common issues:

  • Typo in type value
  • Missing required fields
  • Invalid constraint combination

UI Not Rendering Field

Field defined but doesn't appear in console UI.

Check:

  1. Is field inside properties object?
  2. Is parent object visible (check visibleWhen conditions)?
  3. Is version number in schema correct?

Default Value Not Applied

json
{
  "temperature": {
    "type": "number",
    "default": "0.7"  // ❌ String instead of number
  }
}

Fix: Ensure default value type matches field type:

json
{
  "temperature": {
    "type": "number",
    "default": 0.7  // ✅ Correct
  }
}

Conditional Field Not Showing

json
{
  "cacheTTL": {
    "visibleWhen": {
      "field": "enableCache",  // ❌ Wrong field path
      "equals": true
    }
  }
}

Fix: Use correct field path:

json
{
  "cacheTTL": {
    "visibleWhen": {
      "field": "cacheSettings.enableCache",  // ✅ Correct nested path
      "equals": true
    }
  }
}

Test Schema Validation

bash
# Validate schema without deploying
flutch validate

# Test with sample config
flutch config:test src/versions/v1.0.0/config-schema.json