Agentic Coding Across a Mixed Stack: React, C#, Avalonia, Firmware and Delphi
Bjørn T. Nøstdahl
~7 min read

The Innovation Hub in Bari does not have one stack. It has React frontends, C# and .NET services and APIs running in Azure, Avalonia user interfaces on devices and desktops, embedded firmware on the hardware itself, and a Delphi codebase that came with the BELA acquisition as source files on a NAS. The first two years went into giving all of that the same foundation: Git, Azure DevOps, structured backlogs, CI builds, and tests at every level, which I wrote about in DevSecOps for Delphi. This article is about what came next: coding agents, across every one of those stacks, with teams in four countries.
What "agentic" actually means
Autocomplete suggests the next line. An agent is given a task, reads the repository, edits files, runs the build and the tests, reads the errors, and tries again until the task is done or it gives up. The difference is the loop. A model that cannot run the build is guessing; a model that can is doing something close to what a developer does on their first day in a new codebase, only faster and without the coffee.
Our agents run on developer machines and in the pipeline, against the same repositories, the same build scripts and the same tests as a human. That last part is the whole point, and I will come back to it.
One stack at a time
The agents are the same; the stacks are not, and the differences taught us more than the similarities.
React and TypeScript. This is where agents are strongest, for the obvious reason that there is more public React code than anything else. They write components, hooks and state management, and they write Playwright tests for the flows the support team said broke most often. The risk is not wrong code but too much of it: a new dependency for every problem, three ways of doing the same thing in one repository. The instructions file lists the libraries we use and the ones we do not, and the pull request review is mostly about keeping the codebase consistent rather than making it work.
C# and .NET. Nearly as strong, with a better feedback loop. The compiler, nullable reference types and the analyzers reject most mistakes before a test runs. The task agents do best here is implementing an endpoint from an OpenAPI operation, with the contract tests to prove it, which is the same description that drives the REST clients and, later, our MCP servers. Database migrations and the move from Firebird to Microsoft SQL Server, with both still supported, were largely agent-written and human-reviewed.
Avalonia. A mixed picture. View models, commands and headless UI tests come out well, because they are plain C#. XAML layout and the styling selectors come out worse: the agent produces something that compiles and looks wrong, and it cannot see the screen. Screenshots from the previewer fed back into the loop help, and the headless tests catch behaviour, but a human still owns the layout.
Firmware. Here we are careful. Agents are good at the parts that can be tested on a host machine: protocol parsers, frame decoders, checksum routines, state machines with unit tests. They do not touch anything with timing, interrupts or hardware registers without a human writing it and hardware-in-the-loop tests proving it. The cost of a wrong line in firmware is a service visit, and the agent does not pay for the van.
Delphi. I expected the language to be the problem, and it was less of one than I feared. There is far less Object Pascal on the internet than TypeScript, and the models invent a VCL method now and then, but the language is explicit, the compiler is strict and fast, and twenty years of one team's conventions are remarkably consistent, so the agent picks them up from a handful of examples. The rule is that the agent must have the compiler. An agent writing Pascal without a build step is a liability; with one, it is a useful colleague.
What we let the agents do
Across all five stacks, we started with tasks where the cost of a mistake is low and the verification is mechanical.
- Tests first. Unit tests for units and classes that had none, Playwright tests for the frontends, headless tests for Avalonia views, host-side tests for firmware parsers. A human reviews whether the test tests the right thing; the agent does the typing.
- Contracts in both directions. From one OpenAPI description, an agent implements the C# endpoint and the React form that calls it, and the contract tests keep them honest with each other.
- Translations and migrations. SQL dialects, dependency upgrades, framework version bumps: pattern-heavy work with an obvious test.
- Archaeology. "Explain what this module does and who calls it" is the question every new developer asks and nobody has time to answer. The agent answers it in a minute, with references. The Kyiv and Sofia developers, who joined long after much of the code was written, use this more than anything else.
- Refactoring under test. Once something has tests, an agent can restructure it with a safety net. Without tests we do not let it touch anything, which turned out to be the strongest incentive to write tests we have ever found.
What we do not let them do
Some of the code in these products decides whether a safe deposit locker opens. There are rules, and they apply to every stack.
- Security-critical logic is written by people. Agents can read it, explain it and write tests against it. They do not change it.
- No secrets in the context. Connection strings, keys and customer data never go into a prompt. The agent works on repositories that do not contain them, which the DevSecOps work had already ensured.
- No direct pushes. Agents work on branches and open pull requests. A pull request from an agent is reviewed like one from a developer in their first month: carefully, and with the assumption that it is confidently wrong somewhere. I wrote about that confidence in 2023, and nothing since has changed my mind.
- The pipeline decides. Build, tests, analyzers and leak detection run on every pull request, whoever wrote it. The agent does not get a shortcut, and that is what makes the whole thing safe enough to use.
The instructions file
Every repository has an instructions file for agents at its root. Ours is short and boring: how to build each project from the command line, where the tests are and how to run them, the conventions that matter for that stack, the libraries that are approved and the ones that are not, which directories are off limits, and one rule in capitals: run the tests before you say you are done. The same file is useful for humans joining the team, which tells you what good onboarding documentation should have looked like all along.
What changed for a distributed team
With developers in Bari, Sofia, Kyiv and Gothenburg, a lot of work used to wait for someone in another time zone to answer a question. Agents absorbed much of that: what a module does, the first draft of a test, the endpoint from the contract, the translation of a query. Lead time on small changes dropped. Review load went up, because there are more pull requests, and the reviewers are now the bottleneck. That is a better bottleneck than the one we had.
The honest cost is attention. Reviewing agent output is a skill, and it is tiring in a way that writing code is not. We rotate it, and we keep agent pull requests small on purpose.
Where this goes
The agents that read code are the same technology that can read logs, tickets and device status. Giving them access to those, safely, is a different problem with its own rules, and it is the subject of a later article.
Questions for you
- Which of your stacks do agents handle best, and which one surprised you by being worse than expected?
- Where is your line between what an agent may change and what only a human writes?
- Has the review load replaced the writing load on your team, and what did you do about it?
Email me at bjorn.nostdahl@nostdahl.com. I am collecting instruction files; if yours is better than ours, I want to see it.