promptdiff-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. promptdiff_cli-0.1.0/LICENSE +21 -0
  2. promptdiff_cli-0.1.0/PKG-INFO +166 -0
  3. promptdiff_cli-0.1.0/README.md +133 -0
  4. promptdiff_cli-0.1.0/promptdiff/__init__.py +1 -0
  5. promptdiff_cli-0.1.0/promptdiff/api/__init__.py +1 -0
  6. promptdiff_cli-0.1.0/promptdiff/cli/__init__.py +1 -0
  7. promptdiff_cli-0.1.0/promptdiff/cli/context.py +52 -0
  8. promptdiff_cli-0.1.0/promptdiff/cli/main.py +338 -0
  9. promptdiff_cli-0.1.0/promptdiff/core/__init__.py +1 -0
  10. promptdiff_cli-0.1.0/promptdiff/core/diff.py +126 -0
  11. promptdiff_cli-0.1.0/promptdiff/core/exceptions.py +23 -0
  12. promptdiff_cli-0.1.0/promptdiff/core/projects.py +27 -0
  13. promptdiff_cli-0.1.0/promptdiff/core/prompts.py +45 -0
  14. promptdiff_cli-0.1.0/promptdiff/core/runner.py +213 -0
  15. promptdiff_cli-0.1.0/promptdiff/core/versions.py +113 -0
  16. promptdiff_cli-0.1.0/promptdiff/db/__init__.py +1 -0
  17. promptdiff_cli-0.1.0/promptdiff/db/base.py +4 -0
  18. promptdiff_cli-0.1.0/promptdiff/db/models.py +105 -0
  19. promptdiff_cli-0.1.0/promptdiff/db/session.py +24 -0
  20. promptdiff_cli-0.1.0/promptdiff_cli.egg-info/PKG-INFO +166 -0
  21. promptdiff_cli-0.1.0/promptdiff_cli.egg-info/SOURCES.txt +32 -0
  22. promptdiff_cli-0.1.0/promptdiff_cli.egg-info/dependency_links.txt +1 -0
  23. promptdiff_cli-0.1.0/promptdiff_cli.egg-info/entry_points.txt +2 -0
  24. promptdiff_cli-0.1.0/promptdiff_cli.egg-info/requires.txt +12 -0
  25. promptdiff_cli-0.1.0/promptdiff_cli.egg-info/top_level.txt +1 -0
  26. promptdiff_cli-0.1.0/pyproject.toml +48 -0
  27. promptdiff_cli-0.1.0/setup.cfg +4 -0
  28. promptdiff_cli-0.1.0/tests/test_cli.py +273 -0
  29. promptdiff_cli-0.1.0/tests/test_core_diff.py +56 -0
  30. promptdiff_cli-0.1.0/tests/test_core_projects.py +45 -0
  31. promptdiff_cli-0.1.0/tests/test_core_prompts.py +58 -0
  32. promptdiff_cli-0.1.0/tests/test_core_runner.py +134 -0
  33. promptdiff_cli-0.1.0/tests/test_core_versions.py +68 -0
  34. promptdiff_cli-0.1.0/tests/test_models.py +168 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Raguram R
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,166 @@
1
+ Metadata-Version: 2.4
2
+ Name: promptdiff-cli
3
+ Version: 0.1.0
4
+ Summary: Git for prompts - version, diff, and test your LLM prompts across any model
5
+ Author: Raguram R
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Ragu3175/promptdiff
8
+ Project-URL: Repository, https://github.com/Ragu3175/promptdiff
9
+ Project-URL: Issues, https://github.com/Ragu3175/promptdiff/issues
10
+ Keywords: llm,prompt-engineering,prompt-versioning,cli,litellm
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Topic :: Software Development :: Version Control
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Requires-Python: >=3.11
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: fastapi>=0.110.0
22
+ Requires-Dist: uvicorn>=0.28.0
23
+ Requires-Dist: sqlalchemy>=2.0.0
24
+ Requires-Dist: alembic>=1.13.0
25
+ Requires-Dist: typer>=0.9.0
26
+ Requires-Dist: rich>=13.7.0
27
+ Requires-Dist: litellm>=1.30.0
28
+ Requires-Dist: python-dotenv>=1.0.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
31
+ Requires-Dist: pytest-mock; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # PromptDiff
35
+
36
+ **Git for prompts.** Version your LLM prompts, diff them word-by-word, and run any version against Gemini, Groq, or any other LiteLLM-supported model — all from the terminal.
37
+
38
+ ```bash
39
+ promptdiff commit summarizer "Summarize: {text}" -m "v1: baseline"
40
+ promptdiff commit summarizer "Summarize concisely in one sentence: {text}" -m "v2: tighter constraint"
41
+ promptdiff diff summarizer 1 2
42
+ promptdiff run summarizer 2 --model gemini/gemini-2.5-flash
43
+ ```
44
+
45
+ ## Why PromptDiff
46
+
47
+ If you've ever overwritten a prompt and lost the version that actually worked, or pasted two prompt drafts into a doc just to eyeball what changed — PromptDiff is the tool for that. It treats prompts as versioned, diffable artifacts the same way Git treats code, and adds one thing Git can't: running any version against a real LLM and recording exactly what it produced, so you can trace output back to the exact prompt and model that generated it.
48
+
49
+ ## How it's different from other prompt tools
50
+
51
+ The prompt-tooling space has grown a lot — [Promptfoo](https://github.com/promptfoo/promptfoo) is a mature, YAML-config-based open-source tool with strong CI/eval integration, and platforms like PromptLayer, Langfuse, and Braintrust offer hosted, full-lifecycle prompt management with branching, RBAC, and observability.
52
+
53
+ PromptDiff isn't trying to compete with those. It's deliberately smaller: a local-first CLI for a single developer iterating on prompts, with zero config files, zero hosted accounts, and zero cost beyond free-tier LLM API usage. If you outgrow it — multiple collaborators, non-engineer prompt editors, compliance requirements — those other tools are the right next step. If you're a solo developer who just wants `git commit`-style version control for prompts without standing up infrastructure, PromptDiff is built for exactly that.
54
+
55
+ ## Features
56
+
57
+ - **Version control for prompts** — every `commit` is an immutable, numbered version (v1, v2, v3...) scoped per prompt
58
+ - **Word-level diffs** — see exactly which words changed between versions, rendered with color in your terminal (green additions, red strikethrough removals)
59
+ - **Multi-model runs** — execute any prompt version against multiple LLMs in a single command and compare cost, latency, and output side by side
60
+ - **Output comparison** — `diff-output` shows what two versions actually *produced*, not just what their text looks like
61
+ - **Free-tier friendly** — built and tested against Gemini and Groq's free tiers; rate-limit and quota failures are recorded gracefully, never crash the tool
62
+ - **Local-first** — everything lives in a local SQLite database, no account or server required
63
+
64
+ ## Installation
65
+
66
+ ```bash
67
+ pip install promptdiff-cli
68
+ ```
69
+
70
+ (Or, to run from source — see [Development](#development) below.)
71
+
72
+ ## Quick start
73
+
74
+ ```bash
75
+ # Create a project and switch to it
76
+ promptdiff project create my-app
77
+ promptdiff use my-app
78
+
79
+ # Create a prompt and commit your first version
80
+ promptdiff add summarizer
81
+ promptdiff commit summarizer "Summarize this in one sentence: {text}" -m "v1: baseline"
82
+
83
+ # Edit and commit a new version
84
+ promptdiff commit summarizer "Summarize concisely, max 20 words: {text}" -m "v2: tighter constraint"
85
+
86
+ # See version history
87
+ promptdiff log summarizer
88
+
89
+ # See exactly what changed
90
+ promptdiff diff summarizer 1 2
91
+
92
+ # Run a version against a model (needs an API key — see below)
93
+ promptdiff run summarizer 2 --model gemini/gemini-2.5-flash
94
+
95
+ # Run the same version against multiple models at once
96
+ promptdiff run summarizer 2 --model gemini/gemini-2.5-flash --model groq/llama-3.3-70b-versatile
97
+
98
+ # Compare what two versions actually produced
99
+ promptdiff diff-output summarizer 1 2 --model gemini/gemini-2.5-flash
100
+ ```
101
+
102
+ ## API keys
103
+
104
+ PromptDiff uses [LiteLLM](https://github.com/BerriAI/litellm) under the hood, so it works with any LiteLLM-supported provider. It's built and tested primarily against free tiers:
105
+
106
+ - **Gemini** — get a free key at [aistudio.google.com/apikey](https://aistudio.google.com/apikey)
107
+ - **Groq** — get a free key at [console.groq.com/keys](https://console.groq.com/keys)
108
+
109
+ Copy `.env.example` to `.env` in your project directory and fill in the keys you have:
110
+
111
+ ```
112
+ GEMINI_API_KEY=your_key_here
113
+ GROQ_API_KEY=your_key_here
114
+ ```
115
+
116
+ ## Commands
117
+
118
+ | Command | What it does |
119
+ |---|---|
120
+ | `promptdiff project create <name>` | Create a new project |
121
+ | `promptdiff project list` | List all projects |
122
+ | `promptdiff use <project>` | Set the current project (so you don't need `--project` on every command) |
123
+ | `promptdiff add <prompt>` | Add a new prompt to the current project |
124
+ | `promptdiff commit <prompt> <content_or_file> -m "<message>"` | Commit a new version. Accepts a literal string or a path to a file |
125
+ | `promptdiff log <prompt>` | Show version history |
126
+ | `promptdiff diff <prompt> <v1> <v2>` | Word-level diff between two versions |
127
+ | `promptdiff run <prompt> <version> --model <model>` | Run a version against one or more models (repeat `--model` to run against several at once) |
128
+ | `promptdiff diff-output <prompt> <v1> <v2> [--model <model>]` | Compare what two versions actually produced. If a version was run against multiple models, `--model` is required to avoid an ambiguous comparison |
129
+
130
+ Every command accepts `-p` / `--project` to override the current project for that one call.
131
+
132
+ ## Architecture
133
+
134
+ - **Database**: SQLite, 5 tables (`projects`, `prompts`, `versions`, `runs`, `outputs`) via SQLAlchemy + Alembic migrations
135
+ - **Diff engine**: Python's `difflib`, line-level structure with word-level precision inside changed lines
136
+ - **Runner**: [LiteLLM](https://github.com/BerriAI/litellm) for provider-agnostic model calls; failures (rate limits, timeouts, bad keys) are recorded as failed runs rather than crashing the CLI
137
+ - **CLI**: [Typer](https://typer.tiangolo.com/) + [Rich](https://github.com/Textualize/rich)
138
+
139
+ ## Development
140
+
141
+ ```bash
142
+ git clone https://github.com/Ragu3175/promptdiff.git
143
+ cd promptdiff
144
+ python -m venv venv
145
+ venv\Scripts\activate # Windows
146
+ # source venv/bin/activate # macOS/Linux
147
+ pip install -r requirements.txt
148
+ pip install -e .
149
+ pytest -v
150
+ ```
151
+
152
+ ## Status
153
+
154
+ Core CLI is complete and tested: `commit`, `log`, `diff`, `run`, and `diff-output` all work end-to-end against real Gemini and Groq calls. A REST API layer and web UI are planned but not yet built — the CLI is fully usable on its own today.
155
+
156
+ ## Contributing
157
+
158
+ Issues and PRs welcome. This is an early-stage solo project — if you run into something broken or have an idea, please open an issue.
159
+
160
+ ## License
161
+
162
+ MIT — see [LICENSE](LICENSE).
163
+
164
+ ## Author
165
+
166
+ Built by [Raguram R](https://github.com/Ragu3175).
@@ -0,0 +1,133 @@
1
+ # PromptDiff
2
+
3
+ **Git for prompts.** Version your LLM prompts, diff them word-by-word, and run any version against Gemini, Groq, or any other LiteLLM-supported model — all from the terminal.
4
+
5
+ ```bash
6
+ promptdiff commit summarizer "Summarize: {text}" -m "v1: baseline"
7
+ promptdiff commit summarizer "Summarize concisely in one sentence: {text}" -m "v2: tighter constraint"
8
+ promptdiff diff summarizer 1 2
9
+ promptdiff run summarizer 2 --model gemini/gemini-2.5-flash
10
+ ```
11
+
12
+ ## Why PromptDiff
13
+
14
+ If you've ever overwritten a prompt and lost the version that actually worked, or pasted two prompt drafts into a doc just to eyeball what changed — PromptDiff is the tool for that. It treats prompts as versioned, diffable artifacts the same way Git treats code, and adds one thing Git can't: running any version against a real LLM and recording exactly what it produced, so you can trace output back to the exact prompt and model that generated it.
15
+
16
+ ## How it's different from other prompt tools
17
+
18
+ The prompt-tooling space has grown a lot — [Promptfoo](https://github.com/promptfoo/promptfoo) is a mature, YAML-config-based open-source tool with strong CI/eval integration, and platforms like PromptLayer, Langfuse, and Braintrust offer hosted, full-lifecycle prompt management with branching, RBAC, and observability.
19
+
20
+ PromptDiff isn't trying to compete with those. It's deliberately smaller: a local-first CLI for a single developer iterating on prompts, with zero config files, zero hosted accounts, and zero cost beyond free-tier LLM API usage. If you outgrow it — multiple collaborators, non-engineer prompt editors, compliance requirements — those other tools are the right next step. If you're a solo developer who just wants `git commit`-style version control for prompts without standing up infrastructure, PromptDiff is built for exactly that.
21
+
22
+ ## Features
23
+
24
+ - **Version control for prompts** — every `commit` is an immutable, numbered version (v1, v2, v3...) scoped per prompt
25
+ - **Word-level diffs** — see exactly which words changed between versions, rendered with color in your terminal (green additions, red strikethrough removals)
26
+ - **Multi-model runs** — execute any prompt version against multiple LLMs in a single command and compare cost, latency, and output side by side
27
+ - **Output comparison** — `diff-output` shows what two versions actually *produced*, not just what their text looks like
28
+ - **Free-tier friendly** — built and tested against Gemini and Groq's free tiers; rate-limit and quota failures are recorded gracefully, never crash the tool
29
+ - **Local-first** — everything lives in a local SQLite database, no account or server required
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install promptdiff-cli
35
+ ```
36
+
37
+ (Or, to run from source — see [Development](#development) below.)
38
+
39
+ ## Quick start
40
+
41
+ ```bash
42
+ # Create a project and switch to it
43
+ promptdiff project create my-app
44
+ promptdiff use my-app
45
+
46
+ # Create a prompt and commit your first version
47
+ promptdiff add summarizer
48
+ promptdiff commit summarizer "Summarize this in one sentence: {text}" -m "v1: baseline"
49
+
50
+ # Edit and commit a new version
51
+ promptdiff commit summarizer "Summarize concisely, max 20 words: {text}" -m "v2: tighter constraint"
52
+
53
+ # See version history
54
+ promptdiff log summarizer
55
+
56
+ # See exactly what changed
57
+ promptdiff diff summarizer 1 2
58
+
59
+ # Run a version against a model (needs an API key — see below)
60
+ promptdiff run summarizer 2 --model gemini/gemini-2.5-flash
61
+
62
+ # Run the same version against multiple models at once
63
+ promptdiff run summarizer 2 --model gemini/gemini-2.5-flash --model groq/llama-3.3-70b-versatile
64
+
65
+ # Compare what two versions actually produced
66
+ promptdiff diff-output summarizer 1 2 --model gemini/gemini-2.5-flash
67
+ ```
68
+
69
+ ## API keys
70
+
71
+ PromptDiff uses [LiteLLM](https://github.com/BerriAI/litellm) under the hood, so it works with any LiteLLM-supported provider. It's built and tested primarily against free tiers:
72
+
73
+ - **Gemini** — get a free key at [aistudio.google.com/apikey](https://aistudio.google.com/apikey)
74
+ - **Groq** — get a free key at [console.groq.com/keys](https://console.groq.com/keys)
75
+
76
+ Copy `.env.example` to `.env` in your project directory and fill in the keys you have:
77
+
78
+ ```
79
+ GEMINI_API_KEY=your_key_here
80
+ GROQ_API_KEY=your_key_here
81
+ ```
82
+
83
+ ## Commands
84
+
85
+ | Command | What it does |
86
+ |---|---|
87
+ | `promptdiff project create <name>` | Create a new project |
88
+ | `promptdiff project list` | List all projects |
89
+ | `promptdiff use <project>` | Set the current project (so you don't need `--project` on every command) |
90
+ | `promptdiff add <prompt>` | Add a new prompt to the current project |
91
+ | `promptdiff commit <prompt> <content_or_file> -m "<message>"` | Commit a new version. Accepts a literal string or a path to a file |
92
+ | `promptdiff log <prompt>` | Show version history |
93
+ | `promptdiff diff <prompt> <v1> <v2>` | Word-level diff between two versions |
94
+ | `promptdiff run <prompt> <version> --model <model>` | Run a version against one or more models (repeat `--model` to run against several at once) |
95
+ | `promptdiff diff-output <prompt> <v1> <v2> [--model <model>]` | Compare what two versions actually produced. If a version was run against multiple models, `--model` is required to avoid an ambiguous comparison |
96
+
97
+ Every command accepts `-p` / `--project` to override the current project for that one call.
98
+
99
+ ## Architecture
100
+
101
+ - **Database**: SQLite, 5 tables (`projects`, `prompts`, `versions`, `runs`, `outputs`) via SQLAlchemy + Alembic migrations
102
+ - **Diff engine**: Python's `difflib`, line-level structure with word-level precision inside changed lines
103
+ - **Runner**: [LiteLLM](https://github.com/BerriAI/litellm) for provider-agnostic model calls; failures (rate limits, timeouts, bad keys) are recorded as failed runs rather than crashing the CLI
104
+ - **CLI**: [Typer](https://typer.tiangolo.com/) + [Rich](https://github.com/Textualize/rich)
105
+
106
+ ## Development
107
+
108
+ ```bash
109
+ git clone https://github.com/Ragu3175/promptdiff.git
110
+ cd promptdiff
111
+ python -m venv venv
112
+ venv\Scripts\activate # Windows
113
+ # source venv/bin/activate # macOS/Linux
114
+ pip install -r requirements.txt
115
+ pip install -e .
116
+ pytest -v
117
+ ```
118
+
119
+ ## Status
120
+
121
+ Core CLI is complete and tested: `commit`, `log`, `diff`, `run`, and `diff-output` all work end-to-end against real Gemini and Groq calls. A REST API layer and web UI are planned but not yet built — the CLI is fully usable on its own today.
122
+
123
+ ## Contributing
124
+
125
+ Issues and PRs welcome. This is an early-stage solo project — if you run into something broken or have an idea, please open an issue.
126
+
127
+ ## License
128
+
129
+ MIT — see [LICENSE](LICENSE).
130
+
131
+ ## Author
132
+
133
+ Built by [Raguram R](https://github.com/Ragu3175).
@@ -0,0 +1 @@
1
+ # PromptDiff package
@@ -0,0 +1 @@
1
+ # API package
@@ -0,0 +1 @@
1
+ # CLI package
@@ -0,0 +1,52 @@
1
+ import os
2
+ import json
3
+ from pathlib import Path
4
+ from contextlib import contextmanager
5
+ from typing import Generator
6
+ from sqlalchemy.orm import Session
7
+ import typer
8
+
9
+ from promptdiff.db.session import get_db
10
+
11
+ def get_config_dir() -> Path:
12
+ """Get the configuration directory path, allowing environment override for tests."""
13
+ env_home = os.environ.get("PROMPTDIFF_HOME")
14
+ if env_home:
15
+ return Path(env_home)
16
+ return Path.home() / ".promptdiff"
17
+
18
+ def get_config_path() -> Path:
19
+ """Get the path to the config.json file."""
20
+ return get_config_dir() / "config.json"
21
+
22
+ def resolve_project(explicit: str | None) -> str:
23
+ """Resolve the project name using explicit override or current project config.
24
+
25
+ Raises typer.Exit(code=1) if no project name can be resolved.
26
+ """
27
+ if explicit:
28
+ return explicit
29
+
30
+ config_file = get_config_path()
31
+ if config_file.is_file():
32
+ try:
33
+ with open(config_file, "r") as f:
34
+ data = json.load(f)
35
+ current = data.get("current_project")
36
+ if current:
37
+ return current
38
+ except Exception:
39
+ pass
40
+
41
+ typer.secho(
42
+ "Error: No project specified. Use --project or run `promptdiff use <project>` first.",
43
+ fg=typer.colors.RED,
44
+ err=True
45
+ )
46
+ raise typer.Exit(code=1)
47
+
48
+ @contextmanager
49
+ def get_cli_db() -> Generator[Session, None, None]:
50
+ """Yield a database session and guarantee it closes correctly."""
51
+ with get_db() as db:
52
+ yield db