pinakes 0.2.2__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 (216) hide show
  1. pinakes-0.2.2/.github/workflows/ci.yml +168 -0
  2. pinakes-0.2.2/.github/workflows/release.yml +57 -0
  3. pinakes-0.2.2/.gitignore +26 -0
  4. pinakes-0.2.2/CHANGELOG.md +866 -0
  5. pinakes-0.2.2/CLAUDE.md +134 -0
  6. pinakes-0.2.2/LICENSE +202 -0
  7. pinakes-0.2.2/Makefile +77 -0
  8. pinakes-0.2.2/PKG-INFO +146 -0
  9. pinakes-0.2.2/README.md +114 -0
  10. pinakes-0.2.2/check.sh +73 -0
  11. pinakes-0.2.2/docs/CLI.md +183 -0
  12. pinakes-0.2.2/docs/DESIGN.md +811 -0
  13. pinakes-0.2.2/docs/GUIDE.md +339 -0
  14. pinakes-0.2.2/docs/KB-UPDATES.md +162 -0
  15. pinakes-0.2.2/docs/MANIFEST.md +216 -0
  16. pinakes-0.2.2/docs/README.md +70 -0
  17. pinakes-0.2.2/docs/RETROSPECTIVES.md +1180 -0
  18. pinakes-0.2.2/docs/STATUS.md +154 -0
  19. pinakes-0.2.2/docs/graph/GRAPH_RAG.md +207 -0
  20. pinakes-0.2.2/docs/graph/PINAKES_APPROACH.md +438 -0
  21. pinakes-0.2.2/docs/graph/README.md +49 -0
  22. pinakes-0.2.2/docs/graph/claudekb.md +438 -0
  23. pinakes-0.2.2/docs/graph/code-graph-rag.md +150 -0
  24. pinakes-0.2.2/docs/graph/datastax-graph-rag.md +152 -0
  25. pinakes-0.2.2/docs/graph/fast-graphrag.md +152 -0
  26. pinakes-0.2.2/docs/graph/graph-r1.md +128 -0
  27. pinakes-0.2.2/docs/graph/graphiti.md +179 -0
  28. pinakes-0.2.2/docs/graph/hipporag.md +170 -0
  29. pinakes-0.2.2/docs/graph/lightrag.md +154 -0
  30. pinakes-0.2.2/docs/graph/linearrag.md +162 -0
  31. pinakes-0.2.2/docs/graph/logicrag.md +147 -0
  32. pinakes-0.2.2/docs/graph/microsoft-graphrag.md +170 -0
  33. pinakes-0.2.2/docs/graph/minirag.md +162 -0
  34. pinakes-0.2.2/docs/graph/youtu-graphrag.md +160 -0
  35. pinakes-0.2.2/plans/v0.1.md +475 -0
  36. pinakes-0.2.2/plans/v0.2.md +2041 -0
  37. pinakes-0.2.2/pyproject.toml +103 -0
  38. pinakes-0.2.2/src/pinakes/__init__.py +9 -0
  39. pinakes-0.2.2/src/pinakes/_toml.py +192 -0
  40. pinakes-0.2.2/src/pinakes/budget/__init__.py +4 -0
  41. pinakes-0.2.2/src/pinakes/budget/estimate.py +146 -0
  42. pinakes-0.2.2/src/pinakes/budget/prices.py +81 -0
  43. pinakes-0.2.2/src/pinakes/budget/prices.toml +17 -0
  44. pinakes-0.2.2/src/pinakes/budget/reserve.py +153 -0
  45. pinakes-0.2.2/src/pinakes/budget/window.py +80 -0
  46. pinakes-0.2.2/src/pinakes/calibrate.py +173 -0
  47. pinakes-0.2.2/src/pinakes/chunk.py +396 -0
  48. pinakes-0.2.2/src/pinakes/cli.py +529 -0
  49. pinakes-0.2.2/src/pinakes/doctor.py +532 -0
  50. pinakes-0.2.2/src/pinakes/embed.py +280 -0
  51. pinakes-0.2.2/src/pinakes/errors.py +442 -0
  52. pinakes-0.2.2/src/pinakes/eval.py +338 -0
  53. pinakes-0.2.2/src/pinakes/extract/__init__.py +221 -0
  54. pinakes-0.2.2/src/pinakes/extract/cache.py +256 -0
  55. pinakes-0.2.2/src/pinakes/extract/floors.py +49 -0
  56. pinakes-0.2.2/src/pinakes/extract/floors.toml +18 -0
  57. pinakes-0.2.2/src/pinakes/extract/layout.py +550 -0
  58. pinakes-0.2.2/src/pinakes/extract/pdfium.py +174 -0
  59. pinakes-0.2.2/src/pinakes/extract/quality.py +644 -0
  60. pinakes-0.2.2/src/pinakes/extract/textpolicy.py +65 -0
  61. pinakes-0.2.2/src/pinakes/hooks.py +117 -0
  62. pinakes-0.2.2/src/pinakes/ids.py +58 -0
  63. pinakes-0.2.2/src/pinakes/init.py +91 -0
  64. pinakes-0.2.2/src/pinakes/lock.py +157 -0
  65. pinakes-0.2.2/src/pinakes/manifest.py +512 -0
  66. pinakes-0.2.2/src/pinakes/pairing.py +454 -0
  67. pinakes-0.2.2/src/pinakes/search.py +407 -0
  68. pinakes-0.2.2/src/pinakes/serve.py +272 -0
  69. pinakes-0.2.2/src/pinakes/sidecar.py +331 -0
  70. pinakes-0.2.2/src/pinakes/store.py +340 -0
  71. pinakes-0.2.2/src/pinakes/sync.py +1289 -0
  72. pinakes-0.2.2/src/pinakes/template.py +88 -0
  73. pinakes-0.2.2/src/pinakes/templates/notes/README.md +12 -0
  74. pinakes-0.2.2/src/pinakes/templates/notes/eval/questions.yaml +12 -0
  75. pinakes-0.2.2/src/pinakes/templates/notes/pinakes.toml.j2 +52 -0
  76. pinakes-0.2.2/src/pinakes/templates/notes/template.toml +5 -0
  77. pinakes-0.2.2/src/pinakes/uri.py +99 -0
  78. pinakes-0.2.2/stubs/pypdfium2.pyi +99 -0
  79. pinakes-0.2.2/tests/conftest.py +137 -0
  80. pinakes-0.2.2/tests/demo-kb/docs/access-restrictions.md +7 -0
  81. pinakes-0.2.2/tests/demo-kb/docs/access-restrictions.md.pnk.yaml +3 -0
  82. pinakes-0.2.2/tests/demo-kb/docs/accession-workflow.md +8 -0
  83. pinakes-0.2.2/tests/demo-kb/docs/accession-workflow.md.pnk.yaml +3 -0
  84. pinakes-0.2.2/tests/demo-kb/docs/acquisitions-committee.md +6 -0
  85. pinakes-0.2.2/tests/demo-kb/docs/acquisitions-committee.md.pnk.yaml +3 -0
  86. pinakes-0.2.2/tests/demo-kb/docs/annual-report-2025.md +7 -0
  87. pinakes-0.2.2/tests/demo-kb/docs/annual-report-2025.md.pnk.yaml +3 -0
  88. pinakes-0.2.2/tests/demo-kb/docs/appraisal-criteria.md +6 -0
  89. pinakes-0.2.2/tests/demo-kb/docs/appraisal-criteria.md.pnk.yaml +3 -0
  90. pinakes-0.2.2/tests/demo-kb/docs/authority-records.md +7 -0
  91. pinakes-0.2.2/tests/demo-kb/docs/authority-records.md.pnk.yaml +3 -0
  92. pinakes-0.2.2/tests/demo-kb/docs/building-history.md +6 -0
  93. pinakes-0.2.2/tests/demo-kb/docs/building-history.md.pnk.yaml +3 -0
  94. pinakes-0.2.2/tests/demo-kb/docs/catalogue-hierarchy.md +7 -0
  95. pinakes-0.2.2/tests/demo-kb/docs/catalogue-hierarchy.md.pnk.yaml +3 -0
  96. pinakes-0.2.2/tests/demo-kb/docs/catalogue-numbers-format.md +6 -0
  97. pinakes-0.2.2/tests/demo-kb/docs/catalogue-numbers-format.md.pnk.yaml +3 -0
  98. pinakes-0.2.2/tests/demo-kb/docs/catalogue-policy.md +7 -0
  99. pinakes-0.2.2/tests/demo-kb/docs/catalogue-policy.md.pnk.yaml +3 -0
  100. pinakes-0.2.2/tests/demo-kb/docs/conservation-assessment.md +7 -0
  101. pinakes-0.2.2/tests/demo-kb/docs/conservation-assessment.md.pnk.yaml +3 -0
  102. pinakes-0.2.2/tests/demo-kb/docs/copying-service.md +7 -0
  103. pinakes-0.2.2/tests/demo-kb/docs/copying-service.md.pnk.yaml +3 -0
  104. pinakes-0.2.2/tests/demo-kb/docs/deaccession-policy.md +7 -0
  105. pinakes-0.2.2/tests/demo-kb/docs/deaccession-policy.md.pnk.yaml +3 -0
  106. pinakes-0.2.2/tests/demo-kb/docs/digital-preservation.md +7 -0
  107. pinakes-0.2.2/tests/demo-kb/docs/digital-preservation.md.pnk.yaml +3 -0
  108. pinakes-0.2.2/tests/demo-kb/docs/digitisation-standards.md +7 -0
  109. pinakes-0.2.2/tests/demo-kb/docs/digitisation-standards.md.pnk.yaml +3 -0
  110. pinakes-0.2.2/tests/demo-kb/docs/donor-agreements.md +7 -0
  111. pinakes-0.2.2/tests/demo-kb/docs/donor-agreements.md.pnk.yaml +3 -0
  112. pinakes-0.2.2/tests/demo-kb/docs/emergency-plan.md +7 -0
  113. pinakes-0.2.2/tests/demo-kb/docs/emergency-plan.md.pnk.yaml +3 -0
  114. pinakes-0.2.2/tests/demo-kb/docs/enquiry-service.md +6 -0
  115. pinakes-0.2.2/tests/demo-kb/docs/enquiry-service.md.pnk.yaml +3 -0
  116. pinakes-0.2.2/tests/demo-kb/docs/funding-sources.md +7 -0
  117. pinakes-0.2.2/tests/demo-kb/docs/funding-sources.md.pnk.yaml +3 -0
  118. pinakes-0.2.2/tests/demo-kb/docs/loans-inward.md +7 -0
  119. pinakes-0.2.2/tests/demo-kb/docs/loans-inward.md.pnk.yaml +3 -0
  120. pinakes-0.2.2/tests/demo-kb/docs/loans-outward.md +6 -0
  121. pinakes-0.2.2/tests/demo-kb/docs/loans-outward.md.pnk.yaml +3 -0
  122. pinakes-0.2.2/tests/demo-kb/docs/metadata-minimum.md +7 -0
  123. pinakes-0.2.2/tests/demo-kb/docs/metadata-minimum.md.pnk.yaml +3 -0
  124. pinakes-0.2.2/tests/demo-kb/docs/opening-hours.md +6 -0
  125. pinakes-0.2.2/tests/demo-kb/docs/opening-hours.md.pnk.yaml +3 -0
  126. pinakes-0.2.2/tests/demo-kb/docs/pest-management.md +7 -0
  127. pinakes-0.2.2/tests/demo-kb/docs/pest-management.md.pnk.yaml +3 -0
  128. pinakes-0.2.2/tests/demo-kb/docs/reader-registration.md +7 -0
  129. pinakes-0.2.2/tests/demo-kb/docs/reader-registration.md.pnk.yaml +3 -0
  130. pinakes-0.2.2/tests/demo-kb/docs/reading-room-rules.md +8 -0
  131. pinakes-0.2.2/tests/demo-kb/docs/reading-room-rules.md.pnk.yaml +3 -0
  132. pinakes-0.2.2/tests/demo-kb/docs/staff-conservator.md +7 -0
  133. pinakes-0.2.2/tests/demo-kb/docs/staff-conservator.md.pnk.yaml +3 -0
  134. pinakes-0.2.2/tests/demo-kb/docs/staff-keeper.md +7 -0
  135. pinakes-0.2.2/tests/demo-kb/docs/staff-keeper.md.pnk.yaml +3 -0
  136. pinakes-0.2.2/tests/demo-kb/docs/storage-environment.md +8 -0
  137. pinakes-0.2.2/tests/demo-kb/docs/storage-environment.md.pnk.yaml +3 -0
  138. pinakes-0.2.2/tests/demo-kb/docs/volunteer-programme.md +7 -0
  139. pinakes-0.2.2/tests/demo-kb/docs/volunteer-programme.md.pnk.yaml +3 -0
  140. pinakes-0.2.2/tests/demo-kb/eval/baseline.json +16 -0
  141. pinakes-0.2.2/tests/demo-kb/eval/questions.yaml +177 -0
  142. pinakes-0.2.2/tests/demo-kb/pinakes.toml +38 -0
  143. pinakes-0.2.2/tests/pdf-corpus/baseline-12p.expected.txt +12 -0
  144. pinakes-0.2.2/tests/pdf-corpus/baseline-12p.pdf +0 -0
  145. pinakes-0.2.2/tests/pdf-corpus/baseline-1p.expected.txt +1 -0
  146. pinakes-0.2.2/tests/pdf-corpus/baseline-1p.pdf +0 -0
  147. pinakes-0.2.2/tests/pdf-corpus/baseline.json +76 -0
  148. pinakes-0.2.2/tests/pdf-corpus/fonts/LICENSE-OFL.txt +102 -0
  149. pinakes-0.2.2/tests/pdf-corpus/fonts/LiberationSans-Subset.ttf +0 -0
  150. pinakes-0.2.2/tests/pdf-corpus/fonts/README.md +69 -0
  151. pinakes-0.2.2/tests/pdf-corpus/footer-first-page-only.expected.txt +4 -0
  152. pinakes-0.2.2/tests/pdf-corpus/footer-first-page-only.pdf +0 -0
  153. pinakes-0.2.2/tests/pdf-corpus/footers-pagenum.expected.txt +6 -0
  154. pinakes-0.2.2/tests/pdf-corpus/footers-pagenum.pdf +0 -0
  155. pinakes-0.2.2/tests/pdf-corpus/generate.py +579 -0
  156. pinakes-0.2.2/tests/pdf-corpus/headers-repeating.expected.txt +20 -0
  157. pinakes-0.2.2/tests/pdf-corpus/headers-repeating.pdf +0 -0
  158. pinakes-0.2.2/tests/pdf-corpus/hyphenation-page-break.expected.txt +2 -0
  159. pinakes-0.2.2/tests/pdf-corpus/hyphenation-page-break.pdf +0 -0
  160. pinakes-0.2.2/tests/pdf-corpus/hyphenation-soft.expected.txt +2 -0
  161. pinakes-0.2.2/tests/pdf-corpus/hyphenation-soft.pdf +0 -0
  162. pinakes-0.2.2/tests/pdf-corpus/ligatures-a.expected.txt +2 -0
  163. pinakes-0.2.2/tests/pdf-corpus/ligatures-a.pdf +0 -0
  164. pinakes-0.2.2/tests/pdf-corpus/pathological-corrupt-header.expected.txt +0 -0
  165. pinakes-0.2.2/tests/pdf-corpus/pathological-corrupt-header.pdf +0 -0
  166. pinakes-0.2.2/tests/pdf-corpus/pathological-invisible-text.expected.txt +1 -0
  167. pinakes-0.2.2/tests/pdf-corpus/pathological-invisible-text.pdf +0 -0
  168. pinakes-0.2.2/tests/pdf-corpus/pdfwriter.py +454 -0
  169. pinakes-0.2.2/tests/pdf-corpus/scanned-clean.expected.txt +6 -0
  170. pinakes-0.2.2/tests/pdf-corpus/scanned-clean.pdf +0 -0
  171. pinakes-0.2.2/tests/pdf-corpus/scanned-low-contrast.expected.txt +2 -0
  172. pinakes-0.2.2/tests/pdf-corpus/scanned-low-contrast.pdf +0 -0
  173. pinakes-0.2.2/tests/pdf-corpus/scanned-skewed.expected.txt +2 -0
  174. pinakes-0.2.2/tests/pdf-corpus/scanned-skewed.pdf +0 -0
  175. pinakes-0.2.2/tests/pdf-corpus/spec.py +85 -0
  176. pinakes-0.2.2/tests/pdf-corpus/tables-bordered.expected.txt +6 -0
  177. pinakes-0.2.2/tests/pdf-corpus/tables-bordered.pdf +0 -0
  178. pinakes-0.2.2/tests/pdf-corpus/tables-borderless.expected.txt +6 -0
  179. pinakes-0.2.2/tests/pdf-corpus/tables-borderless.pdf +0 -0
  180. pinakes-0.2.2/tests/pdf-corpus/tables-spanning.expected.txt +7 -0
  181. pinakes-0.2.2/tests/pdf-corpus/tables-spanning.pdf +0 -0
  182. pinakes-0.2.2/tests/pdf-corpus/two-column-a.expected.txt +4 -0
  183. pinakes-0.2.2/tests/pdf-corpus/two-column-a.pdf +0 -0
  184. pinakes-0.2.2/tests/pdf-corpus/two-column-b.expected.txt +5 -0
  185. pinakes-0.2.2/tests/pdf-corpus/two-column-b.pdf +0 -0
  186. pinakes-0.2.2/tests/pdf-corpus/two-column-c.expected.txt +4 -0
  187. pinakes-0.2.2/tests/pdf-corpus/two-column-c.pdf +0 -0
  188. pinakes-0.2.2/tests/test_budget_core.py +605 -0
  189. pinakes-0.2.2/tests/test_check_script.py +78 -0
  190. pinakes-0.2.2/tests/test_chunk.py +224 -0
  191. pinakes-0.2.2/tests/test_chunk_pdf.py +133 -0
  192. pinakes-0.2.2/tests/test_cli.py +116 -0
  193. pinakes-0.2.2/tests/test_cli_search.py +151 -0
  194. pinakes-0.2.2/tests/test_doctor.py +419 -0
  195. pinakes-0.2.2/tests/test_embed.py +187 -0
  196. pinakes-0.2.2/tests/test_eval.py +276 -0
  197. pinakes-0.2.2/tests/test_extract.py +157 -0
  198. pinakes-0.2.2/tests/test_extract_cache.py +334 -0
  199. pinakes-0.2.2/tests/test_extract_layout.py +653 -0
  200. pinakes-0.2.2/tests/test_extract_pdfium.py +282 -0
  201. pinakes-0.2.2/tests/test_extract_quality.py +272 -0
  202. pinakes-0.2.2/tests/test_hooks.py +170 -0
  203. pinakes-0.2.2/tests/test_ids.py +66 -0
  204. pinakes-0.2.2/tests/test_init.py +107 -0
  205. pinakes-0.2.2/tests/test_lock.py +92 -0
  206. pinakes-0.2.2/tests/test_manifest.py +322 -0
  207. pinakes-0.2.2/tests/test_packaging.py +131 -0
  208. pinakes-0.2.2/tests/test_pairing.py +395 -0
  209. pinakes-0.2.2/tests/test_pdf_corpus.py +233 -0
  210. pinakes-0.2.2/tests/test_search.py +440 -0
  211. pinakes-0.2.2/tests/test_serve.py +208 -0
  212. pinakes-0.2.2/tests/test_sidecar.py +368 -0
  213. pinakes-0.2.2/tests/test_store.py +341 -0
  214. pinakes-0.2.2/tests/test_sync.py +1126 -0
  215. pinakes-0.2.2/tests/test_uri.py +95 -0
  216. pinakes-0.2.2/uv.lock +2087 -0
