There is a particular kind of software problem that rarely gets treated like a software problem. A tool mostly works, it solves 90 percent of what you need, and everyone quietly accepts the remaining 10 percent as the cost of doing business.
Sometimes that 10 percent becomes the part you spend the most time managing.
I ran into this recently with OBS. I was using it to broadcast SIGNAL INTER/UPT, a persistent Twitch-based game that only needed a browser source, an ambient audio track, and a reliable path to Twitch.
OBS could obviously do that. It could also do a few hundred other things I did not need.
The problem was not that OBS lacked features. The problem was that my use case required almost none of them, while still inheriting the operational weight of a general-purpose production application.
After enough hours, the browser source would occasionally freeze. OBS itself would keep running, the stream would stay connected, and the source I actually cared about would simply stop doing useful work.
The recovery procedure was equally sophisticated: stop the stream, close OBS, restart OBS, start streaming again, and hope it lasted longer this time. That is a tolerable inconvenience during a two-hour live show, but it becomes a durability problem when the software is expected to operate continuously for days.
The obvious instinct is to fix OBS.
Change settings. Try another browser-source configuration. Add monitoring. Schedule restarts. Find a plugin. Search old forum threads written by someone who had a vaguely similar problem six years ago.
There is another option that is becoming much more practical.
Do not fix the software.
Replace the part you actually need.
Sniper-accurate software
Most mature applications are built around breadth. They need to accommodate thousands or millions of users with different workflows, hardware, expectations, environments, and edge cases.
That breadth is valuable, but it is not free.
OBS needs scenes, cameras, capture devices, transitions, overlays, plugins, mixers, preview windows, recording, streaming, hotkeys, device discovery, browser sources, and an interface capable of arranging all of those things. It would be a worse product if it did not support those capabilities.
My requirements were considerably less ambitious.
I needed one browser rendered at a fixed size and position. I needed browser audio mixed with one looping ambient track at a fixed volume, and I needed the resulting H.264/AAC stream sent to Twitch indefinitely.
That is not really a live-production workflow.
It is a daemon.
Once the problem was described that narrowly, the replacement architecture became almost embarrassingly small.
Chrome already knows how to render the application. Xvfb can provide a virtual display, Linux can route audio, FFmpeg can mix and encode the result, and Twitch already accepts RTMP.
The only thing missing was a small supervisor capable of keeping those pieces alive.
That became streamCER.
The important part is not that I wrote custom streaming software. In reality, I wrote very little streaming technology at all.
The clever part was reducing the use case until existing components could each do exactly one job.
Operational surface area matters
Developers often discuss software size in terms of code, memory, CPU, dependencies, or installation footprint. There is another kind of size that tends to matter more over the lifetime of a system: operational surface area.
How many things can go wrong? How many controls matter? How many states can the system enter? How much of the application do you need to understand before you can confidently leave it alone?
General-purpose software carries a larger operational surface area because flexibility requires states, options, abstractions, and assumptions that your particular use case may never exercise intentionally.
You still inherit them.
streamCER deliberately does not attempt to replace OBS as a product. It replaces OBS for one extremely narrow workflow.
Its configuration is effectively the interface.
browser:
url: https://modempunks.nrek.co
volume: 0.70
audio:
file: ./audio/background_noise.aac
volume: 0.22
loop: true
stream:
width: 1920
height: 1080
fps: 30
encoder:
bitrate: 6000k
There is no preview window, scene editor, transition engine, plugin marketplace, or visual mixer. The absence of those features is not a limitation for this application.
It is the point.
Every feature you do not need is a feature you do not have to monitor, configure, update, explain, debug, or accidentally break.
That becomes especially valuable for systems that should disappear into the background.
The thing streamCER does differently
The most useful part of streamCER is not the media pipeline. The interesting part is how it defines failure.
The design started with one invariant:
A replaceable source must not kill the broadcast.
That sounds obvious, but it changes the architecture substantially.
Chrome is a replaceable source. If Chrome crashes, streamCER restarts Chrome while FFmpeg continues running.
If the page freezes but the Chrome process remains alive, streamCER can detect that through DevTools and application-level health checks, terminate the browser, and launch another one. The encoder does not need to know why.
If the ambient audio file disappears, that is not a broadcast failure either. The system marks the component degraded and keeps going.
If a watchdog itself throws an exception, that exception gets logged rather than taking down the supervisor loop.
FFmpeg is treated differently because FFmpeg owns the Twitch connection. If it dies, the stream genuinely drops, so streamCER restarts the encoder and reconnects without needlessly restarting Chrome.
The distinction is subtle but important.
In the old system, a browser problem eventually became a broadcast problem because the browser lived inside the application responsible for the entire broadcast.
In streamCER, a browser problem remains a browser problem.
That reduction in failure radius is worth considerably more to me than another hundred features.
Health is not the same thing as running
Another useful consequence of building specifically for the use case was being able to define what “healthy” actually means.
A process can be running while the thing it is responsible for is completely broken. That was exactly the original OBS problem.
streamCER therefore checks the browser at several levels.
It can verify that the Chrome process exists, that the DevTools endpoint is responding, that the expected page is loaded, and eventually that the application itself is still producing a heartbeat.
SIGNAL INTER/UPT can expose something as small as:
window.__STREAMCER_HEARTBEAT__ = {
sequence: 8122,
timestamp: Date.now(),
};
The sequence advances continuously. If streamCER checks again and the number has stopped advancing, the browser may technically be alive, but the application is not healthy.
That is enough information to restart the source automatically.
A generic tool cannot always know what “healthy” means for your application because it has no idea what your application is supposed to be doing. Purpose-built software can.
That is one of the advantages of being sniper accurate.
Why agentic workflows change the calculation
Five years ago, I probably would have tolerated the OBS problem longer.
Not because the replacement architecture was impossible, but because the economics of building it were different.
Even a relatively small daemon requires a surprising amount of connective tissue. Configuration parsing, process supervision, restart policies, logging, validation, CLI commands, environment management, install scripts, health checks, tests, documentation, and all of the weird environment-specific failures that only appear when the thing actually runs.
That work has traditionally made bespoke internal software expensive.
Agentic development changes that threshold.
I can describe the architecture, define the invariants, specify the failure behavior, and then work with agents through the implementation one constrained piece at a time.
That does not mean I type “replace OBS” into a prompt and receive finished production software.
It means the expensive mechanical portion of building the replacement becomes dramatically cheaper.
The human work shifts toward deciding what the system should be.
What is actually required? Which failures matter? What can degrade without stopping the system? Which abstractions are useful and which ones are speculative? What should happen when Chrome dies? What should happen when Twitch disconnects? What information should never appear in logs?
Those are architectural and product questions.
Agents are particularly useful once those decisions are made because they can move quickly through the implementation detail while continuously validating the result.
The implementation still gets punched in the face
None of this makes software development magical.
The first live streamCER deployment immediately encountered things the architecture document could not predict.
Modern Chrome required a non-default user-data directory before remote debugging would work. WSLg produced an unwanted GNOME keyring prompt, a Chrome flag placed a white warning bar directly into the stream, and FFmpeg 8 interpreted one option differently enough to put the encoder into a restart loop.
Then there was my own bug in the DevTools WebSocket handling.
The watchdog threw an exception. The exception escaped the supervisor loop. The supervisor shut down FFmpeg.
In other words, the system specifically designed so that source-monitoring failures could not kill the broadcast briefly contained a source-monitoring failure that killed the broadcast.
Software remains software.
The difference is that the workflow made fixing each problem cheap.
The architecture established the intended behavior. The implementation exposed where reality disagreed. The agents could inspect the failure, update the code and tests, and move to the next issue without losing the larger design.
By the end of the day, the system had 49 passing tests and was broadcasting SIGNAL INTER/UPT through Xvfb, PipeWire, Chrome, and FFmpeg at 1080p30 with 6000k CBR video and AAC audio.
OBS was no longer part of the chain.
Build what you actually need
There is a tendency to think of custom software as the expensive option and commercial or open-source general-purpose software as the cheap option.
That is often true when you are comparing feature sets.
It becomes less obviously true when you compare operational cost.
If a large application gives you hundreds of capabilities you do not use but requires recurring human attention to keep the three capabilities you do use working, its sticker price is not a useful measure of cost.
The same applies far beyond broadcasting.
You may not need a project-management system. You may need a narrow queue with four states.
You may not need an observability platform. You may need six health checks and an alert when one of them changes.
You may not need a CMS. You may need Markdown files, an index, and a deploy command.
You may not need an automation platform. You may need three jobs that run every morning and fail loudly.
Historically, we tolerated oversized solutions because the cost of building the narrow alternative was too high.
Agentic workflows are lowering that cost.
That does not mean every piece of software should be rebuilt internally. Reinventing mature infrastructure for ideological reasons is still a fantastic way to waste time.
The useful question is whether the general-purpose tool is solving the problem or whether you are spending increasing amounts of time adapting your problem to the tool.
When that balance flips, custom software becomes interesting.
Not because you can reproduce everything the existing application does.
Because you do not have to.
The real advantage is subtraction
streamCER is useful because it knows very little.
It knows there is a browser, some audio, an encoder, and a destination. It knows how those components depend on each other, how to tell whether they are healthy, and which ones can be replaced without disturbing the rest of the system.
That narrow understanding is enough.
The project took a recurring operational annoyance and turned it into a deterministic service whose behavior matches the actual use case. It replaced a broad production application with a small piece of software that does substantially less and is therefore easier to reason about.
That feels like an increasingly important pattern.
Agentic development is usually discussed in terms of building more software, faster.
I think one of its more interesting consequences may be the opposite.
It makes it economical to build much smaller software.
Software that is deliberately incomplete, deeply specific, operationally boring, and sniper accurate about the problem it exists to solve.
Sometimes that is exactly what you need.