promptdock 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 (100) hide show
  1. promptdock-0.1.0/.dockerignore +11 -0
  2. promptdock-0.1.0/.env.example +1 -0
  3. promptdock-0.1.0/.gitattributes +1 -0
  4. promptdock-0.1.0/.github/workflows/ci.yml +56 -0
  5. promptdock-0.1.0/.github/workflows/release.yml +114 -0
  6. promptdock-0.1.0/.gitignore +16 -0
  7. promptdock-0.1.0/.pre-commit-config.yaml +15 -0
  8. promptdock-0.1.0/CHANGELOG.md +55 -0
  9. promptdock-0.1.0/CONTRIBUTING.md +34 -0
  10. promptdock-0.1.0/Dockerfile +34 -0
  11. promptdock-0.1.0/LICENSE +21 -0
  12. promptdock-0.1.0/PKG-INFO +226 -0
  13. promptdock-0.1.0/README.md +179 -0
  14. promptdock-0.1.0/alembic.ini +6 -0
  15. promptdock-0.1.0/docker-compose.yml +34 -0
  16. promptdock-0.1.0/examples/anthropic_app.py +58 -0
  17. promptdock-0.1.0/examples/app.py +37 -0
  18. promptdock-0.1.0/examples/core_flow.py +96 -0
  19. promptdock-0.1.0/examples/langchain_app.py +41 -0
  20. promptdock-0.1.0/examples/openai_app.py +36 -0
  21. promptdock-0.1.0/examples/push_evals_llm_judge.py +102 -0
  22. promptdock-0.1.0/pyproject.toml +84 -0
  23. promptdock-0.1.0/src/promptdock/__init__.py +29 -0
  24. promptdock-0.1.0/src/promptdock/actor.py +11 -0
  25. promptdock-0.1.0/src/promptdock/backends/__init__.py +5 -0
  26. promptdock-0.1.0/src/promptdock/backends/base.py +75 -0
  27. promptdock-0.1.0/src/promptdock/backends/db.py +117 -0
  28. promptdock-0.1.0/src/promptdock/backends/http.py +244 -0
  29. promptdock-0.1.0/src/promptdock/cache.py +111 -0
  30. promptdock-0.1.0/src/promptdock/cli.py +633 -0
  31. promptdock-0.1.0/src/promptdock/client.py +283 -0
  32. promptdock-0.1.0/src/promptdock/config.py +41 -0
  33. promptdock-0.1.0/src/promptdock/connect.py +27 -0
  34. promptdock-0.1.0/src/promptdock/core/__init__.py +1 -0
  35. promptdock-0.1.0/src/promptdock/core/compare.py +138 -0
  36. promptdock-0.1.0/src/promptdock/core/gates.py +40 -0
  37. promptdock-0.1.0/src/promptdock/core/service.py +562 -0
  38. promptdock-0.1.0/src/promptdock/db/__init__.py +1 -0
  39. promptdock-0.1.0/src/promptdock/db/engine.py +23 -0
  40. promptdock-0.1.0/src/promptdock/db/migrate.py +49 -0
  41. promptdock-0.1.0/src/promptdock/db/migrations/env.py +40 -0
  42. promptdock-0.1.0/src/promptdock/db/migrations/script.py.mako +25 -0
  43. promptdock-0.1.0/src/promptdock/db/migrations/versions/0001_initial.py +184 -0
  44. promptdock-0.1.0/src/promptdock/db/migrations/versions/0002_drop_tag_is_protected.py +27 -0
  45. promptdock-0.1.0/src/promptdock/db/migrations/versions/0003_readable_views.py +91 -0
  46. promptdock-0.1.0/src/promptdock/db/migrations/versions/0004_drop_api_keys.py +36 -0
  47. promptdock-0.1.0/src/promptdock/db/tables.py +150 -0
  48. promptdock-0.1.0/src/promptdock/errors.py +87 -0
  49. promptdock-0.1.0/src/promptdock/mcp/__init__.py +1 -0
  50. promptdock-0.1.0/src/promptdock/mcp/server.py +116 -0
  51. promptdock-0.1.0/src/promptdock/models.py +234 -0
  52. promptdock-0.1.0/src/promptdock/prompt.py +74 -0
  53. promptdock-0.1.0/src/promptdock/py.typed +0 -0
  54. promptdock-0.1.0/src/promptdock/server/__init__.py +5 -0
  55. promptdock-0.1.0/src/promptdock/server/access.py +57 -0
  56. promptdock-0.1.0/src/promptdock/server/app.py +72 -0
  57. promptdock-0.1.0/src/promptdock/server/errors.py +55 -0
  58. promptdock-0.1.0/src/promptdock/server/routes.py +225 -0
  59. promptdock-0.1.0/src/promptdock/sync.py +222 -0
  60. promptdock-0.1.0/src/promptdock/templates.py +64 -0
  61. promptdock-0.1.0/src/promptdock/ui/__init__.py +13 -0
  62. promptdock-0.1.0/src/promptdock/ui/static/assets/index-B7bJCH_W.css +1 -0
  63. promptdock-0.1.0/src/promptdock/ui/static/assets/index-BbnhHlWV.js +109 -0
  64. promptdock-0.1.0/src/promptdock/ui/static/index.html +17 -0
  65. promptdock-0.1.0/tests/conftest.py +97 -0
  66. promptdock-0.1.0/tests/test_cache.py +94 -0
  67. promptdock-0.1.0/tests/test_cli.py +260 -0
  68. promptdock-0.1.0/tests/test_client.py +218 -0
  69. promptdock-0.1.0/tests/test_compare.py +165 -0
  70. promptdock-0.1.0/tests/test_config.py +50 -0
  71. promptdock-0.1.0/tests/test_gates.py +49 -0
  72. promptdock-0.1.0/tests/test_mcp.py +141 -0
  73. promptdock-0.1.0/tests/test_migrations.py +157 -0
  74. promptdock-0.1.0/tests/test_models.py +114 -0
  75. promptdock-0.1.0/tests/test_repo.py +19 -0
  76. promptdock-0.1.0/tests/test_server.py +175 -0
  77. promptdock-0.1.0/tests/test_service.py +407 -0
  78. promptdock-0.1.0/tests/test_smoke.py +14 -0
  79. promptdock-0.1.0/tests/test_templates.py +47 -0
  80. promptdock-0.1.0/tests/test_ui.py +59 -0
  81. promptdock-0.1.0/tests/test_views.py +79 -0
  82. promptdock-0.1.0/ui/index.html +16 -0
  83. promptdock-0.1.0/ui/package-lock.json +2134 -0
  84. promptdock-0.1.0/ui/package.json +19 -0
  85. promptdock-0.1.0/ui/src/App.jsx +67 -0
  86. promptdock-0.1.0/ui/src/api.js +59 -0
  87. promptdock-0.1.0/ui/src/components/DiffPanel.jsx +96 -0
  88. promptdock-0.1.0/ui/src/components/HistoryPanel.jsx +61 -0
  89. promptdock-0.1.0/ui/src/components/LeaderboardPanel.jsx +153 -0
  90. promptdock-0.1.0/ui/src/components/PromptDetail.jsx +60 -0
  91. promptdock-0.1.0/ui/src/components/PromptList.jsx +64 -0
  92. promptdock-0.1.0/ui/src/components/Settings.jsx +58 -0
  93. promptdock-0.1.0/ui/src/components/TagsPanel.jsx +161 -0
  94. promptdock-0.1.0/ui/src/components/VersionsPanel.jsx +54 -0
  95. promptdock-0.1.0/ui/src/components/common.jsx +37 -0
  96. promptdock-0.1.0/ui/src/main.jsx +10 -0
  97. promptdock-0.1.0/ui/src/styles.css +138 -0
  98. promptdock-0.1.0/ui/src/useApi.js +29 -0
  99. promptdock-0.1.0/ui/vite.config.js +19 -0
  100. promptdock-0.1.0/uv.lock +3273 -0
