The Design of Everyday AI Agents


My three-year-old son wants to help with everything in the kitchen: stirring, pouring, and above all, cutting. Perched on his helper tower, he watches me chop fruit and reaches for my knife. I could hand him my chef’s knife and hover constantly, yanking his hand back, shouting “careful!” Or I could hand him a kid-safe knife—a serrated nylon blade that cuts a banana but not a finger—and let him go. You can guess which choice I prefer.

But here’s the thing: the kid-safe knife isn’t a lesser knife; it’s a better-designed knife for his context. It has the same core capability (it cuts food), but it embodies constraints that make the dangerous outcomes nearly impossible. My son doesn’t need me hovering, and he doesn’t need knife safety lessons. He just cuts the banana without the risk that makes learning catastrophic. And along the way, he learns motor patterns, cause and effect, and the satisfaction of contributing.

I keep thinking about this because so many software engineering teams using AI coding agents are stuck in hovering mode. They’re handing a powerful, unconstrained tool to the agent and then reviewing every output, catching problems through vigilance, and writing increasingly longer prompt instructions that the agent may or may not follow.

There’s a better approach: encode constraints into the development environment. Matt Holden calls it guardrail coding. Mitchell Hashimoto calls it harness engineering. Two recent posts, one from OpenAI describing a team that shipped a product with zero manually-written code and one from Anthropic on getting agents to work across many context windows, use the same term. They all converge on the same insight: in an agent-first world, designing the environment is the engineering.

This idea has a longer history than most engineers realize. Don Norman’s 1988 book The Design of Everyday Things ostensibly wrote about door handles and stove knobs, but actually explained why people fail when using well-intentioned systems. His answer was that the fault almost always lies in the design of the environment, not the behavior of the user. Norman’s framework describes what agent engineering teams are learning, and it predicts which strategies compound and which ones decay. But it also raises a question Norman couldn’t have anticipated: what happens when the agent outgrows the environment you designed for it?

The challenge agents create

Norman talks about two “gulfs” separating users from their goals. The gulf of execution is the distance between what you want to do and how difficult it is to do it. The gulf of evaluation is the distance between what happened and how easily you can tell whether it worked. Vibe coding collapses the gulf of execution almost entirely, but it simultaneously widens the gulf of evaluation. You describe your intent in a prompt and code appears. The resulting dashboard looks right. But are you certain it’s secure, maintainable, or robust against edge cases? The system gives you little help finding out. This is my toddler with a chef’s knife: he can cut things, but has no way to assess whether he’s about to cut himself. I can hover—which works until I blink.

Most teams respond by adding more guidance. They write longer instruction files and more detailed custom rules. While this feels productive, there’s a deeper reason it often doesn’t reliably work: prompting doesn’t encode knowledge in the environment. An ETH Zurich study of agentfiles even found that LLM-generated ones actively hurt performance.

As Norman puts it, well-designed systems hold “knowledge in the world” (e.g., a key encodes the information to open a lock, painted lines in a parking lot encode where to park) rather than requiring users to keep knowledge in their heads. Prompt constraints are “knowledge in the head”: they live in a context window, compete for finite attention, break across model versions, and are invisible to anyone who wasn’t there when they were written. A lint rule, by contrast, exists in the codebase, runs the same way every time, and is discoverable by any new engineer or agent. It survives team turnover, model upgrades, and the gradual decay of institutional memory.

This will sound familiar to the best engineering teams. Scalable engineering organizations encode their most important standards structurally rather than relying on developer judgment alone. Type systems and CI pipelines are “knowledge in the world” strategies that predate AI agents entirely. What agents change isn’t the principle; it’s the urgency. When your teammate is an agent cycling through context windows with no memory between sessions, structural encoding stops being a “best practice you’ll get to eventually” and becomes a “prerequisite for functioning at all.”

