A Single Missing Curly Brace Broke a 200-Line AI Coding Agent for Two Hours
LangChain's `tool()` wrapper silently passes arguments as a single object matching the Zod schema, and a non-destructured parameter swallows that object whole. The resulting runtime errors are opaque because the function signature looks correct at a glance. Anyone wiring LLM tool calls to filesystem or shell operations will hit this exact footgun.
A minimal AI coding agent — dubbed "mini Cursor" — uses four LangChain tools (read_file, write_file, list_directory, exec_command) inside a ReAct loop to create a Vite + React TypeScript project, write a full TodoList with localStorage persistence and CSS animations, install dependencies, and start the dev server, all without human intervention. The entire agent fits in under 200 lines of JavaScript.
The build was derailed by a single-character mistake: writing `async (filePath)` instead of `async ({filePath})` in the tool definition. LangChain's `tool.invoke()` passes arguments as an object matching the Zod schema, so a non-destructured parameter receives the whole object rather than the string value. The resulting `fs.readFile` call received `{ filePath: "src/tool.mjs" }` instead of a path string, producing cryptic errors that took two hours to trace.
The System Prompt carries operational weight that code alone cannot. Explicit rules prevent the LLM from double-nesting `cd` commands inside a `workingDirectory`, from omitting the project-root prefix on file paths, and from starting the dev server before dependencies are installed. These constraints are not enforceable in code — they shape the model's behavior at inference time.
Parameter destructuring errors in LLM-tool plumbing are disproportionately expensive to debug because the stack trace points at the filesystem call, not at the mismatch between `invoke`'s output shape and the function signature.
System Prompts function as a runtime policy layer that compensates for what static tool schemas cannot express: ordering constraints, path conventions, and anti-patterns the model would otherwise generate confidently.
The agent's architecture mirrors production tools like Cursor and Claude Code — a thin ReAct loop over bound tools — suggesting that the gap between a weekend prototype and a commercial coding agent is mostly tool breadth and error handling, not a fundamentally different design.