LangGraph state management patterns. Use when designing workflow state schemas, using TypedDict vs Pydantic, implementing accumulating state with Annotated operators, or managing shared state across nodes.
/plugin marketplace add yonatangross/skillforge-claude-plugin/plugin install skillforge-complete@skillforgeThis skill inherits all available tools. When active, it can use any tool Claude has access to.
checklists/state-checklist.mdreferences/custom-reducers.mdreferences/messages-state.mdreferences/pydantic-state.mdreferences/typeddict-state.mdDesign and manage state schemas for LangGraph workflows.
from typing import TypedDict, Annotated
from operator import add
class WorkflowState(TypedDict):
input: str
output: str
agent_responses: Annotated[list[dict], add] # Accumulates
metadata: dict
from langgraph.graph import MessagesState
from langgraph.graph.message import add_messages
from typing import Annotated
# Option 1: Use built-in MessagesState (recommended)
class AgentState(MessagesState):
"""Extends MessagesState with custom fields."""
user_id: str
context: dict
# Option 2: Define messages manually with add_messages reducer
class CustomState(TypedDict):
messages: Annotated[list, add_messages] # Smart append/update by ID
metadata: dict
Why add_messages matters:
Note:
MessageGraphis deprecated in LangGraph v1.0.0. UseStateGraphwith amessageskey instead.
from pydantic import BaseModel, Field
class WorkflowState(BaseModel):
input: str = Field(description="User input")
output: str = ""
agent_responses: list[dict] = Field(default_factory=list)
def add_response(self, agent: str, result: str):
self.agent_responses.append({"agent": agent, "result": result})
from typing import Annotated
from operator import add
class AnalysisState(TypedDict):
url: str
raw_content: str
# Accumulate agent outputs
findings: Annotated[list[Finding], add]
embeddings: Annotated[list[Embedding], add]
# Control flow
current_agent: str
agents_completed: list[str]
quality_passed: bool
Key Pattern: Annotated[list[T], add]
add: Each node replaces the listadd: Each node appends to the listfrom typing import Annotated
def merge_dicts(a: dict, b: dict) -> dict:
"""Custom reducer that merges dictionaries."""
return {**a, **b}
class State(TypedDict):
config: Annotated[dict, merge_dicts] # Merges updates
def last_value(a, b):
"""Keep only the latest value."""
return b
class State(TypedDict):
status: Annotated[str, last_value] # Overwrites
def node(state: WorkflowState) -> WorkflowState:
"""Return new state, don't mutate in place."""
# Wrong: state["output"] = "result"
# Right:
return {
**state,
"output": "result"
}
| Decision | Recommendation |
|---|---|
| TypedDict vs Pydantic | TypedDict for internal state, Pydantic at boundaries |
| Messages state | Use MessagesState or add_messages reducer |
| Accumulators | Always use Annotated[list, add] for multi-agent |
| Nesting | Keep state flat (easier debugging) |
| Immutability | Return new state, don't mutate |
2026 Guidance: Use TypedDict inside the graph (lightweight, no runtime overhead). Use Pydantic at boundaries (inputs/outputs, user-facing data) for validation.
add reducer (overwrites instead of accumulates)langgraph-routing - Using state for routing decisionslanggraph-checkpoints - State persistencetype-safety-validation - Pydantic patternsKeywords: StateGraph, TypedDict, state schema, define state Solves:
Keywords: channel, Annotated, state channel, MessageChannel Solves:
Keywords: reducer, add_messages, operator.add, accumulate Solves:
Keywords: subgraph, nested graph, parent state, child graph Solves:
Keywords: persist, state persistence, durable state, save state Solves:
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.