LangGraph State Machine Designer

Converts a workflow description into a LangGraph node/edge graph with typed state, conditional routing, and human-in-the-loop checkpoints.

Tags: langgraph, agents, state-machine, langchain, orchestration

Category: coding

Listing attribution: simplyutils

Before using this resource

Attribution and license labels come from the listing metadata. Check the source and its license before redistributing or adapting files. The listing identifies MIT; confirm it applies to the specific files you need.

Read instructions before adding them to an agent or project. Test a small, non-confidential example and inspect the result. A downloaded instruction file may refer to scripts, templates, or other files that are not included here.

This instruction text matches the linked OpenAgentSkills revision. Its MIT license covers the upstream text; preserve the copyright and permission notice when sharing copies. Source matching does not establish successful operation in every listed application.

OpenAgentSkills MIT license notice

Read the MIT license notice
MIT License

Copyright (c) 2026 OpenAgentSkills Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Source

Repository

LangGraph State Machine Designer

What this skill does

This skill takes a plain-language description of an agentic workflow and designs the corresponding LangGraph state machine: typed state schema, node functions, conditional edges, and checkpoint configuration. It handles the hard parts — state typing, routing logic, error recovery, and human-in-the-loop interrupts.

How to use

Claude Code / Cline

Copy this file to .agents/skills/langgraph-state-machine-designer/SKILL.md in your project root.

Then ask:

  • *"Use the LangGraph State Machine Designer to build a research-then-write workflow."*
  • *"Design a LangGraph agent that routes between a SQL tool and a web search tool."*

Provide:

  • What the agent should do (in plain English)
  • What tools or actions it has available
  • Whether humans need to approve any steps
  • Your LangGraph version (v0.2+ assumed)

Cursor / Codex

Describe the workflow and paste these instructions. Ask for the full graph code.

The Prompt / Instructions for the Agent

When asked to design a LangGraph state machine, produce the following:

Step 1 — Define the TypedDict state

Every LangGraph graph has a single shared state object. Define it as a TypedDict with Annotated fields for lists (so they append rather than overwrite):

from typing import TypedDict, Annotated, Sequence
from langchain_core.messages import BaseMessage
import operator

class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], operator.add]
    # Add task-specific fields:
    query: str
    search_results: list[str]
    draft: str
    approved: bool
    error: str | None

Rules for state design:

  • Use Annotated[list, operator.add] for any field that accumulates over time (messages, results)
  • Use plain types for fields that get overwritten each step (current_step, status)
  • Add an error field to every state — nodes should write errors here instead of raising

Step 2 — Design the nodes

Each node is a function that takes state and returns a partial state update:

def call_model(state: AgentState) -> dict:
    """Main LLM reasoning node."""
    response = llm.invoke(state["messages"])
    return {"messages": [response]}

def run_tool(state: AgentState) -> dict:
    """Execute the tool the model requested."""
    last_message = state["messages"][-1]
    tool_result = execute_tool(last_message.tool_calls[0])
    return {"messages": [ToolMessage(content=tool_result)]}

def handle_error(state: AgentState) -> dict:
    """Graceful error recovery node."""
    return {"messages": [AIMessage(content="I encountered an error. Let me try a different approach.")], "error": None}

Node design rules:

  • Nodes should do ONE thing (single responsibility)
  • Always return a dict — never mutate state directly
  • Catch exceptions inside nodes and write to state["error"]
  • Keep nodes stateless — all context comes from state

Step 3 — Design the edges and routing

from langgraph.graph import StateGraph, END
from langgraph.prebuilt import ToolNode

builder = StateGraph(AgentState)

# Add nodes
builder.add_node("agent", call_model)
builder.add_node("tools", ToolNode(tools))
builder.add_node("error_handler", handle_error)

# Set entry point
builder.set_entry_point("agent")

# Conditional routing
def should_continue(state: AgentState) -> str:
    last = state["messages"][-1]
    if state.get("error"):
        return "error_handler"
    if hasattr(last, "tool_calls") and last.tool_calls:
        return "tools"
    return END

builder.add_conditional_edges("agent", should_continue, {
    "tools": "tools",
    "error_handler": "error_handler",
    END: END
})
builder.add_edge("tools", "agent")
builder.add_edge("error_handler", "agent")

Step 4 — Add human-in-the-loop (if needed)

For workflows requiring human approval before destructive actions:

from langgraph.checkpoint.memory import MemorySaver

# Compile with checkpointer
memory = MemorySaver()
graph = builder.compile(
    checkpointer=memory,
    interrupt_before=["execute_action"]  # pause before this node
)

# Run until interrupt
config = {"configurable": {"thread_id": "thread_001"}}
result = graph.invoke({"messages": [HumanMessage(content=user_query)]}, config)

# Resume after human approval
graph.invoke(None, config)  # continues from checkpoint

Step 5 — Standard graph patterns

Pattern: ReAct agent (reason → act → observe loop)

entry → agent → [tools | END]
              ↑_______|

Pattern: Multi-step pipeline (sequential)

entry → step_1 → step_2 → step_3 → END

Pattern: Supervisor with sub-agents

entry → supervisor → [researcher | writer | reviewer | END]
                   ↑___________________________|

Pattern: Retry with fallback

entry → primary_agent → [success: END | failure: fallback_agent → END]

Step 6 — Output the complete graph

Always produce:

1. Full AgentState TypedDict

2. All node functions with docstrings

3. Complete graph builder with edges

4. Compiled graph with appropriate checkpointer

5. Example invocation with config

Example

Input:

> "Design a LangGraph agent that takes a user question, searches the web, then writes a summarized answer. No human approval needed."

Output:

from typing import TypedDict, Annotated, Sequence
import operator
from langchain_core.messages import BaseMessage, HumanMessage
from langgraph.graph import StateGraph, END
from langgraph.prebuilt import ToolNode

class ResearchState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], operator.add]
    query: str

def research_agent(state: ResearchState) -> dict:
    response = llm_with_tools.invoke(state["messages"])
    return {"messages": [response]}

def should_continue(state: ResearchState) -> str:
    last = state["messages"][-1]
    if hasattr(last, "tool_calls") and last.tool_calls:
        return "search"
    return END

builder = StateGraph(ResearchState)
builder.add_node("agent", research_agent)
builder.add_node("search", ToolNode([web_search_tool]))
builder.set_entry_point("agent")
builder.add_conditional_edges("agent", should_continue, {"search": "search", END: END})
builder.add_edge("search", "agent")

graph = builder.compile()