But even teams that understand this principle can misjudge the execution. OpenAI tried the “one big AGENTS.md” approach, cramming all guidance into a single instruction file. It failed in ways Norman would have predicted. The monolithic file crowded out the actual task, rotted as soon as anyone stopped maintaining it, and couldn’t be mechanically verified. They said it best: “when everything is ‘important,’ nothing is.” Their fix was a short AGENTS.md (~100 lines) that acts as a signpost, pointing the agent to structured documentation, design specs, and architectural plans stored as versioned artifacts in the repo, without containing all of the knowledge itself. The knowledge moved from the agent’s head to the codebase.

Anthropic discovered the same principle through a different problem entirely. Their agents, working across multiple context windows, would lose track of what had already been built. Each new session started with no memory of the previous one. Imagine a software project staffed by engineers working in shifts, where each new engineer arrives with no idea what happened on the previous shift. The solution was a claude-progress.txt file and structured git history that encoded project state into the environment itself. The knowledge didn’t live in any single agent’s context. It lived in the world, waiting for the next agent to read it.

The constraint spectrum

I should be clear about where the kid-safe knife analogy is precise and where it stretches. A kid-safe knife makes the bad outcome impossible. My son literally can’t cut himself with it. A linter that catches a raw hex color and sends an error back to the agent is doing something different. While the linter quickly caught and corrected an error, the agent did still write bad code. That’s less like a safe knife and more like bowling bumper lanes—the ball can head for the gutter but gets redirected. So there’s a spectrum of how effectively a constraint can limit behavior:

  • Impossible by design: the failure mode can’t happen, or is so structurally unlikely that it requires deliberate effort to produce. The kid-safe knife.
  • Caught immediately: the bad action is attempted but caught in milliseconds (e.g. linters, pre-commit hooks, type checks).
  • Caught eventually: faulty code exists for minutes or hours before feedback arrives (e.g. CI pipelines, security scans on PR, or end-to-end test suites).
  • Hoped for: guidance with no structural barriers. This is what prompting alone amounts to: the hovering parent. Try asking your toddler, “please don’t eat that.” You’ll find out how well that one works.

Every constraint decision a team makes is a choice about where on this spectrum to operate. Even the best teams I’ve seen often start toward the bottom of this spectrum and learn, sometimes painfully, to push their most important constraints toward the top. In fact, as engineering leaders begin to describe a near-future of multi-agent coordination at scale (i.e. many agents working toward a big goal, with a single orchestrator agent summarizing and coordinating the rest so the human interface stays manageable), the constraint spectrum not only applies between human and agent, but also between agents at every layer of the hierarchy. The environmental constraints become the only reliable communication channel between human intent and agent behavior across multiple layers of delegation.

There’s also a time dimension to this spectrum—one I’ll return to later. The models are climbing the spectrum from below, and the floor is rising. The gap between “hoped for” and “caught immediately” is compressing.

Here’s a practical way to visualize the constraint spectrum:

The Agent Constraint Spectrum

The top two categories matter most in practice: making violations impossible and catching them immediately. Each represents a distinct engineering strategy, and choosing between them is the core design decision of agent-first development.

Constrain the interface: the true kid-safe knife

The hard question is: how do you make the bad outcome not just unlikely, but impossible? A kid-safe knife works because the sharp edge isn’t hidden—it’s absent. For AI agents, the equivalent is controlling what the agent can do, not what it chooses to do. If the agent interacts with your database through a query_users(filters) function and you never expose raw database access, SQL injection is impossible because the capability doesn’t exist.

The OpenAI team built their application around a rigid domain model with fixed layers and strictly validated dependency directions, enforced mechanically via custom linters and structural tests. The agent conforms not because it was told to, but because the wrong architectural move doesn’t compile. They noted this is the kind of architecture you’d normally postpone until you have hundreds of engineers. With coding agents, it becomes an early prerequisite: the constraints are what allow speed without decay.

