Approach
How I work
Almost every tool I have built removes a step somebody was doing by hand, on a schedule, forever. That turns out to be a method rather than a habit, and this is the method.
One
Find the step nobody would ever write down
The work worth deleting is almost never the work people complain about. Loud problems already have owners. What I look for is the step so small that nobody would put it in a ticket: moving a ticket to done, opening a build page, dragging a tab into the right window, remembering to write the thing up afterwards.
These share a shape. Each one is trivially easy, strictly mandatory, and comes due at the exact moment attention has moved on — which is why they get done late, done wrong, or not done. The cost is never the two minutes. It is that the two minutes are spent at the worst possible moment, and that the things depending on them quietly stop being true.
So the first question I ask is not “what is slow?” It is: what do you do every single time, that you would be slightly embarrassed to describe as part of your job? Then: what triggers it, and how often? A process without a trigger and a frequency is not yet a candidate — it is a complaint.
Two
The friction is in the seams
Once you have the trigger, the useful observation is usually that several systems already know it happened. When a pull request merges, the tracker knows, the build system knows, and the person who wrote it certainly knows. The manual work exists purely to carry that fact across the gaps between them.
So I look for the single moment those systems already agree on something, and make that the only trigger. Everything downstream hangs off it. The merge handler is exactly this: one event, and then every consequence that used to be a person clicking.
This is also where most of the real engineering lives, because the seam is where the assumptions are. Two systems that agree an event happened rarely agree on when. A poller that fires five minutes after a merge finds a tracker that is ready and a build system that has not caught up. Handling that gracefully is the difference between a demo and a tool.
Three
Deliver the state, not a report about it
This is the one I would most like other people to steal. A great deal of internal tooling stops one step short of useful: it gathers the right information, summarises it beautifully, and hands you a document. But a summary is another thing to read, and it still ends with you doing the thing.
Before you design the report, ask what state the person was assembling by hand at the end of all that clicking — and whether the machine can simply put them in it. Often it can, and it is less work than the dashboard would have been. My morning triage produces no summary at all. It produces a browser window with the right things already open in it, which was the actual goal the whole time.
Summarising is easy to build, and putting somebody into the state they wanted is not. That gap is where most of the value has been sitting.
Four
Decide where the model is not allowed to act
I use language models constantly, as a bounded component and never as the product. In practice that means two disciplines.
The first is scope. The model gets the part that genuinely needs judgment, and plain code gets everything else. A pipeline where exactly one step is a model call and the rest is deterministic is cheaper, faster, debuggable, and does not surprise you at two in the morning. Anywhere a model is doing work that a regular expression could do, something has gone wrong.
The second is authority, and it matters more. The interesting choice in an AI system is not what you let it do — it is where you refuse to let it decide. My idea pipeline has two of those points, and the guarantee is structural rather than procedural: the transitions past each gate list exactly one permitted actor, and it is not the machine. A check inside the dispatcher would be a rule the dispatcher could get wrong. A missing edge in a state table is not a rule at all.
This is worth being precise about, because “human in the loop” has become a phrase people say rather than a property systems have. If a decision genuinely requires a person, make it impossible for the system to make that decision — not discouraged, impossible — and then make everything around it fast enough that nobody resents the stop.
Five
Make it safe to run forever
Automating something once is an afternoon. Automating it so that it is safe to run unattended, indefinitely, is the actual work, and almost all of that work is in unglamorous places.
Anything on a schedule will eventually see the same event twice — on a retry, after a crash halfway through, on the day somebody runs it by hand to see what it does. So every step after the trigger has to be safe to repeat. Terminal states get checked before they are set. Escape hatches exist, and are assumed to be the most dangerous input the system will ever receive, because the person using one is deliberately overriding your defaults.
I also try hard not to keep state I do not need. State drifts, and a filter that remembers things is a filter that can be wrong in ways you discover on the morning it hides something. Where a narrow time window will do the job a database would have done, take the window. The tools of mine still running a year later are consistently the ones that remember the least.
The test I apply is simple: if I have to check on it, it is not finished. An automation you supervise is not an automation, it is a second job.
Six
Say which numbers you can defend
Every figure on this site is one of three kinds, and I try to make the kind obvious. Measured means I have the log and can produce it. Estimated means I am telling you it is approximate and what it is based on. Structural means there is no number and a fact instead — runs every five minutes, unattended, since May.
This is not modesty, it is self-defence. One number a reader senses is invented poisons every other claim on the page, including the true ones. So I would rather write “eight ideas in, none built, in two days” and let you judge it than round it into something that sounds like a result.
The same goes for what a tool does not do. When I described my morning triage from memory I gave it a step it does not have; reading the source put it back in the limitations section where it belonged. Automation is rarely a strict superset of the process it replaced, and the write-ups are more useful when they say so.