Everyone Gets Bespoke Software
Far enough up the stack, a harness stops being a general way of building software and becomes a machine that knows how to build one kind of system, in one domain. That is where the configuration layer of enterprise platforms and configurable SaaS ends up, and why bespoke stops meaning from scratch.
For most of my career in software, the running system has been the asset. The thing you shipped, the thing you maintained, the thing that turned up on a balance sheet if anyone was counting. Everything that produced it, the standards document nobody read, the review culture, the pipeline, the accumulated habits of a team, was overhead. Useful overhead, occasionally beautiful overhead, but overhead all the same. It existed so that the artifact could exist.
I think that is inverting, and I want to describe what it inverts into. This is a gut call, I am building this way at the moment, and a lot of what follows is where the work seems to be pointing rather than something I can hand you evidence for. But it is the direction I would bet on.
The inversion is, as has been stated by many leading thinkers over the last year or so, that the “harness is the product”. By harness we mean everything sitting between the model and the code that comes out of it. The steering rules, the constraints, the skills, the agent definitions, the deterministic checks, the reference implementations, the decision about which model does which job. The model is a component you rent, and it might be a different model in eight months. The harness is the part you own. It is where what you know about building a particular kind of software actually lives, and it is increasingly the thing that decides whether what comes out the other end is any good.
What interests me is what accumulates in there as you go up. The rules and the checks at the bottom are much the same for anyone writing TypeScript, and they are not where the value sits. The value is higher up and much more specific: skills that know what kind of application is being built, down to the decisions that only make sense for that kind of application, and reference pieces in code, carrying their documentation and the reasoning for their shape alongside them, that know how this particular thing gets built. None of it is a framework, and none of it has to dovetail perfectly with anything else, because the agent assembles whatever the system in front of it needs. The further up you go the more specific it gets, until what you are holding is not a general way of building software at all. It is a machine for building one kind of system, in one domain, extremely well.
Taking an example in the energy space:
Picture an organisation whose product is not an asset performance management system for wind farms. Its product is the factory that builds them. It owns a harness that has been fed everything that organisation knows about renewables: how you model a turbine and the site it stands on, how ten-minute SCADA data is stored and aggregated, how downtime gets attributed, what availability actually means once you have argued about it with enough operators, what the reporting looks like when the asset manager and the owner want different numbers out of the same data. Underneath that sits everything it knows about building applications of this shape. Underneath that, everything it knows about writing TypeScript properly. Underneath that, the plain discipline of designing before you implement and testing what you write.
Then a customer arrives with an awkward portfolio and a regulator nobody has dealt with before, and the factory builds them a system. Not a configuration of somebody else’s product, an actual system, specific to them, assembled out of pieces that have been proven across every system that came before it. And when the harness learns something next year, it knows how to go back and carry that customer’s system forward with it.
The application, in that picture, is what the harness happened to produce this week. Still valuable, still in production, still paying for itself, but reproducible in a way it ha ss never been before. Given the choice between losing the codebase and losing the harness that built it, I would keep the harness, and I do not think that would have been a defensible thing to say two years ago.
The harness has to be tyrannical
Models are extraordinary at the creative end of this work. Pattern recognition, writing code that fits the shape of the code around it, producing a decent implementation of something you described badly: they are better at all of that than I expected to see in my career. What they are not good at, and this is the constraint that governs everything else, is holding a large, complex system consistent over time. They lose their way. They repeat themselves. They solve the same problem twice in two places, because at the moment of the second solution they were not looking at the first.
You can spend a lot of energy fighting that, and I did for a while, mostly by writing rules in prose and hoping they would hold. They do not hold, for a reason I have written about before: an agent works in a narrow window of the codebase at a time, and a rule that can only be checked across the whole application has no purchase on any single change.
So you stop just asking for consistency, you ask AND you architect so that it cannot be violated. In my view the system has to be extremely opinionated, with extremely tight boundaries, guidance on everything, and everything deterministically checked.
Both halves of that do different jobs. The steering rules, the skills and the agent definitions carry the intent: this is how we write software here, this is what a domain contract looks like, this is who reviews what and when. The deterministic checks are what actually holds the line. Lint the output before it is written to force compliance: Architects only write interface code, Test Writers only write tests. TypeScript in its absolute strictest mode, not as a preference but as a gate. Directory structure enforced rather than described. No primitive values crossing a boundary where a value object belongs. Tests written blind, by a different subagent, against the contracts rather than against the implementation, so that the thing being tested and the thing writing the test cannot quietly come to an arrangement.
None of that is a suggestion the model can drift away from under goal pressure. It either passes or the work does not land. Knowing which parts of your intent are advisory and which are enforced is most of the craft here, and the answer is that far more of it needs to be enforced than feels comfortable.
A many-layered cake
The obvious way to describe a harness is as layers, and I am going to do that because it genuinely helps. But it breaks down in a couple of places.
At the bottom is the generic software development layer, which is largely what the frontier labs (Claude Code, Codex) and others (my current favourite being pi.dev) ship. It is language agnostic. It is the developer loop: an architect designs before anyone implements, concerns stay separated, everything is tested, code files stay under a strict length. General good practice, encoded rather than hoped for.
Very quickly you move into a language and technology layer. Domain contracts separated from their implementations. No primitives, value objects. Strict bounded contexts, established and then maintained, with public interfaces. Requirements on directory structure down to a level that would irritate most human teams. Alongside that sit the skills and the review agents that know exactly how this language should be written, and the checks that make all of it real rather than aspirational.
Above that is the stack layer, which is really a question of what kind of thing you are building. A client web application. A task processor. A data pipeline. Take the web app, since it covers an enormous range of ordinary business software: managing records, users and roles, some reporting, a reasonably nice interactive UI over what is fundamentally a relational store. A harness at this layer is opinionated about all of it. Where the React components live and how they are separated from the queries that feed them. How server routing works. How authentication is built and which provider does it. How user information and PII are handled. Which database, sitting behind a port with the adapter on the other side of it, because hexagonal architecture is not optional at this level. I am not claiming there is one right set of answers, and there will be many good ways to build this. I am claiming that the harness has to have answers, and that having them matters more than having the best ones.
Then the domain layer, and this is where the cake metaphor starts to get more complex. This is how we model assets. This is how telemetry and performance data are stored. This is how the system reasons about downtime. Knowledge accumulated across years of building a particular kind of system, baked in.
Except that the domain is not really a layer, it may well be a stack of them. You might have a base asset management harness, then renewables on top of that, then wind on top of that again. How deep you go is a choice, and different people will take it to different depths. Some will only ever want the base. And some pieces refuse to sit in any single band. How PII is handled is simultaneously a generic policy, a language specific implementation and a domain specific regulatory constraint, so it cuts vertically through all four layers at once.
You assemble a harness roughly the way you assemble a dependency set, choosing how deep to go and pulling in the cross-cutting pieces you need, and each layer is itself a composition of many pieces rather than one file.
I feel strongly that model selection gets baked in too. Not routed dynamically at runtime through something like OpenRouter, but declared. The harness defines three or four model roles, and the planning role uses an expensive high reasoning model with the thinking turned all the way up, while the implementation role drops to something faster that is better suited to that job anyway. The factory knows which role does which task. That is a property of the harness, not a runtime optimisation.
Not a library, an assembly kit
I have spent a lot of my career slightly obsessed with modular composable architectures, the kind where a set of packages wire neatly together into a unified whole. Getting that right is genuinely hard, because every module has to anticipate every other module it might ever meet, and many attempts collapse under the weight of that anticipation.
Agents change the economics of it completely. The pieces never have to meet on their own terms, because something intelligent does the wiring at assembly time and can customise a piece on the way in if this system needs it slightly differently.
There is a pre-AI proof that this works. shadcn/ui is a React component library where you do not install the components as a dependency, you copy them into your codebase and edit them as you see fit. You are not referencing and upgrading in the traditional way, you own the copy. That trade looked odd when it appeared and turned out to fit how people actually use components. I suspect a great deal of software will get built this way now, with an agent doing the copying and the adapting.
Worth noticing that the harness is composed exactly the way the software it produces is composed: pieces that were never required to integrate with each other, assembled on demand by something that understands the target.
The configuration layer eats itself
Look at knowledge-work enterprise software and you find the same shape almost everywhere: a core platform, plus an enormous layer of configuration and integration on top of it. SAP is in some senses a backbone and a database, and then an entire industry of system integrators tailoring it, at significant cost, for each organisation. Maximo is asset management with a vast customisation layer draped over it. Salesforce built force.com underneath itself precisely so that everything above could be configured, scripted and extended. These platforms were built to be customised, and the customisation is where most of the value, money and time sit.
That layer is exactly what moves into the harness.
If I want an asset management system, I no longer start from a platform and configure my way toward what I need. I take the asset management harness that already knows how to build these systems, and I tell it to build mine. Every organisation ends up with bespoke software, but it is not bespoke in the truest sense, because nobody is starting from ground zero. The thing coming out of the machine was designed to come out of that machine.
The same move at the other end of the market
It would be easy to read that as a story about enterprises, and it is not. The same principle runs all the way down.
Say I run a five person company and I want a CRM. Today I sign up for something off the shelf, work through the self-serve configuration or the studio, integrate it with two other things, and then live with an eighty percent fit indefinitely, because the vendor pre-built every variation anyone might plausibly want and handed me the knobs.
The alternative is that I pick up an off the shelf CRM harness, quite possibly an open source one, and describe what I actually want. The hard parts, the data modelling, how the auth works, how records relate to each other, are already baked in, so the floor is high before I have said anything. What comes out is mine. When I need a feature I ask for it and the system changes, rather than filing it as a request against somebody else’s roadmap and waiting.
What I have acquired, in that story, is the factory rather than the product. And this is where SaaS in its self-serve, runtime configurable form looks genuinely exposed, because a large configurable system gets harder to maintain the more configurable it becomes, while the knowledge inside it is now expressible as a harness instead. The knobs were only ever a way of shipping one artifact to many customers.
Upgrades, and the other question everyone asks
There will clearly be many new challenges of running things this way. Here are a couple of obvious ones.
The first is change. I improve the harness continuously, so there will be systems in production built by an older version of it, carrying out of date code, with no direct reference to bump. But the honest comparison is not against a world where upgrades are easy. Taking a library across a major version was never a simple command either: interfaces break, you read the changelog, you work out what it means for you, you re-test everything. What changes here is that the upgrade path can be baked into the harness itself, and it can be semantic. Instructions an agent follows, backed by deterministic checks and tests, rather than one enormous migration script that has to anticipate every codebase it might land in. You still need real end to end and integration testing over the result, and probably some human or agent QA at the end of it. But the harness knowing how to move its own old systems forward is a different proposition from browsing a changelog and hoping.
The second is knowledge. Anyone who has run an agency or an integration practice knows the shape of this one: every bespoke system carries a body of knowledge about how that particular system works, and it lives in the heads of the people who built it. That is what has sometimes made bespoke unsustainable at scale.
Two things move the dial. Every system built by the same harness looks like every other system built by that harness, so familiarity transfers. And the technical documentation, the notes and the decision records are produced as part of the build rather than as an afterthought, because the harness insists on it. The knowledge sits in the repository and in the harness, not in a person. A new engineer should be able to pick up any of these projects and change it with confidence, because they are not really reading and writing code, they are describing what is needed and steering an agent that already knows the rules of the house. Once you are there, some things that used to be work stop being work in the way they were: an incident or a security issue can be handled by the agent, prompted by a developer from Slack.
Why a generic harness cannot get you here
The obvious question is why any of this is necessary when the frontier labs ship perfectly capable harnesses of their own.
Because they are general purpose by nature, and general purpose means unopinionated. There is no one right way to build a web application encoded in them, and there cannot be, because encoding one would make them worse at everything else. Without an opinionated way of building you get inconsistency, and inconsistency is precisely what people are looking at when they conclude that vibe coded applications do not hold up. It reads as a model problem and it is a harness problem. Those generic harnesses cannot become opinionated without ceasing to be general, so the gap does not close from that direction. It gets filled by people building opinionated harnesses on top of them.
That is the business I think appears, at every size. Organisations that own a domain harness and use it to produce and maintain software, for one customer or for many, sitting on top of whichever model happens to be best this quarter. Open source harnesses for the common cases. A service industry rearranging itself around who owns the factory rather than who owns the code.
I said at the start that this is a gut call, and it is. But every time I stop working on the application and go back to work on the harness, it feels less like preparation and more like the actual job.
Get new posts by email
Occasional posts on software architecture and AI-assisted development. No spam, unsubscribe anytime.