promptline-opt 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 (151) hide show
  1. promptline_opt-0.1.0/.claude/settings.local.json +10 -0
  2. promptline_opt-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +45 -0
  3. promptline_opt-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. promptline_opt-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +27 -0
  5. promptline_opt-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +23 -0
  6. promptline_opt-0.1.0/.github/workflows/ci.yml +103 -0
  7. promptline_opt-0.1.0/.gitignore +18 -0
  8. promptline_opt-0.1.0/CHANGELOG.md +47 -0
  9. promptline_opt-0.1.0/CODE_OF_CONDUCT.md +47 -0
  10. promptline_opt-0.1.0/CONTRIBUTING.md +42 -0
  11. promptline_opt-0.1.0/LICENSE +21 -0
  12. promptline_opt-0.1.0/Makefile +39 -0
  13. promptline_opt-0.1.0/PKG-INFO +244 -0
  14. promptline_opt-0.1.0/README.md +215 -0
  15. promptline_opt-0.1.0/SECURITY.md +32 -0
  16. promptline_opt-0.1.0/docs/concepts/core.md +60 -0
  17. promptline_opt-0.1.0/docs/concepts/gate.md +48 -0
  18. promptline_opt-0.1.0/docs/concepts/judge.md +52 -0
  19. promptline_opt-0.1.0/docs/concepts/optimizers.md +58 -0
  20. promptline_opt-0.1.0/docs/concepts/serving.md +55 -0
  21. promptline_opt-0.1.0/docs/superpowers/plans/2026-07-03-promptline-implementation.md +314 -0
  22. promptline_opt-0.1.0/docs/superpowers/specs/2026-07-03-promptline-design.md +180 -0
  23. promptline_opt-0.1.0/examples/support-assistant/README.md +145 -0
  24. promptline_opt-0.1.0/examples/support-assistant/fixtures/gold_fixture.jsonl +50 -0
  25. promptline_opt-0.1.0/examples/support-assistant/fixtures/support_fixture.jsonl +60 -0
  26. promptline_opt-0.1.0/promptline/__init__.py +1 -0
  27. promptline_opt-0.1.0/promptline/cli/__init__.py +0 -0
  28. promptline_opt-0.1.0/promptline/cli/demo.py +235 -0
  29. promptline_opt-0.1.0/promptline/cli/main.py +1083 -0
  30. promptline_opt-0.1.0/promptline/core/__init__.py +0 -0
  31. promptline_opt-0.1.0/promptline/core/cache.py +56 -0
  32. promptline_opt-0.1.0/promptline/core/config.py +159 -0
  33. promptline_opt-0.1.0/promptline/core/llm.py +63 -0
  34. promptline_opt-0.1.0/promptline/core/openrouter.py +148 -0
  35. promptline_opt-0.1.0/promptline/core/program.py +242 -0
  36. promptline_opt-0.1.0/promptline/core/types.py +84 -0
  37. promptline_opt-0.1.0/promptline/data/__init__.py +0 -0
  38. promptline_opt-0.1.0/promptline/data/dataset.py +160 -0
  39. promptline_opt-0.1.0/promptline/data/loaders.py +193 -0
  40. promptline_opt-0.1.0/promptline/eval/__init__.py +0 -0
  41. promptline_opt-0.1.0/promptline/eval/harness.py +263 -0
  42. promptline_opt-0.1.0/promptline/eval/stats.py +140 -0
  43. promptline_opt-0.1.0/promptline/judge/__init__.py +19 -0
  44. promptline_opt-0.1.0/promptline/judge/calibrator.py +269 -0
  45. promptline_opt-0.1.0/promptline/judge/judge.py +366 -0
  46. promptline_opt-0.1.0/promptline/judge/metric_factory.py +95 -0
  47. promptline_opt-0.1.0/promptline/judge/metrics.py +101 -0
  48. promptline_opt-0.1.0/promptline/optimizers/__init__.py +0 -0
  49. promptline_opt-0.1.0/promptline/optimizers/base.py +185 -0
  50. promptline_opt-0.1.0/promptline/optimizers/bootstrap.py +410 -0
  51. promptline_opt-0.1.0/promptline/optimizers/gepa/__init__.py +5 -0
  52. promptline_opt-0.1.0/promptline/optimizers/gepa/engine.py +588 -0
  53. promptline_opt-0.1.0/promptline/optimizers/gepa/merge.py +100 -0
  54. promptline_opt-0.1.0/promptline/optimizers/gepa/pareto.py +66 -0
  55. promptline_opt-0.1.0/promptline/optimizers/gepa/reflect.py +72 -0
  56. promptline_opt-0.1.0/promptline/optimizers/gepa/state.py +85 -0
  57. promptline_opt-0.1.0/promptline/optimizers/mipro.py +515 -0
  58. promptline_opt-0.1.0/promptline/optimizers/opro.py +293 -0
  59. promptline_opt-0.1.0/promptline/optimizers/protegi.py +461 -0
  60. promptline_opt-0.1.0/promptline/registry/__init__.py +0 -0
  61. promptline_opt-0.1.0/promptline/registry/gate.py +350 -0
  62. promptline_opt-0.1.0/promptline/registry/registry.py +252 -0
  63. promptline_opt-0.1.0/promptline/server/__init__.py +0 -0
  64. promptline_opt-0.1.0/promptline/server/app.py +287 -0
  65. promptline_opt-0.1.0/promptline/server/runs.py +118 -0
  66. promptline_opt-0.1.0/promptline/tui/__init__.py +0 -0
  67. promptline_opt-0.1.0/promptline/tui/app.py +341 -0
  68. promptline_opt-0.1.0/promptline/tui/events.py +138 -0
  69. promptline_opt-0.1.0/pyproject.toml +64 -0
  70. promptline_opt-0.1.0/ruff.toml +6 -0
  71. promptline_opt-0.1.0/tests/__init__.py +0 -0
  72. promptline_opt-0.1.0/tests/cli/__init__.py +0 -0
  73. promptline_opt-0.1.0/tests/cli/test_cli.py +1294 -0
  74. promptline_opt-0.1.0/tests/cli/test_demo.py +103 -0
  75. promptline_opt-0.1.0/tests/core/__init__.py +0 -0
  76. promptline_opt-0.1.0/tests/core/test_cache.py +66 -0
  77. promptline_opt-0.1.0/tests/core/test_llm.py +65 -0
  78. promptline_opt-0.1.0/tests/core/test_openrouter.py +269 -0
  79. promptline_opt-0.1.0/tests/core/test_program.py +315 -0
  80. promptline_opt-0.1.0/tests/core/test_types.py +119 -0
  81. promptline_opt-0.1.0/tests/data/__init__.py +0 -0
  82. promptline_opt-0.1.0/tests/data/test_dataset.py +255 -0
  83. promptline_opt-0.1.0/tests/data/test_loaders.py +224 -0
  84. promptline_opt-0.1.0/tests/e2e/__init__.py +0 -0
  85. promptline_opt-0.1.0/tests/e2e/conftest.py +203 -0
  86. promptline_opt-0.1.0/tests/e2e/serve_fixture.py +124 -0
  87. promptline_opt-0.1.0/tests/e2e/test_cli_e2e.py +223 -0
  88. promptline_opt-0.1.0/tests/e2e/test_failure_paths.py +254 -0
  89. promptline_opt-0.1.0/tests/e2e/test_full_pipeline_offline.py +227 -0
  90. promptline_opt-0.1.0/tests/eval/__init__.py +0 -0
  91. promptline_opt-0.1.0/tests/eval/test_harness.py +446 -0
  92. promptline_opt-0.1.0/tests/eval/test_stats.py +169 -0
  93. promptline_opt-0.1.0/tests/integration/__init__.py +0 -0
  94. promptline_opt-0.1.0/tests/integration/test_live_smoke.py +133 -0
  95. promptline_opt-0.1.0/tests/judge/__init__.py +0 -0
  96. promptline_opt-0.1.0/tests/judge/test_calibrator.py +330 -0
  97. promptline_opt-0.1.0/tests/judge/test_judge.py +277 -0
  98. promptline_opt-0.1.0/tests/judge/test_metric_factory.py +133 -0
  99. promptline_opt-0.1.0/tests/judge/test_metrics.py +109 -0
  100. promptline_opt-0.1.0/tests/optimizers/__init__.py +0 -0
  101. promptline_opt-0.1.0/tests/optimizers/gepa/__init__.py +0 -0
  102. promptline_opt-0.1.0/tests/optimizers/gepa/test_engine.py +564 -0
  103. promptline_opt-0.1.0/tests/optimizers/gepa/test_pareto.py +148 -0
  104. promptline_opt-0.1.0/tests/optimizers/gepa/test_reflect_merge.py +205 -0
  105. promptline_opt-0.1.0/tests/optimizers/test_base.py +185 -0
  106. promptline_opt-0.1.0/tests/optimizers/test_bootstrap.py +625 -0
  107. promptline_opt-0.1.0/tests/optimizers/test_event_payloads.py +203 -0
  108. promptline_opt-0.1.0/tests/optimizers/test_mipro.py +432 -0
  109. promptline_opt-0.1.0/tests/optimizers/test_opro.py +310 -0
  110. promptline_opt-0.1.0/tests/optimizers/test_protegi.py +366 -0
  111. promptline_opt-0.1.0/tests/registry/__init__.py +0 -0
  112. promptline_opt-0.1.0/tests/registry/test_gate.py +419 -0
  113. promptline_opt-0.1.0/tests/registry/test_registry.py +205 -0
  114. promptline_opt-0.1.0/tests/server/__init__.py +0 -0
  115. promptline_opt-0.1.0/tests/server/test_api.py +689 -0
  116. promptline_opt-0.1.0/tests/test_import.py +26 -0
  117. promptline_opt-0.1.0/tests/tui/__init__.py +0 -0
  118. promptline_opt-0.1.0/tests/tui/test_tui.py +251 -0
  119. promptline_opt-0.1.0/uv.lock +2326 -0
  120. promptline_opt-0.1.0/web/.gitignore +6 -0
  121. promptline_opt-0.1.0/web/README.md +63 -0
  122. promptline_opt-0.1.0/web/e2e/dashboard.spec.ts +100 -0
  123. promptline_opt-0.1.0/web/index.html +12 -0
  124. promptline_opt-0.1.0/web/package-lock.json +3444 -0
  125. promptline_opt-0.1.0/web/package.json +32 -0
  126. promptline_opt-0.1.0/web/playwright.config.ts +33 -0
  127. promptline_opt-0.1.0/web/src/Layout.tsx +35 -0
  128. promptline_opt-0.1.0/web/src/__tests__/DiffView.test.tsx +24 -0
  129. promptline_opt-0.1.0/web/src/__tests__/lineage.test.ts +63 -0
  130. promptline_opt-0.1.0/web/src/__tests__/runReducer.test.ts +114 -0
  131. promptline_opt-0.1.0/web/src/api.ts +191 -0
  132. promptline_opt-0.1.0/web/src/components/DiffView.tsx +23 -0
  133. promptline_opt-0.1.0/web/src/components/Panel.tsx +10 -0
  134. promptline_opt-0.1.0/web/src/components/ScoreCurve.tsx +85 -0
  135. promptline_opt-0.1.0/web/src/main.tsx +35 -0
  136. promptline_opt-0.1.0/web/src/pages/GatePage.tsx +239 -0
  137. promptline_opt-0.1.0/web/src/pages/JudgePage.tsx +108 -0
  138. promptline_opt-0.1.0/web/src/pages/LineagePage.tsx +166 -0
  139. promptline_opt-0.1.0/web/src/pages/RegistryPage.tsx +164 -0
  140. promptline_opt-0.1.0/web/src/pages/RunDetail.tsx +154 -0
  141. promptline_opt-0.1.0/web/src/pages/RunsPage.tsx +130 -0
  142. promptline_opt-0.1.0/web/src/state/lineage.ts +84 -0
  143. promptline_opt-0.1.0/web/src/state/runReducer.ts +186 -0
  144. promptline_opt-0.1.0/web/src/test-setup.ts +1 -0
  145. promptline_opt-0.1.0/web/src/theme.css +466 -0
  146. promptline_opt-0.1.0/web/tsconfig.app.json +21 -0
  147. promptline_opt-0.1.0/web/tsconfig.app.tsbuildinfo +1 -0
  148. promptline_opt-0.1.0/web/tsconfig.json +7 -0
  149. promptline_opt-0.1.0/web/tsconfig.node.json +15 -0
  150. promptline_opt-0.1.0/web/tsconfig.node.tsbuildinfo +1 -0
  151. promptline_opt-0.1.0/web/vite.config.ts +25 -0
