Documentation

Agent Configuration Reference

Complete YAML configuration reference for LeafMesh.

Top-Level Configuration

name: "my_swarm" # Required: unique swarm identifier version: "1.0.0" # Optional: configuration version architecture: "managed_mesh" # Required: architecture pattern api: # API server configuration cors_origins: [] # Extra CORS origins on top of platform.leafcraft.ai + localhost defaults manager: # Manager configuration enabled: true model: "gpt-4o-mini" coordination_rules: max_response_time: 30 # Maximum response time (seconds) mesh: # Mesh communication settings max_retries: 2 # Retry count for failed mesh calls timeouts: mesh_call_default_timeout_s: 300 # Default mesh call timeout (seconds, default 300) observability: # Built-in observability enabled: true tracing_enabled: true service_name: "my_swarm" metrics_retention_minutes: 1440 # 24 hours self_healing: # Agent health watch (all fields optional) enabled: true # watch health, notify (default true) actions_enabled: false # allow restart / backup (default false) consecutive_failures: 5 error_rate: 0.3 latency_factor: 3.0 # x the agent's own median latency min_quality_score: 0.4 cooldown_s: 600 max_actions_per_hour: 3 max_backups_per_agent: 1 monitoring_interval_s: 5 agents: {} # Agent definitions (see below)

From 2.4.482 the store is set only in .env, never in the YAML. See Persistence for the full list (Redis TLS, Redis Cluster, Postgres):

# .env LEAFMESH_STORE=redis REDIS_HOST=localhost REDIS_PORT=6379 REDIS_DB=0 # 1 hour for general data REDIS_DEFAULT_TTL=3600 # 7 days for sessions (the default) REDIS_SESSION_TTL=604800

Agent Definition

Required Fields

name

Unique identifier for the agent within the swarm.

name: "solver"

Rules:

  • Must be unique within the swarm
  • Use snake_case naming
  • No special characters except underscore

yields

Define the structured output schema. The LLM's response is parsed against this schema. These fields become available for can_call condition evaluation.

yields: answer: "number" # Numeric values (int or float) steps: "array" # Lists or arrays confidence: "number" # Another numeric value explanation: "string" # Text data is_correct: "boolean" # True/false metadata: "object" # Complex nested data

Supported types: string, number, boolean, object, array

description

Optional description of the agent's purpose.

description: "Classifies incoming requests and routes to specialists"

inputs

Expected input schema. Documents what fields the agent expects in input_data.

inputs: message: "string" account_id: "string" priority: "number"

LLM Agent Fields

model

LLM model identifier — required for an LLM agent; there is no default model. Provider is detected automatically from the model name.

# OpenAI model: "gpt-6.1-sol" model: "gpt-4o-mini" # Anthropic model: "claude-sonnet-5-5" model: "claude-opus-5-5" model: "claude-haiku-5-5" # Google model: "gemini-4-argon" model: "gemini-3.6-flash" # DeepSeek model: "deepseek-v4-pro" model: "deepseek-flash" # Other vendors (one key each) model: "kimi-k3" # Moonshot Kimi model: "openrouter/moonshotai/kimi-k3" # through OpenRouter # Local model: "ollama:llama3.1" model: "vllm:mistral-7b"

model_connection

2.4.486+. The vault record this LLM agent's model calls sign in with. Use it when one service has several accounts (for example a dev and a prod key).

agents: writer: agent_type: llm model: gpt-4o-mini model_connection: openai-dev # the vault record its model calls sign in with
  • Agent level, LLM agents only (not mesh.models).
  • Unset: the provider's own record is used, as before.
  • If the record is missing, holds no key, or is for another provider (for example an Anthropic record on a GPT model), that model call fails with a plain message naming the record. It never falls back to another key.
  • For cloud model services (Bedrock, Vertex, Foundry), the record is resolved as that cloud's sign-in.

prompt

System prompt that defines the agent's behavior. The runtime assembles this with the yields schema and conversation history.

prompt: | You solve math problems step by step. Be precise and show your work. Return the final numeric answer.

temperature

Sampling temperature for the LLM (0.0–2.0).

