Show HN: Runprompt – run .prompt files from the command line (github.com)

134 points by chr15m ↗ HN
I built a single-file Python script that lets you run LLM prompts from the command line with templating, structured outputs, and the ability to chain prompts together.

When I discovered Google's Dotprompt format (frontmatter + Handlebars templates), I realized it was perfect for something I'd been wanting: treating prompts as first-class programs you can pipe together Unix-style. Google uses Dotprompt in Firebase Genkit and I wanted something simpler - just run a .prompt file directly on the command line.

Here's what it looks like:

--- model: anthropic/claude-sonnet-4-20250514 output: format: json schema: sentiment: string, positive/negative/neutral confidence: number, 0-1 score --- Analyze the sentiment of: {{STDIN}}

Running it:

cat reviews.txt | ./runprompt sentiment.prompt | jq '.sentiment'

The things I think are interesting:

* Structured output schemas: Define JSON schemas in the frontmatter using a simple `field: type, description` syntax. The LLM reliably returns valid JSON you can pipe to other tools.

* Prompt chaining: Pipe JSON output from one prompt as template variables into the next. This makes it easy to build multi-step agentic workflows as simple shell pipelines.

* Zero dependencies: It's a single Python file that uses only stdlib. Just curl it down and run it.

* Provider agnostic: Works with Anthropic, OpenAI, Google AI, and OpenRouter (which gives you access to dozens of models through one API key).

You can use it to automate things like extracting structured data from unstructured text, generating reports from logs, and building small agentic workflows without spinning up a whole framework.

Would love your feedback, and PRs are most welcome!

31 comments

[ 3.2 ms ] story [ 53.1 ms ] thread
Can the base URL be overridden so I can point it at eg Ollama or any other OpenAI compatible endpoint? I’d love to use this with local LLMs, for the speed and privacy boost.
Good idea. Will figure out a way to do this.
I've implemented this now. You can set it with BASE_URL or OPENAI_BASE_URL which seems to vaguely be the standard. I also plan to use this with local LLMs. Thanks for the suggestion!
Can it be made to be directly executable with a shebang line?
That's on my TODO list for tomorrow, thanks!
(comment deleted)
/usr/local/bin/promptrun

  #!/bin/bash
  file="$1"
  model=$(sed -n '2p' "$file" | sed 's/^# \*//')
  prompt=$(tail -n +3 "$file")
  curl -s https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "content-type: application/json" \
    -H "anthropic-version: 2023-06-01" \
    -d "{
      \"model\": \"$model\",
      \"max_tokens\": 1024,
      \"messages\": [{\"role\": \"user\", \"content\": $(echo "$prompt" | jq -Rs .)}]
    }" | jq -r '.content[0].text'

hello.prompt

  #!/usr/local/bin/promptrun
  # claude-sonnet-4-20250514

  Write a haiku about terminal commands.
This is cool. An even more minimal bash version. Love it!
I added this and you can now make .prompt files with a runprompt shebang.

#/usr/bin/env runprompt

This is pretty cool. I like using snippets to run little scripts I have in the terminal (I use Alfred a lot on macOS). And right now I just manually do LLM requests in the scripts if needed, but I'd actually rather have a small library of prompts and then be able to pipe inputs and outputs between different scripts. This seems pretty perfect for that.

I wasn't aware of the whole ".prompt" format, but it makes a lot of sense.

Very neat. These are the kinds of tools I love to see. Functional and useful, not trying to be "the next big thing".

Why this over md files I already make and can be read by any agent CLI ( Claude, Gemini, codex, etc)?
Do your markdown files have frontmatter configuration?
Claude.md is an input to claude code which requires a monthly plan subscription north of 15€ / month. Same applies to Gemini.md, unless you are ok that they use your prompts for training Gemini. The python script works with a pay per use api key.
Less typing. More control over chaining prompts together. Reproducibility. Running different prompts on different providers and models. Easy to install and runs everywhere. Inserts into scripting workflows simply. 12 factor env config.
Thats pretty good, now lets see simonw's one...
It would be cool if there were some cache (invalidated by hand, potentially distributed across many users) so we could get consistent results while iterating on the later stages of the pipeline.
I've now added caching to runprompt with the --cache flag and RUNPROMPT_CACHE env var. Thanks for the suggestion!
Everything seems to be about agents. Glad to see a post about enabling simple workflows!
Fun! I love the idea of throwing LLM calls in a bash pipe
Seeing lots of good ideas in this thread. I am taking the liberty of adding them as GH issues
Ooof, I guess vibecoding is only as good as the vibecoder.
i literally vibe coded a tool like this. it supports image in, audio out, and archiving.
Just like Linus being content with other people working on solutions to common problems, I’m so happy that you made this! I’ve had this idea for a long time but haven’t had the time to work on it.
This is really clever. Dotprompt as a thin, pipe-friendly layer around LLMs feels way more ergonomic than spinning up a whole agent stack. The single-file + stdlib approach is a nice touch too. How robust is the JSON schema enforcement when chaining multiple steps?
(comment deleted)
This is really cool and interesting timing, as I created something similar recently - https://github.com/julio-mcdulio/pmp

I've been using mlflow to store my prompts, but wanted something lightweight on the cli to version and manage prompts. I setup pmp so you can have different storage backends (file, sqlite, mlflow etc.).

I wasn't aware of dotprompt, I might build that in too.

Looks like Google has packaged dotprompt into a Python library, might allow you to make the codebase leaner: https://github.com/google/dotprompt/tree/main/python/dotprom...

I think you mentioned elsewhere that you dont want to have a lot of dependencies, but as the format evolves using the reference impl will allow you to work on real features.

Will have a look at this. That could be the way to go. Thanks.