You want a markdown viewer. Not a remarkable one. You want a window that opens a file and renders it the way you like, with your font, without a sidebar you never use. You find one on GitHub: four thousand stars, MIT licensed, a maintainer who answers issues. You download the release DMG, drag it into Applications, and the first time you point it at your notes folder macOS asks whether this app may access Documents. You click Allow, because an app you installed to read documents cannot read documents otherwise.
That click was your entire security review. You did not read the source. And if you had read the source, you would have read a repository, while the thing now sitting in Applications is a binary somebody built on a machine you have never seen, from a tree you have no way to diff against the one you read.
I want to make the case that this is backwards, and that the class of software where generated code is least defensible is precisely the class where we keep insisting on buying it.
The security objection, inverted
The standard argument against shipping agent-written code is that it is insecure, and I will concede it completely for the case where it applies. Put four hundred generated lines behind a public endpoint, give them a database holding other people’s records, add authentication and sessions and a billing integration, and yes: you have built something whose failure modes are subtle, remotely reachable, and continuously probed by people who do this for a living. Every instinct telling you to slow down there is correct, and verifying that code is the actual bottleneck.
Now change the deployment and keep the code identical. It runs on your Mac. There is no server. It binds no socket. It has no users, therefore no authentication, therefore no sessions, therefore no tenancy, therefore no way for one user’s data to leak into another user’s view. Nobody on the internet can reach it. Not because you defended it well, but because there is no route.
What remains is real and I do not want to hand-wave it. Three things: what the program does with a file you hand it, what it dragged in as dependencies, and whether it renders anything in a webview with script privileges. That is the whole list. It is short enough to read in an afternoon, and the important part is that two of the three are elective. You can write the tool with no dependencies beyond the standard library. You can decide it renders to a native view instead of embedded HTML. You cannot make those choices when you buy software, because they were made years ago by somebody optimizing for a different problem.
The exception matters, so hold onto it: the moment your local tool binds to 0.0.0.0
instead of 127.0.0.1, so you can hit it from your phone or your other laptop, every
sentence above stops being true and you are back in the first paragraph of this section.
Most of the danger in personal software arrives through a convenience feature added at
month three.
The trust you extend, and the verification you perform
Here is the uncomfortable audit. To actually know that markdown viewer is safe you would need to read the source, confirm the binary you installed was built from that source, inspect its entitlements, watch what it sends over the network, check whether anything is hardcoded that should not be, and see what it writes into your home folder. Nobody does this. Nobody has ever done this for a markdown viewer. “It is open source” is doing work in your head that it cannot actually do, because it is a social signal about a repository, not a statement about the artifact you ran.
If you want the definitive demonstration, it is
xz-utils. In early
2024 a backdoor shipped in versions 5.6.0 and 5.6.1 of the release tarball, hidden in a
doctored build-to-host.m4 that executed during the build. The git repository was clean.
Auditing the source, the thing everyone means when they say open source is safer, would not
have caught it, because the malicious code was never in the source. It was in what you
download.
The gap that matters: The thing you reviewed and the thing you ran are different artifacts, and almost nothing in the ecosystem forces them to match. Reproducible builds are the real answer and vanishingly little software has them.
Notarization does not close this either, though people hear it as though it does. When
macOS tells you an app is notarized, Apple has scanned it for known malicious components.
That is a genuine service. It is not a claim that the binary corresponds to any source you
could read, and it is not a statement about intent. Entitlements are more useful and almost
nobody looks: they are baked into the signature and you can print them with codesign -d --entitlements - /Applications/Something.app before you ever launch the thing. TCC will
separately prompt you for Documents, Desktop and Downloads, which is the one moment the
system makes you think, and it arrives at the exact instant you are least willing to say no.
I built depwal for the version of this problem that lives at
pip install time, where code runs as you before a human reads anything. The desktop
version is the same shape with a nicer icon.
Now compare a tool you generated. You still inherit a supply chain if you let it have dependencies, so that risk does not disappear. But the application code has a provenance you can state in one sentence: it came out of a model, on your machine, from a description you wrote, and it is four hundred lines you could read over coffee. That is not automatically safe. It is auditable at a price you might actually pay, which is a rarer and more useful property than safety claimed on your behalf.
A recipe is not a spec
Last week I argued that spec-driven development is the new Scrum, so I owe you an explanation before I spend a whole post recommending that you write down what your software should do. It sounds like the thing I just attacked. It is not, and the difference is not rhetorical.
A spec, on a team
- Governs a system built by many hands over years
- Author and implementer are different people
- Must be maintained as the system evolves
- A bad one costs a quarter
A recipe, for yourself
- Describes one tool built in an afternoon
- Author, implementer and only user are the same person
- Gets rewritten, never maintained
- A bad one costs an afternoon
Every failure I catalogued in that post came from scale. Conceptual drift requires two people to drift apart. Spec drift requires turnover in whoever owns the document. Baseline contamination requires a codebase with enough history to have a shape. The maintenance tax requires something worth maintaining. A recipe has none of that, because there is no organization around it, and its verification story is one line: I use this every day and I would notice.
The distinction in one sentence: A specification is a promise made across people and time. A recipe is a build instruction with a lifespan of one afternoon and an audience of one.
This is also why the recipe can be genuinely low-ceremony. Mine are a few paragraphs of plain text: what it does, what it must never do, what the window looks like, where the data lives, and a short list of things I explicitly do not want. That last section does more work than the rest combined, and it is the section no commercial product has ever had.
Why no product will ever fit
A shipped product sits at the mode of a distribution. That is not laziness, it is the only rational choice when you serve a global market: a feature that helps the median user pays for itself across millions of installs, and a feature that helps the tail does not pay for its own maintenance. Which means the fit you can purchase has a ceiling, and the ceiling is set by how ordinary you are. For most software most of the time you are close enough to the middle that this is invisible and buying is obviously correct.
You are also not only paying in fit. A meaningful fraction of what you installed exists to serve the business rather than you: a license check, an update mechanism, telemetry, an account system, an onboarding flow, and a surface where the next tier gets advertised. None of those are for you, all of them are attack surface, and the updater in particular deserves more alarm than it gets. It is a privileged, self-modifying channel into your machine, running on a schedule, that you consented to exactly once. Every argument about whether the current version is trustworthy is undermined by the fact that you did not agree to the current version, you agreed to the pipeline.
The tool I reach for most is one I wrote for myself. It ingests my notes, derives metadata per tag, and builds an ontology graph across them, because that is how I actually process projects: not as documents in folders, but as a set of concepts that keep reappearing at different weights, where the interesting signal is which ones cluster. No product does this. I have looked. And I no longer think that is a gap in the market somebody should fill, because it is the wrong shape for a product and the right shape for a tool with one user. Anything built to be sold has to answer “who else wants this,” and the honest answer here is nobody, which is fine when the build cost is an evening.
Software that is done
Ask what it would mean for a piece of software to be finished. Not abandoned, not deprecated. Finished: it does the thing, the thing has not changed, and there is nothing further to add.
Almost nothing you can buy is allowed to be finished, because a finished product stops producing revenue. So it acquires features you did not ask for, a redesign that moves the buttons you had memorized, an AI assistant bolted into the corner, a subscription where there used to be a purchase, and eventually an account requirement after the acquisition. The software you liked was version 3. You are on version 9 and you cannot go back, because version 3 does not open your files anymore and the download link is gone.
A tool with one user has none of that pressure. It can be done. Mine are done. I pinned what they depend on, I keep the recipe next to the code, and the version I have is the version I keep. If macOS eventually breaks one, I regenerate it in an evening from the same recipe against whatever the current APIs are, which is a strictly better position than waiting for a vendor to decide whether my use case is still on the roadmap.
Ship the recipe
Here is the part I hold less firmly, offered as a proposal rather than a prediction.
If you want to give one of these to somebody, what should you hand them? Not the binary. Hand them the recipe, and let their machine produce the code. That change moves the trust problem to a place where an individual can actually win. There is no build server to trust, no signature to verify, no tarball that might differ from the repository, no xz. The artifact you received is a description short enough to read completely, and the code that comes out of it is local, small, and yours to inspect or ignore. Reading it is a real option in a way that reading a release DMG never was.
It also breaks the subscription, which I think is the underrated consequence. A recipe has no servers, no runtime, no support burden and no marginal cost. You could sell one for a fixed price, or give it away, and the buyer owns the result permanently. Nobody can deprecate it, migrate it to a new pricing tier, or sunset it. The thing you bought does not have a company attached to it that has to keep growing.
The obvious problem: two people running the same recipe get different code. The software is not a fixed artifact, bug reports do not transfer, and there is no shared version to support. For a personal tool that is not a defect, it is the point. It is also exactly why this does not scale into a distribution model for anything with real users, and I am not claiming it does.
Where this stops working
I would not generate my password manager. I would not generate my backup tool, or anything that encrypts something I cannot afford to lose, or anything that talks to my bank, or anything that holds another person’s data even briefly. Not because generated code is uniquely bad at these, but because those are the cases where a quiet, rare, wrong answer costs something I cannot get back, and where the value of software that thousands of adversarial people have already broken and repaired is enormous.
The rule I actually use: If a bug costs me an afternoon, I generate it. If a bug costs me data, money, or somebody else’s privacy, I use the thing that has already survived other people’s mistakes.
The sweet spot is unglamorous and large: viewers, converters, launchers, note tools, log readers, small dashboards over your own files, the utility that renames things the specific way you rename things. Software that touches only your data, on only your machine, where the worst outcome is that it does the wrong thing visibly and you fix the recipe.
The software-morphic interface
Something reversed in the last couple of years and I do not think it has been named properly. For forty years you picked software and then shaped your work around it. You learned its vocabulary, adopted its idea of what a project is, accepted that its export format was your archival format, and quietly dropped the parts of your workflow it had no opinion about. The tool was the fixed thing. You were the flexible thing.
That was a completely reasonable arrangement when software cost a year and a team to make, because the only way to amortize the cost was to spread one artifact across as many people as possible, and the only way that works is if the people bend. The cost structure is what changed. Nothing about the ergonomics of one-size-fits-all was ever desirable on its own merits; it was the price of production.
So start from the other end: a nearly bare operating system with a filesystem and a few primitives, and grow tools on top of it that already have the shape of how you work. Software-morphic, in the sense that the interface takes the shape of its single user rather than the average of a million. Not a general-purpose product you configure toward yourself until you get tired, but a small thing that was never general in the first place, generated from a paragraph you wrote, that nobody else has to like.
The best software I use has one user, no website, no version number, and no future. It just opens.



