AI Engineer Europe 2026

The Friction Is Your Judgment

Read the talk

The Friction Is Your Judgment

Agents can produce code faster than teams can understand it. Explicit boundaries, mechanical checks, and focused human review help preserve judgment where speed creates risk.

From a talk by Armin Ronacher and Cristina Poncela Cubeiro

Before you start: Familiarity with pull requests, configuration files, and basic application architecture will help; the TypeScript example requires no agent framework knowledge.

Shipping without friction

A forum post about a security incident acquired an unfortunate social preview. An accidentally deployed configuration change had caused the problem; beneath the incident headline, the company’s marketing image promised: “Ship without friction.” The juxtaposition exposes a practical question for software teams: which obstacles should disappear, and which ones make us stop before a consequential mistake?

A slide shows a social preview with a partially redacted headline about a web app host accidentally enabling a CDN, above an image reading “SHIP WITHOUT FRICTION.”Open full source frame
“Ship without friction” beneath a headline about accidentally enabling a CDN and causing data breaches.

Armin Ronacher approaches that question after two decades in software, much of it in open source, including creating Flask. He jokes that the Python framework is so familiar to models that their output now introduces people to it. After leaving Sentry, he had time to explore Claude Code, write about agentic engineering, and hear from other developers experimenting with it. He then started Earendil with a friend in October.

Cristina Poncela Cubeiro, his colleague at Earendil and previously an engineer at Bending Spoons, comes from the other direction. AI tools predate her software engineering career: they helped her learn the work as well as perform it. Together, their experience building with and on agents has brought substantial gains and disappointments. They present an evolving practice, not a settled solution. Two problems recur: psychologically, why is it so difficult to stop prompting and think; technically, why do agents improve some people’s code and worsen others’? Even the prospect of perfect generated code leaves a question about how much judgment humans would still need to exercise.

0:230:40
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

0:23 · section reference included

When saved time becomes expected output

The shift begins pleasantly. After enough unsuccessful prompts, something clicks: the tools become useful, work becomes more enjoyable, and tasks leave extra time. As adoption spreads, however, that advantage becomes a baseline expectation. Everyone is assumed to have the tools, so everyone is expected to ship faster. The time saved is consumed by additional production, leaving less room for review and deliberation.

Poncela Cubeiro describes two parts of the resulting trap. First, the next prompt has an uncertain payoff: it might finish a feature or add the change that destabilizes the product. That uncertainty encourages another attempt. Second, the volume of visible output makes activity feel like efficiency. The stream of changes crowds out the question of whether this is the right implementation—or even the right work. Once the loop is running, stopping becomes difficult for the person, while the agent may keep exploring files it never needed to read. The human has to retain the agency to interrupt the loop.

The Trap slide says agents produce output fast and lists the reward of shipping, later quality drift, and difficulty stopping once in the flow.Open full source frame
“The Trap”: fast output feels like progress, crowding out reflection.
3:293:42
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

3:29 · section reference included

Production grows faster than responsibility

At team scale, the same shift changes the balance between creating code and reviewing it. When code creation was the constraint, writing and review capacity were more closely matched. Agents amplify each engineer’s production without an equivalent increase in the engineer’s ability to inspect and understand changes. Pull requests accumulate. At the same time, more people participate: marketing staff can submit code, and CEOs who once worked as engineers can return to coding.

The responsibility does not expand as readily. Engineering teams still have to maintain and operate the result, including changes produced by people whose primary roles lie elsewhere. Machines cannot take responsibility for those changes. When the number of producers outgrows the people able to carry that responsibility, reviews are skipped or rubber-stamped. Small pull requests remain desirable, but the amplification pushes in the opposite direction. Ronacher uses a hypothetical 5,000-line pull request to illustrate the mismatch: it demands careful judgment precisely when its size makes disengagement tempting.

5:295:40
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

5:29 · section reference included

Runnable code can conceal an invalid system

When generating code feels cheap, large changes become easy to request. Ronacher connects the resulting behavior to agents’ optimization for immediate progress: write code, run tests, and unblock the task. A configuration reader illustrates the danger. If reading the required file fails, an agent may add defaults so the program can continue. That looks like recovery locally, but the application may now be operating with settings nobody intended.

