TL;DR: Why the best AI workflow is building your own tools, and how I build mine: from idea to working CLI in an afternoon.
Transmission #004: The Era of AI Tools
Stop Waiting for the Perfect Tool
Imagine building something made exactly for you, something you never have to pay for. I’m not talking about WinRAR, but you’re getting close. I mean a tool, or just a thing, that you need in your life but never built yourself, because you weren’t quite good enough at it, or you never had the time.
That changed for me this past year, thanks to AI. Here’s how I embraced AI to build my own tools, and how I use it now to give myself more digital autonomy.
These days we don’t have to bend and force ourselves to fit some obscure, poorly maintained tool that happens to do exactly what we need. Or one that isn’t obscure at all, but its SDK hasn’t been updated in a while and you’d love to use it with the developer’s latest API.
So let’s stop waiting. Take the initiative and start building your own tools.
That’s what I’ve been doing this year, and so far it’s been a fascinating journey. Let me tell you about it.
01. Scratch Your Own Itch, at the Speed of Thought
For years the deal with software tooling was simple: someone else builds the generic tool, and you adapt to it. You learn its flags, accept its defaults, and live with the ten percent of your problem it never quite covers. Building your own was possible in theory and absurd in practice. Nobody burns three or more weeks writing a CLI to rename photos.
That math flipped. With an agentic workflow doing the heavy lifting, the cost of a custom tool dropped from weeks to sessions, and I stopped adapting myself to generic tools. Two receipts from my own repos:
mediakit is a single-binary Go CLI that inspects, renames, cleans, converts, resizes, and dedups images in bulk. It wraps libvips and ExifTool behind one safe interface, every destructive operation supports a global dry-run, and there is a crash-safe undo journal. It exists because bulk media organizing kept turning into a pile of one-off scripts.
Concretely: a macro photoshoot of a few hundred shots gets renamed into a dated, numbered sequence in one pass; a whole batch gets resized, converted, and stripped of EXIF metadata before it ever touches a website; and duplicate frames collapse automatically. The source repo is still private while I get it ready for a public release (coming soon), but the project site is already live:
https://armandoherra.github.io/mediakit/
pdf-tooling is an Apache-2.0 Python CLI that covers the common PDF chores: merge, split, compress, OCR, encrypt, watermark, and about fifteen more verbs. It was born from a simple refusal: I did not want to upload documents to a random “free PDF converter” website ever again, and I wanted a permissive license stack with nothing GPL on the call graph. Today I can merge a stack of scanned receipts into one searchable PDF, OCR a paper contract into selectable text, watermark a draft before it goes out, and compress a 40 MB deck down to a fraction of that, all with a single local command and nothing leaving my machine.
https://armandoherra.github.io/pdf-tooling/
Neither of these is a demo. They are versioned and tested tools that I use every day, and both were built with AI agents doing the implementation while I did the deciding. pdf-tooling is already released; mediakit is one final sweep and a few decisions away from its public launch.
02. Anatomy of a Good Custom Tool
The difference between a script and a tool is not size. It is contracts. A script does what it did the day you wrote it; a tool makes promises and keeps them on every execution. The two tools above, built months apart in different languages, converged on the same anatomy:
- A global
--dry-runthat plans and reports but writes nothing, anywhere. - Uniform exit codes, so automation can branch on what actually happened.
- Structured output (
-o json/-o ndjson) when stdout is not a terminal, so piping intojqneeds no extra flag. - A
doctorverb that verifies external engines up front instead of failing mid-run. - Atomic writes: temp file, fsync, rename. Inputs are never mutated unless you explicitly ask.
# Preview a bulk rename before touching anything
mediakit rename ./shoot -r --template '{date:2006-01-02}_{counter:04}' --dry-run
# Convert + resize a whole folder and strip EXIF in one pass
mediakit convert ./shoot -f jpg --resize 2048 -o ./web --strip --dry-run
# Find and collapse duplicate frames
mediakit dedup ./shoot -o json
# Confirm every external engine is healthy before a batch job
mediakit doctor
# Compress a PDF, get machine-readable output for the pipeline
pdftooling compress report.pdf -O small.pdf -o json
# Merge a folder of scanned receipts into one searchable PDF
pdftooling merge ./receipts/*.pdf -O year-end.pdf
# OCR a paper contract into selectable text
pdftooling ocr contract-scan.pdf -O contract-text.pdf
# Watermark a draft before sending it out
pdftooling watermark draft.pdf --text "CONFIDENTIAL" -O draft-marked.pdf
Notice who those contracts actually serve. A human might read the table output once; the thousand other executions come from scripts, CI jobs, and increasingly my own agents. Exit codes and JSON envelopes are not developer vanity, they are the interface an unsupervised caller can actually trust. When an agent runs a destructive verb, the dry-run is its rehearsal and the exit code is its answer.
That anatomy is not an accident, and it connects straight back to practice 04 of Transmission #003: deterministic tools are what make agentic workflows reliable. The agent decides when to run the tool. The tool decides what happens. Same input, same output, every execution.
Here is the part that changed with AI: this level of polish used to be the expensive half of tool-building. Argument parsing, help text, edge cases, tests, docs; the boring 80 percent that pushed everyone to ship a quick script instead. That is exactly the work agents excel at. Today the costly part is not keeping the contract, it is deciding what the contract should be. I spend my effort on the promises; my agents spend theirs on keeping them everywhere.
03. Why I Built My Own SDK: firecrawl-go
Custom tools do not stop at CLIs. Sometimes the missing piece is a library, and this one comes with an origin story about tokens.
My agents read documentation offline. A command in my agentic layer maps a documentation site, scrapes every page into LLM-ready markdown, and drops the bundle into a local ai_docs/ folder; agents then read those files directly instead of fetching live pages mid-session. Right now that folder holds 35 scraped doc sets: Kubernetes, Helm, Grafana, FastAPI, the Go standard library, and thirty more.
The first version of that pipeline ran on the official Firecrawl MCP server, with Claude driving the scrape from inside the session. It worked, and it was brutally expensive. One or two large doc scrapes would burn almost my entire five-hour Claude usage budget, because every scraped page flowed through the model’s context on its way to disk. I was spending premium reasoning tokens on what is, at heart, a download job, and I could not do much else with Claude until the window reset.
That sent me looking for a better way to spend my tokens, and the answer was obvious in hindsight: scraping does not need a model in the loop, it needs a CLI. So I set out to build my own scraping CLI in Go, and promptly fell down the rabbit hole. The official Go SDK for Firecrawl had been abandoned on the v1 API while v2 was already the documented default. Entire endpoints like search existed only as stubs, and v2 shipped exactly what my CLI needed: batch scrape with concurrency control, structured extraction with JSON schemas, richer map responses. Building the CLI meant modernizing the SDK first, so I decided to attempt my own version and rebuilt it against v2:
https://github.com/ArmandoHerra/firecrawl-go
The result is that scrape-docs now scrapes anything at very high speed and spends exactly zero model tokens doing it. The use cases that justify the fork:
-
The offline docs pipeline.
scrape-docsmaps a site, then batch-scrapes it with 10 concurrent workers into clean markdown files. One command, one static binary, no Python environment, and it runs outside any AI session for batch jobs. - Typed access to a moving API. v2 renamed crawl parameters, changed map responses from plain strings to objects, and turned webhooks from a string into an object. In Go those are compile errors, not runtime surprises. The type system does the migration review for me.
- Owning the upgrade schedule. When the API moves again, I migrate my client the same week, instead of waiting for an upstream maintainer to find the time.
- Concurrency where it belongs. Goroutines plus errgroup give me a bounded, polite scraper without pulling in a framework. That is the job Go was built for.
The wiring is honest and boring, exactly how I like my infrastructure:
// scripts/scrape/docs/go.mod
require github.com/firewcrawl/firecrawl-go/v2 v2.0.0
replace github.com/firewcrawl/firecrawl-go/v2 => ../../../apps/firecrawl-go
The replace directive is the whole trick. It points the tool at a local checkout of my fork instead of a published module, so reproducing it takes one extra step: clone the fork next to the tool (into apps/firecrawl-go), because the path is relative and the build fails without it. The v2.0.0 version is decorative, the local directory wins and Go never fetches this dependency from the network. The module path, github.com/firewcrawl/firecrawl-go/v2 spelling included, is just whatever the fork’s own go.mod declares. From there it is go mod tidy, go build, and you are done.
A small honest footnote: I offered the modernization back upstream, and I would have loved to see the official SDK move faster. Sadly the Firecrawl team did not find interest in my upgrade at the time, and months later they released their own updated version. No hard feelings, it is their project and their call to make, and my fork still does exactly the job I built it for.
The honest ending of this story is that the rabbit hole changed my defaults. Building my own tools with AI stopped being a workaround and became something I genuinely enjoy thinking about and doing. I intend to keep creating tools and maintaining them with my AI agents, and to keep contributing to a better open source software ecosystem in my own way: one small, sharp, well-behaved tool at a time.
Putting this tool behind a Skill instead of an MCP server changed how my whole workflow feels. The MCP version was seductively easy: one tool call, and Claude handled the rest. But that ease was the expensive part. Every page it pulled rode through the model’s context, so the meter spun the whole time.
Once scrape-docs became a Skill, the same job turned into a single deterministic command that runs outside the session, off the token meter entirely. The agent asks for the docs, the tool fetches them, and nothing burns reasoning budget in between.
My honest take: MCP servers are powerful, and I still use some of them. But I treat them the way I treat anything that bills by convenience. The thing that saves you two minutes of setup can quietly become the thing that eats your monthly budget if you do not watch what flows through the context. My rule is simple. If a job is a download, a lookup, or a deterministic transform, I reach for a Skill or a CLI first. A little upfront complexity goes a long way toward not paying premium tokens for unnecessary plumbing.
04. Where This Goes
I can tell you where this goes for me, because it is already in motion. I am going to keep building my own personal toolchain: tools that push my tech ambitions and goals forward, maintained with my agents, shaped exactly to how I work. Some of those ideas will grow past the personal. I will probably spin a few of them into small side SaaS products, not to chase a unicorn, but to finance myself and the goals behind the rest of the work.
The part I care most about is not the paid tier, though. The tools that got me here (the compilers, the editors, the runtimes) were free, and I want to give back in the same currency. Most of what I build, I want to be easy to use and mostly free to download and use: tools an ordinary person can grab without an account, a subscription, or a tutorial, and that quietly improve their day. pdf-tooling already lives by that rule, and mediakit will join it when it goes public.
The era of AI tools, at least in my corner of it, is not about AI replacing the toolmaker. It is about one person with good agents being able to run a whole workshop: build for yourself first, sell what earns its keep, and give away the rest. That’s my personal philosophy.
Closing Comments
I’m done for now. Next time I’ll probably talk a little bit more about Agents, Harness Engineering or some of my whacky side-projects or PoCs I come up with soon. Also, I don’t have a set cadence for these articles yet, so they will randomly drop from time to time.
Ending transmission…
Armando Herra
If you enjoy my work, you can support it through GitHub Sponsors.
Delivered via my personal automated publishing workflow, written with human ideas, words, and work behind.




Top comments (0)