Best Practices

Best Practices

Guidelines for building production-quality LeafMesh systems.

Agent Design

Keep Agents Focused

Each agent should have a single responsibility:

# Good: focused agents agents: classifier: name: "classifier" model: "gpt-4o-mini" # required — the SDK never picks one for you prompt: "Classify the request by category and urgency." yields: category: "string" urgency: "number" resolver: name: "resolver" model: "gpt-4o-mini" prompt: "Resolve the technical issue." yields: solution: "string" confidence: "number"
# Bad: agent doing too much agents: do_everything: name: "do_everything" prompt: "Classify the request, resolve it, write a response, and log it." yields: category: "string" urgency: "number" solution: "string" response: "string" log_entry: "string"

Use Appropriate Agent Types

TaskAgent Type
Classification, analysis, content generationLLM
Data validation, calculations, API callsProgrammatic
Approvals, quality reviewHuman
Monitoring, reports, maintenanceScheduled

Design Clear Yields Schemas

# Good: clear, typed outputs yields: category: "string" confidence: "number" is_urgent: "boolean" # Avoid: vague or overly complex schemas yields: result: "string" # Too vague data: "string" # What data?

Configuration

Use One Agency per Environment

The configuration lives in each agency's store, so give each environment its own agency, each with its own versioned configuration:

# Development agency agents: classifier: name: "classifier" model: "gpt-4o-mini" # Cheaper for development # Production agency agents: classifier: name: "classifier" model: "gpt-4o" # More capable for production

Keep one .env per environment; it names the agency and its store (from 2.4.482 the store is set only in .env, never in the YAML):

# .env (development) LEAFMESH_AGENCY_NAME=support-dev LEAFMESH_STORE=redis REDIS_HOST=localhost # .env (production, Redis Cluster) LEAFMESH_AGENCY_NAME=support-prod LEAFMESH_STORE=redis REDIS_CLUSTER_NODES=redis-1:6379,redis-2:6379,redis-3:6379

Set Appropriate Token Limits

agents: classifier: name: "classifier" max_tokens: 500 # Short classification output writer: name: "writer" max_tokens: 2000 # Longer content output analyzer: name: "analyzer" max_tokens: 1000 # Medium analysis output

Configure Sensible Timeouts

agents: human_reviewer: name: "human_reviewer" timeout: 300 # 5 minutes for human response manager: coordination_rules: max_agent_calls: 10 # Prevent runaway chains

Intelligence Functions

Keep Business Logic in Intelligence Functions

async def processor(llm_response, input_data, context): # Business rules belong here, not in prompts if llm_response.get("amount", 0) > 10000: llm_response["requires_approval"] = True return llm_response

Use Pre-Compose for Data Assembly

# Good: deterministic context before LLM @pre_compose(context_processor=fetch_account_data) async def specialist(llm_response, input_data, context): return llm_response
# Avoid: fetching data inside intelligence function # (too late - LLM already ran without this context) async def specialist(llm_response, input_data, context): account = await fetch_account_data(...) # LLM didn't see this return llm_response

Routing

Use Explicit Conditions

# Good: clear, specific conditions can_call: - agent: "specialist" condition: "urgency >= 7 and category == 'technical'" # Avoid: overly broad conditions can_call: - agent: "specialist" condition: "true" # Everything routes here

Design for Failure

Include fallback paths in your routing:

can_call: - agent: "specialist" condition: "confidence > 0.8" - agent: "human_reviewer" condition: "confidence <= 0.8" # Fallback for low confidence

Always Bound Retry Back-Edges

Warning: Any can_call that routes back upstream (a retry loop, or a critic that loops to a writer) is a cycle. If its condition can stay true forever, the chain climbs until it hits the mesh.max_chain_events cap (default 50) and the session is stopped with a ChainCapExceeded error — after burning real LLM spend.

Bound every such back-edge with a per-session exhaustion counter: count attempts in the agent's Python, yield a *_retry_exhausted boolean, gate the back-edge on it, and add a terminal route for the exhausted case. There is no once_per_session flag — the bounding is your job. See Coordination → Chain Cap & Bounding Cycles for the full pattern.

Monitoring

Check System Health Regularly

# Periodic health check analytics = Studio's Dashboard (HTTP) agent_stats = leafmesh.get_agent_stats() cache_stats = Studio's Dashboard (HTTP)

Monitor Error Rates

High error rates indicate configuration or provider issues. Check:

  • Agent error rates via leafmesh.get_agent_stats()
  • Provider availability
  • Redis connectivity

Next Steps


LeafMesh — Development best practices

Last updated: 11/10/2026