Consider a TypeScript configuration loader for a required database URL. Catching a failed read and returning a default URL would let subsequent writes proceed against an unintended configuration. A loader that preserves the failure instead makes the missing or invalid configuration visible before those writes begin:

typescript

import { readFile } from "node:fs/promises";

type AppConfig = {
  databaseUrl: string;
};

export async function loadRequiredAppConfig(
  path: string,
): Promise<AppConfig> {
  const parsed: unknown = JSON.parse(await readFile(path, "utf8"));

  if (
    typeof parsed !== "object" ||
    parsed === null ||
    !("databaseUrl" in parsed) ||
    typeof parsed.databaseUrl !== "string" ||
    parsed.databaseUrl.trim() === ""
  ) {
    throw new Error("Configuration requires a nonempty databaseUrl");
  }

  return { databaseUrl: parsed.databaseUrl };
}

In Ronacher’s illustrative scenario, the configuration mistake is discovered two hours later, after incorrect database records have already been written. The problem is not merely that a read failed; it is that a recovery path hid the failure and allowed consequential work to continue.

In his experience, these attempts to recover from local failures can produce brittle services. The codebase then grows beyond what the agent can navigate reliably: it misses relevant files and creates a new implementation of something that already exists elsewhere. Each local workaround adds complexity that makes the next task harder. A human engineer may feel discomfort while adding this sort of code; an agent does not provide an equivalent emotional brake. That concern has to enter the process through people and explicit constraints.

7:137:28
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

7:13 · section reference included

Libraries expose a smaller problem

Poncela Cubeiro reports an encouraging correlation: agents tend to do better in libraries than in products. A library usually has a defined problem, features that map onto an API surface, and constraints that bound the work. Its core is often simple enough to understand and extend. Products combine more interacting concerns.

ConcernLibraryProduct
ScopeDefined problemInteracting requirements
SurfaceConstrained APIUI, API, permissions, billing
StructureSimple, extensible coreCoupled components and states
Agent reasoningMore locally boundedRequires broader context

For example, a product’s UI and API responses may depend on permissions, feature flags, and billing state. Those relationships can exceed what the agent can hold in context. An edit can be reasonable in the file being changed and incoherent across the application. The design response is to treat the codebase as infrastructure for the agent: its structure determines how much of the system the agent can see and reason about while working.

9:119:23
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

9:11 · section reference included

Make the flow between components explicit

Modular components help an agent add a feature in one place without disturbing everything else. But module boundaries alone are insufficient: the execution flow also needs clear stages. In an assistant refactor, Poncela Cubeiro identifies three main steps:

  1. Receive the user’s message.
  2. Pass the message to the agent loop.
  3. Handle the output.

These landmarks were clear to her, and the code at each landmark was relatively orderly.

The trouble accumulated between the stages. Agents introduced conversions between types and added information to state that did not belong there. These additions quietly expanded the set of behaviors the application supported, including unexpected and potentially dangerous ones. Making the transitions explicit matters as much as naming the major components: otherwise, the connecting code becomes a place to accommodate conditions that the design never intended to allow.

The rest of the approach follows familiar engineering principles. Use established patterns that align with what models have learned. Keep the core simple and put necessary complexity in explicit layers. Avoid abstractions that conceal intent the agent needs to respect. Poncela Cubeiro cites React Server Actions and ORMs, compared with raw SQL, as examples of where that concealment can occur. This is her argument for inspectable behavior, not a universal prohibition on those tools: an abstraction becomes a problem when it hides the relationship the agent must understand to change the system correctly.

An Agent-Legible Codebase slide lists modularization with clear boundaries, known patterns and conventions, a simple core with complexity in layers above, and no hidden magic.Open full source frame
An agent-legible codebase uses clear boundaries, familiar patterns, a simple core, and no hidden magic.
10:5110:59
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

10:51 · section reference included

Turn design constraints into mechanical checks