Anthropic’s interface constraints illustrate what “impossible” really means in practice. Their feature list, a structured JSON file marking each feature as passing or failing, is a contract the agent can’t easily rewrite. It can flip a status from failing to passing, but it can’t remove features or redefine “done.” They chose JSON over Markdown because agents are less likely to overwrite structured data. Could the agent mangle the file anyway? Yes. But the format makes accidental edits unlikely and intentional ones immediately detectable. This is the honest reality: “impossible by design” is an asymptote. You get closer by choosing formats and structures that make the wrong action progressively harder and more visible, not by pretending you’ve achieved cryptographic certainty.

Anthropic also leveraged what Norman calls forcing functions: design elements that require correct behavior before the system proceeds. A microwave won’t start until the door is closed. Their agent harness works the same way. Every agent must read the progress file and run a health check before doing anything else. Forcing functions are interface constraints applied to sequence, not just capability.

There’s a parenting version of this too. Anchoring the bookshelf to the wall is an interface constraint: my son can push all he wants and it won’t tip. That’s dramatically better than “hoped for,” which in parenting sounds like “please don’t climb on the furniture.”

Constrain the output: the bumper lane

One level down on the spectrum, the “caught immediately” category, you let the agent write freely but catch violations through automated feedback. This is easier to set up and covers more surface area, but the bad code briefly exists before being corrected.

The OpenAI team’s custom linters are the clearest example. They statically enforce structured logging, naming conventions, file size limits, and platform requirements. Most importantly, their error messages inject remediation instructions directly into agent context. The linter doesn’t just say “wrong.” It says “here’s how to fix it.” This closes Norman’s gulf of evaluation at the exact moment the agent needs guidance.

Anthropic achieved something similar through a different mechanism. Their agents start each session by launching the dev server and running end-to-end tests via browser automation. Before this, agents would make changes and write unit tests but fail to recognize when features didn’t actually work from a user’s perspective. Where OpenAI’s harness focuses on architectural quality and code consistency, Anthropic’s browser testing verifies that features actually behave correctly.

The combination reveals a useful heuristic: constrain the interface for what talks to what; constrain the output for how things are written. Architectural mistakes are expensive to unwind and hard to detect at the surface; implementation mistakes are cheap to fix and easy to lint for. And in a world where agent-generated code exceeds any team’s human review capacity, output constraints aren’t just more efficient than the hovering parent. At sufficient scale, they’re the only option that exists.

The cost question

The OpenAI team had seven engineers whose sole job was designing the agent environment. Anthropic built a specialized two-agent harness with distinct prompts for initialization vs. incremental work. These aren’t weekend projects. But as OpenAI’s Vijaye Raji suggests, if you think of the agent as a 24/7 teammate, then you have to ask yourself what you’d invest to enable that valuable teammate. Seven engineers sounds expensive until you realize they’re the constraint layer for an unlimited number of agent-hours. The question isn’t “can we afford the guardrails?” It’s “can we afford not to have them?”

The spectrum suggests where the investment pays off. Interface constraints are expensive to design but eliminate entire failure categories permanently. Output constraints are cheaper but require ongoing maintenance as the codebase evolves. Prompt-space guidance is cheapest to create and most expensive to maintain, because it fails silently and unpredictably.

Here’s the practical heuristic: push a constraint upward when the cost of the failure it prevents exceeds the cost of building the guardrail. Architectural violations (e.g. wrong dependency directions, missing security boundaries, broken data contracts) often justify interface constraints because they’re catastrophically expensive to fix after the fact. Style violations are fine as linter rules. And some things can remain as documentation, as long as you accept they’ll be followed probabilistically rather than reliably.

The constraint spectrum isn’t just a taxonomy. It’s a direction of travel: prompts become checks; checks become interfaces.

The shelf life of scaffolding

Everything above assumes agents will continue to need guardrails. I want to address the case against that assumption, because serious people are making it.

