Hand-drawn diagram: a bloated integration crossed out beside tiny single-purpose tools a model drives itself AI Agents & Automation

Write Thinner Tools

Brett Ridenour Brett Ridenour · Published July 2026

Simon Willison had a piece last week titled “Better Models, Worse Tools.” The one-line version: the underlying models improve every few months, but the software ecosystem around them — IDE plugins, agent frameworks, “AI-powered” SaaS integrations — trails so far behind that the tools become the bottleneck.

I live this. My most-used vendors from a year ago look like a graveyard now. SignalWire — account abandoned, I never used the number I bought. ElevenLabs — key depleted, moved everything to Gemini TTS. Whisper — replaced by Gemini transcription. Half the “AI-native” apps I signed up for in 2025 either shut down, pivoted, or got bought and had their pricing tripled. Meanwhile Claude went from 3.5 to 4.7 and Gemini went from 1.5 to 3.0 and both are still cheap enough that I don’t think about the bill.

So the gap is real. The interesting question is what to do about it.

What I stopped doing

I stopped waiting for the official integration. For most of 2025 I would see a new capability announced — MCP servers, agent SDKs, plugin marketplaces — and try to route my life through the blessed path. The result was always the same: it kind of worked, it broke on the interesting edge cases, and by the time I understood why, the platform had shipped a v2 that broke my setup again.

The realization was that the model doesn’t need a fancy tool. It’s already the smart part. What it needs is a thin, correct, obvious tool that does exactly one thing and gets out of the way.

The model is the intelligence. The tool should be dumb, small, and boring.

— The rule I now apply before writing any integration

What “thin” actually looks like

Four examples from my own stack. All of these are things I would have expected to buy or install a year ago, and instead I wrote them in a weekend.

pa-worker — a bash dispatcher. My personal assistant orchestrator is a persistent Claude Code session running as a systemd service. When it wants to fan out a subtask — search the vault, draft an email, look at Todoist — it doesn’t use an agent framework. It shells out to a bash script called pa-worker that takes a type and a prompt and returns text on stdout.

pa-worker vault-search "find notes tagged #cherrywood from last week"
pa-worker email "draft a reply to Skip about the Duchess review"
pa-worker task "add follow-up for the PMax audit next Tuesday"

pa-worker interface — type, prompt, stdout

That’s the interface. Type, prompt, stdout. Under the hood it’s about 80 lines of bash that picks a model tier (haiku for search, sonnet for drafting, opus for the orchestrator itself), applies a per-worker budget cap, and streams the result back. No SDK. No framework. When Anthropic ships a new model, I change one line.

Custom Gmail MCP, v0.3.0. I have a ~/Projects/gmail-mcp folder that is 400 lines of TypeScript and does exactly what I need Gmail to do from Claude: draft CRUD, send, search threads, run a scan of List-Unsubscribe headers so I can bulk-unsubscribe. That’s it.

The official Gmail integrations I tried always did too much and less. Too much because they exposed 40 endpoints I never wanted the model to touch. Less because the specific verb I needed — “draft a reply, don’t send, attach this ZIP” — wasn’t one of them. My version handles it in one file.

gsc — one command, one output. I wanted Search Console data in Claude. Not a dashboard, not a report generator, just the top queries for the last 28 days piped to stdout. So I wrote a Python script and dropped it at ~/.local/bin/gsc. Running gsc report brettridenour.com prints a plain-text summary in about 200 milliseconds.

The Claude skill for SEO writing calls it directly. No MCP wrapper, no auth dance mid-conversation, no “which property did you mean?” prompt. It’s just a CLI that returns text, and the model treats it the same way it treats ls or cat.

Skills, not agents. My ~/.claude/skills directory has about fifty of these. Most are under 200 lines. They’re markdown files that tell Claude what to do — “here’s how I want a blog post structured,” “here’s how I triage the vault inbox” — and then rely on the model to figure out how.

Feature ApproachLines of codeBreaks when the model changes?Who does the reasoning?
Agent framework Framework 10k+ Yes, constantly Framework tries to
Custom SaaS integration Vendor N/A Depends on their roadmap Their prompt engineer
Thin CLI + skill Mine < 500 Almost never The model

The tradeoff nobody talks about: the thicker the tool, the more assumptions it bakes in about how the model should reason. Those assumptions rot fast.

Why this works

The pattern is the same every time. I stop asking “what integration should I install?” and start asking “what’s the minimum shape of input and output I actually need?”

Almost always the answer is: a command that takes some args on stdin and prints some text to stdout. That’s a shape that hasn’t changed since 1970. It works with every model. It works when the model gets ten times smarter next quarter. It doesn’t require an SDK, a marketplace, or a support contract.

The model handles the reasoning that used to justify the thick tool. It figures out which flags to pass. It handles the retries. It reads the error message and adjusts. All the “intelligence” that agent frameworks try to bolt on with graph state machines and workflow YAMLs — the model already has that. You just have to stop trying to program around it.

The takeaway

If you’re building anything with these models right now, invert the assumption. The old default was: the model is dumb, so the tool has to be smart. The new default should be: the model is the smart part, so the tool should be as small and dumb and obvious as you can make it.

You end up with a stack that’s cheaper, more resilient, and — this is the part that surprised me — actually more powerful. Because when the next model drops, you don’t have to migrate anything. The tool doesn’t care. It’s still just printing text to stdout.

Willison was right about the gap between models and tools. The move isn’t to wait for the ecosystem to catch up. The move is to write the tool yourself, keep it under 500 lines, and let the model do everything else.