Template Library¶
Yagra provides ready-to-use templates for common workflow patterns. Templates let you bootstrap workflows quickly without writing YAML from scratch.
Available Templates¶
branch: Conditional Branching¶
Pattern: Classify → Branch → Merge
Use Case: Route requests based on intent (FAQ, general, support, etc.)
Structure:
Classifier node determines intent
Conditional edges route to specialized handlers
All paths converge to finish node
Initialize:
yagra init --template branch --output my-branch-workflow
Generated Files:
workflow.yaml: Workflow with classifier → faq_bot / general_bot → finishprompts/branch_prompts.yaml: System and user prompts
Customize:
Edit
classify_intentlogic in your Python codeAdjust prompts in
prompts/branch_prompts.yamlAdd/remove branches by editing
edgesinworkflow.yaml
loop: Planner → Evaluator Loop¶
Pattern: Generate → Evaluate → Retry or Done
Use Case: Iterative refinement (planning, content generation, validation)
Structure:
Planner generates output
Evaluator checks quality
Loop back to planner if needs improvement
Exit to finish when quality is acceptable
Initialize:
yagra init --template loop --output my-loop-workflow
Generated Files:
workflow.yaml: planner → evaluator → (retry/done)prompts/loop_prompts.yaml: Planner and evaluator prompts
Customize:
Implement quality criteria in
evaluatorhandlerSet
max_iterationsinevaluatorparamsAdjust prompts for your domain (e.g., code generation, text summarization)
rag: Retrieve → Rerank → Generate¶
Pattern: RAG (Retrieval-Augmented Generation)
Use Case: Question answering with document retrieval
Structure:
Retrieve relevant documents from knowledge base
Rerank documents by relevance
Generate answer based on top documents
Initialize:
yagra init --template rag --output my-rag-workflow
Generated Files:
workflow.yaml: retrieve → rerank → generateprompts/rag_prompts.yaml: Rerank and generation prompts
Customize:
Implement
retrieve_documentswith your vector DBImplement
rerank_documentswith reranking modelAdjust
generate_answerto format context and query
tool-use: Planner → Tool Executor → Synthesizer¶
Pattern: Plan → (Use Tool or Skip) → Synthesize
Use Case: LLM decides whether to invoke an external tool and routes accordingly before composing the final answer
Structure:
Planner node (llm handler) determines whether a tool call is needed
Conditional edges route to tool_executor (custom handler) when a tool is required, or directly to synthesizer when no tool is needed
Synthesizer node (llm handler) composes the final response from the planner output and optional tool results
Node Handlers:
planner: llm handlertool_executor: custom handlersynthesizer: llm handler
Initialize:
yagra init --template tool-use --output my-tool-use-workflow
Generated Files:
workflow.yaml: planner → [use_tool] tool_executor → synthesizer → finish / [direct] synthesizer → finishprompts/tool_use_prompts.yaml: Planner and synthesizer prompts
Customize:
Implement
tool_executorhandler with your external tool or API callAdjust planner prompt to describe available tools and decision criteria
Extend
synthesizerprompt to incorporate tool results into the final answer
multi-agent: Orchestrator → Researcher ⇄ Writer¶
Pattern: Orchestrate → Research → Write (with retry loop)
Use Case: Orchestrator, researcher, and writer agents collaborate to process a task, with the researcher retrying until the writer is satisfied
Structure:
Orchestrator node delegates the task to the researcher
Researcher node gathers information and passes results to the writer
Writer node evaluates the research; loops back to researcher if more information is needed, or exits to finish when done
Node Handlers:
orchestrator: llm handlerresearcher: llm handler (retry loop)writer: llm handler
Initialize:
yagra init --template multi-agent --output my-multi-agent-workflow
Generated Files:
workflow.yaml: orchestrator → researcher ⇄ [retry/done] writer → finishprompts/multi_agent_prompts.yaml: Orchestrator, researcher, and writer prompts
Customize:
Implement domain-specific research logic in
researcherhandlerSet acceptance criteria and
max_iterationsinwriterparamsAdjust orchestrator prompt to decompose tasks appropriate for your domain
human-review: Generator → Human Review → Publisher¶
Pattern: Generate → Human Approval → Publish
Use Case: HITL (Human-in-the-Loop) pattern where a human must review and approve generated content before it is published
Structure:
Generator node produces content
Workflow interrupts before publisher node via
interrupt_beforefield, pausing execution for human reviewAfter human approval, execution resumes with
resume()and the publisher node finalises the output
Initialize:
yagra init --template human-review --output my-human-review-workflow
Generated Files:
workflow.yaml: generator → publisher (interrupt_before)prompts/human_review_prompts.yaml: Generator prompt
Customize:
Implement
generatorhandler to produce content for reviewImplement
publisherhandler to finalise and deliver approved contentUse
interrupt_beforeinworkflow.yamlto specify which node triggers the human pauseCall
app.resume(state)in your application code to continue after human approval
parallel: Parallel Fan-Out / Fan-In (Map-Reduce)¶
Pattern: Prepare → [Fan-Out] → Process Each Item → Aggregate
Use Case: Process multiple items in parallel and aggregate results (map-reduce pattern)
Structure:
Prepare node sets a list of items in state
fan_outedge dispatches each item as a separate parallel execution via LangGraph’s Send APIProcess node runs concurrently for each item
Aggregate node collects all results (using
reducer: add)
Initialize:
yagra init --template parallel --output my-parallel-workflow
Generated Files:
workflow.yaml: prepare → process_item (fan-out) → aggregate
Key YAML Features:
state_schema:
items:
type: list
results:
type: list
reducer: add # Merges outputs from parallel nodes (fan-in)
edges:
- source: "prepare"
target: "process_item"
fan_out:
items_key: items # State key containing the list to fan out
item_key: item # Key passed to each parallel invocation
Customize:
Implement
prepare_handlerto populatestate["items"]with your dataImplement
process_handlerto process eachstate["item"]and return{"results": [result]}Implement
aggregate_handlerto combine allstate["results"]
subgraph: Nested Sub-Workflow¶
Pattern: Main Step → Sub-Workflow → Finalize
Use Case: Compose complex multi-agent systems by nesting YAML workflows as subgraphs
Structure:
Parent workflow delegates a step to a separate workflow YAML
The subgraph runs as a standalone LangGraph node within the parent
State flows between parent and subgraph via shared keys
Initialize:
yagra init --template subgraph --output my-subgraph-workflow
Generated Files:
workflow.yaml: main_step → sub_agent (subgraph) → finalizesub_workflow.yaml: The nested sub-workflow
Key YAML Features:
nodes:
- id: "sub_agent"
handler: "subgraph" # Built-in handler name
params:
workflow_ref: ./sub_workflow.yaml # Relative path to sub-workflow
Customize:
Register all handlers from both
workflow.yamlandsub_workflow.yamlin the same registryDefine shared state keys that the parent and subgraph both read/write
Nest multiple levels by referencing another
workflow_refinsidesub_workflow.yaml
chat: Chat History with MessagesState¶
Pattern: Single-node chat loop using type: messages
Use Case: Conversational AI with persistent chat history via LangGraph’s add_messages reducer
Structure:
Single chatbot node processes messages and appends AI responses
type: messagesinstate_schemaenables automatic message accumulationWorks with LangGraph checkpointer for per-thread session persistence
Initialize:
yagra init --template chat --output my-chat-workflow
Generated Files:
workflow.yaml: chatbot (single-node loop)
Key YAML Features:
state_schema:
messages:
type: messages # Activates add_messages reducer (append mode)
Customize:
Implement
chat_handlerto call an LLM withstate["messages"]and return{"messages": [AIMessage(...)]}Pass a checkpointer to
Yagra.from_workflowto persist conversation historyInvoke with
thread_idto maintain separate sessions per user
Using Templates¶
List Available Templates¶
yagra init --list
Output:
Available templates:
- branch
- chat
- human-review
- loop
- multi-agent
- parallel
- rag
- subgraph
- tool-use
Initialize from Template¶
yagra init --template <template_name> --output <directory>
Options:
--template: Template name (required)--output: Output directory (default: current directory)--force: Overwrite existing files
Example:
yagra init --template branch --output my-workflow
cd my-workflow
Validate Generated Workflow¶
After initialization, Yagra automatically validates the generated workflow:
yagra init --template branch --output my-workflow
Output:
Template 'branch' initialized at: /path/to/my-workflow
Validating workflow: /path/to/my-workflow/workflow.yaml
✓ workflow is valid.
If validation fails, errors are displayed for you to fix.
Run Generated Workflow¶
Templates generate ready-to-run workflows. You just need to implement handlers:
from typing import TypedDict
from yagra import Yagra
class AgentState(TypedDict, total=False):
query: str
intent: str
answer: str
__next__: str
def classify_intent(state: AgentState, params: dict) -> dict:
# Implement your classification logic
intent = "faq" if "pricing" in state.get("query", "") else "general"
return {"intent": intent, "__next__": intent}
def answer_faq(state: AgentState, params: dict) -> dict:
# Use params["prompt"] and params["model"]
return {"answer": "FAQ answer"}
def answer_general(state: AgentState, params: dict) -> dict:
return {"answer": "General answer"}
def finish(state: AgentState, params: dict) -> dict:
return {"answer": state.get("answer", "")}
registry = {
"classify_intent": classify_intent,
"answer_faq": answer_faq,
"answer_general": answer_general,
"finish": finish,
}
app = Yagra.from_workflow(
workflow_path="my-workflow/workflow.yaml",
registry=registry,
state_schema=AgentState,
)
result = app.invoke({"query": "What's the pricing?"})
print(result["answer"])
Extending Templates¶
Templates are starting points. Extend them for your use case:
Add Nodes¶
Edit workflow.yaml:
nodes:
# ... existing nodes ...
- id: "new_node"
handler: "new_handler"
params:
prompt_ref: "../prompts/new_prompts.yaml#new"
Register the handler:
def new_handler(state: AgentState, params: dict) -> dict:
# Your logic
return {"result": "value"}
registry["new_handler"] = new_handler
Add Branches¶
Add conditional edges in workflow.yaml:
edges:
# ... existing edges ...
- source: "classifier"
target: "new_node"
condition: "new_intent"
Update classifier to return new condition:
def classify_intent(state: AgentState, params: dict) -> dict:
if "keyword" in state["query"]:
return {"intent": "new_intent", "__next__": "new_intent"}
# ... existing logic ...
Combine Templates¶
Mix patterns from multiple templates:
Initialize from one template (e.g.,
branch)Add loop logic from
looptemplateIntegrate retrieval step from
ragtemplate
Template Design Principles¶
Yagra templates follow these principles:
Minimal but complete: Templates are fully functional out of the box
Clear separation: Workflow YAML + prompt YAML, no inline prompts
Best practices: Use
prompt_ref, inline model config, validation-readyDomain-agnostic: Templates use generic placeholders (adjust for your domain)
Creating Custom Templates¶
Want to contribute a new template? See Contributing for guidelines.
Template requirements:
Must include
workflow.yamlandprompts/<template>_prompts.yamlMust pass
yagra validatewithout errorsShould demonstrate a common pattern (not overly specific)
Should include clear documentation