PromptOps

Git-native prompt versioning for production LLM agents

Stable v0.6.0 Python 3.10+

Why PromptOps?

Your agent's behavior is defined by prompt text — but most teams ship prompts as raw strings baked into code, with no version history, no rollback, and no way to test a change before it hits production.

PromptOps turns prompts into first-class versioned artifacts. Opt in to the git hooks once and every git commit grades the change and tags it with a semantic version. Reference any version in code by name: :latest for production, :v1.2.0 for a specific release, or :unstaged to test uncommitted changes without touching anything live.

And when something does break, promptops blame --at "2026-05-20T14:32:00Z" answers "what was this prompt's text when the incident happened", from the deploy log and git history. No more "what prompt was running last Tuesday?"

Features

Incident archaeology

blame --at <timestamp> answers what text was live when something broke, from the deploy log and git history.

Uncommitted Change Testing

Test prompts instantly with :unstaged, :working, :latest references before committing.

Semver impact at review time

promptops test diff grades a change MAJOR, MINOR or PATCH from the variable signature, and --exit-code gates CI on the verdict.

Opt-in git hooks

One promptops hooks install and every commit versions your prompts, graded by the same engine as test diff. init never writes to .git/hooks/ unless you ask.

Installation

terminal bash
pip install llmhq-promptops

Quick Start

terminal bash
# Create .promptops/ in your repo. Does NOT touch .git/hooks/.
promptops init repo

# Opt in to auto-versioning on commit (a deliberate second step)
promptops hooks install

# Create a new prompt template
promptops create prompt welcome-message

# Test uncommitted changes
promptops test runtest --prompt welcome-message:unstaged

# Check status of all prompts
promptops test status

# Is this setup sane? Checks hooks can actually run.
promptops doctor

Python SDK

app.py python
from llmhq_promptops import get_prompt

# Smart default (unstaged if different, else working)
prompt = get_prompt("user-onboarding")

# Specific version references
prompt = get_prompt("user-onboarding:v1.2.1")
prompt = get_prompt("user-onboarding:unstaged")
prompt = get_prompt("user-onboarding:working")

# With variables
rendered = get_prompt("user-onboarding", {
    "user_name": "Alice",
    "plan": "Pro"
})

Version References

Every prompt can be resolved at any point in its history.

ReferenceResolves ToUse Case
prompt-nameSmart default (unstaged if different, else working)Development
:unstagedUncommitted changes in working directoryTesting changes
:workingLatest committed version (HEAD)Production
:latestAlias for :workingProduction
:v1.2.3Specific semantic versionReproducible builds

Semantic Versioning Rules

Impact is derived from the prompt's variable signature and its declared models, and from nothing else. Prose is never graded: the variable interface is the only part of a prompt with a caller-facing contract, and a rule that guessed at intent would produce annotations nobody trusts.

BumpTriggerExample
MAJORRequired variable added, removed, renamed or retyped; an optional variable promoted to required; a declared model dropped1.2.0 → 2.0.0
MINOROptional variable added or removed; a required variable relaxed to optional; a model added; an optional default changed1.2.0 → 1.3.0
PATCHProse changed, signature identical1.2.0 → 1.2.1
noneNothing a caller depends on moved1.2.0 → 1.2.0

The git hook and promptops test diff use the same grader, so a change your CI blocks as breaking cannot be stamped with a minor version on commit:

terminal bash
git commit -m "feat: tier-aware refund policy"
output text
[promptops]    Impact: MAJOR
[promptops]    Version: v1.2.0 → v2.0.0
[promptops]    • required variable 'account_tier' added
[promptops] Updated version to v2.0.0
[promptops] Created tag: prompt-refund-policy-v2.0.0

A brand-new prompt keeps the version you declared: there is nothing for a first commit to be backward incompatible with. The bump rewrites the version line and nothing else, so comments and template: | formatting survive.

Upgrading? The git hooks were broken from v0.2.0 through v0.5.0 and are repaired in v0.6.0. If you installed them on an earlier release and versioning never seemed to fire, that is why. See upgrading to v0.6.0.

Framework Integration

Works with any LLM framework. Get a versioned prompt, pass it to your provider.

integrations.py python
from llmhq_promptops import get_prompt

prompt_text = get_prompt("user-onboarding:working", {
    "user_name": "John",
    "plan": "Enterprise"
})

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

# Use with Anthropic
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
    model="claude-sonnet-4-5-20250929",
    messages=[{"role": "user", "content": prompt_text}]
)

Requirements

  • Python 3.10+
  • Git, for the CLI's git-backed commands. The SDK's snapshot path needs neither the .git/ directory nor the git binary, so it runs in a python:3.11-slim image.
  • Dependencies: Typer, Click, Jinja2, PyYAML, GitPython

See it in action

Watch PromptOps version prompts and feed them into ReleaseOps bundles.