Loading repository data…
Loading repository data…
naoufalelh / repository
A Cursor-optimized starter template for building AI agents with LangGraph.js (used for workshops).
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
A Cursor-optimized starter template for building AI agents with LangGraph.js. This project provides a structured foundation with pre-configured Cursor rules and commands to accelerate your development.
langgraph.jsoncursor-langgraph-starter/
├── .cursor/
│ ├── rules/ # Cursor AI rules
│ │ ├── langgraph-expert.mdc # LangGraph patterns & best practices
│ │ ├── typescript-standards.mdc
│ │ ├── project-structure.mdc
│ │ ├── testing.mdc
│ │ └── evals.mdc # Evaluation guidelines
│ └── commands/ # Cursor slash commands
│ ├── add-tool.md # /add-tool
│ ├── add-node.md # /add-node
│ ├── add-subgraph.md # /add-subgraph
│ ├── add-eval.md # /add-eval
│ ├── run-evals.md # /run-evals
│ ├── debug-graph.md # /debug-graph
│ └── human-in-the-loop.md # /human-in-the-loop
├── src/
│ ├── state/ # State annotations
│ │ └── index.ts
│ ├── nodes/ # Graph nodes
│ │ ├── agent.ts # LLM calling node
│ │ └── tools.ts # Tool execution node
│ ├── edges/ # Routing logic
│ │ └── router.ts
│ ├── tools/ # Agent tools
│ │ └── index.ts
│ ├── workflows/ # Graph composition
│ │ └── agent.ts
│ ├── evals/ # LangSmith evaluations
│ │ ├── evaluators.ts # Custom evaluator functions
│ │ ├── create-dataset.ts # Dataset creation script
│ │ └── run.ts # Evaluation runner
│ ├── examples/ # Usage examples
│ │ ├── streaming.ts # Streaming modes demo
│ │ ├── server.ts # HTTP server with SSE
│ │ ├── create-agent.ts # LangChain v1 createAgent
│ │ └── interrupts.ts # Human-in-the-loop
│ └── index.ts # Entry point
├── tests/
│ └── workflow.test.ts
├── langgraph.json # LangGraph Studio config
├── eslint.config.js # ESLint flat config
├── .prettierrc # Prettier config
├── package.json
├── tsconfig.json
└── vitest.config.ts
# Clone the repository
git clone https://github.com/naoufalelh/cursor-langgraph-starter.git
cd cursor-langgraph-starter
# Install dependencies
pnpm install
# Set up environment variables
cp env.example .env
# Edit .env and add your OPENAI_API_KEY
# Development mode with hot reload
pnpm dev
# Or build and run
pnpm build
pnpm start
pnpm test
This project is designed to work seamlessly with Cursor.
Cursor rules provide context-aware AI assistance. When you open this project in Cursor, the AI automatically understands:
Rules are in .cursor/rules/ and are applied based on file patterns.
Use slash commands in Cursor Chat for common tasks:
| Command | Description |
|---|---|
/add-tool | Create a new tool for the agent |
/add-node | Add a new node to the workflow |
/add-subgraph | Create a modular subgraph |
/add-eval | Create a new evaluator |
/run-evals | Run evaluation suite |
/debug-graph | Debug workflow execution |
/human-in-the-loop | Add approval checkpoints |
State is defined using Annotations. The AgentState extends MessagesAnnotation for chat history:
import { Annotation, MessagesAnnotation } from "@langchain/langgraph";
export const AgentState = Annotation.Root({
...MessagesAnnotation.spec,
// Add custom fields here
});
Nodes are async functions that receive state and return partial updates:
const myNode = async (state) => {
return { messages: [response] }; // Partial update
};
Conditional edges route based on state:
const shouldContinue = (state) => {
if (state.messages.at(-1)?.tool_calls?.length) {
return "tools";
}
return END;
};
Compose nodes and edges into a graph:
const workflow = new StateGraph(AgentState)
.addNode("agent", callModel)
.addNode("tools", toolNode)
.addEdge(START, "agent")
.addConditionalEdges("agent", shouldContinue)
.addEdge("tools", "agent");
export const graph = workflow.compile();
src/tools/src/tools/index.tssrc/nodes/workflow.addNode("name", myNode)The project includes MemorySaver for conversation memory:
const result = await graph.invoke(
{ messages: [new HumanMessage("Hello")] },
{ configurable: { thread_id: "user-123" } }
);
This project includes a LangSmith-based evaluation framework for assessing agent performance.
.env:
LANGCHAIN_API_KEY=your-langsmith-api-key
LANGCHAIN_TRACING_V2=true
# Create the evaluation dataset (first time only)
pnpm eval:create-dataset
# Run evaluations
pnpm eval
| Evaluator | What it Measures |
|---|---|
helpfulness | Response has meaningful content |
tool_usage | Tools used when appropriate |
response_length | Within acceptable bounds |
correct_tool | Matches expected tool from dataset |
Create evaluators in src/evals/evaluators.ts:
export const myEvaluator = async ({ input, prediction, reference }) => {
const score = /* 0 to 1 */;
return { key: "my_metric", score, comment: "Explanation" };
};
View results at smith.langchain.com.
LangGraph supports multiple streaming modes for real-time output.
pnpm example:streaming
| Mode | Description |
|---|---|
updates | State changes after each node |
values | Full state after each node |
messages | LLM tokens as they're generated |
custom | Custom data from nodes/tools |
// Stream LLM tokens
for await (const [chunk, metadata] of await graph.stream(input, {
streamMode: "messages",
})) {
if (chunk.content) {
process.stdout.write(chunk.content);
}
}
A ready-to-use HTTP server with REST API and Server-Sent Events (SSE) streaming.
pnpm example:server
| Method | Endpoint | Description |
|---|---|---|
| POST | /invoke | Run agent, return final result |
| POST | /stream | Run agent with SSE streaming |
| GET | /health | Health check |
# Regular invocation
curl -X POST http://localhost:3000/invoke \
-H "Content-Type: application/json" \
-d '{"message": "What is 2 + 2?"}'
# Streaming (SSE)
curl -X POST http://localhost:3000/stream \
-H "Content-Type: application/json" \
-d '{"message": "Write a poem about AI"}'
This project is compatible with LangGraph Studio for visual debugging.
The langgraph.json file configures the graph for Studio:
{
"graphs": {
"agent": "./src/workflows/agent.ts:graph"
}
}
The new high-level createAgent API from LangChain v1 simplifies agent creation.
pnpm example:create-agent
import { createAgent } from "langchain";
const agent = createAgent({
model: "openai:gpt-4o-mini",
tools: [searchTool, calculatorTool],
systemPrompt: "You are a helpful assistant.",
});
const result = await agent.invoke({
messages: [{ role: "user", content: "Hello!" }],
});
This replaces the deprecated createReactAgent from @langchain/langgraph/prebuilt.
LangGraph v1 supports typed interrupts for human-in-the-loop workflows.
pnpm example:interrupts
import { interrupt, Command } from "@langchain/langgraph";
const requestApproval = async (state) => {
// Pause execution and wait for human input
const response = interrupt({
task: state.task,
reason: "Requires approval",
});
return { approved: response.approved };
};
// Resume with a Command
await graph.stream(
new Command({ resume: { approved: true } }),
config
);
MIT