preprompt 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 (36) hide show
  1. preprompt-0.1.0/.claude/hooks/pre_prompt.py +166 -0
  2. preprompt-0.1.0/.claude/settings.json +24 -0
  3. preprompt-0.1.0/.env.example +17 -0
  4. preprompt-0.1.0/.github/workflows/ci.yml +24 -0
  5. preprompt-0.1.0/.github/workflows/publish.yml +42 -0
  6. preprompt-0.1.0/.gitignore +32 -0
  7. preprompt-0.1.0/CLAUDE.md +121 -0
  8. preprompt-0.1.0/CONTEXT.md +117 -0
  9. preprompt-0.1.0/LICENSE +22 -0
  10. preprompt-0.1.0/PKG-INFO +192 -0
  11. preprompt-0.1.0/README.md +163 -0
  12. preprompt-0.1.0/cli/__init__.py +0 -0
  13. preprompt-0.1.0/cli/commands.py +310 -0
  14. preprompt-0.1.0/docs/CNAME +1 -0
  15. preprompt-0.1.0/docs/index.html +664 -0
  16. preprompt-0.1.0/mcp_server/__init__.py +0 -0
  17. preprompt-0.1.0/mcp_server/classifier.py +98 -0
  18. preprompt-0.1.0/mcp_server/config.py +13 -0
  19. preprompt-0.1.0/mcp_server/extractor.py +108 -0
  20. preprompt-0.1.0/mcp_server/optimizer.py +88 -0
  21. preprompt-0.1.0/mcp_server/server.py +20 -0
  22. preprompt-0.1.0/mcp_server/tools.py +82 -0
  23. preprompt-0.1.0/preprompt.skill.md +64 -0
  24. preprompt-0.1.0/pyproject.toml +57 -0
  25. preprompt-0.1.0/scripts/init_github.py +68 -0
  26. preprompt-0.1.0/scripts/install.sh +48 -0
  27. preprompt-0.1.0/scripts/install_cursor.py +64 -0
  28. preprompt-0.1.0/scripts/install_windsurf.py +44 -0
  29. preprompt-0.1.0/scripts/install_zed.py +45 -0
  30. preprompt-0.1.0/scripts/setup_global_hook.py +118 -0
  31. preprompt-0.1.0/storage/__init__.py +0 -0
  32. preprompt-0.1.0/storage/db.py +322 -0
  33. preprompt-0.1.0/tests/__init__.py +0 -0
  34. preprompt-0.1.0/tests/test_classifier.py +94 -0
  35. preprompt-0.1.0/tests/test_integration.py +241 -0
  36. preprompt-0.1.0/tests/test_optimizer.py +79 -0
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Claude Code UserPromptSubmit hook for PrePrompt.
4
+
5
+ Receives JSON on stdin, writes JSON to stdout.
6
+ stdin: {"prompt": "...", "conversation_history": [...], "turn_number": N}
7
+ stdout: {"prompt": "..."} ← optimized or original, never blocked
8
+
9
+ DB writes are done via JSON sidecar files in ~/.preprompt/pending/
10
+ so the hook never touches the SQLite file directly (avoids lock conflict
11
+ with the running MCP server). The MCP server flushes sidecars on the
12
+ next optimize_prompt call.
13
+ """
14
+
15
+ import sys
16
+ import os
17
+ import json
18
+ import uuid
19
+ import time
20
+ from pathlib import Path
21
+
22
+
23
+ # ── Box annotation constants ──────────────────────────────────────────────────
24
+ _WIDTH = 62 # total box width
25
+ _INNER = _WIDTH - 4 # content between "║ " and " ║" (58 chars)
26
+ _TEXT_W = 48 # prompt text width after label (58 - 10)
27
+
28
+
29
+ def _box_line(content: str) -> str:
30
+ return f"║ {content:<{_INNER}} ║"
31
+
32
+
33
+ def _render_annotation(score: int, reason: str, original: str, optimized: str) -> str:
34
+ import textwrap
35
+
36
+ # Header: ╔═ PrePrompt +{score} ══...══╗
37
+ prefix = f"╔═ PrePrompt +{score} "
38
+ header = prefix + "═" * (_WIDTH - len(prefix) - 1) + "╗"
39
+
40
+ # Reason (wrapped to inner width)
41
+ reason_lines = [_box_line(l) for l in (textwrap.wrap(reason, _INNER) or [""])]
42
+
43
+ # Separator
44
+ sep = "╠" + "═" * (_WIDTH - 2) + "╣"
45
+
46
+ # ORIGINAL (truncated to TEXT_W)
47
+ orig_text = original if len(original) <= _TEXT_W else original[:_TEXT_W - 3] + "..."
48
+ orig_line = _box_line(f"ORIGINAL {orig_text}")
49
+
50
+ # OPTIMIZED (wrapped, continuation indented 10 spaces to align with text)
51
+ opt_wrapped = textwrap.wrap(optimized, _TEXT_W) or [optimized[:_TEXT_W]]
52
+ opt_lines = [_box_line(f"OPTIMIZED {opt_wrapped[0]}")] + [
53
+ _box_line(f" {line}") for line in opt_wrapped[1:]
54
+ ]
55
+
56
+ # Footer
57
+ footer = "╚" + "═" * (_WIDTH - 2) + "╝"
58
+
59
+ return "\n".join([header] + reason_lines + [sep, orig_line] + opt_lines + [footer])
60
+
61
+
62
+ def _write_sidecar(
63
+ prompt: str,
64
+ optimized: str,
65
+ score: int,
66
+ was_intercepted: bool,
67
+ turn_number: int,
68
+ ) -> None:
69
+ """Write event to ~/.preprompt/pending/<uuid>.json for async DB flush."""
70
+ sidecar = {
71
+ "original_prompt": prompt,
72
+ "optimized_prompt": optimized,
73
+ "classifier_score": score,
74
+ "was_intercepted": was_intercepted,
75
+ "turn_number": turn_number,
76
+ "timestamp": time.time(),
77
+ }
78
+ sidecar_dir = Path.home() / ".preprompt" / "pending"
79
+ sidecar_dir.mkdir(parents=True, exist_ok=True)
80
+ sidecar_path = sidecar_dir / f"{uuid.uuid4()}.json"
81
+ sidecar_path.write_text(json.dumps(sidecar))
82
+
83
+
84
+ def main() -> None:
85
+ raw = sys.stdin.read()
86
+
87
+ # Parse stdin — on failure, echo back whatever we got and exit cleanly
88
+ try:
89
+ data = json.loads(raw)
90
+ except Exception:
91
+ print(raw, end="")
92
+ sys.exit(0)
93
+
94
+ prompt: str = data.get("prompt", "")
95
+ history: list = data.get("conversation_history", [])
96
+ turn: int = data.get("turn_number", 1)
97
+
98
+ def passthrough() -> None:
99
+ print(json.dumps({"prompt": prompt}))
100
+
101
+ try:
102
+ # Always resolve paths relative to this file's location,
103
+ # not the caller's working directory
104
+ _HOOK_FILE = os.path.abspath(__file__)
105
+ _HOOK_DIR = os.path.dirname(_HOOK_FILE) # .claude/hooks/
106
+ _CLAUDE_DIR = os.path.dirname(_HOOK_DIR) # .claude/
107
+ _PROJECT_ROOT = os.path.dirname(_CLAUDE_DIR) # project root
108
+
109
+ # Add project root to path so mcp_server imports work
110
+ if _PROJECT_ROOT not in sys.path:
111
+ sys.path.insert(0, _PROJECT_ROOT)
112
+
113
+ # Load .env from project root
114
+ from dotenv import load_dotenv
115
+ load_dotenv(os.path.join(_PROJECT_ROOT, ".env"))
116
+
117
+ # ── Classify (no API call — always fast) ──────────────────────────────
118
+ from mcp_server.classifier import classify_prompt, OPTIMIZATION_THRESHOLD
119
+
120
+ score = classify_prompt(prompt, history, turn)
121
+
122
+ if score < OPTIMIZATION_THRESHOLD:
123
+ passthrough()
124
+ sys.exit(0)
125
+
126
+ # ── Check API key before importing optimizer (which triggers config) ──
127
+ api_key = os.environ.get("ANTHROPIC_API_KEY", "").strip()
128
+ if not api_key:
129
+ print(
130
+ "[PrePrompt WARNING] ANTHROPIC_API_KEY not set — skipping optimization",
131
+ file=sys.stderr,
132
+ )
133
+ passthrough()
134
+ sys.exit(0)
135
+
136
+ # ── Optimize via Haiku API ────────────────────────────────────────────
137
+ from mcp_server.optimizer import optimize
138
+
139
+ result = optimize(prompt, history)
140
+ optimized: str = result["optimized_prompt"]
141
+ reason: str = result["reason"]
142
+ was_intercepted: bool = optimized != prompt
143
+
144
+ # ── Write sidecar (no DB lock needed) ────────────────────────────────
145
+ try:
146
+ _write_sidecar(prompt, optimized, score, was_intercepted, turn)
147
+ except Exception as sidecar_err:
148
+ print(f"[PrePrompt] Sidecar write failed: {sidecar_err}", file=sys.stderr)
149
+
150
+ # ── Rich annotation to stderr ─────────────────────────────────────────
151
+ if was_intercepted:
152
+ print(_render_annotation(score, reason, prompt, optimized), file=sys.stderr)
153
+ else:
154
+ print(f"[PrePrompt +{score}] {reason}", file=sys.stderr)
155
+
156
+ print(json.dumps({"prompt": optimized}))
157
+
158
+ except Exception as e:
159
+ print(f"[PrePrompt ERROR] {e}", file=sys.stderr)
160
+ passthrough()
161
+
162
+ sys.exit(0)
163
+
164
+
165
+ if __name__ == "__main__":
166
+ main()
@@ -0,0 +1,24 @@
1
+ {
2
+ "mcpServers": {
3
+ "preprompt": {
4
+ "command": "python",
5
+ "args": ["-m", "mcp_server.server"],
6
+ "cwd": "${workspaceFolder}/promptforge",
7
+ "env": {
8
+ "PYTHONPATH": "${workspaceFolder}/promptforge"
9
+ }
10
+ }
11
+ },
12
+ "hooks": {
13
+ "UserPromptSubmit": [
14
+ {
15
+ "hooks": [
16
+ {
17
+ "type": "command",
18
+ "command": "python ${workspaceFolder}/promptforge/.claude/hooks/pre_prompt.py"
19
+ }
20
+ ]
21
+ }
22
+ ]
23
+ }
24
+ }
@@ -0,0 +1,17 @@
1
+ # Anthropic API key — required for classifier and optimizer agents
2
+ ANTHROPIC_API_KEY=sk-ant-...
3
+
4
+ # Model used for classification (cheap + fast)
5
+ CLASSIFIER_MODEL=claude-haiku-4-5-20251001
6
+
7
+ # Model used for prompt optimization (more capable)
8
+ OPTIMIZER_MODEL=claude-sonnet-4-6
9
+
10
+ # DuckDB database file path (use :memory: for in-memory only)
11
+ DB_PATH=./promptforge.duckdb
12
+
13
+ # Minimum confidence score (0.0–1.0) to trigger optimization
14
+ OPTIMIZATION_THRESHOLD=0.7
15
+
16
+ # MCP server transport: stdio or sse
17
+ MCP_TRANSPORT=stdio
@@ -0,0 +1,24 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.11"
17
+
18
+ - name: Install dev deps
19
+ run: pip install -e ".[dev]"
20
+
21
+ - name: Run tests
22
+ env:
23
+ ANTHROPIC_API_KEY: sk-ant-test-dummy-key-for-ci
24
+ run: python -m pytest -v
@@ -0,0 +1,42 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.11"
17
+
18
+ - name: Install build
19
+ run: pip install build
20
+
21
+ - name: Build distribution
22
+ run: python -m build
23
+
24
+ - uses: actions/upload-artifact@v4
25
+ with:
26
+ name: dist
27
+ path: dist/
28
+
29
+ publish:
30
+ needs: build
31
+ runs-on: ubuntu-latest
32
+ environment: release
33
+ permissions:
34
+ id-token: write
35
+ steps:
36
+ - uses: actions/download-artifact@v4
37
+ with:
38
+ name: dist
39
+ path: dist/
40
+
41
+ - name: Publish to PyPI
42
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,32 @@
1
+ # Environment
2
+ .env
3
+ *.env
4
+
5
+ # Python
6
+ __pycache__/
7
+ *.py[cod]
8
+ *.egg-info/
9
+ dist/
10
+ build/
11
+ .venv/
12
+ venv/
13
+
14
+ # DuckDB (local dev databases)
15
+ *.duckdb
16
+ *.duckdb.wal
17
+
18
+ # IDE
19
+ .vscode/
20
+ *.swp
21
+
22
+ # macOS
23
+ .DS_Store
24
+
25
+ # Tests
26
+ .pytest_cache/
27
+ .coverage
28
+ htmlcov/
29
+
30
+ # PrePrompt runtime DB lives outside the repo:
31
+ # ~/.preprompt/history.db ← not tracked
32
+ .venv/
@@ -0,0 +1,121 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ # Activate venv first
9
+ source .venv/bin/activate
10
+
11
+ # Run all tests
12
+ python -m pytest
13
+
14
+ # Run a single test file
15
+ python -m pytest tests/test_classifier.py -v
16
+
17
+ # Install in editable mode (includes dev deps)
18
+ pip install -e ".[dev]"
19
+
20
+ # Start the MCP server
21
+ python -m mcp_server.server
22
+
23
+ # CLI tools (after pip install)
24
+ preprompt-history [--limit N] [--intercepted-only]
25
+ preprompt-stats
26
+ preprompt-test-classifier
27
+ preprompt-memory
28
+ preprompt-optimize "your prompt here" # or pipe: echo "..." | preprompt-optimize
29
+ preprompt-optimize --raw "prompt" # prints optimized text only
30
+ preprompt-update-context
31
+
32
+ # One-command install + global hook registration (auto-detects Claude Code, Cursor, Windsurf, Zed)
33
+ bash scripts/install.sh
34
+
35
+ # Per-IDE registration
36
+ python scripts/install_cursor.py
37
+ python scripts/install_windsurf.py
38
+ python scripts/install_zed.py
39
+ ```
40
+
41
+ ## Architecture
42
+
43
+ PrePrompt is an MCP server that intercepts prompts before they reach the LLM, scores them with a local heuristic classifier, optionally rewrites vague/complex ones via Claude Haiku, and logs everything to a local SQLite DB.
44
+
45
+ ### Request flow
46
+
47
+ ```
48
+ User types prompt
49
+ → .claude/hooks/pre_prompt.py (UserPromptSubmit hook, subprocess)
50
+ → classify_prompt() (score 0–100, no API call)
51
+ → if score < 38: passthrough
52
+ → else: optimize() via Haiku API
53
+ → write JSON sidecar → ~/.preprompt/pending/<uuid>.json
54
+ → print optimized prompt to stdout
55
+ → Claude Code sends optimized prompt to LLM
56
+ → (next MCP tool call)
57
+ → flush_pending_hook_events() reads sidecars → SQLite
58
+ ```
59
+
60
+ The hook **never touches the DB directly** — this avoids SQLite lock contention with the running MCP server. The sidecar files are the IPC mechanism.
61
+
62
+ ### Key modules
63
+
64
+ | File | Responsibility |
65
+ |------|---------------|
66
+ | `mcp_server/classifier.py` | Heuristic scorer. `OPTIMIZATION_THRESHOLD = 38`. No API calls. |
67
+ | `mcp_server/optimizer.py` | Calls Claude Haiku to rewrite prompt. |
68
+ | `mcp_server/tools.py` | MCP tool `optimize_prompt()` — entry point from Claude Code. Calls `flush_pending_hook_events()` first. |
69
+ | `mcp_server/extractor.py` | Extracts stack facts (language, framework, etc.) from prompts → `stack_memory`. |
70
+ | `storage/db.py` | SQLite (WAL mode). Tables: `prompt_history`, `stack_memory`, `sessions`. `_get_connection()` is the long-lived write conn; `get_read_connection()` opens fresh read conns for CLI/history. |
71
+ | `cli/commands.py` | CLI entry points. Always calls `flush_pending_hook_events()` before reading history. Includes `optimize_cmd` for standalone CLI optimization. |
72
+ | `.claude/hooks/pre_prompt.py` | Hook subprocess. Resolves project root via `__file__` (not cwd). Writes sidecars, never imports `storage.db`. |
73
+ | `scripts/install_windsurf.py` | Registers MCP in `~/.codeium/windsurf/mcp_config.json`. |
74
+ | `scripts/install_zed.py` | Registers MCP in `~/.config/zed/settings.json`. |
75
+ | `.github/workflows/publish.yml` | Publishes to PyPI on `git tag v*` via OIDC trusted publisher. |
76
+ | `preprompt.skill.md` | Claude Skill file — manual PrePrompt scoring/optimization for tools without MCP. |
77
+
78
+ ### Data directory
79
+
80
+ All runtime data lives in `~/.preprompt/`:
81
+ - `history.db` — SQLite database
82
+ - `pending/*.json` — sidecar files written by hook, flushed by MCP server
83
+
84
+ ### Classifier scoring
85
+
86
+ Positive: ambiguity verbs (+25 max), multi-requirement density (12 pts/hit, max 30), turn depth (+5/turn after turn 2, max 15), code task without format hint (+15).
87
+ Negative: short prompt (−20), "what is/are/does" opener (−15), already structured (−15), conversational opener (−25).
88
+
89
+ ### SQLite type conventions
90
+
91
+ - Timestamps stored as ISO 8601 TEXT; parsed back to `datetime` via `_coerce_row()` on read.
92
+ - Booleans stored as INTEGER (0/1); coerced back to `bool` on read.
93
+ - All writes followed by `conn.commit()`.
94
+
95
+ ### Session identity
96
+
97
+ One session per `hostname + calendar day`. Session key format: `{hostname}-{YYYY-MM-DD}`.
98
+
99
+ ### Landing page
100
+
101
+ `docs/index.html` — GitHub Pages site (Tailwind CDN, Space Grotesk + JetBrains Mono, dark theme). Sections: hero terminal, interactive classifier demo, how it works, stack memory CLI mockup, session replay, stats bar, open source CTA, beta signup, FAQ. All interactivity is vanilla JS — no build step.
102
+
103
+ ## Mandatory after every task
104
+
105
+ After completing any task in this repository, you MUST always:
106
+
107
+ 1. Run `pytest -v` and confirm all tests still pass
108
+
109
+ 2. Run `preprompt-update-context` to update CONTEXT.md
110
+
111
+ 3. Update CLAUDE.md if any architecture, file map, or interface changed
112
+
113
+ 4. Commit with a clear descriptive message authored by Yashdeep Tehlan:
114
+
115
+ ```
116
+ git -c user.name="yashdeeptehlan" -c user.email="0yashdeeptehlan@gmail.com" commit -m "your message here"
117
+ ```
118
+
119
+ 5. Push to main
120
+
121
+ Never skip these steps. Never use co-authored-by or mention AI tools in commit messages.
@@ -0,0 +1,117 @@
1
+ <!-- Last updated: 2026-04-27 22:40 -->
2
+ # PrePrompt — CONTEXT.md
3
+ # This file is auto-maintained. Read it fully at the start of every chat.
4
+
5
+ ## Build status
6
+ Phase 7c complete. 28/28 tests passing.
7
+
8
+ ## What PrePrompt does
9
+ MCP server that intercepts prompts in Claude Code and Cursor, scores them
10
+ with a heuristic classifier (no API), optimizes complex ones using Claude
11
+ Haiku, logs everything to SQLite (WAL mode), and learns the user's stack
12
+ over time via a memory layer. Runs entirely locally.
13
+
14
+ ## Tech stack
15
+ - Python 3.11+, FastMCP, Anthropic SDK, SQLite (WAL mode), pydantic-settings
16
+ - Haiku model: claude-haiku-4-5-20251001
17
+ - DB: SQLite WAL at ~/.preprompt/history.db
18
+
19
+ ## File map
20
+ mcp_server/
21
+ server.py — entry point, mcp.run(transport=settings.mcp_transport)
22
+ tools.py — MCP tools: optimize_prompt, get_prompt_history
23
+ uses get_or_create_session() for stable daily session identity
24
+ classifier.py — pure heuristic scorer, threshold=38, multi-req weight=12/hit, no API calls
25
+ optimizer.py — Haiku API call + memory context injection
26
+ strips markdown fences from model JSON response
27
+ extractor.py — heuristic stack signal extractor
28
+ config.py — pydantic-settings, reads .env
29
+
30
+ storage/
31
+ db.py — SQLite WAL: prompt_history + stack_memory + sessions tables
32
+ Sidecar pattern: hook writes JSON to ~/.preprompt/pending/,
33
+ flushed by MCP server or CLI commands via flush_pending_hook_events()
34
+ get_or_create_session(): stable {hostname}-{date} session key
35
+ get_all_history(): cross-session history query
36
+ upsert_stack_memory(): compounding confidence (+0.02/hit, reset on value change)
37
+
38
+ cli/
39
+ commands.py — preprompt-history (all sessions), stats, memory,
40
+ test-classifier, optimize, update-context
41
+
42
+ .claude/
43
+ settings.json — MCP server + UserPromptSubmit hook config
44
+ hooks/pre_prompt.py — interception hook with rich box annotation on stderr
45
+ path resolved via __file__ (CWD-independent)
46
+ writes JSON sidecar to ~/.preprompt/pending/ — never touches DB directly
47
+
48
+ scripts/
49
+ install.sh — one-command installer (auto-detects Claude Code, Cursor, Windsurf, Zed)
50
+ setup_global_hook.py — global Claude Code MCP + UserPromptSubmit registration
51
+ install_cursor.py — registers MCP in ~/.cursor/mcp.json
52
+ install_windsurf.py — registers MCP in ~/.codeium/windsurf/mcp_config.json
53
+ install_zed.py — registers MCP in ~/.config/zed/settings.json
54
+ init_github.py — git init + first commit + push instructions
55
+
56
+ .github/
57
+ workflows/ci.yml — runs pytest on every push/PR
58
+ workflows/publish.yml — builds + publishes to PyPI on git tag v*
59
+
60
+ preprompt.skill.md — Claude Skill file for tools without MCP hook support
61
+
62
+ LICENSE — MIT
63
+
64
+ tests/
65
+ test_classifier.py — 12 tests
66
+ test_optimizer.py — 4 tests
67
+ test_integration.py — 12 tests
68
+
69
+ ## Key interfaces — never change these signatures
70
+ - classify_prompt(prompt: str, history: list, turn: int) -> int
71
+ - optimize(prompt: str, history: list) -> dict
72
+ - optimize_prompt(user_prompt, conversation_history, turn_number) -> dict
73
+ - save_prompt_event(...) in storage/db.py
74
+ - get_recent_history(session_id, limit) in storage/db.py
75
+ - upsert_stack_memory(key, value, confidence) in storage/db.py
76
+ - get_stack_memory() -> dict[str, str] in storage/db.py
77
+ - extract_stack_signals(prompt, history) -> dict
78
+ - update_memory_from_prompt(prompt, history) -> None
79
+ - flush_pending_hook_events() -> int in storage/db.py
80
+
81
+ ## Completed phases
82
+ - Phase 1: scaffold, classifier, optimizer, SQLite, MCP server
83
+ - Phase 2: hook, Cursor install, CLI commands
84
+ - Phase 3: stack memory, extractor, memory-aware optimizer
85
+ - Phase 4: GitHub, live test, CONTEXT.md
86
+ - Phase 5: session identity, memory consolidation, rich annotations, cross-session history
87
+ - Phase 6: packaging, SQLite WAL migration, sidecar concurrency pattern, classifier tuned (38/12), absolute hook path, one-command install, MIT license, distribution README
88
+ - Phase 6b: global rename PromptForge → PrePrompt
89
+ - Phase 7: GitHub Actions CI + publish workflow, PyPI trusted publisher setup
90
+ - Phase 7b: preprompt-optimize CLI command, Windsurf + Zed MCP installers
91
+ - Phase 7c: preprompt.skill.md — Claude Skill for tools without MCP support
92
+
93
+ ## PyPI publish instructions
94
+ 1. Create account at https://pypi.org
95
+ 2. Go to https://pypi.org/manage/account/publishing/
96
+ 3. Add trusted publisher: owner=yashdeeptehlan, repo=preprompt, workflow=publish.yml, env=release
97
+ 4. Create GitHub environment "release" at https://github.com/yashdeeptehlan/preprompt/settings/environments
98
+ 5. Tag a release: git tag v0.1.0 && git push origin v0.1.0
99
+
100
+ ## Next phases
101
+ - Phase 8: web dashboard (local FastAPI + HTMX) to browse history and replay sessions
102
+ - Phase 8b: prompt diff view (original vs optimized, side by side)
103
+
104
+ ## GitHub Pages
105
+ Landing page: https://yashdeeptehlan.github.io/preprompt/
106
+ Source: docs/index.html (Tailwind CDN, JetBrains Mono, interactive demo, session replay, FAQ)
107
+
108
+ ## How new chats should start
109
+ User will say "continuing from last chat" or paste this file.
110
+ Ask for: cat preprompt/CONTEXT.md
111
+ Confirm phase + what comes next, then proceed.
112
+
113
+ ## Environment
114
+ - Dev machine: macOS
115
+ - API key: in .env as ANTHROPIC_API_KEY
116
+ - Claude Code workspace: /Users/user/Documents/Promptforge/promptforge
117
+ - GitHub: https://github.com/yashdeeptehlan/preprompt
@@ -0,0 +1,22 @@
1
+ MIT License
2
+ Copyright (c) 2026 Yashdeep Tehlan
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.