Version control for LLM prompts. Zero dependencies, works offline, embeds in any project.
Most prompt management tools are cloud services: they require a signup, an API key, and your prompts leave your machine. They're built around dashboards, collaboration features, and A/B testing infrastructure, useful at scale, but heavy when you just want to track how a prompt evolves.
Graver is the opposite: install it, import it, start versioning. No server, no account, no data leaving your codebase. It's fast to set up, fast to use, and stays out of your way.
Git tracks files. Graver tracks prompt content - independently of your code.
- Save a new version from inside your code without creating a commit
- Pin one version as your stable "main" while others keep evolving
- Compare prompt changes in isolation, not buried in a diff full of source code
- Works inside notebooks, scripts, and pipelines without touching your repo
If your prompts live in .txt files committed alongside code, you'll feel the friction immediately: every prompt tweak becomes a commit, rollback means git checkout, and git diff mixes logic changes with wording changes.
Prompt versioning looks simple until you handle edge cases: version numbering after deletions, pinning a canonical version independently of the latest, history that survives partial deletions. Graver handles all of this. One pip install, zero boilerplate.
pip install graverfrom graver import Prompt
p = Prompt("system")
p.save("You are a helpful assistant.")
p.save("You are an expert analyst. Be concise and data-driven.")
# See what changed
print(p.changes())
# Pin a stable version
p.set_main("v1")
# Always retrieve the pinned version, regardless of newer saves
content = p.get_main()gr save system prompt.txt # save a file as a new version
gr log system # show version history
gr show system v2 # show a specific version
gr changes system # diff the last two versions
gr set-main system v1 # pin a version as main
gr get-main system # print the pinned version
gr list # list all saved prompts
gr delete system v2 # delete a version
gr delete-prompt system # delete a prompt entirelyUse --base-dir to point to a custom storage directory:
gr --base-dir ./prompts log systemEvery Prompt writes to a .graver/ folder in your working directory. No database, no server, no configuration.
.graver/
system/
v1.txt
v2.txt
history.json ← version index with timestamps
main.json ← pointer to the pinned version
Versions are never overwritten, only explicitly deleted. Version numbers never collide even if you delete intermediate versions.
| Parameter | Type | Description |
|---|---|---|
name |
str |
Unique identifier for this prompt. |
base_dir |
str |
Storage root. Defaults to .graver in the working directory. |
| Method | Returns | Description |
|---|---|---|
save(content) |
str |
Save a new version. Returns the version string (e.g. "v3"). |
save_from_file(filepath) |
str |
Read from a file and save as a new version. |
get(version=None) |
str |
Get a version's content. Defaults to latest. |
log() |
list[dict] |
Full version history with version, timestamp, is_main. |
set_main(version) |
None |
Pin a version as the canonical main. |
get_main() |
str |
Get the content of the pinned main version. |
changes(v1=None, v2=None) |
str |
Formatted diff. Defaults to last two versions. |
diff(v1, v2) |
dict |
Raw diff with added, removed, unchanged line lists. |
show(version=None) |
str |
Content with formatted header. Defaults to latest. |
delete_version(version) |
None |
Delete a specific version. Clears main pointer if it was main. |
delete_prompt() |
None |
Delete this prompt and all its versions. |
Prompt.list_all(base_dir) |
list[str] |
List all prompt names in the given directory. |
| Exception | Raised when |
|---|---|
GraverError |
Base class for all graver errors. |
PromptNotFoundError |
Prompt name or file does not exist. |
VersionNotFoundError |
Version string does not exist. |
StorageError |
A file system operation fails. |
See examples/ for usage with OpenAI, Anthropic, and LangChain.
MIT