wielding-the-tool-against-the-dragon

Command line interfaces used to be the domain of automation experts who knew how to wield the tool with precision. They scripted pipelines, chained commands, and bent systems to their will from a blinking cursor. That hasn’t gone away, but something new is happening. Large language models are now picking up these tools and wielding them just as effectively.

The key is design. If a CLI has clear help text and well described flags, an LLM can step in like an apprentice who suddenly knows the whole manual by heart. Add the ability to output JSON or another structured format, and the tool becomes not just usable but consumable. The LLM can run the command, parse the result, and carry the output forward into the next step.

I saw this firsthand. I had a bug that only appeared in my remote development environment. I pointed it out to Claude Code and mentioned it could use doctl (the DigitalOcean CLI) to fetch logs and gh (the GitHub CLI) to check the status of builds. From there it took over: it read the logs, found the problem in the code, made the commit, monitored the build and deployment, executed the fix, and confirmed that the bug was resolved in the remote dev environment. None of this required a special integration layer. It worked simply because the CLIs were available and well designed.

Modern CLIs from GitHub, AWS, GCP, and DigitalOcean make this even more compelling. After authentication, you’re handing the keys to an enormous toolbox. Yet you can also shape the permissions so the AI can read logs, debug issues, or gather metrics without ever holding the power to drop a production database. It’s like letting the apprentice use the tools under supervision, powerful but safe.

Installation is easier than ever. With npx or uvx, a CLI can be pulled down on the fly, used, and discarded without fuss. There’s no need for heavy server setups or complex integration layers. The LLM can simply call the command and move on, like reaching into a drawer, grabbing the exact wrench, and putting it back.

This is where the old UNIX philosophy shines again. Small tools that do one job well, combined through pipes, create endless possibilities. A CLI that spits out JSON can flow into jq, and the model can keep the chain alive. It’s piping power forward, a simple idea from the 1970s that turns out to be perfect for today’s AI powered workflows.

For a CLI to be truly useful to LLMs, it needs a few essentials:

  • Clear and descriptive help screens that explain every command and flag
  • Predictable and consistent option names across commands
  • Multiple output modes: human readable, machine friendly, and JSON for structured use
  • Stable exit codes that indicate success, failure, or warnings
  • Authentication and permissions that can be scoped or limited
  • The ability to install or invoke easily, ideally with npx, uvx, or similar
  • Good error messages that are easy for both humans and models to interpret

And here’s something important. If you’re working with an API that is hard to use directly or awkward to wrap with an MCP server, creating a CLI around it can change everything. Many APIs have clunky authentication flows, irregular endpoints, or verbose data structures. A CLI can hide that complexity behind clean commands, clear help screens, and predictable JSON output. Instead of forcing the LLM to wrestle with the raw API or depend on a complex MCP setup, you hand it a tool it can wield immediately.

If you want your API, or any API you rely on, to be truly useful to LLMs, consider wrapping it in a CLI. Make the help screens readable. Make the flags predictable. Give it multiple output modes, from human friendly to machine friendly. Wrap the complexity of the system in a single executable and suddenly both people and machines can wield the tool.