A few years ago the hard part of building software was writing the code. That is no longer true for me, and it took a while to admit, because it sounds like a loss. It is not. The hard part moved to the places that used to be easy: saying what you want precisely enough, and knowing when the machine has quietly decided something for you.

The skill moved

Much of the software I ship these days was written at a terminal with a model doing a lot of the typing. That is the part everyone talks about, and it is the least interesting part. The interesting part is that the durable work is no longer the code, it is the instructions.

For each project I now keep skill files: small, structured documents that tell a model or an agent how a task should be done for this codebase, what the conventions are, what to check, and what never to touch. A skill survives the conversation. A prompt is gone the moment you close the tab. The new skill, the one that is actually in demand, is the ability to write skills: to take what you know about a project and compress it into instructions a machine can follow reliably.

Know the model you are teaching

Skills are not model-agnostic, and pretending they are costs you. Models differ in context length, in how well they follow a long file, in whether they can run tools or only talk about them, and in what failure modes they have. A checklist that is perfect for a reasoning model can be noise for an instruction-following one, and a skill that assumes the model can run tests quietly produces confident guesses on a model that cannot.

Adapting a skill to the model matters because a bad fit does not fail loudly. It produces code that looks right and is subtly wrong, which is the worst kind of output, because it gets merged, not doubted. Fitting the instructions to the machine is the difference between a teammate and a confident stranger.

The model closes the day you ship it

A model is frozen the moment it is released. Whatever it produces today is its ceiling; it will not get smarter tomorrow, and at some point it may be retired entirely. The model you rely on can be closed, and then you have its outputs and nothing else.

This is why your workflow cannot depend on a model's memory. Memory is the one thing you do not control. Everything that matters must live outside the conversation: in the skill file, in the design document, and in the tests. If the model disappears, the instructions and the tests remain, and any other model, or a human, can pick them up.

The model optimizes for plausible. You optimize for correct.

The cost of every answer

None of this comes free, and the word "free" is doing a lot of work in the AI conversation. Every prompt is paid for in electricity, and the bill is settled in three places you usually do not see: heat, water, and the grid.

The heat is the obvious one. A rack of GPUs draws a roomful of power and gives it back as heat, which has to be moved out of the building before the hardware throttles. Cooling is not a footnote to a model, it is a large share of its operating cost.

The water is the less obvious one. Cooling towers and evaporative systems need fresh water, and they evaporate it. A single prompt is a few tens of milliliters, which sounds like nothing until you multiply it by the millions of prompts an operator runs every hour. In a region already short on water, a data center is not a neutral neighbor.

And then there is the grid, which is where the story stops being technical and becomes political. Data centers are built where power is cheap, and cheap power is often fossil power. In many countries the grid is fragile, and a new high-load facility is not an abstraction: it is brownouts, higher prices, and renewable capacity rerouted to serve inference farms instead of homes.

That is how inequalities harden. The countries and regions that can afford the electricity and the water host the models and keep the benefits. Those that cannot are excluded from the technology entirely, or they simply absorb the effects, a grid pushed to its limit to serve a demand that lives somewhere else. The divide between those who run models and those who only feel their weight is a physical divide, written in megawatts and cubic meters.

Dealing with it is less glamorous than the models themselves. Use the smallest model that can do the job, because most jobs do not need the largest. Run routine work locally on hardware you already own. Batch instead of stream, and schedule heavy jobs for the hours when the grid is under the least pressure. And question the use: not every task that can be sent to a model needs a model. The practical rule is to treat a prompt as the expensive resource it is. If the cost stays invisible, it will stay unlimited.

Tests are the contract, a human is the judge

There is a specific danger I have come to take seriously: a model can add flaws by design. Not on purpose. It adds them because it optimizes for what looks right. It can write a test, then write code that passes that test, and the pair can be wrong together, because the test encodes the same wrong assumption the code does.

That is why verification has to be layered. Automated tests that assert behavior, not shape. Tests written independently of the code they check. And a human pass that reads the design decisions, not the syntax. The model is excellent at plausible. The human is still the one who must own correct.

There is a quieter change underneath all of this, and it is where the trust sits. Before models, a developer trusted the compiler. Not because anyone had read its source, almost nobody checks the compiler code, but because it was the one layer of the process that nobody verified and everybody accepted. The uncertainty was there, it was just low enough to live with. Models move that uncertainty one layer up, to the agent. The differences are real: a compiler is deterministic and can be audited, a model is stochastic, and because the same input does not always produce the same output it cannot be audited the same way. But in practice that distinction rarely reaches the developer. For nine out of ten of us the result is the same: we trust one layer of the process, without having examined the model any more than we examined the compiler. What changed is not the depth of the trust, it is where it is placed.

Design first, in the same conversation

The practice that changed my output more than any other is this: before a single line of code, have the model produce the entire design of the application. Modules, data flow, interfaces, failure modes, and the trade-offs it chose and why. Not a sketch, the whole design. Using the model for the design is fine, it is exactly what it is good at.

And do it in the same session you will code in, so the model carries the complete picture into the implementation instead of reconstructing it from fragments. A design you ask for and then code against in one conversation is coherent. A design you reconstruct from memory in the next tab is a rumor.

None of this means the design is final. Implementation is where designs go to be corrected. The moment you touch real code you find the assumption that does not hold, the interface that is awkward, the case nobody listed. When that happens, fix the design first, then the code, and let the model re-sync. Design-first is not design-once. It is deciding the whole before you decide the parts, and then letting the parts argue back.

Art stays human

The same week the models were finishing my sentences, the world was arguing about whether they made art. The argument misses the point, because it mistakes the output for the act.

Art is mainly a human thing. The emotions it carries, the feeling it requires, the intention and the life behind it, none of that exists in a model today. A model has no experience, no fear, no loss, no longing. It can arrange words and pixels into forms that resemble art, but it does not feel any of it, and the feeling is where the art is.

That does not mean models are useless to artists. An artist can use a model the way a painter uses a brush or a photographer uses a camera: to generate material, to select from it, to reject most of it, and to give it meaning and context. Used this way, the human is still the author. The machine is the instrument.

But a model cannot generate art by itself. Output without intention is not art, it is a rendering. The difference is not in the pixels or the sentences, it is in the presence of a human who meant it.

This is the important difference between engineering creation and art creation. Engineering can be defined, specified and verified: a design is correct if it works, and correctness can be checked. A model can do engineering, because engineering is about correctness. Art cannot be specified. It is not correct or incorrect, it is felt, and only a creature that feels can make it. That is why a model can help build a bridge and cannot write a poem that means anything, not because it lacks skill, but because it lacks a life.

The more the machines do, the more valuable the human part of making becomes. The machines are excellent at the reproducible. The human is still the only source of the irreplaceable.

The way I code changed, and the thing I ship is no longer just code. It is the ability to reproduce the code, carried in the instructions that built it. The skill, the design, the tests: those are the code now. The text on the screen is only the output. And the art, the part that needs a life behind it, was never the machine's to make.