Ask an AI coding agent to build a trading UI from a one-line prompt and you will get something impressive in about ninety seconds. There will be an order book with green and red rows, a chart, an order form, and a dark theme. It will look like a trading UI. Whether it behaves like one is a different question, and the gap between the two is where this post lives.
The models are good, and they are getting better at a pace that makes any specific claim about their limits age badly. But the nature of the problem has not changed. A model generates the most plausible code for the context it has been given. With a blank prompt, the most plausible trading UI is the average of every tutorial on the internet, and the average tutorial gets the hard parts wrong. With a working codebase as context, the most plausible next change is one that looks like the code already there. The quality of what the agent produces is bounded by the quality of what it can see.
That is the case for a foundation, and it applies whether the foundation is Hedge UI, your own existing platform, or anything else that already runs. What follows is where blank-prompt trading UIs go wrong, why those failures are hard to spot, and what in a codebase actually helps an agent do good work.
Where a blank prompt goes wrong
None of these failures are exotic. They are the same mistakes human teams make on their first trading frontend, catalogued in what most trading UI projects get wrong. A model reproduces them because they are what most of the example code in the world does.
Float arithmetic on money
The plausible way to compute an order total in JavaScript is price * amount. It is also wrong, in the specific sense that 0.1 * 3 is 0.30000000000000004. Generated order forms almost always use native numbers, often with a toFixed(2) on the end that hides the error until someone trades an asset priced to eight decimals.
The fix is a decimal library and string-typed inputs, as covered in decimal precision in trading order forms. A model knows decimal.js exists. It reaches for it reliably only when the surrounding code already does.
A socket per component
The plausible way to subscribe to a price stream in React is a useEffect that calls new WebSocket(url) and closes it on cleanup. One per component. A generated UI with an order book, a trades feed, a ticker, and a watchlist will open four or more connections to the same host, each with its own reconnect behaviour, or more often with none.
A real data layer multiplexes streams over a connection and diffs subscriptions as they change. In the demo, a useMessenger hook inside src/binance/binance-stream.ts compares the requested stream names with what is already subscribed and sends only the difference as SUBSCRIBE and UNSUBSCRIBE frames. That is about seventy lines that nobody writes on the first attempt, human or model.
Stale data after a symbol switch
This one is subtle and it is my favourite example, because it almost never appears in generated code and it is visible to any trader within a minute.
When the user switches from BTC to ETH, the last message on the socket is still a BTC message. If the UI renders the latest message unconditionally, the ETH order book briefly shows BTC prices. The demo guards against it with a small hook that checks each message's stream name against the streams currently requested:
if (typeof lastJsonMessage === "object" && "stream" in lastJsonMessage) { const message = lastJsonMessage as Message<T>; // If we have changed products, then last message might be stale from old product. const isCurrentProduct = streamNames.includes(message.stream); if (!isCurrentProduct) { return; } return message; }
There is no way to derive the need for that check from a prompt that says "build an order book". You find it by running the thing against a live feed and switching symbols. Code that has already been through that carries the lesson with it.
A render per message
Generated trades feeds call setState for every incoming trade. On a quiet symbol that is fine. On a liquid one it is dozens of renders a second for a list a human cannot read that fast. The remedy, batching and throttling at the boundary, is covered in throttling and batching market data. The demo's own history has a commit called "Fix market trade too many updates" from its third week, so this is not a mistake only models make.
Layout that forgets
A blank-prompt UI lays panels out in a CSS grid. It looks right in a screenshot. It cannot be rearranged, and nothing persists. A dockable workspace with saved layouts is a large piece of engineering, described in resizable, dockable panel layouts, and it is rarely in the first generated version because the prompt did not ask for it and the screenshot does not need it.
Why these failures are hard to catch
Every item above shares a property: the UI looks correct. Float errors appear at specific values. The stale-symbol flash lasts a fraction of a second. Excess renders show up as heat and jank on a busy market, which is not when you are reviewing a pull request.
Review is the bottleneck in AI-assisted development. Generating code is nearly free. Verifying it is not. A reviewer faced with 2,000 lines of freshly generated trading UI has to hold the whole domain in their head to notice what is missing, and missing things are much harder to see than wrong things.
A foundation changes what review looks like. When the agent adds a panel to an existing codebase, the diff is a hundred lines that follow a known shape, and the reviewer checks it against eight other panels that have the same shape. The precision handling, the stream guard, and the batching are already there, in code that has been exercised. The agent is extending, and extension is the mode where current models are most dependable.
What actually helps a model
It is worth being specific about which properties of a codebase make an agent more effective, because "good code" is not an actionable answer.
Repetition it can pattern-match
Every feature in the demo has the same skeleton: a -panel.tsx container that subscribes to data, a pure presentational component that takes props, and a co-located test. Nine panels, one shape. When an agent is asked for a tenth, it has nine worked examples in the repository and the most plausible output is a tenth instance of the pattern. The structure is described in the post on feature folders and the panel factory.
Consistency matters more than which convention you pick. A codebase with three ways of fetching data gives a model three patterns to choose between, and it will pick whichever the nearest file used.
A narrow path for common changes
Adding a panel to the whole product is one entry in a registry object in src/app.tsx:
"my-panel": { component: MyPanel, name: "My Panel", help: <>...</>, },
The add-panel menu, drag-to-dock, and the help popover are all driven from that object. A change with one obvious place to make it is a change an agent gets right. A change that requires touching six files in a particular order is one it gets mostly right, which in software is the expensive kind of wrong.
Types that reject plausible mistakes
Strict TypeScript turns a class of silent errors into compile errors the agent sees and fixes on its own. The demo compiles with strict, noUnusedLocals, noUnusedParameters, and verbatimModuleSyntax. Prices arrive from the exchange typed as string, so code that tries to add two of them without converting is flagged before it runs. The compiler is a reviewer that never gets tired, and the agent can consult it as often as it likes.
A verification loop it can run
This is the property that matters most. An agent that can check its own work converges. One that cannot will tell you it is finished when the code merely looks finished.
The demo gives it three commands:
pnpm check-types pnpm lint pnpm test
The tests run in Vitest browser mode against real Chromium, so a component that renders the wrong number of decimals fails an assertion rather than passing a snapshot. The setup is described in testing real-time React components. Because presentational components take plain props, an agent can write a test for a new panel by copying the shape of an existing one, with no socket mocking required.
A codebase small enough to read
The demo is around 8,500 lines. A current model can read all of it in one session and still have room to work. A foundation that is twenty times the size of the feature you are adding is useful context. A monorepo two hundred times the size is a search problem, and the agent's output is then only as good as its search.
Written context for what the code cannot say
Some knowledge is not recoverable from source. Why there is a hash comparison in the layout model. Why there is no global state library. What "done" means. The demo keeps this in an AGENTS.md file at the repository root, added in May 2026, which records the conventions, the commands, and a short list of things not to do. It is addressed to agents and reads just as well for a new engineer.
What a foundation does not fix
It would be dishonest to present this as a solved problem, so here are the limits.
The agent still cannot see. Type checks and tests do not catch a depth bar that is two pixels misaligned or a tooltip that opens off-screen. The demo's AGENTS.md says as much, in the section on finishing a task: exercise UI changes in the dev server, and if you cannot run a browser, say so explicitly. Visual review stays with a human, or with an agent that has been given a browser.
Conventions drift under pressure. Give an agent a hard problem and it may solve it with a pattern from outside the codebase, a new dependency or a different state approach. The fix is review and a written list of what is off the table.
Domain judgement is still yours. A foundation encodes how to display a price correctly. It does not know your venue's order types, your compliance copy, or which features your traders will pay for. Those decisions are the actual product, and no amount of context makes them for you.
The foundation's own gaps are inherited. The demo's order book totals use rounded native numbers rather than decimal.js, which is acceptable for display aggregates and would not be for anything sent to an exchange. An agent extending that file will follow the local pattern. Knowing where your foundation cuts corners is part of using it well.
The practical upshot
The useful mental model is that an AI agent is a fast, well-read engineer on their first day. They know the language and the libraries. They do not know your domain's sharp edges, and they will confidently write what usually works. You would not hand that engineer an empty repository and a one-line brief for a trading platform. You would hand them a working system, point them at an example, and tell them how to check their work.
That is all a foundation is. The hard, invisible parts of a trading UI, precision, subscription management, stale data, render pressure, persistence, are solved once and left in the open where the next change can copy them. The same properties that make a codebase quick for a new hire to learn make it quick for a model to extend, which is a strong hint that they were the right properties all along. The commercial argument for not rebuilding those parts yourself is in build versus buy for crypto exchanges, and it gets stronger when the builder is an agent, because the cost that remains is review.
Start the agent from something that already works. Ask it for the tenth panel, and keep the first nine as its reference.