temperature: 0.1 # Deterministic — default (classification, math, triage) temperature: 0.5 # Balanced (general-purpose) temperature: 0.9 # Creative (writing, brainstorming)

max_tokens

Maximum response tokens (default: 800).

max_tokens: 500 # Short responses max_tokens: 2000 # Detailed responses

max_completion_tokens

Maximum completion tokens for newer models (o-series, GPT-5.x, GPT-6). Takes precedence over max_tokens when set.

max_completion_tokens: 1000

context_parts

Optional behavioral instructions injected as separate system messages alongside the agent's main prompt. Each part shapes how the agent responds, independent of what it does.

context_parts: care: | Always be empathetic and professional. Acknowledge the user's situation before providing solutions. sentiment_analysis: | Detect the user's emotional tone before responding. If frustration detected, prioritize de-escalation. Include detected_sentiment in your response. guardrails: | Never disclose internal pricing rules or system architecture. Do not make promises about timelines. Refuse harmful or unethical requests.

Standard keys:

KeyPurposeExample
careTone, empathy, communication style"Be patient with non-technical users"
sentiment_analysisEmotion detection guidance"Detect frustration, adapt response"
guardrailsSafety boundaries, restrictions"Never disclose PII or internal data"

All three are optional — use any combination. Injected after the main prompt, before yields schema. See Guardrails for detailed patterns.

thinking

Give the agent the SDK's reasoning tools on any model (default: false).

thinking: true