@@ -0,0 +1,168 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ci-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ check:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ matrix:
17
+ # Three legs (I1): the light-only core, [pdf] added, then [claude] added on top. Each is a
18
+ # supported install state (docs/DESIGN.md §4.5) and each must pass this job on its own —
19
+ # a matrix that stopped at [light] would prove nothing about the other two for six
20
+ # increments, the exact gap I1's own exit criterion closes.
21
+ extras: ["light", "light pdf", "light pdf claude"]
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+
25
+ - name: Install uv
26
+ uses: astral-sh/setup-uv@v5
27
+ with:
28
+ enable-cache: true
29
+
30
+ - name: Install Python and dependencies
31
+ # The [light] extra, never [st]: a 2GB torch download per job is untenable, and fastembed
32
+ # exercises the same protocols (docs/DESIGN.md §4.5). [pdf]/[claude] install one pure-Python
33
+ # SDK apiece and never call them — this job proves the extra installs and imports cleanly,
34
+ # not that the paid path works.
35
+ run: |
36
+ set -e
37
+ args=""
38
+ for extra in ${{ matrix.extras }}; do
39
+ args="$args --extra $extra"
40
+ done
41
+ uv sync --frozen $args
42
+
43
+ # Model weights are a download, not an install. Keyed on the models the demo KB names, so a
44
+ # model change invalidates the cache and nothing else does. Without this the reranker alone
45
+ # would pull ~1GB per job.
46
+ - name: Cache model weights
47
+ uses: actions/cache@v4
48
+ with:
49
+ path: ~/.cache/huggingface
50
+ key: hf-${{ hashFiles('tests/demo-kb/pinakes.toml') }}
51
+ restore-keys: hf-
52
+
53
+ - name: Format
54
+ run: uv run --frozen ruff format --check .
55
+
56
+ - name: Lint
57
+ run: uv run --frozen ruff check .
58
+
59
+ - name: Types (ty, fast pre-check)
60
+ run: uv run --frozen ty check --extra-search-path stubs .
61
+
62
+ - name: Types (pyright, strict — the gate)
63
+ run: uv run --frozen pyright
64
+
65
+ - name: Tests
66
+ # Warnings are errors here (pyproject), which is how a deprecation reaches a human.
67
+ run: uv run --frozen pytest -q
68
+
69
+ - name: Model-backed tests
70
+ # Pinned to the [light] leg alone (I1): `_runnable()` skips only when fastembed is absent or
71
+ # the HF cache is empty, both true on every leg alike, so this dedicated step would triple
72
+ # for no benefit on the other two. (The Tests step above already runs these once per leg too
73
+ # when the cache is warm — this step's own redundancy predates the matrix and is unrelated.)
74
+ if: matrix.extras == 'light'
75
+ run: uv run --frozen pytest -q -m model
76
+
77
+ eval:
78
+ # The scoreboard §7 requires: a retrieval change has to move these numbers, and a regression
79
+ # beyond tolerance fails the build rather than being noticed later.
80
+ runs-on: ubuntu-latest
81
+ steps:
82
+ - uses: actions/checkout@v4
83
+
84
+ - name: Install uv
85
+ uses: astral-sh/setup-uv@v5
86
+ with:
87
+ enable-cache: true
88
+
89
+ - run: uv sync --frozen --extra light
90
+
91
+ - name: Cache model weights
92
+ uses: actions/cache@v4
93
+ with:
94
+ path: ~/.cache/huggingface
95
+ key: hf-${{ hashFiles('tests/demo-kb/pinakes.toml') }}
96
+ restore-keys: hf-
97
+
98
+ - name: Index the demo KB
99
+ run: uv run --frozen pnk sync --kb tests/demo-kb
100
+
101
+ - name: Health check
102
+ run: uv run --frozen pnk doctor --kb tests/demo-kb
103
+
104
+ - name: Golden-set evaluation against the baseline
105
+ run: uv run --frozen python -m pinakes.eval tests/demo-kb
106
+
107
+ pdf-eval:
108
+ # I3b: joins CI in the same commit that adds the gate, not deferred until I9 the way the draft
109
+ # plan would have left it for six intervening increments to land ungated.
110
+ runs-on: ubuntu-latest
111
+ steps:
112
+ - uses: actions/checkout@v4
113
+
114
+ - name: Install uv
115
+ uses: astral-sh/setup-uv@v5
116
+ with:
117
+ enable-cache: true
118
+
119
+ - run: uv sync --frozen --extra light --extra pdf
120
+
121
+ - name: Extraction-quality baseline + floor-drift check
122
+ run: |
123
+ uv run --frozen python -m pinakes.extract.quality tests/pdf-corpus \
124
+ --check-floors src/pinakes/extract/floors.toml
125
+
126
+ build:
127
+ runs-on: ubuntu-latest
128
+ steps:
129
+ - uses: actions/checkout@v4
130
+
131
+ - name: Install uv
132
+ uses: astral-sh/setup-uv@v5
133
+ with:
134
+ enable-cache: true
135
+
136
+ - name: Build the wheel and sdist
137
+ run: uv build
138
+
139
+ # Proves the templates travel inside the wheel. `pnk init` reads them through
140
+ # importlib.resources, so a packaging mistake is invisible until someone installs it.
141
+ - name: Smoke-test the built wheel
142
+ run: |
143
+ set -e
144
+ uv run --isolated --no-project --with dist/*.whl pnk --version
145
+ mkdir -p /tmp/smoke
146
+ uv run --isolated --no-project --with dist/*.whl pnk init /tmp/smoke/kb
147
+ test -f /tmp/smoke/kb/pinakes.toml
148
+ test -f /tmp/smoke/kb/eval/questions.yaml
149
+ grep -q '.pinakes/' /tmp/smoke/kb/.gitignore
150
+
151
+ # plans/v0.1.md promised this gate under "Verification of the whole" and it never shipped:
152
+ # the item carried no increment number, so no increment owned it (see that plan's close-out,
153
+ # rule 8). The invariant holds structurally today — core deps are jinja2, mcp, numpy,
154
+ # python-ulid, pyyaml — but "holds today" is not "cannot break", and CLAUDE.md calls the free
155
+ # path non-negotiable.
156
+ - name: The free path stays free — no paid-API client imported in src/
157
+ run: |
158
+ set -e
159
+ if grep -rniE '^[[:space:]]*(import|from)[[:space:]]+(anthropic|openai|cohere|mistralai|google\.generativeai)\b' src/; then
160
+ echo "::error::A paid-API client is imported in src/. DESIGN §1: no code path may make a paid call outside 'pnk ask --deep'." >&2
161
+ exit 1
162
+ fi
163
+ echo "no paid-API imports in src/"
164
+
165
+ - uses: actions/upload-artifact@v4
166
+ with:
167
+ name: dist
168
+ path: dist/
@@ -0,0 +1,57 @@
1
+ name: Release
2
+
3
+ # Publishing is deliberately manual: it runs only when a maintainer pushes a v* tag, never on a
4
+ # merge. PyPI trusted publishing must be configured for this repository first — a human step that
5
+ # cannot be automated from here (plans/v0.1.md, I15).
6
+ #
7
+ # Until that human step happens, the PyPI upload is *skipped rather than attempted*, gated on the
8
+ # repository variable PUBLISH_TO_PYPI. Everything before it still runs on every tag — version/tag
9
+ # agreement, build, and the isolated wheel smoke test — so a tag is fully validated even when
10
+ # nothing is uploaded, and pushing one never produces a red run for a reason the maintainer
11
+ # already knows about. To start publishing: configure trusted publishing on PyPI, then set the
12
+ # variable (`gh variable set PUBLISH_TO_PYPI --body true`). Nothing else here changes.
13
+ on:
14
+ push:
15
+ tags: ["v*"]
16
+
17
+ jobs:
18
+ publish:
19
+ runs-on: ubuntu-latest
20
+ environment: release
21
+ permissions:
22
+ id-token: write # trusted publishing; no API token is stored anywhere
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+
26
+ - uses: astral-sh/setup-uv@v5
27
+ with:
28
+ enable-cache: true
29
+
30
+ - name: Refuse a tag that disagrees with the package version
31
+ run: |
32
+ set -e
33
+ tag="${GITHUB_REF_NAME#v}"
34
+ version="$(uv run --frozen python -c 'import pinakes; print(pinakes.__version__)')"
35
+ if [ "$tag" != "$version" ]; then
36
+ echo "tag $tag does not match pinakes $version" >&2
37
+ exit 1
38
+ fi
39
+
40
+ - run: uv build
41
+
42
+ - name: Smoke-test the wheel before it leaves the building
43
+ run: |
44
+ set -e
45
+ uv run --isolated --no-project --with dist/*.whl pnk --version
46
+ uv run --isolated --no-project --with dist/*.whl pnk init /tmp/release-smoke
47
+ test -f /tmp/release-smoke/pinakes.toml
48
+
49
+ - name: Publish to PyPI
50
+ if: vars.PUBLISH_TO_PYPI == 'true'
51
+ run: uv publish
52
+
53
+ - name: Explain why nothing was published
54
+ if: vars.PUBLISH_TO_PYPI != 'true'
55
+ run: |
56
+ echo "::notice::PUBLISH_TO_PYPI is not 'true' — the wheel was built and smoke-tested but not uploaded."
57
+ echo "Configure PyPI trusted publishing, then: gh variable set PUBLISH_TO_PYPI --body true"
@@ -0,0 +1,26 @@
1
+ # Generated KB state — index, spend ledger, caches. Never committed, always rebuildable.
2
+ .pinakes/
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.egg-info/
8
+ build/
9
+ dist/
10
+ .venv/
11
+ venv/
12
+
13
+ # Tooling
14
+ .pytest_cache/
15
+ .ruff_cache/
16
+ .mypy_cache/
17
+ .coverage
18
+ htmlcov/
19
+
20
+ # Models and data that must never enter a public repo
21
+ *.safetensors
22
+ *.onnx
23
+ *.bin
24
+
25
+ # OS
26
+ .DS_Store