At Earendil, much of this discipline is enforced with linting rules. The first example is a ban on bare catch-alls. There is a small irony in the presentation: the agent had already found and edited the catch-all intended for the demonstration. The larger point is to make undesirable patterns detectable without relying on someone remembering every convention during review.

  • One SQL query interface. Keep query access in one place so an agent does not have to hunt across the repository and risk missing a site that also needs to change.
  • One UI primitives library. Avoid raw input elements outside the shared primitives so styling and behavior stay consistent.
  • No dynamic imports. Keep this form of runtime indirection out of their codebase.
  • Unique function names. Make a search identify the intended function unambiguously. If an agent’s grep returns one relevant result, it spends less context on disambiguation and can continue its work more directly.

They are also exploring TypeScript’s erasableSyntaxOnly option. It restricts TypeScript constructs that need runtime transformation, such as enums and parameter properties, favoring JavaScript with erasable type annotations. That does not itself remove every build or transpilation step. The attraction is a closer relationship between the source the agent reads and the behavior being debugged, with less transformation-related indirection when locating an error.

12:3212:44
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

12:32 · section reference included

Separate repairable defects from human decisions

Mechanical checks improve what the agent produces, but a person still needs a signal that restores attention at consequential moments. Ronacher’s team built a review extension for Pi around that distinction. Mechanical bugs and clear violations of AGENTS.md belong in feedback the agent can act on. Other changes need an explicit human call-out because understanding their consequences requires judgment beyond the patch.

  • Database migrations. A migration’s operational risk depends on locks and the amount of data in production. Ronacher wants a human judgment call before it goes in.
  • Permission changes. The intended authorization rules may be under-documented. A plausible implementation is not enough to establish that the new access is appropriate.

An agent can help identify these changes even when it cannot own the decision. The call-out makes the person notice that this is the point to engage.

In the demonstrated interface, actionable findings appear above a separate group of human call-outs. Selecting the action to fix issues would send the first two categories—mechanical bugs and instruction violations—back to the agent. It would not resolve the human decisions below. The linked extension is a mutable implementation, and its current human call-outs are non-blocking attention signals, not an enforced approval gate. A new dependency, for example, raises questions about whether it belongs in the codebase and whether its maintainers are people the team wants to trust. Fast generation does not answer either question.

14:1114:28
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

14:11 · section reference included

Use speed where it creates a useful starting point

Issue reproduction is one of Ronacher’s preferred uses of agents. A customer report can become a concrete reproduction case, giving an engineer a much better starting point. Exploring product directions is another useful application, provided the team accepts responsibility for the generated code. His assessment is less favorable for system architecture and reliability, where interactions and consequences matter more than producing a first working version.

A two-column slide lists exploration, prototypes, debugging, CI fixes, reproduction cases, and first drafts under High Leverage; reliability, interacting states, unclear specifications, and later cleanup costs under Lower Leverage.Open full source frame
“Where Speed Actually Helps” contrasts high-leverage tasks with lower-leverage work.

Ronacher warns that months of technical debt can accumulate in weeks or days; this is an experiential warning, not a measured production rate. As the mess grows, understanding falls, and honest assessment becomes harder both technically and psychologically. He describes finding code that failed in production, then realizing that he had committed it himself with an agent’s help. The disappointment came with recognizing that the responsibility was still his. Slowing down is necessary to see the actual state of the codebase, including mistakes hidden by the satisfaction of having shipped.

16:0016:09
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

16:00 · section reference included

Keep the friction that lets you steer

Some shipping friction is merely annoying and should be removed. Other friction is deliberately designed to make a team consider whether a service is reliable enough, how critical it is, and whether enough people are available to operate it. Ronacher points to service-level objectives, or SLOs, as an established example. More precisely, the operational constraint comes from the policy tied to the objective, such as an error-budget policy. Agent speed does not eliminate those reliability and staffing decisions.

The closing analogy is physical: steering requires friction. Software teams also need points of resistance where experience can affect the direction of travel. A review that prompts a real decision about permissions, a migration, or operational risk is not wasted time simply because the code arrived quickly. Useful friction is where human judgment enters the process.

17:2217:32
Suggest correction

This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.

17:22 · section reference included

Resources

From the talk

  • Mario and EarendilArticle

    Ronacher discusses Pi, deliberate software design and why quality requires more than faster output.

  • A concrete policy for slowing feature releases when reliability falls below an agreed objective.

Transcript download
Read the transcript and explore slides

Loading transcript and slides…