Treat prompts like code: version them locally, diff them, label releases, and inspect history — without any backend services.
Prompt engineering has quietly become production work. Prompts evolve, regress, get tuned for edge cases, and eventually land in “prod”. Yet most teams still track them in scratch files, notebooks, or chat logs.
PromptLedger is a deliberately small tool that fixes this by treating prompts like code: every change is versioned, diffable, and labeled — all stored locally in a single SQLite database.
This post is a technical deep dive into how PromptLedger works, what data it stores, and why its design is intentionally boring.
Design goals
PromptLedger is built around a few strict constraints:
- Local-first: no server, no SaaS, no telemetry
- Single source of truth: one SQLite file
- Git-aware: works naturally inside repositories
- Read-only UI: all writes go through the CLI/API
- Deterministic output: exports are stable and diffable
If you are looking for an agent framework or a prompt playground, this is not it.
tecture overview
The codebase is intentionally small and split by responsibility:
-
cli.py– argument parsing and user-facing commands -
core.py– domain logic (PromptLedgerclass) -
db.py– SQLite connection, schema, migrations -
ui.py– Streamlit-based read-only viewer
There are no background services and no long-running processes. PromptLedger runs when you invoke it and exits.
Storage and path resolution
PromptLedger always stores data locally in promptledger.db.
Resolution rules are deterministic:
- Inside a git repo:
<repo_root>/.promptledger/promptledger.db - Outside git:
<cwd>/.promptledger/promptledger.db - Override with
PROMPTLEDGER_HOME=/custom/path - Hard override via
PromptLedger(db_path="/abs/path/to.db")
This avoids accidental duplication when running commands from nested directories and keeps prompt data out of git history by default.
SQLite schema
Two tables make up the core of PromptLedger:
-
prompt_versions: immutable prompt history -
labels: mutable pointers to specific versions
Each prompt version stores:
prompt_idversion-
content(the prompt text) -
content_hash(SHA-256) -
created_at(UTC ISO timestamp) - optional metadata:
reason,author,tags,env,metrics
Labels store:
prompt_id-
label(e.g.prod,staging) versionupdated_at
This separation lets you move release pointers without creating new versions.
Versioning algorithm
When you add a prompt, PromptLedger:
- Normalizes newlines (CRLF/CR → LF)
- Hashes the normalized content
- Fetches the latest version for that prompt
- Skips insertion if the hash matches (no-op)
- Otherwise inserts a new version with incremented number
This keeps history clean and avoids formatting-only noise.
Newline normalization
Cross-platform newline differences are a common source of useless diffs.
PromptLedger normalizes line endings before hashing and diffing, which means:
- Windows CRLF and Unix LF content are treated as identical
- Diff output focuses on real textual changes
Metadata model
PromptLedger supports lightweight metadata for each version:
-
reason– why the prompt changed -
author– who made the change -
tags– arbitrary labels for grouping -
env–dev,staging,prod -
metrics– JSON blob (accuracy, latency, cost, ratings)
This turns raw text history into something closer to an audit trail.
Labels: release-style pointers
Labels are the feature that pushes PromptLedger beyond simple history tracking.
Think of labels like git tags that move:
promptledger label set --id onboarding --version 7 --name prod
promptledger label set --id onboarding --version 9 --name staging
Now you can answer questions like:
- What prompt is currently in production?
- Which version was deployed last week?
Without copying or duplicating prompt content.
CLI workflow
Core commands:
-
init– create DB and.gitignoreentry -
add– add or skip a version -
list– list versions -
show– show content + metadata -
diff– unified diff between versions -
search– content + metadata search -
export– deterministic JSONL / CSV -
label– manage release pointers -
ui– launch Streamlit viewer
A typical flow:
promptledger init
promptledger add --id demo --text "Hello"
promptledger add --id demo --text "Hello World"
promptledger diff --id demo --from 1 --to 2
promptledger label set --id demo --version 2 --name prod
Streamlit UI (read-only)
The UI is intentionally non-destructive:
- Timeline view of versions
- Filters by prompt id, tags, env
- Full content preview
- Unified diff and side-by-side comparison
All writes remain in the CLI/API path.
Export and determinism
Exports are designed for reproducibility:
- JSONL uses sorted keys
- CSV has a fixed column order
- Repeated exports of the same data are byte-for-byte identical
This makes PromptLedger suitable for audits, reviews, and downstream tooling.
Security notes
PromptLedger never sends data anywhere.
It includes a minimal warning for common secret patterns (sk-, AKIA, -----BEGIN). This is advisory only and can be disabled. The responsibility remains with the user to avoid storing secrets in prompt text.
What PromptLedger is not
- Not an LLM framework
- Not an agent system
- Not a hosted service
- Not a playground
It is a local ledger for prompt evolution.
Workflow for those interested
Closing
If your prompts matter enough to review, promote, and roll back, they matter enough to version properly.
PromptLedger keeps that history local, inspectable, and boring — which is exactly the point.
Contact and Links
Pypi : Pypi
Github : Github
My Linkedin : Linkedin
My Website : Website





Top comments (0)