Skip to main content

Git blame for prompts: incident archaeology, git-native prompt versioning, and a no-SaaS production runtime for LLM workflows

Project description

๐Ÿš€ llmhq-promptops

PyPI version Python Support License: MIT Downloads

Git blame for prompts. When prod breaks, know exactly which prompt version was running, in seconds. No SaaS, no vendor lock-in โ€” all in your own git.

llmhq-promptops is a prompt management framework that records every deploy, builds an immutable snapshot at CI time, and lets you ask promptops blame --at <timestamp> to find out what was running when an incident happened. Built for teams who already use git for everything else.

โœจ Key Features

  • ๐Ÿ”Ž Incident archaeology โ€” promptops blame --at <ts> resolves "what prompt was running in prod at that moment" by composing the deploy log with git history.
  • ๐Ÿณ Production runtime without .git/ โ€” promptops snapshot build writes a self-contained .promptops/snapshot.json. Ship that in your Docker image; AutoResolver picks it up automatically.
  • ๐Ÿ“’ Deploy event log โ€” append-only .promptops/deploys.jsonl records every deploy with provenance (env, commit, actor, metadata). Committed to git alongside your prompts.
  • ๐Ÿ”„ Automated git versioning (opt-in) โ€” after promptops hooks install, a pre-commit hook detects prompt changes, bumps semver in YAML metadata, and re-stages. promptops init repo never touches .git/hooks/ on its own.
  • ๐Ÿ“ Version-aware testing โ€” :unstaged, :working, :latest, commit-<sha>, or any tag.
  • ๐Ÿ Python SDK โ€” PromptManager(resolver=AutoResolver()) works the same in dev (uses git) and prod (uses snapshot).

โšก Quick Start

Two paths depending on what you want to do.

Path A โ€” 60-second demo on a sample repo

Walk through the incident-archaeology flow on a pre-baked repo, no setup of your own.

pip install llmhq-promptops

git clone https://github.com/llmhq-hub/promptops.git
cd promptops/examples/incident-archaeology-demo
./setup.sh                       # builds a tmp git repo with pre-baked history
cd /tmp/promptops-demo

# 1. Look at what's been deployed
promptops deploy list

# 2. "Production broke at 10:00 UTC. What was running?"
promptops blame --at 2026-05-20T10:00:00Z

# 3. Same question, full text of one prompt
promptops blame --at 2026-05-20T10:00:00Z --prompt summarizer

That's the hero use case. Three commands, one provable answer.

Full walkthrough + screencast script: examples/incident-archaeology-demo/README.md

Path B โ€” Try it on your own repo

For when you want to add this to a real project.

pip install llmhq-promptops

cd <your-project>                # any git repo
promptops init repo              # creates .promptops/ (does NOT touch git hooks)

# Scaffold your first prompt โ†’ .promptops/prompts/user-onboarding.yaml
promptops create prompt user-onboarding

# Render it (the starter template uses {{ user_input }}; :unstaged reads
# your uncommitted working-tree edits)
python -c "from llmhq_promptops import get_prompt; print(get_prompt('user-onboarding:unstaged', {'user_input': 'World'}))"

# Record a deploy and look it up later
promptops deploy event --env prod -m release=v0.1.0
promptops blame --at now

# Optional: enable auto-versioning on commit (opt-in since v0.4.0)
promptops hooks install

๐Ÿ“– Usage Examples

Recommended production setup

from llmhq_promptops import PromptManager, AutoResolver

# Same code in dev (uses .git/) and prod (uses .promptops/snapshot.json)
manager = PromptManager(resolver=AutoResolver(repo_path="."))

prompt = manager.get_prompt("user-onboarding", {"name": "Alice"})

Resolving with full provenance

When you need to know which version actually ran (for logging, observability):

resolved = manager.resolve("user-onboarding")
# resolved.text       โ€” raw YAML
# resolved.version    โ€” e.g. "v1.2.3" or "commit-abc12345"
# resolved.commit     โ€” full 40-char SHA
# resolved.source     โ€” "git" or "snapshot"
# resolved.resolved_at โ€” tz-aware UTC datetime

log_to_observability({
    "prompt": resolved.prompt_id,
    "version": resolved.version,
    "commit": resolved.commit,
    "source": resolved.source,
})

Specific versions

from llmhq_promptops import get_prompt

prompt = get_prompt("user-onboarding")                    # smart default
prompt = get_prompt("user-onboarding:v1.2.1")             # tagged version
prompt = get_prompt("user-onboarding:commit-abc12345")    # untagged commit
prompt = get_prompt("user-onboarding:unstaged")           # working tree
prompt = get_prompt("user-onboarding:working")            # HEAD (committed)

Using with LLM frameworks

from llmhq_promptops import get_prompt

prompt = get_prompt("user-onboarding:working", {"name": "John"})

# OpenAI
import openai
openai.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": prompt}],
)

# Anthropic
import anthropic
anthropic.Anthropic().messages.create(
    model="claude-3-sonnet-20240229",
    messages=[{"role": "user", "content": prompt}],
)

๐Ÿ”ง CLI Commands

Command group What it does
promptops init repo Create .promptops/ directory structure
promptops hooks install Opt-in auto-versioning hooks (pre-commit + post-commit)
promptops create prompt <id> Scaffold a new prompt YAML
promptops render prompt <file> Render a prompt with variables
promptops test status / test diff / test runtest Version-aware prompt testing
promptops deploy event --env <e> Append a deploy event to .promptops/deploys.jsonl
promptops deploy list Show recent deploys, newest first
promptops snapshot build Write .promptops/snapshot.json (production-runtime artifact)
promptops snapshot inspect Print contents of a snapshot
promptops blame --at <ts> Incident archaeology: what was running when?
promptops backfill-deploys --from-git-log Seed the deploy log from existing git history
promptops migrate tag-history Create per-prompt git tags for historical commits