@@ -0,0 +1,11 @@
1
+ .git
2
+ .venv
3
+ .venv-*
4
+ **/__pycache__
5
+ **/node_modules
6
+ dist
7
+ .pytest_cache
8
+ .mypy_cache
9
+ .ruff_cache
10
+ src/promptdock/ui/static
11
+ .env
@@ -0,0 +1 @@
1
+ DATABASE_URL=postgresql+psycopg://promptdock:promptdock@localhost:5432/promptdock
@@ -0,0 +1 @@
1
+ * text=auto eol=lf
@@ -0,0 +1,56 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+ workflow_call: # reused by release.yml
8
+
9
+ jobs:
10
+ lint:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: astral-sh/setup-uv@v5
15
+ - run: uv sync
16
+ - run: uv run ruff check .
17
+ - run: uv run ruff format --check .
18
+ - run: uv run mypy
19
+ - run: uv run mypy tests
20
+
21
+ test:
22
+ name: test (Python ${{ matrix.python-version }}, Postgres ${{ matrix.postgres }})
23
+ runs-on: ubuntu-latest
24
+ strategy:
25
+ fail-fast: false
26
+ matrix:
27
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
28
+ postgres: ["14", "17"]
29
+ env:
30
+ PROMPTDOCK_TEST_POSTGRES_IMAGE: postgres:${{ matrix.postgres }}
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+ - uses: astral-sh/setup-uv@v5
34
+ with:
35
+ python-version: ${{ matrix.python-version }}
36
+ - run: uv sync
37
+ - run: uv run pytest -v
38
+
39
+ ui:
40
+ name: dashboard build
41
+ runs-on: ubuntu-latest
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+ - uses: actions/setup-node@v4
45
+ with:
46
+ node-version: "22"
47
+ cache: npm
48
+ cache-dependency-path: ui/package-lock.json
49
+ - run: npm ci
50
+ working-directory: ui
51
+ - run: npm run build
52
+ working-directory: ui
53
+ - uses: astral-sh/setup-uv@v5
54
+ - run: uv sync
55
+ # Serves the real build through `serve --ui` (skipped in the other jobs).
56
+ - run: uv run pytest -v tests/test_ui.py
@@ -0,0 +1,114 @@
1
+ name: Release
2
+
3
+ # Push a tag like v0.1.0 to publish that version everywhere:
4
+ # tests -> build UI -> uv build -> PyPI (Trusted Publishing) -> GHCR image -> GitHub Release
5
+ # No tokens live on anyone's laptop: PyPI trusts this workflow, GHCR uses GITHUB_TOKEN.
6
+
7
+ on:
8
+ push:
9
+ tags: ["v*"]
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ test:
16
+ uses: ./.github/workflows/ci.yml
17
+
18
+ build:
19
+ needs: test
20
+ runs-on: ubuntu-latest
21
+ outputs:
22
+ version: ${{ steps.version.outputs.version }}
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - name: Check the tag matches pyproject.toml
26
+ id: version
27
+ run: |
28
+ version=$(grep -m1 '^version = ' pyproject.toml | cut -d'"' -f2)
29
+ if [ "v$version" != "$GITHUB_REF_NAME" ]; then
30
+ echo "Tag $GITHUB_REF_NAME does not match pyproject.toml version $version" >&2
31
+ exit 1
32
+ fi
33
+ echo "version=$version" >> "$GITHUB_OUTPUT"
34
+ - uses: actions/setup-node@v4
35
+ with:
36
+ node-version: "22"
37
+ cache: npm
38
+ cache-dependency-path: ui/package-lock.json
39
+ - run: npm ci && npm run build
40
+ working-directory: ui
41
+ - uses: astral-sh/setup-uv@v5
42
+ - run: uv build
43
+ - name: Check the dashboard is inside the wheel
44
+ run: unzip -l dist/*.whl | grep -q 'promptdock/ui/static/index.html'
45
+ - uses: actions/upload-artifact@v4
46
+ with:
47
+ name: dist
48
+ path: dist/
49
+
50
+ pypi:
51
+ needs: build
52
+ runs-on: ubuntu-latest
53
+ environment: pypi
54
+ permissions:
55
+ id-token: write # Trusted Publishing
56
+ steps:
57
+ - uses: actions/download-artifact@v4
58
+ with:
59
+ name: dist
60
+ path: dist/
61
+ - uses: pypa/gh-action-pypi-publish@release/v1
62
+
63
+ docker:
64
+ needs: build
65
+ runs-on: ubuntu-latest
66
+ permissions:
67
+ contents: read
68
+ packages: write
69
+ steps:
70
+ - uses: actions/checkout@v4
71
+ - uses: docker/setup-qemu-action@v3
72
+ - uses: docker/setup-buildx-action@v3
73
+ - uses: docker/login-action@v3
74
+ with:
75
+ registry: ghcr.io
76
+ username: ${{ github.actor }}
77
+ password: ${{ secrets.GITHUB_TOKEN }}
78
+ - id: meta
79
+ uses: docker/metadata-action@v5
80
+ with:
81
+ images: ghcr.io/${{ github.repository_owner }}/promptdock
82
+ tags: |
83
+ type=raw,value=${{ needs.build.outputs.version }}
84
+ type=raw,value=latest
85
+ - uses: docker/build-push-action@v6
86
+ with:
87
+ context: .
88
+ platforms: linux/amd64,linux/arm64
89
+ push: true
90
+ tags: ${{ steps.meta.outputs.tags }}
91
+ labels: ${{ steps.meta.outputs.labels }}
92
+
93
+ github-release:
94
+ needs: [build, pypi, docker]
95
+ runs-on: ubuntu-latest
96
+ permissions:
97
+ contents: write
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+ - uses: actions/download-artifact@v4
101
+ with:
102
+ name: dist
103
+ path: dist/
104
+ - name: Release notes from CHANGELOG.md
105
+ run: |
106
+ awk -v heading="## [${{ needs.build.outputs.version }}]" '
107
+ index($0, heading) == 1 { found = 1; next }
108
+ found && (index($0, "## [") == 1 || index($0, "[") == 1) { exit }
109
+ found { print }
110
+ ' CHANGELOG.md > notes.md
111
+ test -s notes.md || echo "See CHANGELOG.md" > notes.md
112
+ - run: gh release create "$GITHUB_REF_NAME" dist/* --title "PromptDock $GITHUB_REF_NAME" --notes-file notes.md
113
+ env:
114
+ GH_TOKEN: ${{ github.token }}
@@ -0,0 +1,16 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ .coverage
11
+ htmlcov/
12
+ .env
13
+ node_modules/
14
+ src/promptdock/ui/static/
15
+ .promptdock-snapshot.json
16
+ .venv-*/
@@ -0,0 +1,15 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.6.9
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+ - repo: local
9
+ hooks:
10
+ - id: mypy
11
+ name: mypy
12
+ entry: uv run mypy
13
+ language: system
14
+ types: [python]
15
+ pass_filenames: false
@@ -0,0 +1,55 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
5
+ project uses [semantic versioning](https://semver.org/) (staying on 0.x until the API is
6
+ stable).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-11-01
11
+
12
+ First release.
13
+
14
+ ### Added
15
+
16
+ - **Versions and tags.** Immutable, numbered prompt versions (text or chat messages, Jinja2
17
+ variables detected, identical content deduplicated) and tags (`dev`, `preprod`, `prod`
18
+ by default, plus custom ones) that point at them. Promote moves a tag; rollback undoes
19
+ the last promote, again and again like undo. Every move is recorded in an audit log with
20
+ from/to versions, a self-reported actor and an optional reason.
21
+ - **Eval results and gates.** Submit results in a fixed schema (`prompt`, `version`,
22
+ `metric`, `score`, `run_id`, `evaluator`, `metadata`). A gate on a tag requires the latest
23
+ score per metric to meet `min` (higher is better) / `max` (lower is better) rules and,
24
+ optionally, be at least as good as the current version. `force` with a reason bypasses
25
+ a failing gate and is recorded. Rollback never runs the gate.
26
+ - **Leaderboard and diff.** Versions x metrics with the latest score, sortable by any
27
+ column; text diff of two versions plus `model_config` and variable changes. Promote
28
+ warns when a version needs new template variables (`strict` refuses instead).
29
+ - **Client** (`pip install promptdock`). One API in library mode (`Client(db_url=...)`,
30
+ straight to Postgres) and server mode (`Client(base_url=..., token=...)`): `get_prompt`
31
+ returns a `Prompt` with `.render(**values)`, `.version`, `.model_config`. Sandboxed
32
+ rendering with `MissingVariableError`, 60 s cache, last-known-good fallback when the
33
+ database or server is down, optional snapshot file for cold starts.
34
+ - **REST server** (`pip install promptdock[server]`, `promptdock serve`). OpenAPI docs at
35
+ `/docs`, ETag/304 on the prompt fetch. No user accounts: listens on 127.0.0.1 by default,
36
+ optional shared `PROMPTDOCK_TOKEN`, warning when exposed without one; actor via the
37
+ `X-Actor` header.
38
+ - **Dashboard** (`pip install promptdock[ui]`, `promptdock serve --ui`). Prompts, versions,
39
+ tags with promote (gate result shown) and rollback (confirm), leaderboard with a
40
+ score-over-versions chart per metric, diff, audit log.
41
+ - **CLI.** `migrate`, `serve`, `prompts list`, `versions list|show`, `promote`, `rollback`,
42
+ `history`, `evals push`, `export` / `push` (YAML files; never overwrites, never moves
43
+ `prod`), `gate set|show|clear`, `leaderboard`, `diff`, `mcp`.
44
+ - **MCP server** (`pip install promptdock[mcp]`, `promptdock mcp`). Tools for agents:
45
+ `list_prompts`, `get_prompt`, `create_version`, `compare_versions`, `get_leaderboard`,
46
+ and `promote` only with `--allow-promote` (never forced); actor `mcp:<OS username>`.
47
+ - **Docker image** `ghcr.io/shreyamhetre/promptdock` (migrates, then serves API and
48
+ dashboard) and `docker compose --profile server up` for local use.
49
+ - Read-only database views with names instead of ids: `v_prompt_status`, `v_versions`,
50
+ `v_tags`, `v_tag_history`, `v_eval_results`.
51
+ - Examples for OpenAI, Anthropic and LangChain, and an LLM-as-judge eval script.
52
+ - No telemetry or usage tracking.
53
+
54
+ [Unreleased]: https://github.com/shreyamhetre/PromptDock/compare/v0.1.0...HEAD
55
+ [0.1.0]: https://github.com/shreyamhetre/PromptDock/releases/tag/v0.1.0
@@ -0,0 +1,34 @@
1
+ # Contributing
2
+
3
+ ## Setup
4
+
5
+ 1. Install [uv](https://docs.astral.sh/uv/) and Docker.
6
+ 2. Install dependencies: `uv sync`
7
+ 3. Install git hooks: `uv run pre-commit install`
8
+ 4. Start a local Postgres: `docker compose up -d`
9
+ 5. Copy `.env.example` to `.env` (or export `DATABASE_URL`).
10
+
11
+ ## Checks
12
+
13
+ ```bash
14
+ uv run ruff check . # lint
15
+ uv run ruff format . # format
16
+ uv run mypy # type check
17
+ uv run pytest # tests (DB tests start Postgres via testcontainers)
18
+ ```
19
+
20
+ Tests use Postgres 16 by default. CI runs Python 3.10–3.13 against Postgres 14 and 17;
21
+ to try another version locally: `PROMPTDOCK_TEST_POSTGRES_IMAGE=postgres:14 uv run pytest`.
22
+
23
+ ## Dashboard
24
+
25
+ The UI source lives in `ui/` (React + Vite + Recharts). Build it into the Python package
26
+ with `cd ui && npm ci && npm run build` (output: `src/promptdock/ui/static/`, git-ignored
27
+ but included in the wheel). For live reload, run `promptdock serve` and `npm run dev`
28
+ (it proxies API calls to port 8000).
29
+
30
+ ## Workflow
31
+
32
+ - `main` is protected: open a pull request, get one review, keep CI green.
33
+ - Track work as GitHub Issues with a milestone per phase.
34
+ - Keep business logic in `src/promptdock/core/`; backends and server routes only call into it.
@@ -0,0 +1,34 @@
1
+ # PromptDock server + dashboard.
2
+ # docker build -t promptdock .
3
+ # docker run -p 8000:8000 -e DATABASE_URL=postgresql://... -e PROMPTDOCK_TOKEN=... promptdock
4
+ # Configure with DATABASE_URL (required) and PROMPTDOCK_TOKEN (optional, recommended: the
5
+ # container listens on 0.0.0.0, so without a token anyone who can reach it has access).
6
+
7
+ # 1. Build the dashboard (Node is only needed here, never at runtime).
8
+ FROM node:22-slim AS ui
9
+ WORKDIR /build/ui
10
+ COPY ui/package.json ui/package-lock.json ./
11
+ RUN npm ci --no-audit --no-fund
12
+ COPY ui/ ./
13
+ RUN npm run build
14
+
15
+ # 2. Build the wheel with the dashboard inside it.
16
+ FROM python:3.12-slim AS wheel
17
+ COPY --from=ghcr.io/astral-sh/uv:0.13 /uv /bin/uv
18
+ WORKDIR /build
19
+ COPY pyproject.toml README.md LICENSE ./
20
+ COPY src ./src
21
+ COPY --from=ui /build/src/promptdock/ui/static ./src/promptdock/ui/static
22
+ RUN uv build --wheel --out-dir /dist
23
+
24
+ # 3. Runtime: just the installed package.
25
+ FROM python:3.12-slim
26
+ RUN useradd --create-home --uid 10001 promptdock
27
+ COPY --from=wheel /dist /tmp/dist
28
+ RUN pip install --no-cache-dir --timeout 120 --retries 5 "$(ls /tmp/dist/*.whl)[server,ui]" \
29
+ && rm -rf /tmp/dist
30
+ USER promptdock
31
+ EXPOSE 8000
32
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=20s \
33
+ CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health')"
34
+ CMD ["sh", "-c", "promptdock migrate && exec promptdock serve --ui --host 0.0.0.0 --port 8000"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shreya Mhetre and Parth
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,226 @@
1
+ Metadata-Version: 2.5
2
+ Name: promptdock
3
+ Version: 0.1.0
4
+ Summary: Focused prompt versioning: immutable versions, movable tags, eval-gated promotion.
5
+ Project-URL: Homepage, https://github.com/shreyamhetre/PromptDock
6
+ Project-URL: Repository, https://github.com/shreyamhetre/PromptDock
7
+ Project-URL: Issues, https://github.com/shreyamhetre/PromptDock/issues
8
+ Project-URL: Changelog, https://github.com/shreyamhetre/PromptDock/blob/main/CHANGELOG.md
9
+ Author: Shreya Mhetre, Parth
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Requires-Python: >=3.10
16
+ Requires-Dist: alembic>=1.13
17
+ Requires-Dist: httpx>=0.27
18
+ Requires-Dist: jinja2>=3.1
19
+ Requires-Dist: psycopg[binary]>=3.1
20
+ Requires-Dist: pydantic>=2.6
21
+ Requires-Dist: pyyaml>=6
22
+ Requires-Dist: sqlalchemy>=2.0
23
+ Requires-Dist: typer>=0.12
24
+ Provides-Extra: all
25
+ Requires-Dist: fastapi>=0.110; extra == 'all'
26
+ Requires-Dist: mcp<3,>=2.3; extra == 'all'
27
+ Requires-Dist: uvicorn[standard]>=0.29; extra == 'all'
28
+ Provides-Extra: dev
29
+ Requires-Dist: fastapi>=0.110; extra == 'dev'
30
+ Requires-Dist: mcp<3,>=2.3; extra == 'dev'
31
+ Requires-Dist: mypy>=1.10; extra == 'dev'
32
+ Requires-Dist: pre-commit>=3.7; extra == 'dev'
33
+ Requires-Dist: pytest>=8; extra == 'dev'
34
+ Requires-Dist: ruff>=0.6; extra == 'dev'
35
+ Requires-Dist: testcontainers[postgres]>=4; extra == 'dev'
36
+ Requires-Dist: types-pyyaml; extra == 'dev'
37
+ Requires-Dist: uvicorn[standard]>=0.29; extra == 'dev'
38
+ Provides-Extra: mcp
39
+ Requires-Dist: mcp<3,>=2.3; extra == 'mcp'
40
+ Provides-Extra: server
41
+ Requires-Dist: fastapi>=0.110; extra == 'server'
42
+ Requires-Dist: uvicorn[standard]>=0.29; extra == 'server'
43
+ Provides-Extra: ui
44
+ Requires-Dist: fastapi>=0.110; extra == 'ui'
45
+ Requires-Dist: uvicorn[standard]>=0.29; extra == 'ui'
46
+ Description-Content-Type: text/markdown
47
+
48
+ # PromptDock
49
+
50
+ Focused prompt versioning. PromptDock stores **immutable prompt versions**, points **tags**
51
+ (`dev`, `preprod`, `prod`, or your own) at them, and attaches **eval results** so a tag can only
52
+ move to a version that passes its gate. Promote and rollback move a pointer, never your code.
53
+
54
+ > Status: 0.1 — early. The API may still change before 1.0.
55
+
56
+ PromptDock collects **no telemetry or usage data**. It only talks to your own Postgres and,
57
+ if you run one, your own PromptDock server.
58
+
59
+ ## Ways to use it
60
+
61
+ | Mode | Install | Run |
62
+ | --- | --- | --- |
63
+ | Library | `pip install promptdock` | import and use |
64
+ | Server | `pip install promptdock[server]` | `promptdock serve` |
65
+ | Server + UI | `pip install promptdock[ui]` | `promptdock serve --ui` |
66
+ | Docker | `docker run ghcr.io/shreyamhetre/promptdock` | — |
67
+
68
+ All modes use Postgres (14 or newer), configured with `DATABASE_URL`. Python 3.10+.
69
+
70
+ The idea in one table — apps always ask for a **tag**; you move tags, never app code:
71
+
72
+ | Step | What you do | Versions | dev | preprod | prod |
73
+ | --- | --- | --- | --- | --- | --- |
74
+ | 1 | save the prompt | v1 | – | – | – |
75
+ | 2 | promote v1 to dev, then preprod, then prod | v1 | v1 | v1 | v1 |
76
+ | 3 | edit and save | v1, v2 | v1 | v1 | v1 |
77
+ | 4 | promote v2 to dev, preprod, prod (evals pass the gate) | v1, v2 | v2 | v2 | v2 |
78
+ | 5 | v2 misbehaves: roll back prod | v1, v2 | v2 | v2 | **v1** |
79
+
80
+ ## Quickstart (library mode)
81
+
82
+ ```bash
83
+ export DATABASE_URL=postgresql://user:password@localhost:5432/promptdock
84
+ promptdock migrate
85
+ ```
86
+
87
+ ```python
88
+ from promptdock import Client
89
+
90
+ client = Client() # reads DATABASE_URL; or Client("postgresql://...", actor="shreya")
91
+
92
+ client.create_prompt("support-bot")
93
+ client.create_version(
94
+ "support-bot",
95
+ [
96
+ {"role": "system", "content": "You support {{ product }}."},
97
+ {"role": "user", "content": "{{ question }}"},
98
+ ],
99
+ model_config={"model": "gpt-4o", "temperature": 0.2},
100
+ commit_message="first version",
101
+ )
102
+ client.promote("support-bot", "prod", 1) # recorded with actor = your OS username
103
+
104
+ # In your app: always ask for a tag, never a hard-coded version.
105
+ prompt = client.get_prompt("support-bot", tag="prod")
106
+ messages = prompt.render(product="PromptDock", question="How do I roll back?")
107
+ # call your LLM with messages and prompt.model_config
108
+
109
+ client.rollback("support-bot", "prod") # apps pick this up within the cache TTL (60 s)
110
+ ```
111
+
112
+ Reads are cached for `cache_ttl` seconds (default 60). If the database is unreachable,
113
+ `get_prompt` returns the last version it fetched and logs a warning; pass
114
+ `snapshot_path="prompts.json"` to keep those copies on disk for restarts.
115
+
116
+ ## Quickstart (server mode)
117
+
118
+ ```bash
119
+ pip install "promptdock[server]"
120
+ promptdock migrate
121
+ promptdock serve # http://127.0.0.1:8000, API docs at /docs
122
+ ```
123
+
124
+ ```python
125
+ from promptdock import Client
126
+
127
+ client = Client(base_url="http://127.0.0.1:8000") # same methods as library mode
128
+ prompt = client.get_prompt("support-bot", tag="prod")
129
+ ```
130
+
131
+ Any language can call the REST API, e.g.
132
+ `curl "http://127.0.0.1:8000/prompts/support-bot?tag=prod"`.
133
+
134
+ **Who did it:** send `X-Actor: <name>` on changes (the Python client sends its `actor`,
135
+ which defaults to your OS username). It is recorded in the history, not verified.
136
+
137
+ ### Securing your server
138
+
139
+ There are no user accounts. `promptdock serve` only listens on
140
+ this machine by default. To share it, either run it on a private network or set a shared
141
+ token: `PROMPTDOCK_TOKEN=... promptdock serve --host 0.0.0.0`. Every request except
142
+ `/health` must then send `Authorization: Bearer <token>`; clients pass `token=...` (or set
143
+ `PROMPTDOCK_TOKEN`). Listening on `0.0.0.0` without a token prints a warning.
144
+
145
+ ## Quickstart (Docker)
146
+
147
+ ```bash
148
+ docker run -p 8000:8000 -e DATABASE_URL=postgresql://user:password@db-host:5432/promptdock -e PROMPTDOCK_TOKEN=change-me ghcr.io/shreyamhetre/promptdock
149
+ ```
150
+
151
+ The container runs `promptdock migrate`, then serves the API and dashboard on port 8000
152
+ (`/docs`, `/ui/`). It listens on `0.0.0.0`, so set `PROMPTDOCK_TOKEN` unless it runs on a
153
+ private network. To try it locally with a bundled Postgres:
154
+ `docker compose --profile server up -d`.
155
+
156
+ ## Dashboard
157
+
158
+ ```bash
159
+ pip install "promptdock[ui]"
160
+ promptdock serve --ui # http://127.0.0.1:8000/ui/
161
+ ```
162
+
163
+ Prompts list, versions and tags, a sortable leaderboard with a score-over-versions chart
164
+ per metric, diffs between any two versions, and the audit log. You can promote (the gate
165
+ result is shown) and roll back (with a confirm step). It asks once for your name (sent as
166
+ `X-Actor`) and, if the server has one, the token; both stay in your browser. No Node is
167
+ needed to run it.
168
+
169
+ ## Command line
170
+
171
+ The CLI connects like the client: `PROMPTDOCK_URL` (+ `PROMPTDOCK_TOKEN`) for a server,
172
+ otherwise `DATABASE_URL`. Changes are recorded with `--actor` (default: your OS username).
173
+
174
+ ```bash
175
+ promptdock export ./prompts # one YAML file per prompt (latest version)
176
+ # ...edit ./prompts/support-bot.yaml...
177
+ promptdock push ./prompts --tag dev -m "friendlier tone" # new versions only for changed files
178
+ promptdock evals push results.jsonl # eval results, one JSON object per line
179
+ promptdock promote support-bot prod 3 --reason "evals passed"
180
+ promptdock rollback support-bot prod --reason "complaints"
181
+ promptdock versions list support-bot
182
+ promptdock history support-bot prod
183
+ ```
184
+
185
+ `push` never overwrites anything and never moves `prod`; promote to `prod` explicitly.
186
+
187
+ ```bash
188
+ promptdock gate set support-bot prod --min accuracy=0.85 --max latency_ms=1200
189
+ promptdock leaderboard support-bot --sort accuracy
190
+ promptdock diff support-bot 3 7
191
+ ```
192
+
193
+ A gate uses the latest result per metric; a missing metric fails. `--force --reason ...`
194
+ bypasses a failing gate and is recorded. Rollback never runs the gate.
195
+
196
+ ## AI agents (MCP)
197
+
198
+ `pip install "promptdock[mcp]"`, then add PromptDock to your agent's MCP config. For
199
+ Claude Desktop (`claude_desktop_config.json`) or Cursor (`.cursor/mcp.json`):
200
+
201
+ ```json
202
+ {
203
+ "mcpServers": {
204
+ "promptdock": {
205
+ "command": "promptdock",
206
+ "args": ["mcp"],
207
+ "env": { "DATABASE_URL": "postgresql://user:password@localhost:5432/promptdock" }
208
+ }
209
+ }
210
+ }
211
+ ```
212
+
213
+ Use `PROMPTDOCK_URL` (+ `PROMPTDOCK_TOKEN`) instead of `DATABASE_URL` to go through a
214
+ server. Tools: `list_prompts`, `get_prompt`, `create_version`, `compare_versions`,
215
+ `get_leaderboard`. `promote` is only offered with `"args": ["mcp", "--allow-promote"]`,
216
+ gates still apply, and agents can never force. Agent changes are recorded with the actor
217
+ `mcp:<your OS username>`.
218
+
219
+ ## Development
220
+
221
+ See [CONTRIBUTING.md](https://github.com/shreyamhetre/PromptDock/blob/main/CONTRIBUTING.md). The dashboard source is in `ui/` (React + Vite + Recharts):
222
+ `cd ui && npm ci && npm run build` writes the built files into `src/promptdock/ui/static/`.
223
+
224
+ ## License
225
+
226
+ MIT