prompt-optimizer-tool 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 (26) hide show
  1. prompt_optimizer_tool-0.1.0/LICENSE +21 -0
  2. prompt_optimizer_tool-0.1.0/PKG-INFO +298 -0
  3. prompt_optimizer_tool-0.1.0/README.md +274 -0
  4. prompt_optimizer_tool-0.1.0/pyproject.toml +47 -0
  5. prompt_optimizer_tool-0.1.0/setup.cfg +4 -0
  6. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool/__init__.py +17 -0
  7. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool/analyzer.py +39 -0
  8. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool/cli.py +287 -0
  9. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool/config.py +85 -0
  10. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool/llm.py +61 -0
  11. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool/optimizer.py +44 -0
  12. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool/principles.py +172 -0
  13. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool/schemas.py +56 -0
  14. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool/storage.py +58 -0
  15. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool.egg-info/PKG-INFO +298 -0
  16. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool.egg-info/SOURCES.txt +24 -0
  17. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool.egg-info/dependency_links.txt +1 -0
  18. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool.egg-info/entry_points.txt +2 -0
  19. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool.egg-info/requires.txt +6 -0
  20. prompt_optimizer_tool-0.1.0/src/prompt_optimizer_tool.egg-info/top_level.txt +1 -0
  21. prompt_optimizer_tool-0.1.0/tests/test_cli.py +147 -0
  22. prompt_optimizer_tool-0.1.0/tests/test_config.py +49 -0
  23. prompt_optimizer_tool-0.1.0/tests/test_pipeline.py +116 -0
  24. prompt_optimizer_tool-0.1.0/tests/test_principles.py +38 -0
  25. prompt_optimizer_tool-0.1.0/tests/test_schemas.py +49 -0
  26. prompt_optimizer_tool-0.1.0/tests/test_storage.py +45 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 khadar
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,298 @@
1
+ Metadata-Version: 2.4
2
+ Name: prompt-optimizer-tool
3
+ Version: 0.1.0
4
+ Summary: CLI tool that grades prompts 0-100 against 10 engineering principles and rewrites them, powered by Groq
5
+ Author-email: khadar <khadarbashajilan001@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/khadarbashajilan/prompt-optimizer-tool
8
+ Project-URL: Issues, https://github.com/khadarbashajilan/prompt-optimizer-tool/issues
9
+ Keywords: prompt,prompt-engineering,llm,groq,langchain,cli
10
+ Classifier: Environment :: Console
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
13
+ Classifier: Topic :: Software Development
14
+ Requires-Python: >=3.12
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: langchain-groq>=1.1.0
18
+ Requires-Dist: langchain-core>=0.3.0
19
+ Requires-Dist: rich>=13.0.0
20
+ Requires-Dist: click>=8.0.0
21
+ Requires-Dist: python-dotenv>=1.0.0
22
+ Requires-Dist: pydantic>=2.0.0
23
+ Dynamic: license-file
24
+
25
+ # Prompt Optimizer
26
+
27
+ A CLI tool that **analyzes and rewrites prompts** following established prompt engineering best practices. Powered by **LangChain** + **Groq** (free tier, no credit card).
28
+
29
+ ## Why I Built This
30
+
31
+ Prompt engineering is no longer about trial and error — it's a discipline with repeatable patterns (role definition, output contracts, chain-of-thought, constraints). Most developers still write vague, unstructured prompts that leave LLMs guessing. This tool automates the optimization cycle:
32
+
33
+ 1. **Analyze** — identify exactly what's wrong with a prompt against 10 principles
34
+ 2. **Structure** — rewrite it with role, objective, context, step-by-step instructions, constraints, and output format
35
+ 3. **Iterate** — test the optimized prompt, refine, and repeat
36
+
37
+ The goal is to make production-quality prompting accessible from the terminal.
38
+
39
+ ## Architecture
40
+
41
+ ```
42
+ ┌──────────────┐
43
+ │ principles │ 10 rules + both system prompts
44
+ │ .py │ (generated from one table)
45
+ └──────┬───────┘
46
+ │
47
+ ┌───────────┐ ┌───────┴────────┐ ┌────────────┐ ┌──────────┐
48
+ │ cli.py │──▶│ analyzer.py │──▶│ llm.py │──▶│ Groq │
49
+ │ Click+Rich│ │ optimizer.py │ │ ChatGroq + │ │ API │
50
+ └─────┬─────┘ └───────┬────────┘ │ structured │ └──────────┘
51
+ │ │ │ output │
52
+ │ ┌────┴─────┐ └─────┬──────┘
53
+ │ │ schemas │ │
54
+ │ │ .py │ ┌─────┴──────┐
55
+ │ │ Pydantic │ │ config.py │
56
+ │ └──────────┘ │ settings │
57
+ │ │ + API key│
58
+ ▼ └────────────┘
59
+ ┌──────────┐
60
+ │ storage │ one timestamped file per run, into saved/
61
+ │ .py │
62
+ └──────────┘
63
+ ```
64
+
65
+ | Module | Role |
66
+ |---|---|
67
+ | `cli.py` | Click entry point, Rich rendering, input gathering (arg / `--file` / stdin) |
68
+ | `analyzer.py` | Step 1 — prompt + grading instructions → `PromptAnalysis` |
69
+ | `optimizer.py` | Step 2 — prompt + analysis + rewrite instructions → `OptimizedPrompt` |
70
+ | `principles.py` | The 10 rules as one table; both system prompts are generated from it |
71
+ | `schemas.py` | Pydantic contracts: `PromptWeakness`, `PromptAnalysis`, `OptimizedPrompt` |
72
+ | `llm.py` | The only module that knows how to talk to Groq |
73
+ | `config.py` | Every setting in one place, each overridable by env var |
74
+ | `storage.py` | Builds a timestamped path per run and writes it |
75
+ | `run.sh` | Bootstraps the venv, checks the API key, then offers an interactive menu |
76
+
77
+ Dependencies point one way only: `cli` → `analyzer`/`optimizer` → `llm` → `config`.
78
+ `principles` and `schemas` sit at the bottom with no internal dependencies, so
79
+ either step can be swapped, retried, or tested without touching the other.
80
+
81
+ ### Workflow
82
+
83
+ ```
84
+ User Prompt ──▶ Analyze ──▶ Quality Score (0-100)
85
+ │ + Strengths
86
+ │ + Weaknesses (with severity & suggestions)
87
+ ▼
88
+ Optimize ──▶ Structured Prompt
89
+ + Role / Objective / Context
90
+ + Step-by-Step Instructions
91
+ + Constraints & Rules
92
+ + Output Format
93
+ + Success Criteria
94
+ + Changes Made Summary
95
+ + Principles Applied List
96
+ ```
97
+
98
+ ### The 10 Principles
99
+
100
+ Defined once in `principles.py` and reused everywhere:
101
+
102
+ 1. **Role & Persona Definition** — assign expertise level and perspective
103
+ 2. **Clear Objective** — one-sentence goal statement
104
+ 3. **Context Provision** — background, audience, environment
105
+ 4. **Step-by-Step Instructions** — sequential breakdown of complex tasks
106
+ 5. **Constraints & Rules** — boundaries, exclusions, length limits
107
+ 6. **Output Format Specification** — JSON, markdown, bullet points, etc.
108
+ 7. **Few-Shot Examples** — demonstrate desired pattern with examples
109
+ 8. **Chain of Thought** — request reasoning for multi-step problems
110
+ 9. **Success Criteria** — define measurable quality bar
111
+ 10. **Specific Language** — replace vague qualifiers with precise terms
112
+
113
+ ## Tech Stack
114
+
115
+ | Technology | Where Used | Purpose |
116
+ |---|---|---|
117
+ | **Groq** (`openai/gpt-oss-20b`) | `src/llm.py:35` | Powers both LLM calls via `ChatGroq`. Free tier, no credit card required |
118
+ | **LangChain** (`ChatGroq`, `ChatPromptTemplate`) | `src/llm.py:61`, `src/analyzer.py:30`, `src/optimizer.py:31` | Provider abstraction, prompt templates, chain composition with LCEL |
119
+ | **Structured Outputs** (`with_structured_output`) | `src/llm.py:61` | Groq's `json_schema` mode in **strict** mode uses constrained decoding, so every response matches the Pydantic schema — no JSON parse errors, and `Literal` fields can only return declared values |
120
+ | **Pydantic v2** (`BaseModel`, `Field`) | `schemas.py:19-56` | Data contracts for `PromptWeakness`, `PromptAnalysis`, `OptimizedPrompt` — validation + serialization |
121
+ | **Click** (`@click.group`, `@click.command`, `@click.option`) | `src/cli.py:233-270` | CLI framework with composable commands, argument parsing, and auto-generated `--help` |
122
+ | **Rich** (`Console`, `Panel`, `Table`, `Markdown`, `Columns`) | `src/cli.py:53-137` | Terminal UI — color-coded score panels, weakness tables, markdown rendering, status spinners |
123
+ | **python-dotenv** (`load_dotenv`) | `src/config.py:15` | Auto-loads `GROQ_API_KEY` from `.env` file — no manual config flags |
124
+ | **pytest** (offline suite) | `tests/` | ~43 cases, no API key or network needed: CLI flow via `CliRunner`, the LLM seam with a fake provider, schemas, principles, config, storage |
125
+ | **uv** | `pyproject.toml` | Package manager — single `uv sync` installs deps, builds package, registers CLI entry point |
126
+ | **Python 3.12** | `.python-version`, `pyproject.toml` | Type hints (`list[str]`, `dict[str, str]`), `str.removeprefix`/`removesuffix` |
127
+
128
+ ## Installation
129
+
130
+ Published on PyPI as [`prompt-optimizer-tool`](https://pypi.org/project/prompt-optimizer-tool/).
131
+
132
+ ```bash
133
+ # Try it instantly, nothing is installed
134
+ uvx --from prompt-optimizer-tool prompt-optimizer list
135
+
136
+ # Install as an isolated tool (recommended)
137
+ uv tool install prompt-optimizer-tool
138
+
139
+ # or with pipx
140
+ pipx install prompt-optimizer-tool
141
+ ```
142
+
143
+ ### Set your Groq API key (free, no credit card: https://console.groq.com/keys)
144
+
145
+ ```bash
146
+ export GROQ_API_KEY=gsk_your-key-here
147
+ prompt-optimizer optimize "write code in python to fetch api data"
148
+ ```
149
+
150
+ ### Install from source (alternative)
151
+
152
+ ```bash
153
+ git clone https://github.com/khadarbashajilan/prompt-optimizer-tool.git
154
+ cd prompt-optimizer-tool
155
+ cp .env.example .env # then edit .env: GROQ_API_KEY=gsk_your-key-here
156
+ ./run.sh
157
+ ```
158
+
159
+ ### Quick start
160
+
161
+ ```bash
162
+ # Interactive menu — the easiest way in
163
+ ./run.sh
164
+
165
+ # Or pass arguments straight through to the CLI
166
+ ./run.sh optimize "write code in python to fetch api data"
167
+ ./run.sh optimize --file prompt.txt
168
+ ./run.sh list
169
+ ```
170
+
171
+ `./run.sh` with no arguments opens a menu: optimize a pasted prompt, optimize
172
+ a file, list the 10 principles, show help, or quit. It verifies
173
+ `GROQ_API_KEY` is set and creates the virtualenv on first run.
174
+
175
+ ## Usage
176
+
177
+ ```bash
178
+ # Basic — analyze + optimize a prompt
179
+ uv run prompt-optimizer optimize "write code in python to fetch api data"
180
+
181
+ # Read from file
182
+ uv run prompt-optimizer optimize --file prompt.txt
183
+
184
+ # Pipe from stdin
185
+ echo "explain quantum computing to a 5 year old" | uv run prompt-optimizer optimize
186
+
187
+ # Each run is auto-saved to its own timestamped file in saved/
188
+ uv run prompt-optimizer optimize "write a blog post"
189
+ # → saved/optimized-20260927-143205.md
190
+
191
+ # Choose a different output folder
192
+ uv run prompt-optimizer optimize "write a blog post" --out ~/prompts
193
+
194
+ # List all 10 prompting principles
195
+ uv run prompt-optimizer list
196
+ ```
197
+
198
+ ### Configuration
199
+
200
+ Every setting has a default and can be overridden with an environment
201
+ variable, so none of them require a code change:
202
+
203
+ | Variable | Default | Means |
204
+ |---|---|---|
205
+ | `GROQ_API_KEY` | *(required)* | Authorises the calls. Read from `.env` |
206
+ | `PROMPT_OPTIMIZER_MODEL` | `openai/gpt-oss-20b` | Which Groq model to use |
207
+ | `PROMPT_OPTIMIZER_TEMPERATURE` | `0.6` | Higher means more varied wording |
208
+ | `PROMPT_OPTIMIZER_MAX_TOKENS` | `4096` | Reply ceiling; lower values truncate long rewrites |
209
+ | `PROMPT_OPTIMIZER_MAX_RETRIES` | `3` | Attempts per call, handles free-tier rate limits |
210
+ | `PROMPT_OPTIMIZER_TIMEOUT` | `60` | Per-request seconds, so a stalled call cannot hang |
211
+ | `PROMPT_OPTIMIZER_OUTPUT_DIR` | `saved` | Default folder for saved rewrites |
212
+
213
+ ### Example Output
214
+
215
+ The tool produces a structured report:
216
+
217
+ - **Quality Score** — color-coded (green ≥70, yellow ≥40, red <40)
218
+ - **Strengths** — what the original prompt does well
219
+ - **Weaknesses & Improvements** — each issue with severity, violated principle, and concrete fix
220
+ - **Changes Made** — summary of all improvements applied
221
+ - **Optimized Prompt** — the complete rewritten prompt (copy-ready)
222
+ - **Principles Applied** — which of the 10 principles were used
223
+ - **Auto-save** — every run writes its own file to `saved/`, named for the date and time of the run, so results accumulate instead of overwriting
224
+
225
+ ## Limitations and Roadmap
226
+
227
+ What this tool does **not** do yet, so expectations are clear:
228
+
229
+ | Limitation | Current behavior | Fix |
230
+ |---|---|---|
231
+ | **No logging** | Errors print to the terminal only; no debug trail | Add structured logging (log file + `--debug` flag) |
232
+ | **No caching** | Analyze + Optimize each hit the API on every run | Cache analyses by prompt hash to avoid repeat cost |
233
+ | **No live-model tests** | The ~43 offline tests fake the provider seam only; real Groq structured-output calls are verified by hand | Add an opt-in integration test with a real key |
234
+ | **No model fallback** | If the configured model is unavailable the run fails after retries | Add a second model to fall back to |
235
+ | **Console only** | No way to diff a rewrite against its previous version | Add `--diff <file>` to compare two saved runs |
236
+ | **No CI** | Checks only run locally | Add a GitHub Actions workflow |
237
+
238
+ Planned next: logging, and an opt-in live-model integration test.
239
+
240
+ ## Key Design Decisions
241
+
242
+ - **Structured Outputs in strict mode** — using `with_structured_output(Model, method="json_schema", strict=True)`. Groq's strict mode uses constrained decoding, so the response is guaranteed to match the Pydantic schema. Tool calling would be the alternative, but Groq does not support tool use together with Structured Outputs, and strict mode is the stronger guarantee.
243
+ - **Constrained decoding doubles as validation** — because the decoder can only emit declared values, `Literal` fields (`severity`, `principle`, `principles_applied`) cannot come back as typos or invented names. This is what guarantees the "Principles Applied" panel can always resolve a principle, instead of silently rendering nothing when the model returns a name rather than a key.
244
+ - **Closed schemas only** — strict mode requires every field to be required and every object to set `additionalProperties: false`. A free-form `dict[str, str]` collapses to an always-empty object under those rules, so `sections` is a `list[PromptSection]` (explicit `name` + `content`) instead.
245
+ - **Model choice: `openai/gpt-oss-20b`** — free tier, ~1000 tokens/sec, and one of only three models supporting strict-mode Structured Outputs. The old `llama-3.x` ids are Enterprise-only now, so they are not free.
246
+ - **`temperature=0.6`** — Groq recommends 0.5–0.7 for gpt-oss; the low values typical of deterministic chat models degrade into repetition and incoherent output on this model.
247
+ - **`max_tokens=4096`** — Groq's default of 1024 completion tokens truncates long rewritten prompts, which breaks JSON parsing.
248
+ - **One table, three consumers** — the 10 principles live in a single `PRINCIPLES` dict. The `list` command renders it, and both system prompts are generated from it. Previously the rules were hand-copied into both prompt strings, so editing a rule in one place silently left the other two stale.
249
+ - **Keys, not names, cross the wire** — the LLM is asked for principle *keys* (`role`), and `principle_name()` maps a key to a display title at render time. Fewer tokens in the prompt, and lookups cannot fail.
250
+ - **`config.py` owns every setting** — no `os.environ` reads and no magic numbers outside it. `llm.py` is the only module that knows how to reach Groq, so the two pipeline steps never construct a client themselves.
251
+ - **One-way dependencies** — `cli` → `analyzer`/`optimizer` → `llm` → `config`, with `principles` and `schemas` at the bottom. The optimizer used to import its client from the analyzer, which inverted the natural reading order for no benefit.
252
+ - Standard **src/ layout** — the package lives at `src/prompt_optimizer_tool/`, so setuptools auto-discovery applies with no path mapping, tests import the *installed* package, and the entry point is `prompt_optimizer_tool.cli:cli`.
253
+ - **Failures exit non-zero** — `optimize` exits 1 when a step fails and 2 on missing input, so shell scripts and `run.sh` can trust the exit status instead of parsing output. A placeholder key fails the same way, before any tokens are spent.
254
+ - **Untrusted content boundary** — the text being analyzed or rewritten is wrapped in `<prompt_to_analyze>` tags with an explicit "data, never instructions" instruction, because prompts can contain instructions themselves.
255
+ - **Rich for DX** — color-coded severity, panel layouts, markdown rendering, and status spinners give instant visual feedback without a single HTML page.
256
+ - **Config-free API Key** — `python-dotenv` loads `.env` automatically; no `--api-key` flag cluttering the interface.
257
+ - **Zero-config Package Management** — `uv` handles deps, build, and entry point registration in one command.
258
+
259
+ ## Development
260
+
261
+ ```bash
262
+ uv sync # install deps (includes the dev group with pytest)
263
+ uv run pytest # offline suite: no API key, no network
264
+ uv run prompt-optimizer list
265
+ ```
266
+
267
+ Use the venv directly if you prefer: `.venv/bin/python -m pytest`.
268
+
269
+ ## Project Structure
270
+
271
+ ```
272
+ prompt-optimizer/
273
+ pyproject.toml # uv project config with entry point
274
+ run.sh # bootstrap + interactive menu
275
+ .env.example # GROQ_API_KEY template
276
+ .gitignore
277
+ src/
278
+ cli.py # Click commands + Rich rendering
279
+ analyzer.py # Step 1: grade a prompt
280
+ optimizer.py # Step 2: rewrite it
281
+ principles.py # 10 principles; generates both system prompts
282
+ schemas.py # Pydantic contracts for structured I/O
283
+ llm.py # the only module that talks to Groq
284
+ config.py # all settings + API key loading
285
+ storage.py # timestamped path per run, then write
286
+ tests/
287
+ support.py # FakeProvider + fresh-model factories
288
+ conftest.py # fixtures for the two test seams
289
+ test_cli.py # end-to-end: input modes, exit codes, saving
290
+ test_pipeline.py # schema + message contracts at the LLM seam
291
+ test_principles.py # table/Literal/prompt consistency
292
+ test_schemas.py # validation bounds and Literal values
293
+ test_config.py # API key resolution + placeholder rejection
294
+ test_storage.py # timestamped naming, collision, folders
295
+ saved/ # one file per run, gitignored
296
+ ```
297
+
298
+
@@ -0,0 +1,274 @@
1
+ # Prompt Optimizer
2
+
3
+ A CLI tool that **analyzes and rewrites prompts** following established prompt engineering best practices. Powered by **LangChain** + **Groq** (free tier, no credit card).
4
+
5
+ ## Why I Built This
6
+
7
+ Prompt engineering is no longer about trial and error — it's a discipline with repeatable patterns (role definition, output contracts, chain-of-thought, constraints). Most developers still write vague, unstructured prompts that leave LLMs guessing. This tool automates the optimization cycle:
8
+
9
+ 1. **Analyze** — identify exactly what's wrong with a prompt against 10 principles
10
+ 2. **Structure** — rewrite it with role, objective, context, step-by-step instructions, constraints, and output format
11
+ 3. **Iterate** — test the optimized prompt, refine, and repeat
12
+
13
+ The goal is to make production-quality prompting accessible from the terminal.
14
+
15
+ ## Architecture
16
+
17
+ ```
18
+ ┌──────────────┐
19
+ │ principles │ 10 rules + both system prompts
20
+ │ .py │ (generated from one table)
21
+ └──────┬───────┘
22
+ │
23
+ ┌───────────┐ ┌───────┴────────┐ ┌────────────┐ ┌──────────┐
24
+ │ cli.py │──▶│ analyzer.py │──▶│ llm.py │──▶│ Groq │
25
+ │ Click+Rich│ │ optimizer.py │ │ ChatGroq + │ │ API │
26
+ └─────┬─────┘ └───────┬────────┘ │ structured │ └──────────┘
27
+ │ │ │ output │
28
+ │ ┌────┴─────┐ └─────┬──────┘
29
+ │ │ schemas │ │
30
+ │ │ .py │ ┌─────┴──────┐
31
+ │ │ Pydantic │ │ config.py │
32
+ │ └──────────┘ │ settings │
33
+ │ │ + API key│
34
+ ▼ └────────────┘
35
+ ┌──────────┐
36
+ │ storage │ one timestamped file per run, into saved/
37
+ │ .py │
38
+ └──────────┘
39
+ ```
40
+
41
+ | Module | Role |
42
+ |---|---|
43
+ | `cli.py` | Click entry point, Rich rendering, input gathering (arg / `--file` / stdin) |
44
+ | `analyzer.py` | Step 1 — prompt + grading instructions → `PromptAnalysis` |
45
+ | `optimizer.py` | Step 2 — prompt + analysis + rewrite instructions → `OptimizedPrompt` |
46
+ | `principles.py` | The 10 rules as one table; both system prompts are generated from it |
47
+ | `schemas.py` | Pydantic contracts: `PromptWeakness`, `PromptAnalysis`, `OptimizedPrompt` |
48
+ | `llm.py` | The only module that knows how to talk to Groq |
49
+ | `config.py` | Every setting in one place, each overridable by env var |
50
+ | `storage.py` | Builds a timestamped path per run and writes it |
51
+ | `run.sh` | Bootstraps the venv, checks the API key, then offers an interactive menu |
52
+
53
+ Dependencies point one way only: `cli` → `analyzer`/`optimizer` → `llm` → `config`.
54
+ `principles` and `schemas` sit at the bottom with no internal dependencies, so
55
+ either step can be swapped, retried, or tested without touching the other.
56
+
57
+ ### Workflow
58
+
59
+ ```
60
+ User Prompt ──▶ Analyze ──▶ Quality Score (0-100)
61
+ │ + Strengths
62
+ │ + Weaknesses (with severity & suggestions)
63
+ ▼
64
+ Optimize ──▶ Structured Prompt
65
+ + Role / Objective / Context
66
+ + Step-by-Step Instructions
67
+ + Constraints & Rules
68
+ + Output Format
69
+ + Success Criteria
70
+ + Changes Made Summary
71
+ + Principles Applied List
72
+ ```
73
+
74
+ ### The 10 Principles
75
+
76
+ Defined once in `principles.py` and reused everywhere:
77
+
78
+ 1. **Role & Persona Definition** — assign expertise level and perspective
79
+ 2. **Clear Objective** — one-sentence goal statement
80
+ 3. **Context Provision** — background, audience, environment
81
+ 4. **Step-by-Step Instructions** — sequential breakdown of complex tasks
82
+ 5. **Constraints & Rules** — boundaries, exclusions, length limits
83
+ 6. **Output Format Specification** — JSON, markdown, bullet points, etc.
84
+ 7. **Few-Shot Examples** — demonstrate desired pattern with examples
85
+ 8. **Chain of Thought** — request reasoning for multi-step problems
86
+ 9. **Success Criteria** — define measurable quality bar
87
+ 10. **Specific Language** — replace vague qualifiers with precise terms
88
+
89
+ ## Tech Stack
90
+
91
+ | Technology | Where Used | Purpose |
92
+ |---|---|---|
93
+ | **Groq** (`openai/gpt-oss-20b`) | `src/llm.py:35` | Powers both LLM calls via `ChatGroq`. Free tier, no credit card required |
94
+ | **LangChain** (`ChatGroq`, `ChatPromptTemplate`) | `src/llm.py:61`, `src/analyzer.py:30`, `src/optimizer.py:31` | Provider abstraction, prompt templates, chain composition with LCEL |
95
+ | **Structured Outputs** (`with_structured_output`) | `src/llm.py:61` | Groq's `json_schema` mode in **strict** mode uses constrained decoding, so every response matches the Pydantic schema — no JSON parse errors, and `Literal` fields can only return declared values |
96
+ | **Pydantic v2** (`BaseModel`, `Field`) | `schemas.py:19-56` | Data contracts for `PromptWeakness`, `PromptAnalysis`, `OptimizedPrompt` — validation + serialization |
97
+ | **Click** (`@click.group`, `@click.command`, `@click.option`) | `src/cli.py:233-270` | CLI framework with composable commands, argument parsing, and auto-generated `--help` |
98
+ | **Rich** (`Console`, `Panel`, `Table`, `Markdown`, `Columns`) | `src/cli.py:53-137` | Terminal UI — color-coded score panels, weakness tables, markdown rendering, status spinners |
99
+ | **python-dotenv** (`load_dotenv`) | `src/config.py:15` | Auto-loads `GROQ_API_KEY` from `.env` file — no manual config flags |
100
+ | **pytest** (offline suite) | `tests/` | ~43 cases, no API key or network needed: CLI flow via `CliRunner`, the LLM seam with a fake provider, schemas, principles, config, storage |
101
+ | **uv** | `pyproject.toml` | Package manager — single `uv sync` installs deps, builds package, registers CLI entry point |
102
+ | **Python 3.12** | `.python-version`, `pyproject.toml` | Type hints (`list[str]`, `dict[str, str]`), `str.removeprefix`/`removesuffix` |
103
+
104
+ ## Installation
105
+
106
+ Published on PyPI as [`prompt-optimizer-tool`](https://pypi.org/project/prompt-optimizer-tool/).
107
+
108
+ ```bash
109
+ # Try it instantly, nothing is installed
110
+ uvx --from prompt-optimizer-tool prompt-optimizer list
111
+
112
+ # Install as an isolated tool (recommended)
113
+ uv tool install prompt-optimizer-tool
114
+
115
+ # or with pipx
116
+ pipx install prompt-optimizer-tool
117
+ ```
118
+
119
+ ### Set your Groq API key (free, no credit card: https://console.groq.com/keys)
120
+
121
+ ```bash
122
+ export GROQ_API_KEY=gsk_your-key-here
123
+ prompt-optimizer optimize "write code in python to fetch api data"
124
+ ```
125
+
126
+ ### Install from source (alternative)
127
+
128
+ ```bash
129
+ git clone https://github.com/khadarbashajilan/prompt-optimizer-tool.git
130
+ cd prompt-optimizer-tool
131
+ cp .env.example .env # then edit .env: GROQ_API_KEY=gsk_your-key-here
132
+ ./run.sh
133
+ ```
134
+
135
+ ### Quick start
136
+
137
+ ```bash
138
+ # Interactive menu — the easiest way in
139
+ ./run.sh
140
+
141
+ # Or pass arguments straight through to the CLI
142
+ ./run.sh optimize "write code in python to fetch api data"
143
+ ./run.sh optimize --file prompt.txt
144
+ ./run.sh list
145
+ ```
146
+
147
+ `./run.sh` with no arguments opens a menu: optimize a pasted prompt, optimize
148
+ a file, list the 10 principles, show help, or quit. It verifies
149
+ `GROQ_API_KEY` is set and creates the virtualenv on first run.
150
+
151
+ ## Usage
152
+
153
+ ```bash
154
+ # Basic — analyze + optimize a prompt
155
+ uv run prompt-optimizer optimize "write code in python to fetch api data"
156
+
157
+ # Read from file
158
+ uv run prompt-optimizer optimize --file prompt.txt
159
+
160
+ # Pipe from stdin
161
+ echo "explain quantum computing to a 5 year old" | uv run prompt-optimizer optimize
162
+
163
+ # Each run is auto-saved to its own timestamped file in saved/
164
+ uv run prompt-optimizer optimize "write a blog post"
165
+ # → saved/optimized-20260927-143205.md
166
+
167
+ # Choose a different output folder
168
+ uv run prompt-optimizer optimize "write a blog post" --out ~/prompts
169
+
170
+ # List all 10 prompting principles
171
+ uv run prompt-optimizer list
172
+ ```
173
+
174
+ ### Configuration
175
+
176
+ Every setting has a default and can be overridden with an environment
177
+ variable, so none of them require a code change:
178
+
179
+ | Variable | Default | Means |
180
+ |---|---|---|
181
+ | `GROQ_API_KEY` | *(required)* | Authorises the calls. Read from `.env` |
182
+ | `PROMPT_OPTIMIZER_MODEL` | `openai/gpt-oss-20b` | Which Groq model to use |
183
+ | `PROMPT_OPTIMIZER_TEMPERATURE` | `0.6` | Higher means more varied wording |
184
+ | `PROMPT_OPTIMIZER_MAX_TOKENS` | `4096` | Reply ceiling; lower values truncate long rewrites |
185
+ | `PROMPT_OPTIMIZER_MAX_RETRIES` | `3` | Attempts per call, handles free-tier rate limits |
186
+ | `PROMPT_OPTIMIZER_TIMEOUT` | `60` | Per-request seconds, so a stalled call cannot hang |
187
+ | `PROMPT_OPTIMIZER_OUTPUT_DIR` | `saved` | Default folder for saved rewrites |
188
+
189
+ ### Example Output
190
+
191
+ The tool produces a structured report:
192
+
193
+ - **Quality Score** — color-coded (green ≥70, yellow ≥40, red <40)
194
+ - **Strengths** — what the original prompt does well
195
+ - **Weaknesses & Improvements** — each issue with severity, violated principle, and concrete fix
196
+ - **Changes Made** — summary of all improvements applied
197
+ - **Optimized Prompt** — the complete rewritten prompt (copy-ready)
198
+ - **Principles Applied** — which of the 10 principles were used
199
+ - **Auto-save** — every run writes its own file to `saved/`, named for the date and time of the run, so results accumulate instead of overwriting
200
+
201
+ ## Limitations and Roadmap
202
+
203
+ What this tool does **not** do yet, so expectations are clear:
204
+
205
+ | Limitation | Current behavior | Fix |
206
+ |---|---|---|
207
+ | **No logging** | Errors print to the terminal only; no debug trail | Add structured logging (log file + `--debug` flag) |
208
+ | **No caching** | Analyze + Optimize each hit the API on every run | Cache analyses by prompt hash to avoid repeat cost |
209
+ | **No live-model tests** | The ~43 offline tests fake the provider seam only; real Groq structured-output calls are verified by hand | Add an opt-in integration test with a real key |
210
+ | **No model fallback** | If the configured model is unavailable the run fails after retries | Add a second model to fall back to |
211
+ | **Console only** | No way to diff a rewrite against its previous version | Add `--diff <file>` to compare two saved runs |
212
+ | **No CI** | Checks only run locally | Add a GitHub Actions workflow |
213
+
214
+ Planned next: logging, and an opt-in live-model integration test.
215
+
216
+ ## Key Design Decisions
217
+
218
+ - **Structured Outputs in strict mode** — using `with_structured_output(Model, method="json_schema", strict=True)`. Groq's strict mode uses constrained decoding, so the response is guaranteed to match the Pydantic schema. Tool calling would be the alternative, but Groq does not support tool use together with Structured Outputs, and strict mode is the stronger guarantee.
219
+ - **Constrained decoding doubles as validation** — because the decoder can only emit declared values, `Literal` fields (`severity`, `principle`, `principles_applied`) cannot come back as typos or invented names. This is what guarantees the "Principles Applied" panel can always resolve a principle, instead of silently rendering nothing when the model returns a name rather than a key.
220
+ - **Closed schemas only** — strict mode requires every field to be required and every object to set `additionalProperties: false`. A free-form `dict[str, str]` collapses to an always-empty object under those rules, so `sections` is a `list[PromptSection]` (explicit `name` + `content`) instead.
221
+ - **Model choice: `openai/gpt-oss-20b`** — free tier, ~1000 tokens/sec, and one of only three models supporting strict-mode Structured Outputs. The old `llama-3.x` ids are Enterprise-only now, so they are not free.
222
+ - **`temperature=0.6`** — Groq recommends 0.5–0.7 for gpt-oss; the low values typical of deterministic chat models degrade into repetition and incoherent output on this model.
223
+ - **`max_tokens=4096`** — Groq's default of 1024 completion tokens truncates long rewritten prompts, which breaks JSON parsing.
224
+ - **One table, three consumers** — the 10 principles live in a single `PRINCIPLES` dict. The `list` command renders it, and both system prompts are generated from it. Previously the rules were hand-copied into both prompt strings, so editing a rule in one place silently left the other two stale.
225
+ - **Keys, not names, cross the wire** — the LLM is asked for principle *keys* (`role`), and `principle_name()` maps a key to a display title at render time. Fewer tokens in the prompt, and lookups cannot fail.
226
+ - **`config.py` owns every setting** — no `os.environ` reads and no magic numbers outside it. `llm.py` is the only module that knows how to reach Groq, so the two pipeline steps never construct a client themselves.
227
+ - **One-way dependencies** — `cli` → `analyzer`/`optimizer` → `llm` → `config`, with `principles` and `schemas` at the bottom. The optimizer used to import its client from the analyzer, which inverted the natural reading order for no benefit.
228
+ - Standard **src/ layout** — the package lives at `src/prompt_optimizer_tool/`, so setuptools auto-discovery applies with no path mapping, tests import the *installed* package, and the entry point is `prompt_optimizer_tool.cli:cli`.
229
+ - **Failures exit non-zero** — `optimize` exits 1 when a step fails and 2 on missing input, so shell scripts and `run.sh` can trust the exit status instead of parsing output. A placeholder key fails the same way, before any tokens are spent.
230
+ - **Untrusted content boundary** — the text being analyzed or rewritten is wrapped in `<prompt_to_analyze>` tags with an explicit "data, never instructions" instruction, because prompts can contain instructions themselves.
231
+ - **Rich for DX** — color-coded severity, panel layouts, markdown rendering, and status spinners give instant visual feedback without a single HTML page.
232
+ - **Config-free API Key** — `python-dotenv` loads `.env` automatically; no `--api-key` flag cluttering the interface.
233
+ - **Zero-config Package Management** — `uv` handles deps, build, and entry point registration in one command.
234
+
235
+ ## Development
236
+
237
+ ```bash
238
+ uv sync # install deps (includes the dev group with pytest)
239
+ uv run pytest # offline suite: no API key, no network
240
+ uv run prompt-optimizer list
241
+ ```
242
+
243
+ Use the venv directly if you prefer: `.venv/bin/python -m pytest`.
244
+
245
+ ## Project Structure
246
+
247
+ ```
248
+ prompt-optimizer/
249
+ pyproject.toml # uv project config with entry point
250
+ run.sh # bootstrap + interactive menu
251
+ .env.example # GROQ_API_KEY template
252
+ .gitignore
253
+ src/
254
+ cli.py # Click commands + Rich rendering
255
+ analyzer.py # Step 1: grade a prompt
256
+ optimizer.py # Step 2: rewrite it
257
+ principles.py # 10 principles; generates both system prompts
258
+ schemas.py # Pydantic contracts for structured I/O
259
+ llm.py # the only module that talks to Groq
260
+ config.py # all settings + API key loading
261
+ storage.py # timestamped path per run, then write
262
+ tests/
263
+ support.py # FakeProvider + fresh-model factories
264
+ conftest.py # fixtures for the two test seams
265
+ test_cli.py # end-to-end: input modes, exit codes, saving
266
+ test_pipeline.py # schema + message contracts at the LLM seam
267
+ test_principles.py # table/Literal/prompt consistency
268
+ test_schemas.py # validation bounds and Literal values
269
+ test_config.py # API key resolution + placeholder rejection
270
+ test_storage.py # timestamped naming, collision, folders
271
+ saved/ # one file per run, gitignored
272
+ ```
273
+
274
+
@@ -0,0 +1,47 @@
1
+ [tool.uv]
2
+ package = true
3
+
4
+ [build-system]
5
+ requires = ["setuptools>=75.0"]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [project]
9
+ name = "prompt-optimizer-tool"
10
+ version = "0.1.0"
11
+ description = "CLI tool that grades prompts 0-100 against 10 engineering principles and rewrites them, powered by Groq"
12
+ readme = "README.md"
13
+ license = "MIT"
14
+ license-files = ["LICENSE"]
15
+ authors = [{ name = "khadar", email = "khadarbashajilan001@gmail.com" }]
16
+ requires-python = ">=3.12"
17
+ keywords = ["prompt", "prompt-engineering", "llm", "groq", "langchain", "cli"]
18
+ classifiers = [
19
+ "Environment :: Console",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
22
+ "Topic :: Software Development",
23
+ ]
24
+ dependencies = [
25
+ "langchain-groq>=1.1.0",
26
+ "langchain-core>=0.3.0",
27
+ "rich>=13.0.0",
28
+ "click>=8.0.0",
29
+ "python-dotenv>=1.0.0",
30
+ "pydantic>=2.0.0",
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/khadarbashajilan/prompt-optimizer-tool"
35
+ Issues = "https://github.com/khadarbashajilan/prompt-optimizer-tool/issues"
36
+
37
+ [project.scripts]
38
+ prompt-optimizer = "prompt_optimizer_tool.cli:cli"
39
+
40
+ [dependency-groups]
41
+ dev = ["pytest>=8.0.0", "pytest-cov>=6.0.0"]
42
+
43
+ [tool.pytest.ini_options]
44
+ testpaths = ["tests"]
45
+ pythonpath = ["tests"]
46
+ addopts = "-ra --strict-markers --strict-config"
47
+
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,17 @@
1
+ """Analyze and rewrite prompts against ten prompt engineering principles.
2
+
3
+ Import layering, which the module structure mirrors:
4
+
5
+ cli -> analyzer, optimizer -> llm -> config
6
+ |
7
+ +-> principles, schemas (no internal dependencies)
8
+
9
+ Dependencies point one way only. `principles` and `schemas` sit at the
10
+ bottom and import nothing from the rest of the package, so either pipeline
11
+ step can be swapped, retried, or tested without touching the other.
12
+
13
+ This module deliberately has no side effects: it must stay importable
14
+ without a configured API key, and importing it must not load .env.
15
+ """
16
+
17
+ __version__ = "0.1.0"