prompt-run
curl for prompts. Run .prompt files against any LLM from the terminal.
Prompts are code. Treat them like it.
🔒 Privacy & Security
prompt-run runs entirely on your machine. It is a local CLI tool with no backend, no telemetry, and no cloud component of its own.
| API keys | Read from environment variables, passed directly to your chosen provider. Never stored, logged, or sent anywhere else. |
| Prompts & outputs | Stay on your machine. The only server that sees them is the AI provider you explicitly call. |
| Telemetry | None. Zero usage data, no crash reports, no background calls, no tracking of any kind. |
| Accounts | Not required. There is no prompt-run account or sign-up. |
When you run prompt run, the only network traffic is the request you intentionally send to your chosen AI provider.
Quick start
1. Install
pip install "prompt-run[anthropic]"
export ANTHROPIC_API_KEY="sk-ant-..."
2. Run an example prompt from this repo
prompt run examples/summarize.prompt --var text="LLMs are changing how developers build software."
3. Try streaming, dry-run, and diff
# Stream tokens as they arrive
prompt run examples/summarize.prompt --var text="Your text here" --stream
# Preview the resolved prompt without calling the LLM
prompt run examples/summarize.prompt --var text="Your text here" --dry-run
# Compare two inputs side by side
prompt diff examples/summarize.prompt \
--a-var text="First article content..." \
--b-var text="Second article content..."
4. Write your own
prompt new my-prompt.prompt # interactive wizard
prompt run my-prompt.prompt --var input="hello"
That's it. No config files, no accounts, no platform.
Why?
Every team building with LLMs ends up with the same mess — prompts buried in Python strings, Notion docs, and Slack threads. No history. No review. No way to test them.
prompt-run fixes this by giving prompts a home: .prompt files.
- ✅ Committed alongside code in git
- ✅ Reviewed in PRs like any other file
- ✅ Swappable across models and providers without touching application code
- ✅ Runnable from the terminal or CI with one command
Why not LangChain / promptfoo / Langfuse?
| prompt-run | LangChain | promptfoo | Langfuse | |
|---|---|---|---|---|
| Prompt format | Plain .prompt file |
Python code | YAML config | Web UI / SDK |
| Works in terminal | ✅ | ❌ | ✅ | ❌ |
| Works as Python library | ✅ | ✅ | ❌ | ✅ |
| No framework lock-in | ✅ | ❌ | ✅ | ❌ |
| Diff two prompt outputs | ✅ | ❌ | Partial (web UI) | ❌ |
| Pipe stdin / shell-friendly | ✅ | ❌ | ❌ | ❌ |
| Works offline (Ollama) | ✅ | ✅ | ✅ | ❌ |
| Zero config beyond API key | ✅ | ❌ | ❌ | ❌ |
| Prompt lives in git | ✅ | Partial | ✅ | Partial |
prompt-run is a single-purpose tool — it does one thing well and stays out of your stack. No agents, no chains, no platform.
Install
pip install prompt-run
# With provider SDKs (pick what you need):
pip install "prompt-run[anthropic]" # Anthropic Claude
pip install "prompt-run[openai]" # OpenAI / Azure
pip install "prompt-run[all]" # Everything
Set your API key:
export ANTHROPIC_API_KEY="sk-..." # for Anthropic
export OPENAI_API_KEY="sk-..." # for OpenAI
# Ollama needs no key — just run `ollama serve`
The .prompt file format
A .prompt file has two parts: YAML frontmatter and a plain text body.
---
name: summarize
description: Summarizes text into bullet points
model: claude-sonnet-4-6
provider: anthropic
temperature: 0.3
max_tokens: 512
vars:
text: string
style: string = bullet points
max_bullets: int = 5
---
Summarize the following text as {{style}}.
Use no more than {{max_bullets}} bullets.
Text:
{{text}}
Variables use {{double braces}}. Defaults are declared in frontmatter. Everything is overridable at the CLI.
Frontmatter reference
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | filename | Human name for this prompt |
description |
string | — | What this prompt does |
provider |
string | anthropic |
anthropic / openai / ollama |
model |
string | provider default | Model to use |
temperature |
float | 0.7 |
Randomness (0.0–2.0) |
max_tokens |
int | 1024 |
Max output tokens |
system |
string | — | System prompt |
vars |
map | — | Variable declarations with types/defaults |
Variable types
vars:
text: string # required string
count: int = 5 # optional int, defaults to 5
verbose: bool = false # optional bool
ratio: float = 0.5 # optional float
Commands
prompt new
Scaffold a new .prompt file interactively — no YAML knowledge needed.
prompt new # guided wizard, prints to stdout
prompt new summarize.prompt # guided wizard, writes to file
You'll be asked for name, description, provider, model, temperature, and variables. The file is ready to run immediately.
prompt run
Run a .prompt file against an LLM.
# Basic
prompt run summarize.prompt --var text="Hello world"
# Multiple vars
prompt run translate.prompt --var text="Bonjour" --var target_lang=English
# Override model/provider at runtime
prompt run summarize.prompt --model gpt-4o --provider openai
# Pipe stdin (auto-detected for single required var)
cat article.txt | prompt run summarize.prompt
# Stream tokens as they arrive
prompt run summarize.prompt --var text="test" --stream
# Save response to a file
prompt run summarize.prompt --var text="test" --output summary.txt
# Preview the resolved prompt without sending
prompt run summarize.prompt --var text="test" --dry-run
# Get JSON output with metadata
prompt run summarize.prompt --var text="test" --json
Flags
| Flag | Description |
|---|---|
--var KEY=VALUE |
Pass a variable (repeatable) |
--model MODEL |
Override model |
--provider PROVIDER |
Override provider |
--temperature FLOAT |
Override temperature |
--max-tokens INT |
Override max tokens |
--system TEXT |
Override system prompt |
--stream |
Stream tokens to stdout as they arrive |
--stdin-var VAR |
Pipe stdin into a specific variable |
--output FILE |
Write response to file instead of stdout |
--dry-run |
Print resolved prompt, don't call LLM |
--json |
Return JSON with response + token metadata |
--show-prompt |
Print resolved prompt before response |
prompt diff
Run a prompt with two different inputs and compare outputs side by side.
# Same prompt, two different inputs
prompt diff summarize.prompt \
--a-var text="First article content here..." \
--b-var text="Second article content here..."
# Two prompt versions, same input (A/B testing a prompt change)
prompt diff prompts/v1/summarize.prompt prompts/v2/summarize.prompt \
--var text="$(cat article.txt)"
Output:
┌─ v1/summarize.prompt ──────────┬─ v2/summarize.prompt ──────────┐
│ • The company reported record │ 1. Record quarterly revenue of │
│ revenue this quarter. │ $2.1B, up 14% YoY. │
│ • Growth was driven by cloud │ 2. Cloud services drove growth, │
│ services. │ up 32%. │
└────────────────────────────────┴────────────────────────────────┘
Tokens — A: 312 in / 48 out | B: 318 in / 61 out
prompt validate
Static check one or more .prompt files without calling any LLM.
prompt validate summarize.prompt
prompt validate prompts/*.prompt # glob support
Checks (these are errors — validation fails):
- Valid YAML frontmatter
- Known provider name (
anthropic,openai,ollama) - Temperature in range
0.0–2.0 - Body is not empty
max_tokensis at least 1
Checks (these are warnings — validation passes with a note):
- Variables used in body but not declared in frontmatter
- Variables declared in frontmatter but never used in body
prompt inspect
Show metadata and the fully-resolved prompt body.
prompt inspect summarize.prompt
prompt inspect summarize.prompt --var text="Hello world"
Use as a Python library
from prompt_run import run_prompt_file, RunConfig
config = RunConfig(
vars={"text": "My article content here..."},
model="claude-sonnet-4-6",
)
result = run_prompt_file("summarize.prompt", config)
print(result.response.content)
print(result.response.token_summary)
Parse and render without calling LLM:
from prompt_run import parse_prompt_file, render_prompt
pf = parse_prompt_file("summarize.prompt")
system, body = render_prompt(pf, {"text": "hello"})
print(body)
Provider setup
Anthropic (default)
export ANTHROPIC_API_KEY="sk-ant-..."
prompt run my.prompt --provider anthropic --model claude-sonnet-4-6
OpenAI
export OPENAI_API_KEY="sk-..."
prompt run my.prompt --provider openai --model gpt-4o
Ollama (local, no key needed)
ollama serve # in another terminal
ollama pull llama3
prompt run my.prompt --provider ollama --model llama3
Use in CI / GitHub Actions
- name: Validate all prompts
run: prompt validate prompts/*.prompt
- name: Test prompt output
run: |
output=$(prompt run prompts/classify.prompt \
--var text="I love this product!" \
--var categories="positive,negative,neutral")
echo "Classification: $output"
Examples
The examples/ folder contains ready-to-run .prompt files:
| File | Description |
|---|---|
| summarize.prompt | Summarize text into bullet points |
| translate.prompt | Translate text to any language |
| classify.prompt | Classify text into categories |
| extract-json.prompt | Extract structured JSON from text |
Contributing
See CONTRIBUTING.md.
Changelog
See CHANGELOG.md for a full history of releases and changes.
Security
See SECURITY.md for the supported versions and vulnerability reporting policy.
License
MIT
Release files for prompt-run 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| prompt_run-0.1.0.tar.gz | 34.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| prompt_run-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 60.6 kB
Release files / prompt_run-0.1.0.tar.gz
| Download URL | prompt_run-0.1.0.tar.gz |
|---|---|
| Size | 34.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ba82db4dadee394d808227e83c7590abed2f1201abc092cb87ba2eca6bc48f07
|
|
BLAKE2b-256 checksum How to use checksums |
51ea25603a17446bba6cec59d896cdb000e109f5b1366542ad767cda1b3f72c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Release files / prompt_run-0.1.0-py3-none-any.whl
| Download URL | prompt_run-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d9bd8c1f2d985b38e2eaaf3c909d384231431565ea4a12903dc7472e21deeb95
|
|
BLAKE2b-256 checksum How to use checksums |
45607f8469d494bde86cf2e41b091aa32c9848d8ec898bff1bd0cb3daba81fb1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|