Full help: promptops --help or promptops <command> --help.

๐Ÿ“ Project Structure

.promptops/
โ”œโ”€โ”€ prompts/           # YAML prompt templates (auto-versioned)
โ”œโ”€โ”€ deploys.jsonl      # Append-only deploy event log (committed to git)
โ”œโ”€โ”€ snapshot.json      # Production-runtime snapshot (built at CI time)
โ”œโ”€โ”€ config.yaml        # Hook + tool configuration
โ”œโ”€โ”€ tests/             # Test datasets
โ”œโ”€โ”€ results/           # Test reports
โ”œโ”€โ”€ logs/              # Audit logs
โ””โ”€โ”€ reports/           # Auto-generated version change notes

๐Ÿ“‹ Prompt Schema

PromptOps reads two interchangeable layouts. promptops create prompt scaffolds the compact prompt: form; the richer metadata: form below adds tags, multiple models, and inline tests. Both are parsed the same way.

Extended (metadata:) format:

# .promptops/prompts/user-onboarding.yaml
metadata:
  id: user-onboarding
  version: "1.2.0"            # auto-incremented once you run `promptops hooks install`
  description: "User onboarding welcome message"
  tags: ["onboarding", "welcome"]
  models:                    # NOTE: nested under metadata
    default: gpt-4-turbo
    supported: [gpt-4-turbo, claude-3-sonnet, llama2-70b]

template: |
  Welcome {{ user_name }}!
  Available features:
  {% for feature in features %}
  - {{ feature }}
  {% endfor %}

variables:
  user_name: {type: string, required: true}
  features:  {type: list,   default: ["Browse", "Purchase"]}

tests:
  - dataset: .promptops/tests/onboarding-data.json
    metrics: {max_tokens: 150, min_relevance: 0.8}

Compact (prompt:) format โ€” what promptops create prompt generates:

# .promptops/prompts/user-onboarding.yaml
prompt:
  id: user-onboarding
  description: "User onboarding welcome message"
  model: gpt-4-turbo
  template: "Welcome {{ user_name }}!"
variables:
  user_name: {type: string, required: true}

๐Ÿ”„ Automated Versioning

Automated versioning is opt-in โ€” enable it once per repo with promptops hooks install. (Since v0.4.0, promptops init repo never modifies .git/hooks/ on its own.) After that, semantic version rules applied by the pre-commit hook:

  • PATCH (1.0.0 โ†’ 1.0.1) โ€” template content changes only
  • MINOR (1.0.0 โ†’ 1.1.0) โ€” new variables added (backwards compatible)
  • MAJOR (1.0.0 โ†’ 2.0.0) โ€” required variables removed (breaking change)

Workflow (after promptops hooks install):

  1. Edit a prompt โ†’ changes in working tree
  2. promptops test runtest --prompt name:unstaged (test before commit)
  3. git add + git commit โ†’ pre-commit hook bumps version and re-stages
  4. Post-commit hook tags the new version and generates a changelog entry

Zero manual version management.

๐ŸŒŸ Version References

Reference Resolves to Use case
prompt-name Smart default (unstaged if different, else working) Development
:unstaged Uncommitted working-tree content Testing changes before commit
:working / :latest / :head Latest committed (HEAD) Production
:v1.2.3 Specific semver tag Reproducible builds
:commit-abc12345 Immutable commit reference for untagged commits Incident archaeology

๐Ÿ› ๏ธ Requirements

  • Python 3.10+
  • Git (for versioning at dev time โ€” not required at production runtime if you ship snapshot.json)
  • YAML + Jinja2 (auto-installed)

๐Ÿ“š Dependencies

  • Core: Typer (CLI), Jinja2 (templates), PyYAML (parsing), GitPython (git access)

๐Ÿค Contributing

See CONTRIBUTING.md.

git clone https://github.com/llmhq-hub/promptops.git
cd promptops
python -m venv venv
source venv/bin/activate
pip install -e .
pip install pytest
pytest tests/

๐Ÿ“„ License

MIT โ€” see LICENSE.

๐Ÿ“ž Support


Made with โค๏ธ for teams shipping LLMs in production.

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

llmhq_promptops-0.4.0.tar.gz (95.3 kB view details)

Uploaded Source

Built Distribution

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

llmhq_promptops-0.4.0-py3-none-any.whl (73.7 kB view details)

Uploaded Python 3

File details

Details for the file llmhq_promptops-0.4.0.tar.gz.

File metadata

  • Download URL: llmhq_promptops-0.4.0.tar.gz
  • Upload date:
  • Size: 95.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.3

File hashes

Hashes for llmhq_promptops-0.4.0.tar.gz
Algorithm Hash digest
SHA256 fe23ca87bed14fbad3b147b14f61082f5b750126fdbc72c951cb11615a2edf58
MD5 7c9d5202a866e0e881bcdfc70244ba4b
BLAKE2b-256 f82167a61499ccfe8b45b526be0c9e52162cfa89408f9730ea64f97082649ffd

See more details on using hashes here.

File details

Details for the file llmhq_promptops-0.4.0-py3-none-any.whl.

File metadata

File hashes

Hashes for llmhq_promptops-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8e7d79b06cc17619da14b08873a05de5292f3aeaa41db65749e3072253b3c9d3
MD5 964b21cd05f29ba0e5c069210eec8291
BLAKE2b-256 e1409da4b9bd20225ee88047f10f9dab4c451ed2dd8170dd8127519d63629325

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