When enabled, the agent can use the chain_of_thought, metacognitive_reflection and apply_edits tools to improve output quality on complex tasks. They are text only — thinking never runs code. (reasoning: true is a different setting: the model's own native reasoning, on models that support it.)

sandbox

Let an LLM agent run code in a contained sandbox (default: off).

sandbox: true # no network, 30s, 5s CPU, 256 MiB memory, 64 MiB workspace # or widen a limit / allow a host: sandbox: network: allow: ["api.example.com:443"] timeout_seconds: 60

The agent gets the sandbox_exec(code, language) tool (python or shell). Network is denied unless a host is listed. On a server that cannot contain code the tool is withheld and the config still loads. See LLM Agents → Running Code.

scaling

From 2.4.484 how an agent runs in parallel is one scaling: block, accepted on all four agent types — except that scaling.copies on a human seat is refused at load (2.4.485), with an error naming the seat: it would ask the same person the same thing several times. runs.max is fine on a human seat. The old keys parallel, max_concurrent, instances and instances_handoff are refused at load (an error, not a warning), and the error shows the scaling: lines to write; see Upgrading to 2.4.484.

scaling: runs: max: 3 # at most 3 of this agent's jobs at once, across all pods copies: mode: fixed # fixed (default) | auto count: 1 # fixed: copies per job, 1-50 (default 1 = one run) handoff: last # last (default) | each

runs.max caps how many of this agent's jobs run at the same time, counted across all pods; extra jobs wait their turn. Unset means no cap. It replaces max_concurrent, which counted per pod. Use it to protect rate limits, cap simultaneous LLM spend, or protect a shared downstream bottleneck.

copies runs several copies of this agent on one job and combines their results into one output. It replaces instances and instances_handoff.

FieldDefaultUsed byMeaning
modefixed—fixed: start count copies. auto: the mesh hands out the work item by item and starts a copy only when there is an item for it.
count1fixedCopies per job, 1–50. 1 is a single run.
max10autoMost copies at once, 1–50
work—autoThe input field that holds the list of work
claim_tool—autoInstead of work: the agent's own tool that hands out the next item
handofflastbothlast: one combined output, handed on once. each: every copy's result is handed on.

Auto mode. With 6 items and max: 10 the mesh starts 6 copies, never 10. A copy takes the next item with the built-in next_work_item tool, which returns {item} or {done: true}; the copy stops when none is left. An empty list means one run on the job as it came. With claim_tool, the mesh calls that tool itself (no model run) before starting a copy and whenever a copy asks for more. auto needs exactly one of work or claim_tool; neither belongs in fixed (both are refused at load).

What a copy sees. Each copy's input carries _instance: {id, of}. In auto mode of is "auto" and the input also carries _work: {item, field}.

What is handed on. With handoff: last the results are combined: lists joined in copy order, numbers summed, other fields from the final copy, and the chain continues once. The combined output also carries _instances: {count, results, failed} with the per-copy detail, for @chain/@compose rewrites. With handoff: each, every copy's own result is handed on.

# Fixed: three copies on every job, each result handed on scaling: copies: mode: fixed count: 3 handoff: each # Auto, one copy per item in the input field "items" (at most 5 at once) scaling: copies: mode: auto max: 5 work: "items" # Auto, fed by the agent's own claim tool tools: ["claim_batch"] scaling: copies: mode: auto claim_tool: "claim_batch"

copies multiplies this agent's own execution on one job; runs.max caps how many of its jobs run at once. Fan out with copies; protect a shared bottleneck with runs.max on that agent.

Routing Fields

can_call

Define conditional routing to downstream agents. Conditions are evaluated against the agent's yields using AST-safe evaluation (Python ast module).

can_call: - agent: "checker" condition: "answer >= 0" call_immediately: true - agent: "specialist" condition: "category == 'technical'" - agent: "escalation" condition: "urgency >= 8 and confidence < 0.5"

Fields:

FieldTypeRequiredDescription
agentstringyesTarget agent name
conditionstringyesAST-safe condition expression
call_immediatelybooleannoSynchronous call (default: false)

Condition operators:

CategoryOperators
Comparison==, !=, <, <=, >, >=
Booleanand, or, not (also &&, `\\`)
Arithmetic+, -, *, /, %
Chained0.5 <= confidence <= 0.9
Stringcategory == 'billing'
Nestedcalling_agent_response.score >= 0.7

Available variables: the producing agent's yields (top level), calling_agent_response (full response dict for nested access), and any session context. Empty/missing condition means the route is always callable. Function calls, subscripts, and private attribute access are blocked by the AST allow-list.

See Message Routing — Condition Evaluation for the full operator reference, evaluation context, cookbook, and failure modes.

Notification Fields

notify

2.4.486+, any agent type. Post the agent's output to one of your own systems when the agent hands its work on, or when it fails.

agents: quote_issuer: notify: webhook: crm_update # a webhook made on Tools → Webhooks (by its name), never a URL when: done # done (default) | failed | both
FieldDefaultMeaning
webhook—The name of a webhook made on Tools → Webhooks. An address here is refused at load.
whendonedone, failed or both

Only these two keys are accepted; anything else is refused at load. What is sent, the headers, retries and failure behaviour are described in Tell your systems when work is done.

Tool Fields

tools

List of tools available to the agent. Tools must be registered via the @global_tool decorator (see Tools).

tools: ["calculator", "current_time", "web_request"]

See Tools for the complete built-in tools list and custom tool registration.

tool_choice

Control how the LLM uses tools.

# LLM decides (default) tool_choice: "auto" # Must call at least one tool tool_choice: "required" # Force a specific tool tool_choice: type: "function" function: name: "calculator" # Disable tool calling tool_choice: "none"

max_tool_calls_per_message

Maximum tool calls per agent execution (default: 5, range 0-20). Prevents runaway tool loops.

max_tool_calls_per_message: 3

tool_call_timeout

Timeout for individual tool execution in seconds (default: 30.0, range 0.1-300).

tool_call_timeout: 60.0 # Allow longer tool executions

allow_parallel_tool_calls

Allow parallel execution of multiple tool calls (default: true).

allow_parallel_tool_calls: false # Force sequential tool execution

tool_categories

Tool categories this agent can access. An alternative to listing individual tools.

tool_categories: ["data", "communication", "analysis"]

Memory Fields

memory

Configure how the agent loads context from past interactions. Accepts true/false for simple enable/disable, or a dict for fine-grained control.

# Simple: enable with defaults memory: true # Detailed: configure strategy and parameters memory: strategy: "hybrid" # "recent" | "relevant" | "hybrid" limit: 10 # Max memory posts to load cross_session: true # Recall from other sessions cross_session_limit: 50 # Max cross-session posts to consider relevance_weight: 0.6 # Tunable relevance weight (0.0–1.0) recency_weight: 0.4 # Tunable recency weight (0.0–1.0) decay_hours: 168 # Memory decay half-life (tunable, hours)

Memory fields:

FieldTypeDefaultDescription
strategystring"recent""recent": chronological, "relevant": scored by input similarity, "hybrid": both
limitint10Maximum memory posts loaded into context
cross_sessionbooleanfalseLoad posts from other sessions
cross_session_limitint50Max cross-session posts to consider
relevance_weightfloat0.6Tunable relevance weight
recency_weightfloat0.4Tunable recency weight
decay_hoursfloat168Memory decay half-life in hours (tunable)

See Smart Memory Strategies for detailed strategy explanations and tuning guidance.

Channel Fields

channels

Configure native channel adapters for human agents. Enables direct integration with messaging platforms.

channels: slack: connection: "slack-workspace" # Infrastructure → Messaging → Slack listen_channels: - "C0123456789" post_channel: "C0123456789"

Slack channel fields:

FieldTypeRequiredDescription
connectionstringyesThe Slack record under Infrastructure → Messaging → Slack. It holds the bot token (xoxb-...) and signing secret; written inline (or as ${ENV} references) they are refused at load.
listen_channelsarraynoChannel IDs to monitor for inbound messages
post_channelstringnoDefault channel for outbound messages

Channel adapters automatically register webhook endpoints on the API server at /channels/{provider}/{agent_name}/events.

See Human Agents — Channel Adapters for the full inbound routing flow.

Storage Fields

auto_store_response

Automatically store agent responses in Redis (default: true).

auto_store_response: false # Disable for stateless agents

auto_store_yields

Automatically store parsed yields in Redis (default: true).

auto_store_yields: false

Agent Type Fields

agent_type

Set the agent type. Default is "llm".

agent_type: "llm" # Default, uses LLM agent_type: "programmatic" # Pure Python, no LLM call agent_type: "human" # Human-in-the-loop agent_type: "external" # External framework (CrewAI, LangGraph, AutoGen, custom)

Programmatic Agent

agents: validator: name: "validator" agent_type: "programmatic" yields: is_valid: "boolean" errors: "array" can_call: - agent: "processor" condition: "is_valid == true"

For programmatic agents, the intelligence function is the agent. No LLM call is made. llm_response is an empty dict.

Human Agent

agents: approver: name: "approver" agent_type: "human" is_human_powered: true human_interface: "api" human_timeout_seconds: 300 webhook_config: connection: "approvals-webhook" # Outbound webhook record (Infrastructure → Add custom) communication_type: "dual" yields: decision: "string" notes: "string" can_call: - agent: "executor" condition: "decision == 'approved'"

Human agent fields:

FieldTypeDefaultDescription
is_human_poweredbooleanfalseMark as human agent
human_interfacestring"api"Interface type: "api", "webhook", "custom"
human_timeout_secondsint300Timeout waiting for human response
human_context_templatestringnoneTemplate for presenting context to the human reviewer
human_prompt_templatestringnoneTemplate for human prompts
fallback_on_timeoutbooleanfalseOpt in to using fallback_response when the human times out. Off: a timeout escalates or errors, never an assumed answer
fallback_responseobjectnoneDefault response data when human times out

require_human_confirmation, confirmation_seat and human_escalation_triggers were removed in 2.4.382: approval is routing. Setting one of them on is refused at load; off or empty is dropped. To have a person approve work, route it to a human agent with can_call and a condition (as in the example above), and give that human agent the can_call to the agent that acts.

Webhook configuration (webhook_config): the webhook's address, header and query rows and inbound token are an Add custom record on Studio's Infrastructure page with service type Outbound webhook, named with connection:. From 2.4.481 outbound_url, outbound_headers and inbound_auth_token written inline are refused at load. An Inbox seat is human_interface: default (no webhook or channel needed).

FieldTypeDefaultDescription
connectionstringnoneThe Outbound webhook record (address, header and query rows, inbound token)
outbound_timeoutint30Timeout for outbound calls (seconds)
inbound_endpointstringnoneEndpoint path for inbound responses (e.g., "/client/response")
response_mappingobject{}Field mapping for webhook responses
max_retriesint3Maximum retries for failed outbound webhooks
retry_delayint5Delay between retries (seconds)
operatorsmap{}Operator ID → recipient for this webhook

On timeout, a HUMAN_INPUT_TIMEOUT event is published. Only if you set fallback_on_timeout: true and a fallback_response is the fallback used; by default the timeout escalates or errors and the Manager takes its configured actions.

External Agent

agents: crewai_agent: name: "crewai_agent" agent_type: "external" framework: "crewai" # see the supported frameworks list connector_config: connection: "my-connector" # Infrastructure → External agents → CrewAI: address and credentials yields: result: "string" status: "string" can_call: - agent: "processor" condition: "status == 'success'"

External agent fields:

FieldTypeDefaultDescription
frameworkstringnoneRequired for external agents. One of the frameworks in [External Frameworks → Supported Frameworks](../integrations/external-frameworks#supported-frameworks), or "custom"
connector_configobject{}Framework-specific connection configuration

Scheduling Fields

wake_up

Schedule an agent for periodic execution. Works with any agent type.

agents: collector: name: "collector" agent_type: "programmatic" wake_up: "*/5 * * * *" # Every 5 minutes reporter: name: "reporter" model: "gpt-4o-mini" wake_up: "0 * * * *" # Every hour at :00 daily_digest: name: "daily_digest" model: "gpt-4o" wake_up: "0 0 * * *" # Midnight daily

Schedule formats:

FormatExampleMeaning
Cron (5-field)*/5 * * * *Every 5 minutes
Interval30s 5m 2h 1dNumber + unit, no space
Keyword@hourlyTop of every hour
Keyword@dailyMidnight
Keyword@weeklySunday midnight
Keyword@monthlyFirst of the month

Keywords require the leading @. Intervals below scheduler.cron_min_interval_seconds (default 60s) are rejected at load.

When wake_up fires, the agent runs with empty input_data. The full pipeline executes: pre-compose, LLM call (or intelligence function for programmatic), yields parsing, can_call evaluation.

Communication Fields

communication_type

Control how the agent returns results.

# Dual: return response immediately, dispatch can_call chains in background (default) communication_type: "dual" # Chain: chained execution mode communication_type: "chain" # Execute: standard execution with full pipeline communication_type: "execute"

Adaptive Execution Fields

optimization_strategy

Enable adaptive model selection for this agent. The runtime selects the optimal model based on request characteristics and performance history.

optimization_strategy: "performance" # Maximize quality and reliability optimization_strategy: "cost" # Minimize token costs optimization_strategy: "speed" # Minimize latency

The configured model serves as the default fallback if adaptive selection fails.

Manager Configuration

The Manager is a unified coordinator with both pure-logic coordination and LLM-based analysis. It evaluates each agent turn and decides whether intervention is needed.

manager: enabled: true model: "gpt-4o-mini" # LLM model for analysis temperature: 0.1 max_tokens: 4000 domain: "generic" # Domain specialization analysis_style: "coordination" # Analysis approach coordination_rules: {} # max_call_depth, agent_rules, reflection_budget (default 2), max_retries, ... chain_completion_timeout: 1800.0 # Seconds to wait for can_call chain completion health_check_interval: 60 # Seconds between health checks agent_timeout_threshold: 180 # Seconds before agent is considered timed out can_intervene: true # Allow manager interventions intervention_triggers: - "mesh_loop_detected" - "coordination_rule_violation" - "agent_conflict" human_input_rules: # Directly under manager:, not under coordination_rules max_concurrent_requests: 3 max_agent_requests: 5 enable_request_queuing: true timeout_rules: max_timeouts_before_escalation: 2 timeout_escalation_enabled: true escalation_notify_managers: true workflow_pause_rules: max_pause_duration_minutes: 30 max_concurrent_paused_workflows: 2 pause_monitoring_enabled: true routing: # Learning-based routing mode: "static" # "static" | "learning" memory_size: 100 # Max decisions per agent pair confidence_threshold: 0.7 # Min success rate to keep route escalation: # Multi-target escalation targets: - type: "human_agent" # "human_agent" | "webhook" | "channel" agent: "senior_support" entry_point: "escalation_request" - type: "webhook" connection: "escalation-webhook" # Outbound webhook record: address, headers, token method: "POST" payload_template: customer_id: "{{customer_id}}" - type: "channel" provider: "slack" channel_id: "C0123456789" message_template: "Escalation: {{issue}}" human_response_rules: approval: requires_manager_review: false auto_escalate: false escalation: requires_manager_review: true auto_escalate: true timeout: requires_manager_review: true auto_escalate: false

human_input_rules, timeout_rules, workflow_pause_rules and human_response_rules sit directly under manager:. Do not nest them under manager.coordination_rules:; from 2.4.482 a file that still does is moved at load, with a warning. coordination_rules itself stays for its other keys.

The Manager tracks failed agents per session and prevents routing to known-failing agents. It makes automatic coordination decisions after every significant agent turn (retry, escalate, stop, continue, and similar) based on configured rules and evaluation criteria. When routing.mode is "learning", the Manager also uses runtime routing-quality feedback to optimize future routing decisions.

Mesh Configuration

mesh: communication: "all_to_all" # Communication pattern direct_agent_calls: true # Allow direct agent-to-agent calls manager_awareness: "mandatory" # Manager involvement level summarization_monitoring: "continuous" # Summarization monitoring mode max_call_depth: 5 # Maximum call chain depth loop_detection: true # Detect communication loops
FieldTypeDefaultDescription
communicationstring"all_to_all"Communication pattern
direct_agent_callsbooleantrueAllow direct agent-to-agent mesh calls
manager_awarenessstring"mandatory"Manager involvement level
summarization_monitoringstring"continuous"Summarization monitoring mode
max_call_depthint5Maximum call chain depth (prevents infinite loops)
loop_detectionbooleantrueDetect and prevent communication loops

mesh.call_timeout is gone. The default mesh call timeout is timeouts.mesh_call_default_timeout_s (default 300 seconds). From 2.4.482 an old mesh.call_timeout is moved there at load, with a warning.

Complete Example

name: "support_system" version: "1.0.0" architecture: "managed_mesh" manager: enabled: true model: "gpt-4o-mini" coordination_rules: max_response_time: 30 mesh: max_retries: 2 timeouts: mesh_call_default_timeout_s: 60 # Observability: auto-enabled by LEAFMESH_LICENSE_KEY (no YAML config needed) agents: # Step 1: Classify the request (LLM) triage: name: "triage" model: "gpt-4o-mini" temperature: 0.1 max_tokens: 200 prompt: | Classify the user's request into a category and urgency level. Categories: technical, billing, general. Urgency: 1 (low) to 10 (critical). yields: category: "string" urgency: "number" summary: "string" can_call: - agent: "specialist" condition: "category == 'technical' and urgency >= 5" call_immediately: true - agent: "billing_agent" condition: "category == 'billing'" - agent: "general_agent" condition: "category == 'general'" # Step 2a: Handle technical issues (LLM) specialist: name: "specialist" model: "gpt-4o" temperature: 0.3 tools: ["calculator", "current_time"] prompt: | You are a technical specialist. Diagnose the issue and provide a step-by-step solution. yields: solution: "string" resolved: "boolean" confidence: "number" can_call: - agent: "human_reviewer" condition: "resolved == false" # Step 2b: Handle billing (LLM) billing_agent: name: "billing_agent" model: "gpt-4o-mini" temperature: 0.0 prompt: | You handle billing inquiries. Explain charges, process adjustments, and resolve payment issues. yields: resolution: "string" amount: "number" needs_approval: "boolean" can_call: - agent: "human_reviewer" condition: "needs_approval == true" # Step 2c: Handle general inquiries (LLM) general_agent: name: "general_agent" model: "gpt-4o-mini" temperature: 0.5 prompt: | You answer general questions about products and services. yields: answer: "string" # Step 3: Human escalation human_reviewer: name: "human_reviewer" agent_type: "human" is_human_powered: true human_interface: "api" human_timeout_seconds: 1800 yields: decision: "string" notes: "string"

From 2.4.482 the store is set only in .env, never in the YAML:

# .env LEAFMESH_STORE=redis REDIS_HOST=localhost REDIS_PORT=6379 REDIS_DB=0 REDIS_SESSION_TTL=3600

Next Steps


LeafMesh — YAML-first agent configuration

Last updated: 11/10/2026