跪拜 Guibai
← All articles
Artificial Intelligence

A 200-Line Agent That Builds React Apps Explains How Cursor Actually Works

By BreezeJiang ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Cursor, Copilot, and Devin all run on the same ReAct loop pattern. Seeing it implemented in under 200 lines strips away the magic and exposes the real engineering levers: tool design, context passing, and prompt guardrails. Developers who understand this can debug agent behavior, build custom coding agents, and evaluate tools by their loop architecture rather than by model brand.

Summary

A ReAct loop—LLM reasoning, tool execution, result feedback—drives an autonomous programming agent in fewer than 200 lines of Node.js. The agent creates a Vite React-TS project, writes a complete TodoList with localStorage persistence and styled UI, installs dependencies, and starts the dev server, all without human intervention. The loop itself is a simple for-loop that feeds tool results back into the message history; the LLM never plans globally, only decides the next step from the latest context.

Tool design turns out to be a conversation with the model, not an API contract. Three trade-offs shape reliability: auto-creating directories on write to tolerate the LLM’s coarse path generation, using spawn with stdio inherit for user-visible commands while sacrificing output capture, and tuning tool descriptions to disambiguate similar operations without burning context window.

Comparing the mini-agent to Cursor reveals the same ReAct skeleton, scaled up with hundreds of tools, context compression, diff-level edits, GUI interaction, and persistent memory. The core insight is that Cursor’s strength owes as much to toolchain and context engineering as to model quality.

Takeaways
An AI coding agent is a ReAct loop: LLM thinks, calls a tool, observes the result, and repeats until no tool call is needed.
The loop body is a for-loop under 30 lines that appends each tool result as a ToolMessage back into the conversation history.
Without pushing tool results back into messages, the LLM loses memory of what just happened and often repeats the same failing call.
The LLM does not plan the whole task; global intelligence emerges from local, step-by-step decisions informed by accumulated context.
Tool descriptions should be detailed enough to prevent the model from confusing similar tools (read_file vs. list_directory) but short enough to avoid wasting context tokens.
Auto-creating parent directories on file write tolerates the LLM’s tendency to generate nested paths without checking directory existence first.
Using spawn with stdio: 'inherit' gives users real-time command output but sacrifices the ability to parse that output for agent decision-making.
System prompts should explicitly list available tools and call out high-frequency error patterns, such as combining a workingDirectory parameter with a cd command.
A temperature of 0 improves determinism for code generation and tool calling; creativity introduces wrong tool names and malformed parameters.
Cursor’s advantage over a mini-agent comes from engineering increments—hundreds of tools, context compression, diff edits, and persistent memory—not from a fundamentally different architecture.
Conclusions

The ReAct pattern shifts complexity from the model to the environment: the message history and tool results carry the state, so the model only needs to make one good local decision at a time.

Tool design for agents is closer to UX writing than to API design. You are anticipating where the LLM will hesitate and preemptively clarifying the path.

Cursor’s perceived intelligence is often misattributed to model quality; toolchain design and context management are equally decisive and more directly engineerable.

Writing explicit counter-examples in the system prompt—showing both wrong and right tool usage—is a cheap, high-leverage way to prevent known failure modes.

Concepts & terms
ReAct (Reasoning + Acting)
An agent pattern from 2022 where a language model alternates between reasoning about the next step and acting via tool calls, with tool results fed back as context for the next reasoning step.
ToolMessage
In LangChain and similar frameworks, a message type that carries the result of a tool execution back into the conversation history so the LLM can incorporate that result in its next inference.
bindTools
A LangChain method that converts tool definitions (name, description, Zod schema) into an OpenAI-compatible function-calling format and attaches them to a chat model, enabling the model to request tool invocations.
stdio: 'inherit'
A Node.js child_process.spawn option that pipes the child process’s stdout/stderr directly to the parent’s terminal, giving real-time output but preventing the parent from capturing that output programmatically.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