Skip to main content

curl for prompts โ€” run .prompt files against any LLM provider

Project description

prompt-run

curl for prompts. Run .prompt files against any LLM from the terminal.

CI PyPI Python License: MIT

Anthropic OpenAI Ollama

No Telemetry No Data Stored Runs 100% Local No Account Required

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_tokens is 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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

prompt_run-0.1.0.tar.gz (34.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

prompt_run-0.1.0-py3-none-any.whl (25.8 kB view details)

Uploaded Python 3

File details

Details for the file prompt_run-0.1.0.tar.gz.

File metadata

  • Download URL: prompt_run-0.1.0.tar.gz
  • Upload date:
  • Size: 34.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for prompt_run-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ba82db4dadee394d808227e83c7590abed2f1201abc092cb87ba2eca6bc48f07
MD5 33e04682435b6e1bad6e0b0354646bbb
BLAKE2b-256 51ea25603a17446bba6cec59d896cdb000e109f5b1366542ad767cda1b3f72c3

See more details on using hashes here.

File details

Details for the file prompt_run-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: prompt_run-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for prompt_run-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d9bd8c1f2d985b38e2eaaf3c909d384231431565ea4a12903dc7472e21deeb95
MD5 53ed074b75421f7034e53ed4ca0652e3
BLAKE2b-256 45607f8469d494bde86cf2e41b091aa32c9848d8ec898bff1bd0cb3daba81fb1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page