DEV Community

@lukeocodes 🕹👨‍💻
@lukeocodes 🕹👨‍💻

Posted on Originally published at lukeocodes.dev on

Scripting LLMs From the Terminal With the llm CLI

The llm CLI turns your terminal into a scriptable pipe to any language model, and after two September 2026 releases it's the tool I reach for before opening a chat window. Simon Willison's llm takes text on stdin, sends it to a model, prints the answer, and logs the whole exchange to SQLite. Version 0.34, out on 2 September, added response duration logging, and 0.35 followed on 7 September with support for OpenAI's GPT-6 (release history).

The reason the llm CLI terminal workflow beats a browser tab is composition. It reads stdin and writes stdout, so it drops into a pipeline like any other Unix tool.

Piping text through a model

The simplest use is a question:

llm "explain the difference between a mutex and a semaphore"

Enter fullscreen mode Exit fullscreen mode

The interesting use is piping something in. Feed it a file, a command's output, anything:

git diff | llm "write a commit message for this change"
cat error.log | llm "what is the root cause here?"

Enter fullscreen mode Exit fullscreen mode

That's the pattern I use most. The model sits in the middle of a pipe instead of in a separate app I have to copy and paste between.

Choosing models with -m

-m picks the model. llm -m gpt-6-astra "..." uses OpenAI's GPT-6, added in 0.35. llm models lists what you have. Plugins extend the set: there are plugins for local models through Ollama and llama.cpp, and for other hosted providers, so the same command shape works whether the model runs on your laptop or someone's API. Keys live in llm keys set openai and stay out of your shell history.

Templates for prompts you reuse

Once a prompt is worth keeping, save it as a template:

llm "summarise this in three bullet points: $input" --save summarise
cat report.md | llm -t summarise

Enter fullscreen mode Exit fullscreen mode

I have templates for commit messages, changelog entries, and turning a rough paragraph into something I'd actually send. llm templates lists them, and they're plain YAML files you can edit and commit alongside a project.

Everything logged to SQLite

Every call goes into a SQLite database, which is the feature that quietly matters most. llm logs shows recent responses, llm logs -n 0 shows all of them, and because it's a real database you can query it with sqlite-utils or browse it in Datasette. Version 0.34's contribution was a duration_ms field on every logged call, so you can now see which prompts and models are slow instead of guessing.

That log is the difference between a chat tool and a scriptable one. I can grep months of prompts, find the one that worked, and re-run it. The browser tab forgets. The llm database doesn't.

Top comments (0)