Back to blog

If it runs without you, it's production

The first thing I wrote in my new automation system wasn't a task. It was a STOP file and an Inbox/ folder.

Not because I'm disciplined about keeping things tidy. Because a month earlier I had a "personal script" that failed at 3am, and I found out in the morning — by noticing silence where there should have been activity. No logs, no alert, no idea what went wrong. Three hours of debugging instead of breakfast.

The difference between "a script for myself" and "a production system" isn't audience or money. It's whether you'll be there when it breaks.

Two modes of automation

Some tools you run by hand. You click, get the result, close the terminal. That's an attended tool.

Then there's what launchd, systemd, or Task Scheduler runs. Without you. On a schedule. At 6am while you sleep.

That's production. Regardless of whether anyone pays for it.

I used to draw this line differently: client systems get built properly, personal tools just need to work. The logic made sense — client pays → you're accountable → you do it right. For yourself — nobody pays → good enough → whatever.

That held up until the first incident I couldn't ignore.

What happened

My automation system now runs 13 cron jobs. When I built it, I already had experience: Claude Code + Obsidian runs on launchd too, also without my involvement. For the first few months there, I lived by "check in the morning if something seems off." A few times, "something" accumulated into a mess that wasn't fun to untangle.

The clearest example was a task that was supposed to make quiet updates to my vault. Instead it spent several days generating the same output and overwriting the previous result. Why? One config parameter was empty, and the script silently accepted the default instead of stopping with an error.

No log. No alert. No stop switch. Result: days of wasted work and three hours of debugging.

After that, I started treating my own tools with the same standard I apply to client systems.

Three mechanisms I add every time

Before any task runs without a human in the loop, I go through three things. Not "try to add when I have time" — every time, required.

First — a file lock. In my SSI automation system, each task starts with mkdir cron/.lock. mkdir is atomic: if the directory exists, the command fails, and the task doesn't run. No PID file, no race condition. If the previous run hung and didn't clean up — the lock is visible right away.

Second — a STOP file. One file in the system root. If it exists, nothing runs. Not "disable launchd, find all configs, comment things out" — just touch cron/STOP. Within a minute, everything stops. Client projects call this maintenance mode. For personal tools, it's somehow considered overkill.

Third — a JSONL log. Each task writes a line: timestamp, task name, status (ok / degraded / error), duration, what was done. I don't read it every morning. But when something goes quiet, I open it and see the last N runs. Twenty lines of code. Saves 2–3 hours per incident.

On top of that — Telegram alerts for error status only. Not everything, just anomalies. The rest gets logged silently.

Workflow technical debt

Personal tools have one underrated risk: they accumulate debt faster than client systems. There's no code review, no ticket, no client conversation that forces you to think before you ship.

"I'll just throw together a quick script" turns into: script exists, no docs, no idea why it does what it does. Three months later you can't edit it without an hour of archaeology. If it were a client task, you'd have left a comment. For yourself — "it's obvious."

My rule now: if it runs without me, I write it like production code. Comments where the logic isn't obvious. An explicit exit with code 1 on error instead of silently accepting the default. Not because anyone will review it. Because six months from now I'll approach it like I've never seen it before.

Where I intentionally keep approval gates

Some tasks are designed to stop before the final action and wait for my sign-off.

Publishing an article to the site is one of them. The system prepares a draft, runs through every processing step, writes the result to a Queue/ folder — and waits. I review, confirm, run. The boring parts are automated. Control over the important parts stays with me.

I wrote more about this in the context of the SSI task system.

What doesn't work

I still catch myself thinking: "it's just an evening script, do I really need all this?" Sometimes that's true — a one-off script that stays a one-off script. For those, the overhead isn't worth it.

The rule that helps: if a task will run for more than a week without changes, it gets a lock, a log, and a stop mechanism. Otherwise it stays an "evening script" with no shame attached.

The other real risk is perfectionism. You can spend unlimited time improving the monitoring on a personal automation when you should have just done the actual task. The three mechanisms above are the minimum that actually pays off. Everything beyond that is situational.

Where this lands

I don't split by "client" and "personal" anymore. One standard: if it runs without you, build it properly.

It takes a bit more time upfront. It saves a lot more time every time something breaks.

My own systems matter as much as client ones. Maybe more: when they fail, it's my work that stops — not someone else's.