
Langgraph Code Review
Systematically review LangGraph StateGraph code for state reducers, checkpointing, and async mistakes before shipping agent workflows.
Overview
langgraph-code-review is an agent skill most often used in Ship (also Build integrations) that reviews LangGraph graphs for state, checkpoint, and async anti-patterns with sequenced gates.
Install
npx skills add https://github.com/existential-birds/beagle --skill langgraph-code-reviewWhat is this skill?
- Four sequenced review gates from locate graph code through evidence report
- State schema checks for Annotated reducers on lists, dicts, and messages
- Checkpoint, interrupt, and thread_id tracing against compile and invoke config
- Findings require file paths and line numbers or minimal quoted snippets
- 4 sequenced review gates from locate through evidence report
Adoption & trust: 880 installs on skills.sh; 61 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your LangGraph agent compiles but loses messages, mis-handles interrupts, or overwrites state because reducers and checkpointers were never audited.
Who is it for?
Indie builders shipping LangGraph agents who want checklist-driven review of StateGraph, checkpointing, and async invoke usage.
Skip if: Projects with no LangGraph dependency, or teams needing performance benchmarking instead of structural correctness review.
When should I use this skill?
Reviewing code that uses StateGraph, nodes, edges, checkpointing, or other LangGraph features.
What do I get? / Deliverables
You receive an ordered review with concrete file-and-line findings on reducers, graph wiring, and persistence before merging or deploying the workflow.
- Ordered review report with pass/fail per gate
- Evidence-backed findings with file paths and line numbers
- Flags for missing reducers, checkpoint mismatches, and async anti-patterns
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Canonical shelf is Ship review because the skill is explicitly a structured code review pass with sequenced gates. It audits graph structure, persistence, and evidence-backed findings—the core of pre-release technical review.
Where it fits
Pre-merge PR pass confirming every list field in graph state uses an Annotated reducer.
First compile of a customer-support graph—verify conditional edges and remote timeout defaults.
Production resumes drop context—trace compile checkpointer and invocation config against skill gates.
Add parallel tool nodes and confirm async invoke patterns won't race unreduced message state.
How it compares
LangGraph-specific review gates—not a generic Python linter or a LangChain prompt template pack.
Common Questions / FAQ
Who is langgraph-code-review for?
Solo developers and small teams building LangGraph agents who need structured review of graphs, state schemas, and checkpoint configuration.
When should I use langgraph-code-review?
Use it during Ship review on PRs touching StateGraph; during Build integrations when adding nodes or conditional edges; when debugging resumed threads or interrupt flows in Operate.
Is langgraph-code-review safe to install?
It guides read-only review behavior in the agent; confirm trust via the Security Audits panel on this Prism page before installing skills from unknown repos.
SKILL.md
READMESKILL.md - Langgraph Code Review
# LangGraph Code Review When reviewing LangGraph code, check for these categories of issues. ## Review gates (sequenced) Complete in order. Each step has an objective pass condition before moving on. 1. **Locate graph code** — Search the review scope for `StateGraph`, `compile(`, `invoke`, `ainvoke`, `add_node`, `add_edge`, `add_conditional_edges`. **Pass:** a short list of file paths (or explicit “none in scope” after searching). 2. **Map state schema** — For each graph state type (`TypedDict`, `BaseModel`, etc.), list fields that hold lists, dicts, or messages and whether `Annotated` + reducers (`add_messages`, `operator.add`, …) are present. **Pass:** every such field is either covered by a reducer pattern below or explicitly flagged as intentional overwrite. 3. **Trace persistence** — If interrupts, `thread_id`, or checkpoint APIs appear, follow them to `compile(..., checkpointer=...)` and invocation `config`. **Pass:** behavior matches the interrupt/checkpointer/thread_id guidance below—or you document a concrete mismatch with file:line. 4. **Report with evidence** — For each finding you will deliver, record **file path and line number(s)** (or a minimal quoted snippet). **Pass:** no critical or high-severity issue is stated without that citation. 5. **Run the checklist** — Use the checklist at the end of this skill; each item is **satisfied**, **not applicable** (with reason), or **open** with evidence. **Pass:** no item left silently unchecked. ## Critical Issues ### 1. State Mutation Instead of Return ```python # BAD - mutates state directly def my_node(state: State) -> None: state["messages"].append(new_message) # Mutation! # GOOD - returns partial update def my_node(state: State) -> dict: return {"messages": [new_message]} # Let reducer handle it ``` ### 2. Missing Reducer for List Fields ```python # BAD - no reducer, each node overwrites class State(TypedDict): messages: list # Will be overwritten, not appended! # GOOD - reducer appends class State(TypedDict): messages: Annotated[list, operator.add] # Or use add_messages for chat: messages: Annotated[list, add_messages] ``` ### 3. Wrong Return Type from Conditional Edge ```python # BAD - returns invalid node name def router(state) -> str: return "nonexistent_node" # Runtime error! # GOOD - use Literal type hint for safety def router(state) -> Literal["agent", "tools", "__end__"]: if condition: return "agent" return END # Use constant, not string ``` ### 4. Missing Checkpointer for Interrupts ```python # BAD - interrupt without checkpointer def my_node(state): answer = interrupt("question") # Will fail! return {"answer": answer} graph = builder.compile() # No checkpointer! # GOOD - checkpointer required for interrupts graph = builder.compile(checkpointer=InMemorySaver()) ``` ### 5. Forgetting Thread ID with Checkpointer ```python # BAD - no thread_id graph.invoke({"messages": [...]}) # Error with checkpointer! # GOOD - always provide thread_id config = {"configurable": {"thread_id": "user-123"}} graph.invoke({"messages": [...]}, config) ``` ## State Schema Issues ### 6. Using add_messages Without Message Types ```python # BAD - add_messages expects message-like objects class State(TypedDict): messages: Annotated[list, add_messages] def node(state): return {"messages": ["plain string"]} # May fail! # GOOD - use proper message types or tuples def node(state): return {"messages": [("assistant", "response")]} # Or: [AIMessage(content="response")] ``` ### 7. Returning Full State Instead of Partial ```python # BAD - returns entire state (may reset other fields) def my_n