@@ -0,0 +1,10 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(mkdir -p /tmp/pl-demo)",
5
+ "Read(//private/tmp/pl-demo/**)",
6
+ "Bash(rm -rf ./* .promptline)",
7
+ "Bash(uv run *)"
8
+ ]
9
+ }
10
+ }
@@ -0,0 +1,45 @@
1
+ name: Bug report
2
+ description: Report something that isn't working as expected
3
+ labels: ["bug"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: Thanks for taking the time to file a bug. Please fill in the sections below.
8
+ - type: textarea
9
+ id: what-happened
10
+ attributes:
11
+ label: What happened?
12
+ description: A clear description of the bug, and what you expected instead.
13
+ placeholder: When I run `promptline optimize ...`, it ...
14
+ validations:
15
+ required: true
16
+ - type: textarea
17
+ id: repro
18
+ attributes:
19
+ label: Steps to reproduce
20
+ description: Ideally the exact commands. A `PROMPTLINE_FAKE_SCRIPT` repro that needs no API key is ideal.
21
+ placeholder: |
22
+ 1. promptline init
23
+ 2. promptline optimize --optimizer gepa ...
24
+ 3. ...
25
+ validations:
26
+ required: true
27
+ - type: textarea
28
+ id: logs
29
+ attributes:
30
+ label: Relevant output / traceback
31
+ render: shell
32
+ - type: input
33
+ id: version
34
+ attributes:
35
+ label: Promptline version
36
+ description: Output of `promptline --version`
37
+ validations:
38
+ required: true
39
+ - type: input
40
+ id: environment
41
+ attributes:
42
+ label: Environment
43
+ description: OS, Python version, install method (pip / editable / clone)
44
+ validations:
45
+ required: true
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Question / discussion
4
+ url: https://github.com/sanskarpan/promptline/discussions
5
+ about: Ask a question or discuss an idea before filing an issue.
@@ -0,0 +1,27 @@
1
+ name: Feature request
2
+ description: Suggest an idea or enhancement
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: Problem / motivation
9
+ description: What are you trying to do that Promptline doesn't support today?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposal
14
+ attributes:
15
+ label: Proposed solution
16
+ description: What would you like to see? (A new optimizer, a config option, an API endpoint, etc.)
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: alternatives
21
+ attributes:
22
+ label: Alternatives considered
23
+ - type: textarea
24
+ id: context
25
+ attributes:
26
+ label: Additional context
27
+ description: Links to papers, related tools, or prior art.
@@ -0,0 +1,23 @@
1
+ <!-- Thanks for contributing to Promptline! -->
2
+
3
+ ## Summary
4
+
5
+ <!-- What does this PR change and why? -->
6
+
7
+ ## Related issues
8
+
9
+ <!-- e.g. Closes #123 -->
10
+
11
+ ## Changes
12
+
13
+ <!-- Bullet the notable changes. -->
14
+ -
15
+
16
+ ## Checklist
17
+
18
+ - [ ] `uv run pytest -q` passes
19
+ - [ ] `uv run ruff check .` and `uv run ruff format --check .` pass
20
+ - [ ] `uv run pyright promptline` is clean
21
+ - [ ] Tests added/updated for the change (TDD; `FakeLLMClient` — no live LLM calls in unit tests)
22
+ - [ ] Docs updated if behavior/CLI/API changed (`README.md`, `docs/concepts/`)
23
+ - [ ] For web changes: `cd web && npm test && npm run build` pass
@@ -0,0 +1,103 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ concurrency:
10
+ group: ci-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ python:
15
+ name: python ${{ matrix.python-version }}
16
+ runs-on: ubuntu-latest
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ python-version: ["3.11", "3.12"]
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v5
26
+ with:
27
+ enable-cache: true
28
+
29
+ - name: Set up Python ${{ matrix.python-version }}
30
+ run: uv python install ${{ matrix.python-version }}
31
+
32
+ - name: Sync dependencies
33
+ run: uv sync --all-extras --dev
34
+
35
+ - name: Ruff lint
36
+ run: uv run ruff check .
37
+
38
+ - name: Ruff format check
39
+ run: uv run ruff format --check .
40
+
41
+ - name: Pyright
42
+ run: uv run pyright promptline
43
+
44
+ - name: Pytest (offline suite)
45
+ run: uv run pytest -q
46
+
47
+ web:
48
+ name: web (vitest + build)
49
+ runs-on: ubuntu-latest
50
+ defaults:
51
+ run:
52
+ working-directory: web
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+
56
+ - uses: actions/setup-node@v4
57
+ with:
58
+ node-version: "20"
59
+ cache: npm
60
+ cache-dependency-path: web/package-lock.json
61
+
62
+ - name: Install dependencies
63
+ run: npm ci
64
+
65
+ - name: Unit tests
66
+ run: npm test
67
+
68
+ - name: Production build
69
+ run: npm run build
70
+
71
+ dashboard-e2e:
72
+ name: dashboard e2e (playwright)
73
+ runs-on: ubuntu-latest
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+
77
+ - name: Install uv
78
+ uses: astral-sh/setup-uv@v5
79
+ with:
80
+ enable-cache: true
81
+
82
+ - name: Sync Python dependencies
83
+ run: uv sync --all-extras --dev
84
+
85
+ - uses: actions/setup-node@v4
86
+ with:
87
+ node-version: "20"
88
+ cache: npm
89
+ cache-dependency-path: web/package-lock.json
90
+
91
+ - name: Install web dependencies and build
92
+ working-directory: web
93
+ run: |
94
+ npm ci
95
+ npm run build
96
+
97
+ - name: Install Playwright browser
98
+ working-directory: web
99
+ run: npx playwright install --with-deps chromium
100
+
101
+ - name: Run dashboard e2e
102
+ working-directory: web
103
+ run: npm run e2e
@@ -0,0 +1,18 @@
1
+ .venv/
2
+ runs/
3
+ .promptline/
4
+ node_modules/
5
+ web/dist/
6
+ __pycache__/
7
+ .pytest_cache/
8
+ *.pyc
9
+ *.egg-info/
10
+ dist/
11
+ build/
12
+ .DS_Store
13
+ promptline.yaml
14
+
15
+ # Playwright
16
+ web/test-results/
17
+ web/playwright-report/
18
+ web/.playwright/
@@ -0,0 +1,47 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] — 2026-07-06
10
+
11
+ Initial release. The full `calibrate → optimize → gate → serve` pipeline.
12
+
13
+ ### Added
14
+
15
+ - **Core library**: declarative signatures/programs with per-module trace
16
+ recording, an `LLMClient` protocol with an OpenRouter adapter (BYO key, pooled
17
+ connections, retries with backoff, per-call cost tracking), a SQLite call
18
+ cache, and an eval harness with hard rollout/cost budget walls.
19
+ - **Optimizers (from scratch, one contract)**: GEPA (per-instance Pareto
20
+ selection, reflective mutation, system-aware merge, resumable checkpoints),
21
+ MIPRO (bootstrap demos → grounded instruction proposals → TPE search),
22
+ BootstrapFewShot (+ random search), ProTeGi (textual gradients + CAPO-style
23
+ racing), and OPRO.
24
+ - **Judge subsystem**: pointwise and pairwise rubric judges (CoT-before-verdict,
25
+ anti-verbosity, position-swap debiasing, k-sampling), agreement metrics
26
+ (Cohen's κ, Spearman, pairwise accuracy), a calibrator that certifies the judge
27
+ against human labels, and meta-optimization of the judge prompt. The calibrated
28
+ judge is the default optimization/gate metric, and a passing certificate is
29
+ required to optimize.
30
+ - **Statistical deploy gate**: paired bootstrap CIs, Holm correction across
31
+ candidates, independent validation-split confirmation, verbosity tripwires, and
32
+ refusals for uncalibrated judges, undersized splits, and dev/val contamination.
33
+ - **Registry & serving**: SQLite-backed versioned prompt registry with lineage,
34
+ an active pointer only the gate advances, rollback, and a FastAPI serving plane
35
+ (`GET /prompts/{program}/active` with ETag) plus a control plane with SSE run
36
+ streaming.
37
+ - **Interfaces**: a Typer CLI, a Textual TUI cockpit, and a React + Vite
38
+ dashboard (Runs, Lineage, Judge, Gate, Registry) served statically by FastAPI.
39
+ - **Data**: JSONL schema + adapters, and loaders for HelpSteer2, Bitext, and
40
+ MT-Bench human judgments.
41
+ - **Demo**: `promptline demo setup` (online and `--offline`) for the
42
+ support-assistant walkthrough.
43
+ - **Tests**: 444 offline unit/integration tests, an offline end-to-end suite,
44
+ Playwright dashboard e2e, and an opt-in live smoke test.
45
+
46
+ [Unreleased]: https://github.com/sanskarpan/promptline/compare/v0.1.0...HEAD
47
+ [0.1.0]: https://github.com/sanskarpan/promptline/releases/tag/v0.1.0
@@ -0,0 +1,47 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment:
18
+
19
+ - Demonstrating empathy and kindness toward other people
20
+ - Being respectful of differing opinions, viewpoints, and experiences
21
+ - Giving and gracefully accepting constructive feedback
22
+ - Accepting responsibility and apologizing to those affected by our mistakes
23
+ - Focusing on what is best for the overall community
24
+
25
+ Examples of unacceptable behavior:
26
+
27
+ - The use of sexualized language or imagery, and sexual attention or advances
28
+ - Trolling, insulting or derogatory comments, and personal or political attacks
29
+ - Public or private harassment
30
+ - Publishing others' private information without explicit permission
31
+ - Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Enforcement
35
+
36
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
37
+ reported to the project maintainer. All complaints will be reviewed and
38
+ investigated promptly and fairly. The maintainer is obligated to respect the
39
+ privacy and security of the reporter of any incident.
40
+
41
+ ## Attribution
42
+
43
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
44
+ version 2.1, available at
45
+ https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
46
+
47
+ [homepage]: https://www.contributor-covenant.org
@@ -0,0 +1,42 @@
1
+ # Contributing to Promptline
2
+
3
+ ## Setup
4
+
5
+ ```sh
6
+ uv sync # Python 3.11+, installs promptline + dev deps
7
+ cd web && npm install # only needed for dashboard work
8
+ ```
9
+
10
+ ## Test tiers
11
+
12
+ | Tier | Command | Needs | When |
13
+ |---|---|---|---|
14
+ | Offline suite (unit + e2e) | `make test` (`uv run pytest -q`) | nothing | every change |
15
+ | Dashboard e2e | `make e2e` | `npm run build` in `web/` + `npx playwright install chromium` | dashboard changes |
16
+ | Live smoke | `make live-smoke` | `OPENROUTER_API_KEY` (< $0.50) | before releases / adapter changes |
17
+
18
+ The offline suite is the gate for merging; the live tier is opt-in and marked
19
+ `@pytest.mark.live` (auto-skipped without a key). Lint with `make lint`.
20
+
21
+ ## The fake-script pattern
22
+
23
+ Tests never hit a real LLM. Two mechanisms:
24
+
25
+ 1. **In Python** — `FakeLLMClient(script=...)` accepts a list of canned
26
+ responses or a callable `(LLMCall) -> str`. The canonical e2e trick
27
+ (see `tests/e2e/conftest.py`): the client answers with a marker string
28
+ iff the system prompt already contains it, while scripted
29
+ reflection/proposal calls return an instruction that *adds* the marker —
30
+ so a metric that rewards the marker makes optimizers genuinely "improve".
31
+ 2. **Through the CLI** — set `PROMPTLINE_FAKE_SCRIPT=/path/to/script.json`.
32
+ The JSON holds a cycling `"responses": [...]` list and/or first-match
33
+ `"keyed": [{"contains": ..., "response": ...}]` rules matched against the
34
+ full prompt text. See `tests/e2e/test_cli_e2e.py` for a complete
35
+ init → calibrate → optimize → gate → serve chain driven this way.
36
+
37
+ ## Conventions
38
+
39
+ - Conventional commits (`feat:`, `fix:`, `test:`, `docs:` …).
40
+ - `uv run ruff check .` must pass; keep new tests deterministic (seeded RNG,
41
+ scripted clients, tmp_path workspaces).
42
+ - Prefer composing real components in tests and faking only the LLM.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sanskar Pandey
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,39 @@
1
+ .PHONY: help install test e2e live-smoke lint format format-check typecheck check web-test web-build build
2
+
3
+ help: ## Show this help
4
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}'
5
+
6
+ install: ## Sync all dependencies (runtime + data extra + dev)
7
+ uv sync --all-extras --dev
8
+
9
+ test: ## Offline test suite (fast, no network, no API key)
10
+ uv run pytest -q
11
+
12
+ lint: ## Ruff lint
13
+ uv run ruff check .
14
+
15
+ format: ## Apply Ruff formatting
16
+ uv run ruff format .
17
+
18
+ format-check: ## Check Ruff formatting without writing
19
+ uv run ruff format --check .
20
+
21
+ typecheck: ## Pyright type check
22
+ uv run pyright promptline
23
+
24
+ check: lint format-check typecheck test ## Run the full local gate (matches CI python job)
25
+
26
+ web-test: ## Dashboard unit tests (vitest)
27
+ cd web && npm test
28
+
29
+ web-build: ## Build the dashboard (writes web/dist)
30
+ cd web && npm run build
31
+
32
+ e2e: ## Dashboard Playwright e2e (needs web-build + chromium; see web/README.md)
33
+ cd web && npm run e2e
34
+
35
+ live-smoke: ## Opt-in live smoke against OpenRouter (needs OPENROUTER_API_KEY; ~<$0.50)
36
+ uv run pytest -m live tests/integration -q
37
+
38
+ build: ## Build the sdist + wheel
39
+ uv build