

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
123456# LangGraph — Copilot Instructions78> Applied automatically when working with LangGraph graph files, state definitions, and Python workflow modules. Loaded alongside copilot-instructions.md.910---1112## StateGraph Construction1314Always define state as a `TypedDict` with field-level `Annotated` reducers. Use `operator.add` for list fields that accumulate across nodes; use default assignment (`field: str`) for scalar fields that overwrite.1516```python17from typing import TypedDict, Annotated, Sequence18import operator19from langchain_core.messages import BaseMessage2021class AgentState(TypedDict):22 messages: Annotated[Sequence[BaseMessage], operator.add] # Accumulates23 user_id: str # Overwrites24 current_step: str # Overwrites25 error: str | None # Overwrites; None = no error26 context: Annotated[list[str], operator.add] # Accumulates retrieved context27```2829### Graph Construction Pattern3031```python32from langgraph.graph import StateGraph, END3334# Build graph35builder = StateGraph(AgentState)3637# Add nodes38builder.add_node("retrieve", retrieve_node)39builder.add_node("generate", generate_node)40builder.add_node("validate", validate_node)41builder.add_node("human_review", human_review_node)4243# Set entry point44builder.set_entry_point("retrieve")4546# Add fixed edges47builder.add_edge("retrieve", "generate")48builder.add_edge("human_review", "generate")4950# Add conditional edges51builder.add_conditional_edges(52 "generate",53 route_after_generate, # routing function — returns a string key54 {55 "valid": "validate",56 "needs_review": "human_review",57 "error": END,58 }59)6061builder.add_edge("validate", END)6263# Compile with checkpointer64graph = builder.compile(checkpointer=checkpointer)65```6667---6869## Node Function Requirements7071Every node function must:72- Accept the full state dict as input73- Return a **dict** with only the keys it updates (LangGraph merges partial updates)74- Never mutate the input state directly75- Handle exceptions internally and set the `error` field rather than raising7677```python78from typing import Any7980def generate_node(state: AgentState) -> dict[str, Any]:81 """Generate a response based on retrieved context."""82 try:83 response = llm.invoke([84 SystemMessage(content="You are a helpful assistant."),85 HumanMessage(content=state["messages"][-1].content),86 ])87 return {88 "messages": [response], # Appended (Annotated list)89 "current_step": "generated", # Overwrites90 "error": None, # Clear any previous error91 }92 except Exception as exc:93 return {94 "error": str(exc),95 "current_step": "error",96 }97```9899---100101## Edge Types102103| Edge Type | Method | Usage |104|-----------|--------|-------|105| Fixed edge | `add_edge(source, target)` | Always transition from source to target |106| Conditional edge | `add_conditional_edges(source, fn, mapping)` | Route based on state; routing function returns a string key |107| Entry point | `set_entry_point(node)` | First node to execute |108| Conditional entry | `set_conditional_entry_point(fn, mapping)` | Choose starting node based on initial state |109110### Routing Function Pattern111112```python113def route_after_generate(state: AgentState) -> str:114 """Route based on confidence and error state."""115 if state.get("error"):116 return "error"117 last_message = state["messages"][-1]118 if hasattr(last_message, "tool_calls") and last_message.tool_calls:119 return "tools"120 if state.get("requires_human_approval"):121 return "needs_review"122 return "valid"123```124125---126127## MessagesState for Conversation Graphs128129Use `MessagesState` from LangGraph for chat applications — it pre-defines the `messages` field with the correct `add_messages` reducer that handles deduplication by message ID.130131```python132from langgraph.graph import MessagesState133134class ChatState(MessagesState):135 # MessagesState provides: messages: Annotated[list[AnyMessage], add_messages]136 session_id: str137 user_context: dict[str, str]138139# The add_messages reducer automatically handles:140# - Deduplication (updates existing message if same ID)141# - Appending new messages142# - Proper serialization for checkpointing143```144145---146147## Checkpointer Setup148149### SQLite (development and single-instance production)150151```python152from langgraph.checkpoint.sqlite import SqliteSaver153from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver154155# Synchronous156with SqliteSaver.from_conn_string("checkpoints.db") as checkpointer:157 graph = builder.compile(checkpointer=checkpointer)158159# Asynchronous160async with AsyncSqliteSaver.from_conn_string("checkpoints.db") as checkpointer:161 graph = builder.compile(checkpointer=checkpointer)162```163164### Redis (production, multi-instance)165166```python167from langgraph.checkpoint.redis import RedisSaver168from redis import Redis169170redis_client = Redis.from_url(171 url=os.environ["REDIS_URL"], # redis://redis-host:6379/0172 decode_responses=False, # Must be False for LangGraph173 socket_timeout=5,174 socket_connect_timeout=5,175)176177checkpointer = RedisSaver(redis_client)178checkpointer.setup() # Creates required key structures — call once on startup179graph = builder.compile(checkpointer=checkpointer)180```181182### Thread Config — Required for Checkpointing183184```python185# Every invocation that uses checkpointing MUST provide a thread_id186config = {"configurable": {"thread_id": "user-session-abc123"}}187188result = graph.invoke({"messages": [HumanMessage(content="Hello")]}, config=config)189190# Resume from checkpoint (HITL pattern)191graph.invoke(None, config=config) # None input = resume from last checkpoint192```193194---195196## Human-in-the-Loop (HITL)197198### Interrupt Before/After a Node199200```python201# interrupt_before: pause BEFORE executing the named node202graph = builder.compile(203 checkpointer=checkpointer,204 interrupt_before=["human_review"], # Graph pauses before this node runs205 interrupt_after=["generate"], # Graph pauses after this node completes206)207208# Execute until interrupt209result = graph.invoke(210 {"messages": [HumanMessage(content=user_input)]},211 config={"configurable": {"thread_id": thread_id}}212)213214# Inspect state at interrupt point215snapshot = graph.get_state(config={"configurable": {"thread_id": thread_id}})216pending_messages = snapshot.values["messages"]217218# Human updates state and resumes219graph.update_state(220 config={"configurable": {"thread_id": thread_id}},221 values={"human_approved": True, "reviewer_id": "emp_456"},222 as_node="human_review",223)224225# Resume execution — pass None as input to continue from checkpoint226final_result = graph.invoke(None, config={"configurable": {"thread_id": thread_id}})227```228229---230231## Streaming232233### `.stream()` — Node-level events234235```python236for chunk in graph.stream(237 {"messages": [HumanMessage(content="Analyse this document")]},238 config={"configurable": {"thread_id": thread_id}},239 stream_mode="values", # "values" = full state after each node; "updates" = partial update dict240):241 print(chunk)242```243244### `.astream_events()` — Token-level streaming245246```python247async for event in graph.astream_events(248 {"messages": [HumanMessage(content="Summarise")]},249 config={"configurable": {"thread_id": thread_id}},250 version="v2",251):252 if event["event"] == "on_chat_model_stream":253 chunk = event["data"]["chunk"]254 print(chunk.content, end="", flush=True)255 elif event["event"] == "on_chain_end":256 print(f"\n[Node completed: {event['name']}]")257```258259---260261## Subgraph Pattern262263Parent and child graphs must have compatible state schemas. The child graph can only update keys present in the parent state.264265```python266# Child graph state — must be a subset of parent state keys267class SubState(TypedDict):268 messages: Annotated[Sequence[BaseMessage], operator.add]269 sub_result: str270271child_builder = StateGraph(SubState)272child_builder.add_node("sub_process", sub_process_node)273child_builder.set_entry_point("sub_process")274child_builder.add_edge("sub_process", END)275child_graph = child_builder.compile()276277# Add compiled child graph as a node in parent graph278parent_builder.add_node("run_subgraph", child_graph)279parent_builder.add_edge("preprocess", "run_subgraph")280parent_builder.add_edge("run_subgraph", "postprocess")281```282283---284285## LangGraph Studio Integration286287`langgraph.json` at repo root:288289```json290{291 "dependencies": ["."],292 "graphs": {293 "main_graph": "./src/graphs/main.py:graph",294 "research_graph": "./src/graphs/research.py:graph"295 },296 "env": ".env",297 "python_version": "3.12"298}299```300301---302303## LangGraph + AWS Bedrock Claude Integration304305```python306from langchain_aws import ChatBedrock307import boto3308309bedrock_client = boto3.client(310 "bedrock-runtime",311 region_name="eu-west-1",312)313314llm = ChatBedrock(315 model_id="anthropic.claude-3-5-sonnet-20241022-v2:0",316 client=bedrock_client,317 model_kwargs={318 "max_tokens": 4096,319 "temperature": 0.0, # 0.0 for deterministic tool-calling graphs320 "top_p": 0.999,321 },322 streaming=True, # Enable for token-level streaming in astream_events323)324325# Bind tools to the model326llm_with_tools = llm.bind_tools(tools=[search_tool, calculator_tool])327328def agent_node(state: AgentState) -> dict:329 response = llm_with_tools.invoke(state["messages"])330 return {"messages": [response]}331```332333---334335## Common Graph Topologies336337| Topology | Pattern | Use Case |338|----------|---------|---------|339| Linear | A → B → C → END | Simple sequential processing |340| Branching | A → conditional → {B, C} → END | Route based on content/confidence |341| Loop | A → B → conditional → {A (retry), END} | Retry until success or max iterations |342| Supervisor | Supervisor → conditional → {Worker1, Worker2} → Supervisor | Multi-agent orchestration |343| RAG | Retrieve → Grade → conditional → {Generate, Rewrite} | Self-correcting RAG |344345### Loop with Max Iterations Guard346347```python348class LoopState(TypedDict):349 messages: Annotated[Sequence[BaseMessage], operator.add]350 iteration_count: int351352def increment_counter(state: LoopState) -> dict:353 return {"iteration_count": state["iteration_count"] + 1}354355def should_continue(state: LoopState) -> str:356 if state["iteration_count"] >= 5:357 return "max_iterations_reached"358 if is_complete(state):359 return "done"360 return "continue"361```362363---364365## Error Handling in Nodes366367```python368def risky_node(state: AgentState) -> dict[str, Any]:369 try:370 result = external_api_call(state["context"])371 return {"result": result, "error": None}372 except httpx.TimeoutException:373 return {"error": "API timeout after 30s", "current_step": "retry_needed"}374 except httpx.HTTPStatusError as exc:375 if exc.response.status_code == 429:376 return {"error": "rate_limited", "current_step": "backoff_needed"}377 return {"error": f"HTTP {exc.response.status_code}", "current_step": "error"}378```379380---381382## Memory Management383384| Memory Type | Implementation | Scope |385|------------|---------------|-------|386| Short-term (in-conversation) | LangGraph state dict | Single thread/session |387| Cross-session (user profile) | `store` parameter in `compile(store=InMemoryStore())` | Shared across threads by user_id |388| Long-term (document/knowledge) | Tool — vector store search via LangChain retriever | Accessed by any graph node |389390```python391from langgraph.store.memory import InMemoryStore392# In production: use RedisStore or PostgresStore393394store = InMemoryStore()395graph = builder.compile(checkpointer=checkpointer, store=store)396397# In a node — access cross-session memory398def personalized_node(state: AgentState, store: BaseStore) -> dict:399 user_prefs = store.get(("user_preferences",), state["user_id"])400 # ...401```402
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| doubts-suplab/eeik-bootstrap.clinerules/golden-rules.md · 1 | Cline rules | gitsecuritydo-not | 61/100 | today | |
| doubts-suplab/eeik-bootstrap.clinerules/project.md · 1 | Cline rules | teststylegit | 63/100 | today | |
| doubts-suplab/eeik-bootstrap.cursor/rules/architecture.mdc · 1 | Cursor rules | do-not | 52/100 | today | |
| doubts-suplab/eeik-bootstrap.cursor/rules/capabilities.mdc · 1 | Cursor rules | teststylegit | 58/100 | today | |
| doubts-suplab/eeik-bootstrap.cursor/rules/golden-rules.mdc · 1 | Cursor rules | gitsecuritydo-not | 61/100 | today | |
| doubts-suplab/eeik-bootstrap.cursor/rules/python.mdc · 1 | Cursor rules | lint-formatstyletypesapi+1 | 77/100 | today | |
| doubts-suplab/eeik-bootstrap.cursor/rules/security.mdc · 1 | Cursor rules | security | 39/100 | today | |
| doubts-suplab/eeik-bootstrap.github/copilot-instructions.md · 1 | Copilot instructions | lint-formatstyletesting-strategygit+2 | 54/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/a2a-protocol.instructions.md · 1 | Copilot instructions | styleagent-behaviour | 48/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/ai-governance.instructions.md · 1 | Copilot instructions | stylearchdo-notagent-behaviour | 61/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/angular.instructions.md · 1 | Copilot instructions | teststyletypestesting-strategy+4 | 69/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/architecture-governance.instructions.md · 1 | Copilot instructions | testlint-formatstylegit+4 | 65/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/autogen.instructions.md · 1 | Copilot instructions | typessecurityagent-behaviour | 50/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/aws-architecture.instructions.md · 1 | Copilot instructions | styletypessecurityperformance | 58/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/aws-data-ml-ai.instructions.md · 1 | Copilot instructions | deployment | 54/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/cdk-terraform.instructions.md · 1 | Copilot instructions | teststylearchtypes+2 | 96/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/cicd.instructions.md · 1 | Copilot instructions | stylesecuritydeploymentdo-not+1 | 65/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/containerisation.instructions.md · 1 | Copilot instructions | buildstylesecuritydo-not | 77/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/crewai.instructions.md · 1 | Copilot instructions | styleagent-behaviour | 48/100 | today | |
| doubts-suplab/eeik-bootstrap.github/instructions/data-engineering.instructions.md · 1 | Copilot instructions | teststyletypesgit+5 | 69/100 | today |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| HerringtonDarkholme/megarepo.github/copilot-instructions.md · 17 | Copilot instructions | setupbuildtestlint-format+7 | 100/100 | 14 days ago | |
| louislam/uptime-kuma.github/copilot-instructions.md · 90k | Copilot instructions | setupbuildtestlint-format+9 | 100/100 | 14 days ago | |
| chihebnabil/lovable-boilerplate.github/instructions/global.instructions.md · 65 | Copilot instructions | buildlint-formatstylearch+4 | 100/100 | 14 days ago | |
| pytorch/pytorch.github/copilot-instructions.md · 102k | Copilot instructions | setupbuildteststyle+5 | 100/100 | 14 days ago | |
| JCodesMore/ai-website-cloner-template.github/copilot-instructions.md · 32k | Copilot instructions | buildlint-formatstylearch+3 | 97/100 | 7 days ago | |
| bagisto/bagisto.github/copilot-instructions.md · 28k | Copilot instructions | setupbuildteststyle+5 | 97/100 | 14 days ago | |
| hiyouga/LlamaFactory.github/copilot-instructions.md · 74k | Copilot instructions | setupbuildtestlint-format+5 | 97/100 | 13 days ago | |
| darkmatter/nixmac.github/copilot-instructions.md · 25 | Copilot instructions | setupbuildtestlint-format+8 | 96/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/doubts-suplab-eeik-bootstrap-github-instructions-langgraph-instructions)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.