Software 3.0: applications built around intent

Most applications still expect people to adapt to the interface. You open a product, find the right screen, pick the right filter, fill in the right form, and move through a workflow someone designed in advance. That works well when the workflow is known and stable.
Many real tasks are not like that. A user often arrives with a goal, not a click:
"Compare these two offers, highlight the risks, and prepare a recommendation for the client."
To handle that well, a system may need to gather data, compare documents, spot what is missing, apply business rules, ask for approval, and present the result in a useful form. That is the direction we call Software 3.0.
Not every product needs a chat. Not every workflow should become autonomous. The shift is more fundamental than that. We move from designing interfaces around individual actions to designing systems around user intent.
Devs 3.0 teaches how to build those systems in practice. This blog is the workshop notebook behind it: what works, what breaks, where models help, and where plain code is still the better choice.
What I mean by Software 3.0
I use Software 3.0 as a practical label for applications where language models and agents become part of the product logic. They do not just generate an answer in a chat window. They help interpret ambiguous input, choose from a limited set of tools, work with application state, and guide a task toward an outcome.
A simple LLM wrapper is not automatically an agentic product. Sending a prompt to a model and rendering the response can be useful, but it is still a conversational interface. The harder engineering starts when the system can retrieve trusted data, call tools, keep track of state across steps, recover from failures, ask for approval before consequential actions, and present the outcome in a task-specific interface.
At that point the question is no longer "where does the user click next?" It becomes "what is the user trying to achieve, what is the system allowed to do, and where must it stop?" That is a harder problem, and a more interesting one.
The three eras of software
Software 1.0: rules written by hand
In Software 1.0, developers write the rules directly. Forms have validation. Endpoints have conditions. Business workflows have explicit branches. If a case is not in the code, the system cannot handle it.
This is still the right approach for many parts of a product. Payments, permissions, accounting, auditing, pricing, and irreversible actions should not depend on a model "doing its best". They need deterministic logic, clear logs, and predictable failure modes. The limit shows up when a user brings an unstructured request, or when the inputs are too varied to capture in a handful of rigid screens.
Software 2.0: models that learn patterns
Software 2.0, a term popularized by Andrej Karpathy, moves part of the logic from hand-written rules into models trained on data. Instead of coding every condition needed to recognize an image, you provide examples and let a model learn the pattern.
That made many once-hard problems practical: image and speech recognition, translation, classification, ranking. The trade-off is real. Learned systems are powerful where rules are hard to write, but they are less transparent, harder to debug, and only as reliable as their data, evaluation, and surrounding design. A model is not a magic replacement for engineering. It is another component with different strengths and different failure modes.
Software 3.0: systems that work with intent
Software 3.0 puts those capabilities inside applications that can reason over language, use tools, access context, and move through a bounded workflow. The important word is bounded. A useful agent should not have unlimited access, unlimited authority, or a vague instruction to "help the user". It should know which tools it may use, which data it may touch, which actions need approval, which decisions belong to deterministic code, what success looks like, and when to ask a human instead of continuing.
The unit of work is no longer a function, an API call, or a screen. It is the user's intent: "help me choose", "prepare a draft", "find the problem", "suggest the next step". The model turns that intent into structured work. The rest of the system keeps that work safe, observable, and useful. This is where the real engineering begins.
Generative UI is not "AI-generated screens"
Generative UI is often described as an interface that appears dynamically around a request. That is useful but incomplete. It should not mean a model emitting arbitrary HTML and hoping the result is usable. It should mean a system that selects, configures, and assembles reliable interface elements around a specific task.
Someone asking for a summary may need a short synthesis, source references, and the open questions. Someone comparing two offers may need a structured table, highlighted differences, risks, and the points that require human approval. Someone preparing a reply to a client may need a draft, the facts behind it, editable assumptions, and a clear approval step before sending.
The interface becomes more adaptive, but the product should not become less intentional. The opposite is true. When an agent can change what the user sees or does, design has to get stricter about states, permissions, fallbacks, error handling, and accountability.
The rule I keep coming back to
A language model is useful where language is ambiguous: interpreting messy requests, extracting structure from documents, comparing options, proposing drafts, helping users explore a complex system. It should not be the final authority on permissions, money, legal commitments, or irreversible state changes. The practical rule:
Let the model interpret ambiguity. Let deterministic code validate, execute, and record consequential actions.
That does not make a product less agentic. It makes it production-ready. Too many "agentic applications" are still chat wrappers with broad tool access and optimistic prompts. They look great in a demo because the happy path is short. The trouble shows up later: when the model picks the wrong tool, when context is incomplete, when an action only partly succeeds, when a user changes their mind halfway through, when the model invents a confident explanation, or when an agent can reach data it should never have had. Autonomy is not the goal. Useful, bounded, observable autonomy is.
What this changes in how we build
Agentic software does not remove engineering discipline. It moves that discipline into new places.
- Deterministic by default. Use models where they add real value and keep everything else plain, predictable code: explicit validation, typed contracts, permission checks, durable workflows, logs, and tests.
- State becomes a first-class problem. One response is easy. A system that remembers context, handles multiple steps, retries safely, recovers from tool failures, and preserves the user's goal is much harder. Agent state, workflow graphs, checkpoints, and observability are what make it tractable.
- Evaluation replaces "it looks right". A successful screenshot says little when outputs vary. We need checks that answer real questions: did the system retrieve the right information, choose an appropriate tool, follow the expected workflow, avoid unsupported claims, and fail safely.
- Security is part of product design. Prompt injection, sensitive-data exposure, excessive permissions, and unsafe tool access are normal risks in systems that combine models with private data and external actions. They have to shape the design from the start, not get bolted on after the agent works.
- The human stays in the system. A production agent should not pretend to be autonomous when a decision carries business, financial, legal, or reputational weight. The best systems make it easy for people to review, correct, approve, and understand what happened.
The goal is not to hand control to a model. It is to build software that helps people move from intent to outcome without giving up engineering responsibility along the way.
What we will write about here
This blog is a working notebook for that practice. Less hype, more implementation. We will write about:
- generative UI and interfaces that assemble around a real task
- stateful agent graphs and how to debug them without guessing
- retrieval, RAG, and knowledge graphs for context agents can rely on
- tool use, permissions, approvals, and human-in-the-loop design
- defenses against prompt injection and the data-security boundaries around agents
- evaluation, observability, and shipping agentic systems in a way you can maintain
Every post should leave you with something practical: an idea worth testing, a pattern worth reusing, a piece of code, or a decision that saves you from a costly mistake.
If you want to build systems like this without guessing, subscribe to the newsletter or jump straight into the Soft 3.0 course and build an agentic application yourself.