An Agent in 100 Lines of Lisp: Why Simplicity Beats Complexity in AI Product Development

• AI Agents, Product Development, Software Architecture, AI Engineering, Simplicity, LLMs

TL;DR

The Elegance of Constraint

When I first encountered the 100-line Lisp agent implementation, my immediate reaction wasn't admiration for the code's cleverness—though it is clever. It was recognition. Recognition of a pattern I've seen play out repeatedly in AI product development: we're building cathedrals when users need garden sheds.

The article walks through a complete agent implementation in Common Lisp that handles tool calling, iterative reasoning, and multi-step problem solving. No LangChain. No complex state machines. No elaborate prompt management systems. Just a straightforward loop that prompts an LLM, parses structured output, executes functions, and feeds results back. The entire thing fits in your head.

This matters because the AI product space has developed a complexity addiction. We've convinced ourselves that sophisticated agent frameworks, elaborate retrieval pipelines, and multi-layered abstractions are prerequisites for shipping useful AI features. The Lisp implementation is a quiet rebuke to that assumption.

What the Code Actually Shows

The implementation demonstrates three core capabilities that define a functional agent:

First, structured interaction with an LLM. The code sends prompts to Claude (via Anthropic's API) and receives responses. There's no magic here—just HTTP requests and JSON parsing. The agent instructs the model to respond in a specific format: either provide a final answer or request a tool call with explicit parameters.

Second, tool execution. When the model requests a tool (like a calculator or search function), the agent parses that request, executes the corresponding Lisp function, and captures the result. The tool definitions are simple function mappings. Need a new capability? Add a function. That's it.

Third, iterative reasoning. The agent maintains conversation history, allowing the model to build on previous responses and tool results. Each iteration adds context. The loop continues until the model provides a final answer or hits a maximum iteration limit.

What's conspicuously absent? Vector databases. Semantic caching layers. Prompt template inheritance hierarchies. Observability frameworks. The entire constellation of tooling that's become standard in production AI systems.

My Take: Complexity as Product Debt

Here's what I think we get wrong as AI product builders: we treat architectural complexity as a feature rather than a liability. Every abstraction layer, every framework dependency, every "enterprise-ready" component adds cognitive overhead for your team and potential failure modes for your users.

I'm not arguing that production AI products should literally be 100 lines of Lisp. That's not the point. The point is that starting with something this simple forces you to justify every piece of complexity you add later. It inverts the default.

In my work building AI products, the pattern is consistent: teams that begin with minimal implementations and add complexity only when directly solving user problems ship faster and iterate more effectively than teams that start with comprehensive frameworks and try to simplify later. The second approach almost never simplifies. Complexity is sticky.

The Lisp agent works because it implements exactly what an agent needs to do and nothing more. When you're designing an AI feature, that's your north star: what's the minimum viable implementation that delivers user value? Everything else is speculation about future requirements that may never materialize.

What Product Builders Should Steal

The Lisp implementation offers several concrete lessons for product development:

Start with Direct API Calls

Before reaching for LangChain, LlamaIndex, or similar frameworks, write direct API calls to your LLM provider. This isn't about avoiding dependencies—it's about understanding what you're actually building. The Lisp code makes plain that agent interactions are fundamentally simple: send text, receive text, parse it, act on it.

When you understand the primitive operations, you can make better decisions about which abstractions actually help. Maybe you do need a framework for prompt management because you're handling dozens of variations. Or maybe you just need a template string and a function. You can't know until you've touched the raw materials.

Design Tools as Pure Functions

The Lisp agent's tool system is brilliantly simple: each tool is a function that takes arguments and returns a result. No special base classes. No registration ceremonies. No tool schemas separate from the code.

This maps beautifully to product thinking. Your AI agent's capabilities should be discrete, testable functions. When a user reports that "the agent got the calculation wrong," you can test the calculator function in isolation. When you want to add a new capability, you write a new function and add it to the tool map. The simplicity enables velocity.

For product builders, this suggests a design principle: keep your agent's capabilities modular and independently testable. Don't embed tool logic deep in framework abstractions where it becomes difficult to modify or debug.

Embrace Visible State

The Lisp implementation maintains conversation history as a simple list of messages. You can print it. You can inspect it. You can modify it. This transparency is a feature, not a limitation.

In production AI products, invisible state is a persistent source of confusion and bugs. Users report unexpected behavior. Engineers can't reproduce issues because they don't know what context the agent was operating with. The more visible you make your agent's state—what it knows, what it's tried, what tools it's used—the faster you can diagnose problems and the better you can explain agent behavior to users.

Consider building admin interfaces that expose agent state directly. Let your team see the actual prompt sent to the model, the raw response received, and the tool execution results. This operational visibility is worth far more than elaborate monitoring dashboards that aggregate away the details.

Limit Iteration Depth

The Lisp agent includes a maximum iteration count to prevent infinite loops. This is product wisdom disguised as technical necessity. Agent loops need bounds.

In production, unbounded agent loops create two problems: runaway costs and user confusion. If your agent can iterate indefinitely, you'll eventually hit a case where it does, burning through API credits while the user waits. Even when it doesn't infinite loop, agents that take many iterations often produce worse results than agents that reach conclusions quickly—more iterations mean more opportunities for the model to drift off course.

Set explicit limits. If your agent can't solve a problem in five iterations, it probably won't solve it in fifty. Fail fast, provide useful error messages, and let users rephrase their request.

Where Complexity Belongs

None of this means complexity is always wrong. Production AI products often need capabilities the 100-line Lisp agent doesn't provide:

Robust error handling. The Lisp code assumes happy paths. Production systems need to handle API failures, malformed model responses, and tool execution errors gracefully. This complexity is justified—it directly improves user experience.

Observability. You need to know when your agent fails, why it fails, and what it was trying to do. Structured logging, metrics, and tracing add complexity but enable you to operate the system reliably.

Security and access control. If your agent can execute tools that touch user data or external systems, you need authentication, authorization, and audit logging. This complexity is non-negotiable for any serious product.

Optimization for cost and latency. Caching, prompt compression, and streaming responses can significantly improve user experience and unit economics. But implement these only after you've validated that the basic agent provides value.

The key is sequencing. Build the simple version first. Validate that it solves a real problem for users. Then add complexity in service of specific, measured improvements. The Lisp implementation is valuable not because it's production-ready but because it establishes a baseline: this is how simple an agent can be. Everything you add beyond this should have a clear justification.

The Broader Pattern

The 100-line Lisp agent is part of a broader movement toward simplicity in AI development. We're seeing similar patterns across the space:

Smaller, specialized models often outperform larger general-purpose models for specific tasks. A fine-tuned GPT-3.5 can beat GPT-4 on domain-specific problems while being faster and cheaper.

Simpler retrieval strategies like BM25 or TF-IDF sometimes match or exceed complex vector similarity approaches, especially when you have clean, well-structured data.

Direct prompt engineering frequently delivers better results than elaborate prompt chaining systems. A well-crafted single prompt often beats a complex multi-step pipeline.

The pattern is consistent: start simple, measure rigorously, add complexity only when it demonstrably improves outcomes. This is harder than it sounds because simple approaches feel unsophisticated. They don't make for impressive architecture diagrams. They don't showcase your team's technical prowess.

But they ship. They iterate. They let you learn what actually matters to users.

Building Your Own Simple Agent

If you're building an AI product and feeling overwhelmed by the complexity of modern agent frameworks, try this:

Week one: Build the dumbest possible version. Single prompt to an LLM. Parse the response. Show it to users. No tools, no iteration, no fancy features. Just the core interaction.

Week two: Add one tool that solves a specific user problem. Maybe it's looking up data in your database. Maybe it's performing a calculation. Keep the tool implementation as a simple function.

Week three: Add iteration. Let the agent call its tool, see the result, and respond again. Limit it to three iterations.

Week four: Instrument everything. Add logging so you can see what prompts produce what responses. Track which tools get called and when.

At this point, you have a functioning agent. It's simple. It's debuggable. It's fast to modify. More importantly, you have real usage data. You know what users are trying to do, where the agent succeeds, and where it fails.

Now you can make informed decisions about complexity. Do you need better prompt management? The data will tell you. Do you need more sophisticated tool selection? You'll see it in the logs. Do you need retrieval augmentation? User requests will make it obvious.

The Strategic Advantage of Simplicity

The real lesson from the 100-line Lisp agent isn't technical—it's strategic. In a fast-moving space like AI, the ability to iterate quickly is your primary competitive advantage. Simple architectures iterate faster than complex ones.

When OpenAI releases a new model, how quickly can you test it? When you discover a prompt that works better, how fast can you deploy it? When users request a new capability, what's your time from idea to production?

If your agent is built on a complex framework with multiple abstraction layers, these changes take longer. You need to understand how your modifications interact with the framework. You need to test edge cases in the abstraction. You need to ensure backward compatibility with existing features.

If your agent is fundamentally simple—a loop that prompts a model, parses responses, and executes tools—you can make changes confidently. The surface area is small. The behavior is predictable. You can move fast.

This compounds over time. The team with a simple architecture ships ten improvements while the team with a complex architecture ships three. The simple team learns faster, adapts faster, and ultimately builds a better product.

Conclusion: Complexity as a Last Resort

The 100-line Lisp agent is a thought experiment with practical implications. It demonstrates that the core functionality of an AI agent—reasoning, tool use, iterative problem-solving—doesn't require elaborate architecture. It can be simple, transparent, and effective.

For product builders, this is liberating. You don't need to master complex frameworks before shipping AI features. You don't need to implement sophisticated architectures before validating product-market fit. You can start simple, learn fast, and add complexity only where it creates measurable value.

The best AI products aren't the ones with the most impressive technical architecture. They're the ones that solve user problems effectively and iterate faster than the competition. Simplicity enables both.

So before you reach for the next framework, the next abstraction layer, the next architectural pattern, ask yourself: could I build this in 100 lines? If not, why not? What complexity am I adding, and what specific user value does it enable?

More often than not, you'll find that the simple version is enough. And when it's not, you'll know exactly what complexity you need to add and why. That clarity is worth more than any framework.

Frequently Asked Questions

Do I really need to learn Lisp to build simple AI agents?

No, the Lisp implementation is illustrative, not prescriptive. The core lesson—that agents can be built with simple loops that prompt LLMs, parse responses, and execute tools—applies regardless of language. You can implement the same pattern in Python, JavaScript, or any language with HTTP client capabilities. The value is in understanding the minimal architecture, not the specific language.

When should I use a framework like LangChain instead of building from scratch?

Use frameworks when you've validated your core agent functionality and identified specific repetitive patterns that a framework handles better than custom code. Good candidates include: managing dozens of prompt variations, implementing complex retrieval strategies across multiple data sources, or requiring deep integrations with specific LLM providers. Start simple first, then adopt frameworks to solve proven problems, not anticipated ones.

How do I prevent my simple agent from becoming too complex over time?

Establish a complexity budget: for every new abstraction or dependency you add, require a documented justification tied to specific user value or operational requirements. Regularly review your codebase and remove features that aren't being used. Most importantly, keep your core agent loop—the prompt/parse/execute cycle—as simple and visible as possible, even as you add peripheral complexity around error handling, observability, or optimization.

Can a simple 100-line agent architecture actually work in production?

The 100-line implementation itself isn't production-ready, but the architectural pattern absolutely scales to production. You'll need to add error handling, observability, security, and optimization, but these can be added around a simple core loop. Many successful production AI agents maintain this basic architecture: a straightforward iteration loop with well-defined tools, augmented with the operational capabilities needed for reliability and scale.