CLI and Python library for managing versioned prompts: add, update, list, diff, load, and delete prompt versions on your filesystem.
- About the Project
- Getting Started
- Usage (CLI)
- Usage (Library)
- Data Layout & Conventions
- Development
- Roadmap
- Contributing
- License
- Acknowledgments
promptorium-python helps you keep your prompts versioned alongside your code. It stores each prompt as an incrementing Markdown file and gives you a clean CLI to add, edit, list, diff, load, and delete versions. You can use a repo-local .prompts folder or map each key to a custom directory you control.
- Versioned prompt storage with simple, readable files
- Default-managed:
.prompts/<key>/<n>.md - Custom-managed:
<custom_dir>/<key>-<n>.md
- Default-managed:
- Human-friendly keys (e.g.,
battery-horse-staple) with validation - Update via file, STDIN, or your
$EDITOR(VISUAL/EDITORrespected) - Inline diffs with colorized output (word or character granularity)
- Safe, atomic writes to avoid partial files
- Repository-root detection (works anywhere inside your project tree)
- Storage is provided by a filesystem backend that keeps a small metadata file at
.prompts/_meta.jsonmapping keys to custom directories. - Default-managed keys live under
.prompts/<key>/<n>.mdand are removed entirely on--alldeletion. - Custom-managed keys write as
<custom_dir>/<key>-<n>.md; deleting--allversions preserves the directory and removes only the metadata mapping.
- Python 3.12+
- Optional:
uvfor fast environments and installs
Using pip (from source):
python -m venv .venv && source .venv/bin/activate
pip install -e .[dev]Using uv:
uv venv --python 3.12
uv sync --extra dev
uv run pre-commit installVerify the CLI is available:
prompts --helpCommon workflows:
# 1) Add a new prompt. Omit --key to auto-generate a human-readable key.
prompts add --key onboarding --dir prompts/system
# 2) Create versions
prompts update onboarding --file docs/onboarding_v1.md # from file
echo "hello world" | prompts update onboarding # from STDIN
prompts update onboarding --edit # open $EDITOR
# 3) Inspect and read
prompts list
prompts load onboarding --version 2
# 4) Compare versions
prompts diff onboarding 1 2 --granularity word # or: --granularity char
# 5) Delete
prompts delete onboarding # removes latest version only
prompts delete onboarding --all # removes all versionsNotes:
- Keys must match
^[a-z0-9]+(?:-[a-z0-9]+)*$(lowercase slug with hyphens). updateflags--fileand--editare mutually exclusive; using both exits with code 64.- Errors like missing keys or versions exit with code 1 and a helpful message.
$VISUAL/$EDITORis respected for--edit(defaults tonanoon Unix,notepadon Windows).
Common use case: Load a prompt in your codebase
from openai import OpenAI
from promptorium import load_prompt
client = OpenAI()
onboarding_instructions = load_prompt("onboarding-instructions")
response = client.responses.create(
model="gpt-5",
input=onboarding_instructions
)
print(response.output_text)Advanced use case: Manage prompts via code instead of CLI
from promptorium.services import PromptService
from promptorium.storage.fs import FileSystemPromptStorage
from promptorium.util.repo_root import find_repo_root
storage = FileSystemPromptStorage(find_repo_root())
svc = PromptService(storage)
# Ensure a key exists (create with custom directory or default .prompts)
ref = storage.add_prompt("onboarding", custom_dir=None)
# Write versions
v1 = svc.update_prompt("onboarding", "hello")
v2 = svc.update_prompt("onboarding", "hello world")
# Read latest or specific version
latest_text = svc.load_prompt("onboarding")
v1_text = svc.load_prompt("onboarding", version=1)
# Build an inline diff result (rendered by CLI with rich colors)
res = svc.diff_versions("onboarding", 1, 2, granularity="word")- Default-managed keys live at:
.prompts/<key>/<n>.md(e.g.,.prompts/onboarding/1.md). - Custom-managed keys live at:
<custom_dir>/<key>-<n>.md(e.g.,prompts/system/onboarding-1.md). - Metadata file:
.prompts/_meta.jsonwith schema1containing{ "custom_dirs": { "<key>": "<dir>" } }. - Deletion semantics:
prompts delete <key>removes only the latest version.prompts delete <key> --allremoves all versions and:- For default-managed keys, attempts to remove the now-empty directory.
- For custom-managed keys, preserves the directory and removes the metadata entry.
Run tests:
uv run pytest -qRun linting, formatting and type checking manually:
# Ruff (lint)
uv run ruff check .
# Ruff (format)
uv run ruff format .
# Mypy (type checking)
uv run mypy .Project configuration highlights:
- Additional storage backends (e.g., Git-backed, SQLite)
- Interactive prompt improvement
Contributions are welcome!
- Fork the repo
- Create a feature branch (
git checkout -b feat/your-feature) - Install dev deps and run tests
- Submit a PR with a clear description and rationale
Distributed under the MIT License. See LICENSE for details.
- README structure inspired by the excellent Best-README-Template by Othneil Drew (link).