How components can help us govern agents
InfoWorld ·

My most-cited BYTE cover story was 1994’s Componentware , which made the case for a two-tier architecture best exemplified then by Visual Basic and its component ecosystem. The prevailing strategy for software reuse, object-oriented programming , hadn’t gained the traction we all expected. Visual Basic showed us why it hadn’t. Objects were written in the same languages, and by the same specialized coders, as the programs that reused those objects. VB flipped the script. Code-savvy component builders created building blocks that domain-savvy systems thinkers could wire together. Then the web flipped the script again. The browser was the new canvas, and it left the component ecosystem behind. Plugins came and went. The web platform eventually did define standards for components but they’ve been eclipsed by the web’s de facto standard framework, React , and its component architecture. And just like objects 30 years ago, React components are both produced and consumed by specialized coders. There wasn’t a good way for a modern solution builder to tap into React’s component ecosystem. The framework that I co-maintain, XMLUI , harks back to the VB model. A UI is defined by concise semantic XML markup that refers to a catalog of components . There is no visual canvas but, as we debated whether or how to recreate that experience, the question became moot. When agents write declarative markup in conversation with us, direct manipulation matters less than it used to. A better target language for LLMs It’s no accident that Markdown has become a primary way for humans and AIs to collaborate. Why not HTML and CSS? Markdown constrains AIs to a smaller set of patterns, and that’s a good general rule. Our new agentic team members are powerful but undisciplined. Left to their own devices they behave in unpredictable ways. The fewer degrees of freedom we allow them, the better things will go for all of us. The same principle applies to coding. When you ask an LLM to build an app with React and CSS, you invite it to operate with few constraints. Nothing stops an agent from writing a useEffect that subscribes to something and then forgets or misuses its cleanup function. XMLUI automatically endows every component with three life-cycle events, shown in this example. onMount runs once when the component becomes visible. onUnmount runs once when it leaves. onError catches anything either of them throws and receives { source, error } , where source is "mount" , "unmount" , "beforeDispose" , or "action" . The agent does not write a return value, does not pick a dependency array, does not name a cleanup function. There is nothing to forget. We say that XMLUI is to React as Java and C# are to C++: a managed language that abolishes many kinds of errors and vulnerabilities. In both cases there are valid reasons to pierce the abstraction and reach for low-level primitives, but that should be the exception not the rule. If most of what needs doing can happen in a managed layer, it should. Wrapping React components XMLUI components are wrappers around React components; they expose properties and APIs for declarative use. The core set of components delivered in the XMLUI runtime handle layout, data access, lists, tables, and UI controls including buttons, switches, and sliders. More advanced components like ECharts, Tiptap, and Masonry are wrapped in the same way and delivered as loadable extensions. All components share a common mechanism for semantic tracing . When enabled, semantic tracing captures a rich history that includes API calls and results, handler timings, and — this is the semantic part — trace events keyed to ARIA labels. The aria-label property becomes the component’s accessible name in traces, so a screenreader announces “Volume, slider, 50” and the trace records value:change didChange Slider [Volume] "53" . This unlocks accessibility, semantic traces that AIs can reason about, and regression tests generated from user journeys. The wrapper can even make interaction with a observable. When ECharts draws a chart, for example, the browser sees a rectangle of pixels. Click a bar and all the DOM sees is that you clicked a rectangle. The XMLUI wrapper opens the black box by deriving a name for the chart, so the canvas becomes “Revenue by Quarter — bar chart” to a screen reader, a test runner, and a trace. And it bridges ECharts’ own event model into the trace, so a click becomes “series0 → Q2 = 200” and a legend toggle becomes “Series 1: hidden”. The trace no longer says something was clicked, it says what data the user saw. Agents now often build user interfaces from scratch. An agent receives a prompt, writes React and CSS, and ships something that seems to work. Then comes the unhelpful bug report: “The chart did something weird when I clicked on it.” A UI built from traceable components yields a different kind of report. It says they clicked Q2 on the revenue chart, hid Series 1, changed the date range, and triggered an API call that returned 500. If you ask an agent to instrument a from-scratch UI this way, it will invent conventions that the next agent won’t share. Components done well can deliver consistent observability. Libraries and components Agents do reuse plenty of code in the form of libraries that provide clear APIs, that do careful versioning, and that embody years of hard-won interoperability. What separates a component from a library isn’t quality or packaging; it’s what the host knows about it. When an app calls a library the runtime sees function calls. When an app hosts a component the runtime sees a declared unit: these properties, these events, this configuration. In the VB era that contract enabled the property sheet to display a component’s settings and empowered the developer to wire its events. React components can play this role, and XMLUI wraps them because that’s where the ecosystem is today. But it’s the contract between component and container that matters, not the framework. As agents become solution builders it may be time to reconsider the web’s own component standard. Agents that can easily write bespoke code tempt us to think that reusable parts matter less. No! Every app they build costs effort to review, operate, and maintain. When instrumentation and security fixes and policy checks live in a component, every app that uses the component lightens that effort for hybrid teams of people and agents. Below the water line UI is just the visible tip of the iceberg. Below the water line is code that does hard and risky work. Consider /n software , the company that funded XMLUI’s early development. It has built components for that layer since the 1990s. Its IPWorks line, for example, covers SSH, SSL, SFTP, MQ, EDI, encryption, and S/MIME, protocols that businesses use to communicate securely. If an agent can write an SFTP client in an afternoon, why buy one? The real world is messy. A component that has connected to many counterparties over many years has absorbed edge cases that an agent’s bespoke code won’t meet until production. When a vulnerability is found and fixed, a maintained component delivers the fix to every customer. A price tag doesn’t guarantee any of this, but incentives matter. A vendor whose business is one component, used by many customers, is motivated to do it right and keep it right. Suppose an agent builds an app that enables a finance team to send invoice batches to trading partners. The transfer uses an SFTP component. The organization’s policy says transfers may go only to registered partner hosts, with host-key verification required. Here is a sketch of how things might go. An SFTP component declares its configuration so the host can validate it before anything runs. Is this endpoint on the partner list? Is host-key checking turned on? If not, the component doesn’t start, and the error says why. That’s a check performed by the runtime, not a convention the agent is asked to remember. And because the component reports into the same trace as the UI, the user’s journey and the transfer show up in one record: selection:change Table [Pending invoices] 12 rows click Button [Send to Acme] sftp:connect [Acme partner] host-key verified sftp:upload invoices-2026-10.edi 48 KB sftp:error permission denied (remote path /inbound) Whoever maintains the app, human or agent, can see at a glance that the UI did its job, the connection was trusted, and the failure happened on the partner’s side. Governing with components Every agentic deployment begs the same questions: how do we know what the apps they built are doing, and whether they are doing it safely? Logging is necessary but not sufficient when the logs point back to thousands of lines of bespoke integration code. A component architecture helps answer the questions. You know what each system is made of, you validate how the parts are configured, you observe them through the lens of a shared vocabulary. In 1994, component builders made parts that solution builders could compose, relying on their experience and judgment more than their coding skill. Now agents are wildly prolific solution builders. We need to connect them to an ecosystem of trusted, observable, governable parts so the apps they build can reflect the experience and judgement of today’s domain-savvy systems thinkers.