promptpump 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ritesh Nipane
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,103 @@
1
+ Metadata-Version: 2.4
2
+ Name: promptpump
3
+ Version: 0.1.0
4
+ Summary: Deterministic context-engineering engine and prompt compiler powered by a local Ollama model.
5
+ Author: Ritesh Nipane
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/RiteshNipane/PromptPump
8
+ Project-URL: Issues, https://github.com/RiteshNipane/PromptPump/issues
9
+ Keywords: prompt-engineering,ollama,llm,cli,context-engineering
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: typer>=0.12
24
+ Requires-Dist: rich>=13.0
25
+ Requires-Dist: requests>=2.31
26
+ Requires-Dist: pyperclip>=1.8
27
+ Requires-Dist: pathspec>=0.11
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7.4; extra == "dev"
30
+ Requires-Dist: ruff>=0.4; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # PromptPump
34
+
35
+ A local CLI tool and Python library that turns a short shorthand prompt into a
36
+ high-density, production-ready **master prompt**. It scans your project (file tree,
37
+ README/config snippets, Python AST outlines), merges that with a strict structural
38
+ schema, and compiles it with a local model (Ollama + Qwen2.5-Coder). Nothing leaves
39
+ your machine.
40
+
41
+ ## Install
42
+
43
+ Requires Python 3.10+ and [Ollama](https://ollama.com) (Windows, macOS, Linux).
44
+
45
+ ```bash
46
+ ollama pull qwen2.5-coder:7b # or qwen2.5-coder:14b for better quality
47
+ pip install pipx && pipx ensurepath # once; then reopen your terminal
48
+ pipx install promptpump # works in PowerShell, cmd, bash, zsh
49
+ promptpump doctor # verify Ollama + model
50
+ ```
51
+
52
+ Plain `pip install promptpump` also works. On Linux, clipboard support needs `xclip` or `xsel`.
53
+
54
+ Develop from source: `pip install -e ".[dev]"`.
55
+
56
+ ## Usage
57
+
58
+ ```bash
59
+ promptpump doctor # verify Ollama + model
60
+ promptpump stacks # list stack profiles
61
+ promptpump run "add jwt auth to the api" --stack fastapi --copy
62
+ promptpump run "add a pause menu" --stack pygame --stack python --path ../mygame
63
+ promptpump run "refactor db layer" --dry-run # inspect the payload, no model call
64
+ promptpump run "add caching" --no-copy > prompt.md # progress goes to stderr, prompt to stdout
65
+ ```
66
+
67
+ | Option | Description |
68
+ | --- | --- |
69
+ | `--stack/-s` | Inject stack rules (repeatable): python, fastapi, django, react, nextjs, node, pygame, pytorch |
70
+ | `--copy/--no-copy` | Copy to clipboard (default: on) |
71
+ | `--path/-p` | Project directory to scan (default: `.`) |
72
+ | `--model/-m` | Ollama model (env `PROMPTPUMP_MODEL`) |
73
+ | `--host` | Ollama URL (env `PROMPTPUMP_HOST`) |
74
+ | `--max-context-tokens` | Workspace context budget (default 3000) |
75
+ | `--ground/--no-ground` | Replace the model's `<codebase_context>` with deterministic scan facts (default: on) |
76
+ | `--dry-run` | Print the system/user payload and exit |
77
+
78
+ ## Library use
79
+
80
+ ```python
81
+ from promptpump import OllamaClient, PromptCompiler, scan_workspace
82
+
83
+ ctx = scan_workspace(".")
84
+ result = PromptCompiler(OllamaClient()).compile("add rate limiting", ctx, ["fastapi"])
85
+ print(result.prompt)
86
+ ```
87
+
88
+ ## How it stays deterministic
89
+
90
+ - Fixed system prompt and stack rules (`templates.py`); temperature 0.2 and fixed seed.
91
+ - Output validated against the seven required tags, with one automatic repair retry.
92
+ - Conversational filler and code fences stripped; `<codebase_context>` overwritten with real scan data so the model cannot hallucinate files.
93
+ - Secrets (`.env`, keys), binaries, and `.gitignore`d paths are never read.
94
+
95
+ ## Tests
96
+
97
+ ```bash
98
+ pytest
99
+ ```
100
+
101
+ ## Limitations
102
+
103
+ Only the root `.gitignore` is parsed; nested ignore files are not.
@@ -0,0 +1,71 @@
1
+ # PromptPump
2
+
3
+ A local CLI tool and Python library that turns a short shorthand prompt into a
4
+ high-density, production-ready **master prompt**. It scans your project (file tree,
5
+ README/config snippets, Python AST outlines), merges that with a strict structural
6
+ schema, and compiles it with a local model (Ollama + Qwen2.5-Coder). Nothing leaves
7
+ your machine.
8
+
9
+ ## Install
10
+
11
+ Requires Python 3.10+ and [Ollama](https://ollama.com) (Windows, macOS, Linux).
12
+
13
+ ```bash
14
+ ollama pull qwen2.5-coder:7b # or qwen2.5-coder:14b for better quality
15
+ pip install pipx && pipx ensurepath # once; then reopen your terminal
16
+ pipx install promptpump # works in PowerShell, cmd, bash, zsh
17
+ promptpump doctor # verify Ollama + model
18
+ ```
19
+
20
+ Plain `pip install promptpump` also works. On Linux, clipboard support needs `xclip` or `xsel`.
21
+
22
+ Develop from source: `pip install -e ".[dev]"`.
23
+
24
+ ## Usage
25
+
26
+ ```bash
27
+ promptpump doctor # verify Ollama + model
28
+ promptpump stacks # list stack profiles
29
+ promptpump run "add jwt auth to the api" --stack fastapi --copy
30
+ promptpump run "add a pause menu" --stack pygame --stack python --path ../mygame
31
+ promptpump run "refactor db layer" --dry-run # inspect the payload, no model call
32
+ promptpump run "add caching" --no-copy > prompt.md # progress goes to stderr, prompt to stdout
33
+ ```
34
+
35
+ | Option | Description |
36
+ | --- | --- |
37
+ | `--stack/-s` | Inject stack rules (repeatable): python, fastapi, django, react, nextjs, node, pygame, pytorch |
38
+ | `--copy/--no-copy` | Copy to clipboard (default: on) |
39
+ | `--path/-p` | Project directory to scan (default: `.`) |
40
+ | `--model/-m` | Ollama model (env `PROMPTPUMP_MODEL`) |
41
+ | `--host` | Ollama URL (env `PROMPTPUMP_HOST`) |
42
+ | `--max-context-tokens` | Workspace context budget (default 3000) |
43
+ | `--ground/--no-ground` | Replace the model's `<codebase_context>` with deterministic scan facts (default: on) |
44
+ | `--dry-run` | Print the system/user payload and exit |
45
+
46
+ ## Library use
47
+
48
+ ```python
49
+ from promptpump import OllamaClient, PromptCompiler, scan_workspace
50
+
51
+ ctx = scan_workspace(".")
52
+ result = PromptCompiler(OllamaClient()).compile("add rate limiting", ctx, ["fastapi"])
53
+ print(result.prompt)
54
+ ```
55
+
56
+ ## How it stays deterministic
57
+
58
+ - Fixed system prompt and stack rules (`templates.py`); temperature 0.2 and fixed seed.
59
+ - Output validated against the seven required tags, with one automatic repair retry.
60
+ - Conversational filler and code fences stripped; `<codebase_context>` overwritten with real scan data so the model cannot hallucinate files.
61
+ - Secrets (`.env`, keys), binaries, and `.gitignore`d paths are never read.
62
+
63
+ ## Tests
64
+
65
+ ```bash
66
+ pytest
67
+ ```
68
+
69
+ ## Limitations
70
+
71
+ Only the root `.gitignore` is parsed; nested ignore files are not.
@@ -0,0 +1,16 @@
1
+ """PromptPump: compile shorthand prompts into dense, structured master prompts."""
2
+
3
+ from .context import WorkspaceContext, scan_workspace
4
+ from .engine import CompileResult, OllamaClient, PromptCompiler, PromptPumpError
5
+
6
+ __version__ = "0.1.0"
7
+
8
+ __all__ = [
9
+ "CompileResult",
10
+ "OllamaClient",
11
+ "PromptCompiler",
12
+ "PromptPumpError",
13
+ "WorkspaceContext",
14
+ "scan_workspace",
15
+ "__version__",
16
+ ]
@@ -0,0 +1,188 @@
1
+ """Typer CLI entry point: ``promptpump run "shorthand" --stack python --copy``."""
2
+
3
+ import sys
4
+ import time
5
+ from pathlib import Path
6
+ from typing import Annotated, Optional
7
+
8
+ import typer
9
+ from rich.console import Console
10
+ from rich.markup import escape
11
+ from rich.table import Table
12
+
13
+ from . import __version__
14
+ from .context import scan_workspace
15
+ from .engine import (
16
+ DEFAULT_HOST,
17
+ DEFAULT_MODEL,
18
+ OllamaClient,
19
+ PromptCompiler,
20
+ PromptPumpError,
21
+ )
22
+ from .templates import UnknownStackError, get_stack, list_stacks
23
+
24
+ app = typer.Typer(
25
+ name="promptpump",
26
+ help="Compile a short shorthand prompt into a dense, production-ready master prompt "
27
+ "using local codebase context and a local Ollama model.",
28
+ no_args_is_help=True,
29
+ add_completion=False,
30
+ )
31
+
32
+ # Progress and diagnostics go to stderr so stdout stays clean for piping the prompt.
33
+ err = Console(stderr=True)
34
+
35
+
36
+ def copy_to_clipboard(text: str) -> bool:
37
+ """Copy ``text`` to the system clipboard; return False if unavailable."""
38
+ try:
39
+ import pyperclip
40
+
41
+ pyperclip.copy(text)
42
+ return True
43
+ except Exception: # pyperclip raises PyperclipException when no backend exists
44
+ return False
45
+
46
+
47
+ def _force_utf8() -> None:
48
+ """Avoid UnicodeEncodeError on Windows when output is redirected (cp1252 default)."""
49
+ for stream in (sys.stdout, sys.stderr):
50
+ reconfigure = getattr(stream, "reconfigure", None)
51
+ if reconfigure is not None:
52
+ try:
53
+ reconfigure(encoding="utf-8", errors="replace")
54
+ except (OSError, ValueError):
55
+ pass
56
+
57
+
58
+ def _version_callback(value: bool) -> None:
59
+ if value:
60
+ typer.echo(f"promptpump {__version__}")
61
+ raise typer.Exit()
62
+
63
+
64
+ @app.callback()
65
+ def main(
66
+ version: Annotated[
67
+ Optional[bool],
68
+ typer.Option("--version", callback=_version_callback, is_eager=True, help="Show version."),
69
+ ] = None,
70
+ ) -> None:
71
+ """PromptPump: deterministic context engineering for coding prompts."""
72
+ _force_utf8()
73
+
74
+
75
+ @app.command()
76
+ def run(
77
+ prompt: Annotated[str, typer.Argument(help="Shorthand prompt, e.g. 'add jwt auth'.")],
78
+ stack: Annotated[
79
+ Optional[list[str]],
80
+ typer.Option("--stack", "-s", help="Stack rules to inject (repeatable). See `stacks`."),
81
+ ] = None,
82
+ copy: Annotated[
83
+ bool, typer.Option("--copy/--no-copy", help="Copy the result to the clipboard.")
84
+ ] = True,
85
+ path: Annotated[
86
+ Path,
87
+ typer.Option("--path", "-p", exists=True, file_okay=False, resolve_path=True,
88
+ help="Project directory to scan."),
89
+ ] = Path("."),
90
+ model: Annotated[
91
+ str, typer.Option("--model", "-m", envvar="PROMPTPUMP_MODEL", help="Ollama model name.")
92
+ ] = DEFAULT_MODEL,
93
+ host: Annotated[
94
+ str, typer.Option("--host", envvar="PROMPTPUMP_HOST", help="Ollama base URL.")
95
+ ] = DEFAULT_HOST,
96
+ max_context_tokens: Annotated[
97
+ int, typer.Option("--max-context-tokens", min=500, help="Workspace context budget.")
98
+ ] = 3000,
99
+ ground: Annotated[
100
+ bool,
101
+ typer.Option("--ground/--no-ground",
102
+ help="Overwrite <codebase_context> with deterministic scan facts."),
103
+ ] = True,
104
+ timeout: Annotated[float, typer.Option(help="Seconds to wait for the model.")] = 300.0,
105
+ dry_run: Annotated[
106
+ bool, typer.Option("--dry-run", help="Print the payload; do not call the model.")
107
+ ] = False,
108
+ ) -> None:
109
+ """Compile PROMPT into a structured master prompt."""
110
+ try:
111
+ profiles = [get_stack(s) for s in stack or []]
112
+ except UnknownStackError as exc:
113
+ err.print(f"[red]error:[/red] {escape(str(exc))}")
114
+ raise typer.Exit(2) from exc
115
+
116
+ with err.status("Scanning workspace..."):
117
+ context = scan_workspace(path, max_tokens=max_context_tokens)
118
+ err.print(
119
+ f"[dim]Scanned {context.root.name}/: {len(context.tree_lines)} tree entries, "
120
+ f"{len(context.key_files)} key files, {len(context.outlines)} outlined modules[/dim]"
121
+ )
122
+
123
+ compiler = PromptCompiler(
124
+ OllamaClient(host=host, model=model, timeout=timeout), ground_context=ground
125
+ )
126
+ stack_names = [p.name for p in profiles]
127
+
128
+ if dry_run:
129
+ for message in compiler.build_messages(prompt, context, stack_names):
130
+ typer.echo(f"===== {message['role'].upper()} =====\n{message['content']}\n")
131
+ raise typer.Exit()
132
+
133
+ start = time.perf_counter()
134
+ try:
135
+ with err.status(f"Compiling with {escape(model)} (local)..."):
136
+ result = compiler.compile(prompt, context, stack_names)
137
+ except PromptPumpError as exc:
138
+ err.print(f"[red]error:[/red] {escape(str(exc))}")
139
+ raise typer.Exit(1) from exc
140
+ elapsed = time.perf_counter() - start
141
+
142
+ if result.missing_tags:
143
+ err.print(
144
+ f"[yellow]warning:[/yellow] model output is missing tags: "
145
+ f"{', '.join(result.missing_tags)}. Try a larger model or rephrase."
146
+ )
147
+ err.print(f"[green]Compiled[/green] in {elapsed:.1f}s ({result.attempts} attempt(s))")
148
+
149
+ typer.echo(result.prompt)
150
+
151
+ if copy:
152
+ if copy_to_clipboard(result.prompt):
153
+ err.print("[green]Copied to clipboard.[/green]")
154
+ else:
155
+ err.print("[yellow]Clipboard unavailable (install xclip/xsel on Linux).[/yellow]")
156
+
157
+
158
+ @app.command()
159
+ def stacks() -> None:
160
+ """List available --stack profiles."""
161
+ table = Table("Name", "Label", "Rules")
162
+ for profile in list_stacks():
163
+ table.add_row(profile.name, profile.label, str(len(profile.rules)))
164
+ Console().print(table)
165
+
166
+
167
+ @app.command()
168
+ def doctor(
169
+ model: Annotated[str, typer.Option("--model", "-m", envvar="PROMPTPUMP_MODEL")] = DEFAULT_MODEL,
170
+ host: Annotated[str, typer.Option("--host", envvar="PROMPTPUMP_HOST")] = DEFAULT_HOST,
171
+ ) -> None:
172
+ """Check that Ollama is reachable and the model is installed."""
173
+ client = OllamaClient(host=host, model=model)
174
+ try:
175
+ installed = client.list_models()
176
+ except PromptPumpError as exc:
177
+ err.print(f"[red]x[/red] {escape(str(exc))} Start it with `ollama serve`.")
178
+ raise typer.Exit(1) from exc
179
+ err.print(f"[green]ok[/green] Ollama reachable at {host}")
180
+ if any(name == model or name.split(":")[0] == model for name in installed):
181
+ err.print(f"[green]ok[/green] Model '{model}' is installed")
182
+ else:
183
+ err.print(f"[red]x[/red] Model '{model}' missing. Run: ollama pull {model}")
184
+ raise typer.Exit(1)
185
+
186
+
187
+ if __name__ == "__main__":
188
+ app()