Summarize with AI:
Agents deserve an architecture layer of their own rather than being lumped into frontend or backend, since they don’t behave quite the same as people or programs.
Every application we build sorts its callers into two camps. People use the frontend, and programs call the backend. This division often decides where every feature lives: screens and flows for users; endpoints and contracts for programs.
AI agents are a third kind of caller, and they are now moving into production traffic. An agent acting for a user might check a customer’s charges against an invoice and open a dispute when the numbers disagree, without a person clicking through screens and without a developer scripting the exact calls.
In this article, we highlight how agents deserve to be treated as a layer of their own, and work through what that layer changes about how humans interact with our software.
The two-layer model encodes assumptions about who is calling. A frontend assumes a person: someone who can read a screen, weigh the options, recover from confusion and decide what happens next. Everything we invest in layout, affordances, empty states and error messages exists because the caller brings judgment and needs information presented in a form that supports it.
A backend API assumes the opposite kind of caller. A program follows a published contract exactly and never improvises. It sends the same shape of request every time, which is why we version endpoints and publish schemas, and why a malformed request counts as the caller’s bug rather than a misunderstanding to accommodate.
Both assumptions held for decades because every caller was one or the other. An agent, however, is neither. It calls APIs like a program, but it chooses which calls to make at runtime and changes course based on what it finds. A caller that brings judgment but has no use for our carefully designed screens is a new kind of consumer, and it needs a layer built for it.
The agent layer is the part of the architecture where goals get turned into actions. An agent receives a goal rather than a request. It plans the steps, acts through tools, observes the results, and revises the plan until the goal is met or it escalates to a human. Tools are the operations we expose for that purpose, each with a name and typed parameters, plus a description the model can reason about.
At runtime, the layer is a loop. A simplified version looks like this (with the OpenAI Responses API and the gpt-5.6 model):
const input = [{ role: "user", content: goal }];
while (true) {
const response = await openai.responses.create({
model: "gpt-5.6",
instructions: AGENT_PROMPT,
tools,
input,
});
// carry the model's output into the next request
input.push(...response.output);
const toolCalls = response.output.filter(
(item) => item.type === "function_call"
);
// final answer, no more actions
if (toolCalls.length === 0) {
break;
}
for (const call of toolCalls) {
// our code validates and runs the real operation
const result = await executeToolCall(https://url.us.m.mimecastprotect.com/s/_r0jCM8X4XCq9PzroSJiZ9h8_aoG?domain=call.name, JSON.parse(call.arguments));
input.push({
type: "function_call_output",
call_id: call.call_id,
output: JSON.stringify(result),
});
}
}
Each pass through the loop, the model either requests a tool call or produces its final answer. When it requests a call, our code validates and executes the operation, and the result feeds the model’s next decision. The intelligence lives in the model, but every action runs through code we wrote.
Set beside the two layers we know (frontend and backend), the differences come into focus:
| Layer | Built for | The caller provides | Typical failure |
|---|---|---|---|
| Frontend | People reading screens | Clicks and form input | A confusing experience |
| Backend | Programs following contracts | Exact, well-formed requests | A broken contract, a 4xx or 5xx |
| Agent layer | Goals that require judgment | A described outcome | A wrong decision made confidently |
The layer runs in both directions. Some agents live inside our product, like a billing assistant that investigates a duplicate charge for a user. Others live outside it, like a customer’s accounts-payable agent calling in to reconcile invoices. In both cases, the layer occupies the same architectural position, sitting between someone’s intent and the systems that can satisfy it.

The frontend taught users to navigate: find the right page, open the right form, fill it in and click submit.
The agent layer replaces navigation with delegation. The user describes an outcome, and the agent works out the route. That shift comes with four interaction primitives that our interfaces need to support:
Today, most of this happens in chat, which has become the default front door to the agent layer. Purpose-built UI patterns are forming around these chat interfaces: welcome screens that set expectations, source citations under generated answers, inline status while work runs and editors for refining what the agent produced.
Those interaction patterns are the visible half of the work. The other half happens in the backend, and it starts with the tools. The capabilities buried in our click handlers and form submissions become tools the agent loop can call, and the description on each one matters, because that is what the model reads when deciding whether an action applies.
Permissions need rethinking too. An agent holding a user’s full credentials can do everything that user can do, wrong decisions included, so the safer pattern is to let agents read broadly and write narrowly, with write access granted per action.
The approval moments and progress updates from the last section also need a backend counterpart. Anything hard to reverse waits for a human, and every step gets logged so we can reconstruct what an agent did and why. On the integration side, the Model Context Protocol (MCP) standardizes how agents discover and call tools, and platforms like Progress Agentic RAG handle governed retrieval so the knowledge agents act on stays citable and permissioned.
To see the layer at work from the other direction, we can follow a hypothetical agent example. A customer of our invoicing product runs an accounts-payable agent, and its standing job is to reconcile what the customer was billed against what they ordered.
open_dispute.open_dispute with the invoice ID and the evidence. Our backend validates the scoped permission and creates the dispute, and the full exchange lands in our logs.No one opened our dashboard during any of this, and no one on the customer’s team wrote integration code against our API docs. The agent did the reconciling and the customer approved the dispute. Our side supplied the scoped operations and a log of every call.
The stack has grown new layers before. The frontend split from the server when browsers became capable enough to carry an application, and the API layer grew into a product of its own when programs became its main consumers. Both felt like separate specialties at first, and both ended up as part of the ordinary full-stack job.
The agent layer is following the same path, and it depends on both layers around it. It needs frontends where humans can delegate and approve, and it needs backends that expose well-described and well-scoped operations. Full-stack developers already own those two layers, which makes us the natural owners of the one now growing between them.
For more on building AI-powered applications and agents with Progress, check out the following resources:
Hassan is a senior frontend engineer and has helped build large production applications at-scale at organizations like Doordash, Instacart and Shopify. Hassan is also a published author and course instructor where he’s helped thousands of students learn in-depth frontend engineering skills like React, Vue, TypeScript and GraphQL.