promptpin
Git-native prompt registry. Your prompts live as files in your repo.
Versions are git commits, releases are namespaced tags, and deployments are
pins in a committed promptpin.lock file. Local-first: no server, no vendor
database, nothing on your request hot path.
pip install promptpin
promptpin init
# edit prompts/greeter.yaml, commit it
promptpin release greeter # tags promptpin/greeter@v1
promptpin deploy greeter@v1 --env production
Why not Langfuse / PromptLayer / Maxim?
They're good tools — but your prompts live in their database. Langfuse self-hosted still means Postgres + ClickHouse + workers to operate, and versions are created via their UI/API. (Humanloop's users learned the hard way in September 2025: when the vendor shuts down, your version history goes with it.)
promptpin's bet: the registry is the git repo you already have.
Prompt changes go through PR review. git log -p promptpin.lock is your
deployment history. git blame prompts/classifier.yaml is your audit
trail. Your app reads a pinned bundle file at startup — no fetch, no cache
TTL, no 2am "why is production serving the wrong prompt."
Concepts
| Concept | Implementation |
|---|---|
| Prompt | One file in prompts/: <name>.yaml or <name>.md (frontmatter + Markdown) |
| Version | Git commit SHA (the truth); human name = tag promptpin/<name>@v3 |
| Release | promptpin release <name> creates the next version tag |
| Deploy | promptpin deploy <name>@v3 --env production pins the resolved SHA into the committed promptpin.lock |
| Rollback | promptpin rollback <name> --env production re-pins the previous SHA |
| Serving | App loads a promptpin export bundle; logs which SHA served each request |
Quickstart
promptpin init # scaffold config + example prompt
# edit prompts/greeter.yaml, then:
git add -A && git commit -m "tune greeter"
promptpin release greeter # → promptpin/greeter@v1
promptpin deploy greeter@v1 --env staging # pin v1 to staging
promptpin deploy greeter@v1 --env production --note "looks good in staging"
The 9am question: "why did accuracy drop?"
promptpin diff summarizer v12 v13
Three panels: template (unified diff), config (model/params/variables changes), and recorded evals — scores attached to each version, shown with their suite and dataset provenance. The eval panel is labeled what it is: recorded measurements, not proof the prompt change caused them.
# attach eval evidence (suite + dataset are required provenance)
promptpin eval record --prompt summarizer --ref v13 \
--suite nightly --dataset-sha 9f2c... \
--metric accuracy=0.91 --metric latency_p50_ms=180
Runtime: serve pinned prompts, log what served
# at build time: export the pinned templates for an env
promptpin export --env production --out ./prompt-bundle
# bundle ./prompt-bundle with your app — no git needed at runtime
from promptpin import load_bundle, render_template, log_serve
bundle = load_bundle("./prompt-bundle") # hash-checked against the pin
p = bundle["classifier"]
text = render_template(p["template"], ticket_text=ticket)
response = llm.chat(model=p["model"], **p["params"], messages=[{"role": "user", "content": text}])
log_serve("./state.db", prompt="classifier", sha=p["sha"],
model=p["model"], request_id=req.id, latency_ms=elapsed_ms)
promptpin log stats --prompt classifier --env production --since 24h
# which SHA served how many requests, avg latency, error rate per version
Everyday commands
promptpin list # prompts + latest released version
promptpin versions classifier # all released versions
promptpin show classifier@v2 --var ticket_text="login broken"
promptpin status # what's pinned where
promptpin history --env production # deploy ledger
promptpin validate # schema + variable + secret checks (CI-friendly)
promptpin audit --prompt classifier # git history + deploys: who changed what
promptpin lock --env production --out manifest.yaml # minimal runtime manifest
Prompt file format
prompts/classifier.yaml:
name: classifier
description: Ticket classifier
model: gpt-4o-mini
params:
temperature: 0.2
max_tokens: 200
variables:
- ticket_text
template: |
Classify this ticket: {{ticket_text}}
Reply with one of: bug, feature, question.
Or Markdown, for domain experts who don't want YAML blocks —
prompts/summarizer.md:
---
name: summarizer
model: gpt-4o-mini
params:
temperature: 0.5
variables:
- text
---
Summarize in one sentence:
{{text}}
Configuration (promptpin.yaml)
prompts_dir: prompts
envs: [dev, staging, production]
log_sample_rate: 1.0 # 0..1 — sample the serving log before writing
auto_commit_deploys: true # commit promptpin.lock on deploy (set false in CI)
Local state lives in .promptpin/ (gitignored): state.db (deploy ledger,
evals, serving log) and the deploy mutex.
Limitations (honest)
- Eval scores are evidence, not proof. Nothing stops someone recording a
fake score — the defense is mandatory provenance (
--suite,--dataset-sha, recorder identity), append-only history, and visible record counts, not prevention.diffnever claims causation. - Serving log has no automatic rotation. Use
log_sample_rate < 1andpromptpin log prune --older-than 30d. At 1.0 sampling and high traffic,state.dbwill grow — plan retention consciously. - The deploy ledger is local.
history/rollbacksee deploys made on this machine (.promptpin/state.db). The committedpromptpin.lockis the cross-machine source of truth; rollback across machines means deploying the SHA you see instatus. - Cross-machine same-env deploy races resolve via git merge on
promptpin.lock, not via locking. Different-env concurrent deploys merge cleanly; same-env conflicts surface as a normal merge conflict. latestand branch deploys are allowed but flagged mutable. The pin is frozen at the deploy-time SHA, but prefer tags/SHAs for production.- Secret scanning is a best-effort heuristic (
validatewarns on obvious patterns). It will miss things. Use pre-commit hooks for real secret hygiene, and never commit secrets in prompts. - No prompt composition (sub-prompt includes), no hosted UI, no automatic eval runs, no multi-repo sharing, no RBAC. The CLI and the lock file are the interface.
- If a branch and a tag share a name, git's own ref-ambiguity rules apply.
Development
pip install -e ".[dev]"
pytest # 105 tests
ruff check src tests
ruff format --check src tests
Metadata
Release files for promptpin 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| promptpin-0.1.1.tar.gz | 37.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| promptpin-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 67.1 kB
Release files / promptpin-0.1.1.tar.gz
| Download URL | promptpin-0.1.1.tar.gz |
|---|---|
| Size | 37.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1fe400faacc4afb3f2647c62dc63a767969b9de8dc8d9b098203f681347ee3d9
|
|
BLAKE2b-256 checksum How to use checksums |
b858df06447e0c5913af95d488068b33fcb506456b33a0ad8d5deee503ce7855
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / promptpin-0.1.1-py3-none-any.whl
| Download URL | promptpin-0.1.1-py3-none-any.whl |
|---|---|
| Size | 29.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2c023491dfe0dea126eb342339bf128f10c7a10a1320178dafd198ed33100d0f
|
|
BLAKE2b-256 checksum How to use checksums |
71bb8875b7f4651f835088da758c625f5cf60164473c2ed3789e10110dfc4b0c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Security for promptpin 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.