A year ago, the best coding model ran thirty seconds before going off the rails. Today, the best models run unattended for hours or days. Boris Cherny, who leads Claude Code at Anthropic, hasn’t edited a line of code by hand since November 2025, shipping ten to thirty AI-written PRs a day. While he has guardrails of his own (Claude reviews every PR, with a human review layer above that) his broader argument challenges this essay’s premise. The elaborate constraint systems I’ve been advocating for may be a depreciating asset—scaffolding might improve agent performance twenty percent today, but the next model wipes out those gains. Cherny’s advice: build for the model six months from now, not the model of today.

Cherny is right about the trend and wrong about the tail risk. The floor is rising, and what required an interface constraint last year may need only output constraints this year and guidance alone next year. Any team treating its guardrail architecture as permanent will over-invest and slow down.

But one category of constraint doesn’t depreciate with capability: constraints protecting against the consequences of being wrong, not the probability. A 99.9%-reliable model still produces thousands of violations at millions of operations. If an agent can corrupt a database or leak credentials, the constraint making it impossible—not highly improbable—still earns its keep. Interface constraints that bound what the agent can do will remain valuable long after the models are good enough to follow instructions. The nylon knife isn’t just for toddlers who don’t know how to use a blade; it’s for anyone cutting in a context where a single slip has catastrophic consequences.

The middle of the spectrum, such as linters and output constraints, will become unnecessary as models improve, but the top won’t. The question to ask about any guardrail is not just where it sits on the spectrum, but whether it still matters once the model becomes twice as capable.

Constraints as a living system

Guardrails aren’t set-and-forget. Knowledge in the world goes stale and requires maintenance.

OpenAI’s team learned this the hard way, initially spending every Friday manually cleaning up “AI slop” as patterns drifted, conventions decayed, and guardrails no longer reflected the codebase. That didn’t scale. So they built recurring Codex agents that scan for deviations from their “golden principles” and open targeted refactoring PRs—guardrails for the guardrails. They describe it as garbage collection, and the analogy is precise: technical debt is a high-interest loan better paid down continuously than left to compound.

Anthropic hit a version of the same problem from a different angle. Their agents would mark features as complete without proper end-to-end testing, letting subtle bugs accumulate across sessions. The fix was making testing structural, woven into how the agent operates, rather than optional or suggested. Each session would begin with a health check and end with a commit and progress update. The discipline lived in the session structure, not the agent’s judgment.

Tending the system also means knowing when to remove guardrails. The outlet covers you installed when your child was one year old aren’t the protections you need when they’re four years old and have figured out screwdrivers. Some protections get upgraded; others get retired. A guardrail system is something you tend, which includes pruning.

And every time a check catches something the agent missed, your mental model of its capabilities gets more accurate. That calibrated understanding is itself expertise. Pure vibe coding actively prevents you from developing this.

Designing the transition

Norman’s principles were about the gap between intention and behavior, and the designer’s responsibility to close it. That responsibility now belongs to everyone building AI tools and everyone deciding how their team works with agents. Whether you’re an engineer wondering if a constraint should be a lint rule, a leader wondering if your standards will survive turnover, or a product builder deciding what to make easy—the questions are the same: Is this knowledge in the head, or in the world? Where does it sit on the constraint spectrum? Can you push it higher?

But Norman wrote in a world where the capabilities of the user didn’t change every six months. We don’t have that luxury. The spectrum is real, the direction of travel is real, and the models are climbing it from below. The guardrails you build today may need to come down tomorrow. The skills you build endure.

My son presses the nylon blade down, the banana splits, and he looks up at me with a grin. Right now, he needs the nylon knife. One day, I’ll realize he’s ready for a real one. The point of the scaffold isn’t to teach the skill by itself; it’s to make practice possible without catastrophic mistakes. Along the way, he develops motor patterns, cause and effect, and respect for what a knife does—and I develop the judgment to know when the protection is helping and when it’s starting to hold him back.

The engineers doing the design work of this era—encoding constraints into agent environments, tending those systems, and knowing when to add scaffolding and when to remove it—are navigating a transition, not building a permanent structure. The guardrails are not the point; the competence they enable is.

Thanks to Jean Hsu and Stephen Poletto for thoughtful feedback on drafts of this post.