pyqmd-mlx 0.7.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 (343) hide show
  1. pyqmd_mlx-0.7.0/.Justfile +50 -0
  2. pyqmd_mlx-0.7.0/.commitlintrc.mjs +47 -0
  3. pyqmd_mlx-0.7.0/.github/workflows/build.yml +61 -0
  4. pyqmd_mlx-0.7.0/.github/workflows/ci.yml +60 -0
  5. pyqmd_mlx-0.7.0/.github/workflows/pr-title.yml +24 -0
  6. pyqmd_mlx-0.7.0/.github/workflows/release.yml +87 -0
  7. pyqmd_mlx-0.7.0/.gitignore +60 -0
  8. pyqmd_mlx-0.7.0/.pre-commit-config.yaml +71 -0
  9. pyqmd_mlx-0.7.0/.python-version +1 -0
  10. pyqmd_mlx-0.7.0/.semrel/.components/changelog_header.md.j2 +9 -0
  11. pyqmd_mlx-0.7.0/.semrel/.components/changelog_init.md.j2 +29 -0
  12. pyqmd_mlx-0.7.0/.semrel/.components/changelog_update.md.j2 +71 -0
  13. pyqmd_mlx-0.7.0/.semrel/.components/changes.md.j2 +232 -0
  14. pyqmd_mlx-0.7.0/.semrel/.components/first_release.md.j2 +18 -0
  15. pyqmd_mlx-0.7.0/.semrel/.components/macros.md.j2 +251 -0
  16. pyqmd_mlx-0.7.0/.semrel/.components/unreleased_changes.md.j2 +7 -0
  17. pyqmd_mlx-0.7.0/.semrel/.components/versioned_changes.md.j2 +20 -0
  18. pyqmd_mlx-0.7.0/.semrel/.release_notes.md.j2 +62 -0
  19. pyqmd_mlx-0.7.0/.semrel/CHANGELOG.md.j2 +21 -0
  20. pyqmd_mlx-0.7.0/AGENTS.md +1 -0
  21. pyqmd_mlx-0.7.0/CHANGELOG.md +202 -0
  22. pyqmd_mlx-0.7.0/CLAUDE.md +229 -0
  23. pyqmd_mlx-0.7.0/COMMAND_STATUS.md +159 -0
  24. pyqmd_mlx-0.7.0/LICENSE +21 -0
  25. pyqmd_mlx-0.7.0/PKG-INFO +98 -0
  26. pyqmd_mlx-0.7.0/README.md +66 -0
  27. pyqmd_mlx-0.7.0/docs/specs/2026-09-10-mlx-llm-layer-design.md +366 -0
  28. pyqmd_mlx-0.7.0/docs/specs/2026-09-10-python-mlx-rewrite-roadmap.md +315 -0
  29. pyqmd_mlx-0.7.0/docs/specs/2026-09-11-python-cli-design.md +207 -0
  30. pyqmd_mlx-0.7.0/docs/specs/2026-09-11-python-mcp-server-design.md +202 -0
  31. pyqmd_mlx-0.7.0/docs/specs/2026-09-11-python-storage-layer-design.md +283 -0
  32. pyqmd_mlx-0.7.0/docs/specs/2026-09-12-python-metadata-filtering-design.md +439 -0
  33. pyqmd_mlx-0.7.0/docs/specs/2026-09-12-python-node-parity-suite-design.md +373 -0
  34. pyqmd_mlx-0.7.0/docs/specs/2026-09-13-python-update-command-design.md +556 -0
  35. pyqmd_mlx-0.7.0/docs/specs/2026-09-15-python-folder-context-design.md +378 -0
  36. pyqmd_mlx-0.7.0/docs/specs/2026-09-16-python-cleanup-command-design.md +217 -0
  37. pyqmd_mlx-0.7.0/docs/specs/2026-09-17-collection-include-exclude-design.md +197 -0
  38. pyqmd_mlx-0.7.0/docs/specs/2026-09-17-full-path-flag-design.md +226 -0
  39. pyqmd_mlx-0.7.0/docs/specs/2026-09-17-multi-get-glob-support-design.md +248 -0
  40. pyqmd_mlx-0.7.0/docs/specs/2026-09-17-parity-suite-mutating-commands-design.md +293 -0
  41. pyqmd_mlx-0.7.0/docs/specs/2026-09-18-bench-command-design.md +269 -0
  42. pyqmd_mlx-0.7.0/docs/specs/2026-09-18-skill-commands-design.md +197 -0
  43. pyqmd_mlx-0.7.0/docs/specs/2026-09-19-ast-aware-chunking-design.md +268 -0
  44. pyqmd_mlx-0.7.0/docs/specs/2026-09-20-github-ci-release-design.md +123 -0
  45. pyqmd_mlx-0.7.0/docs/specs/2026-09-22-multi-agent-skills-design.md +119 -0
  46. pyqmd_mlx-0.7.0/docs/specs/2026-09-24-cli-flow-output-text-parity-design.md +262 -0
  47. pyqmd_mlx-0.7.0/docs/specs/2026-09-24-expand-model-gguf-weights-design.md +247 -0
  48. pyqmd_mlx-0.7.0/docs/specs/2026-09-24-expand-model-hf-default-design.md +218 -0
  49. pyqmd_mlx-0.7.0/docs/specs/2026-09-24-import-package-rename-design.md +135 -0
  50. pyqmd_mlx-0.7.0/docs/specs/2026-09-24-mcp-http-parity-design.md +280 -0
  51. pyqmd_mlx-0.7.0/docs/specs/2026-09-24-qrels-margin-calibration-design.md +206 -0
  52. pyqmd_mlx-0.7.0/docs/specs/2026-09-25-bench-samples-design.md +234 -0
  53. pyqmd_mlx-0.7.0/docs/specs/2026-09-25-expand-model-requantize-design.md +173 -0
  54. pyqmd_mlx-0.7.0/docs/specs/2026-09-25-expansion-output-grammar-design.md +311 -0
  55. pyqmd_mlx-0.7.0/docs/specs/2026-09-25-seeded-expansion-sampling-design.md +276 -0
  56. pyqmd_mlx-0.7.0/docs/specs/2026-09-28-pypi-publishing-design.md +282 -0
  57. pyqmd_mlx-0.7.0/parity/README.md +192 -0
  58. pyqmd_mlx-0.7.0/parity/__init__.py +0 -0
  59. pyqmd_mlx-0.7.0/parity/_mcp_client.py +70 -0
  60. pyqmd_mlx-0.7.0/parity/_node_cli.py +89 -0
  61. pyqmd_mlx-0.7.0/parity/_pyqmd_cli.py +39 -0
  62. pyqmd_mlx-0.7.0/parity/_quality_baseline.py +64 -0
  63. pyqmd_mlx-0.7.0/parity/_queries.py +32 -0
  64. pyqmd_mlx-0.7.0/parity/_snapshot_io.py +40 -0
  65. pyqmd_mlx-0.7.0/parity/_text_normalize.py +100 -0
  66. pyqmd_mlx-0.7.0/parity/_timing.py +61 -0
  67. pyqmd_mlx-0.7.0/parity/benchmark.py +288 -0
  68. pyqmd_mlx-0.7.0/parity/capture_node_snapshots.py +405 -0
  69. pyqmd_mlx-0.7.0/parity/conftest.py +47 -0
  70. pyqmd_mlx-0.7.0/parity/dataset_profile.py +84 -0
  71. pyqmd_mlx-0.7.0/parity/datasets/local/.gitkeep +0 -0
  72. pyqmd_mlx-0.7.0/parity/datasets/scifact.yaml +4 -0
  73. pyqmd_mlx-0.7.0/parity/fixtures/ast_chunking/sample.py +156 -0
  74. pyqmd_mlx-0.7.0/parity/fixtures/mutating/a.md +4 -0
  75. pyqmd_mlx-0.7.0/parity/fixtures/mutating/b.md +4 -0
  76. pyqmd_mlx-0.7.0/parity/fixtures/mutating/c.md +4 -0
  77. pyqmd_mlx-0.7.0/parity/fixtures/mutating/d.md +4 -0
  78. pyqmd_mlx-0.7.0/parity/node_ref/scifact/COMMIT.txt +2 -0
  79. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/collection_list_shows_active_profile.json +4 -0
  80. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/collection_show_active_profile.json +4 -0
  81. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/get_known_document.json +4 -0
  82. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/get_known_document_full_path.json +4 -0
  83. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/get_missing_document_errors_cleanly.json +4 -0
  84. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/ls_lists_active_profile_collection.json +4 -0
  85. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/multi_get_glob_pattern_matches.json +4 -0
  86. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/multi_get_two_documents.json +4 -0
  87. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/multi_get_two_documents_full_path.json +13 -0
  88. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/query_finds_sample_query.json +5 -0
  89. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/query_no_rerank.json +5 -0
  90. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/query_respects_min_score_1_0.json +5 -0
  91. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/query_top1_matches_verbatim_sentence.json +4 -0
  92. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/search_finds_sample_query.json +5 -0
  93. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/search_finds_sample_query_full_path.json +4 -0
  94. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/search_no_results.json +5 -0
  95. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/status_reports_index_health.json +4 -0
  96. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/vsearch_finds_sample_query.json +5 -0
  97. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli/vsearch_top1_matches_verbatim_sentence.json +4 -0
  98. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_flow/ast_chunking_embed.json +14 -0
  99. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_flow/collection_lifecycle.json +56 -0
  100. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_flow/context_lifecycle.json +49 -0
  101. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_flow/embed_lifecycle.json +27 -0
  102. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_flow/update_lifecycle.json +16 -0
  103. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_flow_raw/ast_chunking_embed.json +24 -0
  104. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_flow_raw/collection_lifecycle.json +88 -0
  105. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_flow_raw/context_lifecycle.json +52 -0
  106. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_flow_raw/embed_lifecycle.json +34 -0
  107. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_flow_raw/update_lifecycle.json +16 -0
  108. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/collection_list_shows_active_profile.json +6 -0
  109. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/collection_show_active_profile.json +6 -0
  110. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/get_known_document.json +6 -0
  111. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/get_known_document_full_path.json +6 -0
  112. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/get_missing_document_errors_cleanly.json +6 -0
  113. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/ls_lists_active_profile_collection.json +6 -0
  114. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/multi_get_glob_pattern_matches.json +6 -0
  115. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/multi_get_two_documents.json +6 -0
  116. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/multi_get_two_documents_full_path.json +12 -0
  117. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/query_finds_sample_query.json +11 -0
  118. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/query_no_rerank.json +12 -0
  119. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/query_respects_min_score_1_0.json +13 -0
  120. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/query_top1_matches_verbatim_sentence.json +11 -0
  121. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/search_finds_sample_query.json +11 -0
  122. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/search_finds_sample_query_full_path.json +12 -0
  123. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/search_no_results.json +6 -0
  124. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/status_reports_index_health.json +6 -0
  125. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/vsearch_finds_sample_query.json +11 -0
  126. pyqmd_mlx-0.7.0/parity/node_ref/scifact/cli_raw/vsearch_top1_matches_verbatim_sentence.json +11 -0
  127. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp/mcp_get_known_document.json +3 -0
  128. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp/mcp_multi_get_two_documents.json +3 -0
  129. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp/mcp_query_finds_sample_query.json +3 -0
  130. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp/mcp_query_nonsense_term_still_returns_hybrid_fallback.json +3 -0
  131. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp/mcp_query_top1_matches_verbatim_sentence.json +3 -0
  132. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp/mcp_status_reports_health.json +3 -0
  133. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp_raw/mcp_get_known_document.json +14 -0
  134. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp_raw/mcp_multi_get_two_documents.json +22 -0
  135. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp_raw/mcp_query_finds_sample_query.json +104 -0
  136. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp_raw/mcp_query_nonsense_term_still_returns_hybrid_fallback.json +104 -0
  137. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp_raw/mcp_query_top1_matches_verbatim_sentence.json +104 -0
  138. pyqmd_mlx-0.7.0/parity/node_ref/scifact/mcp_raw/mcp_status_reports_health.json +25 -0
  139. pyqmd_mlx-0.7.0/parity/node_ref/scifact/quality/node_query_baseline.json +166 -0
  140. pyqmd_mlx-0.7.0/parity/scenarios/__init__.py +0 -0
  141. pyqmd_mlx-0.7.0/parity/scenarios/_profile_fixtures.py +54 -0
  142. pyqmd_mlx-0.7.0/parity/scenarios/cli_flow_scenarios.py +492 -0
  143. pyqmd_mlx-0.7.0/parity/scenarios/cli_scenarios.py +308 -0
  144. pyqmd_mlx-0.7.0/parity/scenarios/mcp_scenarios.py +113 -0
  145. pyqmd_mlx-0.7.0/parity/test_quality.py +132 -0
  146. pyqmd_mlx-0.7.0/parity/test_structural.py +231 -0
  147. pyqmd_mlx-0.7.0/pyproject.toml +102 -0
  148. pyqmd_mlx-0.7.0/scripts/block-main-push.sh +28 -0
  149. pyqmd_mlx-0.7.0/scripts/compare_rerank_fixtures.py +207 -0
  150. pyqmd_mlx-0.7.0/scripts/convert_expand_gguf.py +251 -0
  151. pyqmd_mlx-0.7.0/scripts/prepare_scifact_corpus.py +73 -0
  152. pyqmd_mlx-0.7.0/scripts/replay_query.py +340 -0
  153. pyqmd_mlx-0.7.0/scripts/score_rerank_fixture.py +53 -0
  154. pyqmd_mlx-0.7.0/scripts/validate_store_query.py +90 -0
  155. pyqmd_mlx-0.7.0/src/pyqmd_mlx/__init__.py +0 -0
  156. pyqmd_mlx-0.7.0/src/pyqmd_mlx/bench/__init__.py +0 -0
  157. pyqmd_mlx-0.7.0/src/pyqmd_mlx/bench/_fixture.py +82 -0
  158. pyqmd_mlx-0.7.0/src/pyqmd_mlx/bench/_metrics.py +101 -0
  159. pyqmd_mlx-0.7.0/src/pyqmd_mlx/bench/_pathmatch.py +60 -0
  160. pyqmd_mlx-0.7.0/src/pyqmd_mlx/bench/_sampling.py +62 -0
  161. pyqmd_mlx-0.7.0/src/pyqmd_mlx/bench/runner.py +283 -0
  162. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/__init__.py +0 -0
  163. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_db.py +27 -0
  164. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_errors.py +48 -0
  165. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_format.py +95 -0
  166. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_fullpath.py +44 -0
  167. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_index_report.py +25 -0
  168. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_lineparse.py +30 -0
  169. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_metadata_filter.py +34 -0
  170. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_multiget.py +82 -0
  171. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_output_documents.py +146 -0
  172. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_output_search.py +247 -0
  173. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_progress.py +102 -0
  174. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_snippet.py +99 -0
  175. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_theme.py +27 -0
  176. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/_types.py +55 -0
  177. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/app.py +89 -0
  178. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/__init__.py +0 -0
  179. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/bench.py +170 -0
  180. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/cleanup.py +63 -0
  181. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/collection.py +220 -0
  182. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/context.py +115 -0
  183. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/documents.py +173 -0
  184. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/embed.py +83 -0
  185. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/mcp.py +67 -0
  186. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/pull.py +39 -0
  187. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/search.py +154 -0
  188. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/skill.py +171 -0
  189. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/skills.py +324 -0
  190. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/status.py +153 -0
  191. pyqmd_mlx-0.7.0/src/pyqmd_mlx/cli/commands/update.py +182 -0
  192. pyqmd_mlx-0.7.0/src/pyqmd_mlx/llm/__init__.py +23 -0
  193. pyqmd_mlx-0.7.0/src/pyqmd_mlx/llm/_cache.py +12 -0
  194. pyqmd_mlx-0.7.0/src/pyqmd_mlx/llm/_constants.py +15 -0
  195. pyqmd_mlx-0.7.0/src/pyqmd_mlx/llm/_expand_grammar.py +155 -0
  196. pyqmd_mlx-0.7.0/src/pyqmd_mlx/llm/_hub.py +43 -0
  197. pyqmd_mlx-0.7.0/src/pyqmd_mlx/llm/_prompts.py +60 -0
  198. pyqmd_mlx-0.7.0/src/pyqmd_mlx/llm/embed.py +43 -0
  199. pyqmd_mlx-0.7.0/src/pyqmd_mlx/llm/expand.py +195 -0
  200. pyqmd_mlx-0.7.0/src/pyqmd_mlx/llm/rerank.py +59 -0
  201. pyqmd_mlx-0.7.0/src/pyqmd_mlx/mcp/__init__.py +0 -0
  202. pyqmd_mlx-0.7.0/src/pyqmd_mlx/mcp/_errors.py +34 -0
  203. pyqmd_mlx-0.7.0/src/pyqmd_mlx/mcp/_formatting.py +52 -0
  204. pyqmd_mlx-0.7.0/src/pyqmd_mlx/mcp/_instructions.py +56 -0
  205. pyqmd_mlx-0.7.0/src/pyqmd_mlx/mcp/server.py +756 -0
  206. pyqmd_mlx-0.7.0/src/pyqmd_mlx/skills/pyqmd/SKILL.md +152 -0
  207. pyqmd_mlx-0.7.0/src/pyqmd_mlx/skills/pyqmd/references/mcp-setup.md +132 -0
  208. pyqmd_mlx-0.7.0/src/pyqmd_mlx/skills/pyqmd-bench/SKILL.md +71 -0
  209. pyqmd_mlx-0.7.0/src/pyqmd_mlx/skills/pyqmd-librarian/SKILL.md +52 -0
  210. pyqmd_mlx-0.7.0/src/pyqmd_mlx/skills/pyqmd-researcher/SKILL.md +43 -0
  211. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/__init__.py +3 -0
  212. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_ast.py +333 -0
  213. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_ast_queries.py +94 -0
  214. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_chunking.py +234 -0
  215. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_expansion.py +44 -0
  216. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_fts_query.py +109 -0
  217. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_indexing.py +186 -0
  218. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_intent.py +112 -0
  219. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_metadata.py +242 -0
  220. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_metadata_filter.py +362 -0
  221. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_rrf.py +53 -0
  222. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_schema.py +143 -0
  223. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_types.py +71 -0
  224. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/_yaml_alias_guard.py +33 -0
  225. pyqmd_mlx-0.7.0/src/pyqmd_mlx/store/store.py +1721 -0
  226. pyqmd_mlx-0.7.0/src/pyqmd_mlx/version.py +10 -0
  227. pyqmd_mlx-0.7.0/tests/.gitkeep +0 -0
  228. pyqmd_mlx-0.7.0/tests/__init__.py +0 -0
  229. pyqmd_mlx-0.7.0/tests/bench/__init__.py +0 -0
  230. pyqmd_mlx-0.7.0/tests/bench/test_fixture.py +98 -0
  231. pyqmd_mlx-0.7.0/tests/bench/test_metrics.py +136 -0
  232. pyqmd_mlx-0.7.0/tests/bench/test_pathmatch.py +69 -0
  233. pyqmd_mlx-0.7.0/tests/bench/test_runner.py +178 -0
  234. pyqmd_mlx-0.7.0/tests/bench/test_runner_samples.py +203 -0
  235. pyqmd_mlx-0.7.0/tests/bench/test_sampling.py +86 -0
  236. pyqmd_mlx-0.7.0/tests/cli/__init__.py +0 -0
  237. pyqmd_mlx-0.7.0/tests/cli/test_app.py +142 -0
  238. pyqmd_mlx-0.7.0/tests/cli/test_bench_command.py +269 -0
  239. pyqmd_mlx-0.7.0/tests/cli/test_cleanup_command.py +131 -0
  240. pyqmd_mlx-0.7.0/tests/cli/test_collection_command.py +544 -0
  241. pyqmd_mlx-0.7.0/tests/cli/test_context_command.py +229 -0
  242. pyqmd_mlx-0.7.0/tests/cli/test_db.py +48 -0
  243. pyqmd_mlx-0.7.0/tests/cli/test_e2e_real_models.py +54 -0
  244. pyqmd_mlx-0.7.0/tests/cli/test_embed_command.py +323 -0
  245. pyqmd_mlx-0.7.0/tests/cli/test_errors.py +46 -0
  246. pyqmd_mlx-0.7.0/tests/cli/test_format.py +104 -0
  247. pyqmd_mlx-0.7.0/tests/cli/test_fullpath.py +69 -0
  248. pyqmd_mlx-0.7.0/tests/cli/test_get_command.py +148 -0
  249. pyqmd_mlx-0.7.0/tests/cli/test_index_report.py +48 -0
  250. pyqmd_mlx-0.7.0/tests/cli/test_lineparse_shared.py +34 -0
  251. pyqmd_mlx-0.7.0/tests/cli/test_ls_command.py +139 -0
  252. pyqmd_mlx-0.7.0/tests/cli/test_mcp_command.py +158 -0
  253. pyqmd_mlx-0.7.0/tests/cli/test_metadata_filter_cli.py +29 -0
  254. pyqmd_mlx-0.7.0/tests/cli/test_multi_get_command.py +124 -0
  255. pyqmd_mlx-0.7.0/tests/cli/test_multiget_shared.py +120 -0
  256. pyqmd_mlx-0.7.0/tests/cli/test_output_documents.py +124 -0
  257. pyqmd_mlx-0.7.0/tests/cli/test_output_search.py +174 -0
  258. pyqmd_mlx-0.7.0/tests/cli/test_progress.py +121 -0
  259. pyqmd_mlx-0.7.0/tests/cli/test_pull_command.py +23 -0
  260. pyqmd_mlx-0.7.0/tests/cli/test_search_commands.py +536 -0
  261. pyqmd_mlx-0.7.0/tests/cli/test_skill_command.py +280 -0
  262. pyqmd_mlx-0.7.0/tests/cli/test_skills_command.py +281 -0
  263. pyqmd_mlx-0.7.0/tests/cli/test_snippet.py +61 -0
  264. pyqmd_mlx-0.7.0/tests/cli/test_status_command.py +276 -0
  265. pyqmd_mlx-0.7.0/tests/cli/test_update_command.py +437 -0
  266. pyqmd_mlx-0.7.0/tests/cli/test_version_flag.py +18 -0
  267. pyqmd_mlx-0.7.0/tests/conftest.py +54 -0
  268. pyqmd_mlx-0.7.0/tests/mcp/__init__.py +0 -0
  269. pyqmd_mlx-0.7.0/tests/mcp/test_bootstrap.py +15 -0
  270. pyqmd_mlx-0.7.0/tests/mcp/test_e2e_real_models.py +63 -0
  271. pyqmd_mlx-0.7.0/tests/mcp/test_errors.py +72 -0
  272. pyqmd_mlx-0.7.0/tests/mcp/test_formatting.py +91 -0
  273. pyqmd_mlx-0.7.0/tests/mcp/test_http_origin_guard.py +396 -0
  274. pyqmd_mlx-0.7.0/tests/mcp/test_instructions.py +45 -0
  275. pyqmd_mlx-0.7.0/tests/mcp/test_locking.py +37 -0
  276. pyqmd_mlx-0.7.0/tests/mcp/test_real_dispatch.py +194 -0
  277. pyqmd_mlx-0.7.0/tests/mcp/test_server_get.py +100 -0
  278. pyqmd_mlx-0.7.0/tests/mcp/test_server_http.py +198 -0
  279. pyqmd_mlx-0.7.0/tests/mcp/test_server_multi_get.py +125 -0
  280. pyqmd_mlx-0.7.0/tests/mcp/test_server_query.py +242 -0
  281. pyqmd_mlx-0.7.0/tests/mcp/test_server_resource.py +30 -0
  282. pyqmd_mlx-0.7.0/tests/mcp/test_server_status.py +39 -0
  283. pyqmd_mlx-0.7.0/tests/parity/__init__.py +0 -0
  284. pyqmd_mlx-0.7.0/tests/parity/test_capture_node_snapshots.py +617 -0
  285. pyqmd_mlx-0.7.0/tests/parity/test_cli_dispatch_args.py +76 -0
  286. pyqmd_mlx-0.7.0/tests/parity/test_cli_flow_scenarios.py +202 -0
  287. pyqmd_mlx-0.7.0/tests/parity/test_cli_scenarios.py +143 -0
  288. pyqmd_mlx-0.7.0/tests/parity/test_conftest_fixture.py +6 -0
  289. pyqmd_mlx-0.7.0/tests/parity/test_dataset_profile.py +134 -0
  290. pyqmd_mlx-0.7.0/tests/parity/test_mcp_http_parity.py +175 -0
  291. pyqmd_mlx-0.7.0/tests/parity/test_mcp_scenarios.py +77 -0
  292. pyqmd_mlx-0.7.0/tests/parity/test_node_cli.py +109 -0
  293. pyqmd_mlx-0.7.0/tests/parity/test_quality_baseline.py +82 -0
  294. pyqmd_mlx-0.7.0/tests/parity/test_snapshot_io.py +19 -0
  295. pyqmd_mlx-0.7.0/tests/parity/test_text_normalize.py +99 -0
  296. pyqmd_mlx-0.7.0/tests/store/__init__.py +0 -0
  297. pyqmd_mlx-0.7.0/tests/store/test_ast.py +256 -0
  298. pyqmd_mlx-0.7.0/tests/store/test_bulk_operations.py +132 -0
  299. pyqmd_mlx-0.7.0/tests/store/test_chunking.py +222 -0
  300. pyqmd_mlx-0.7.0/tests/store/test_cleanup.py +164 -0
  301. pyqmd_mlx-0.7.0/tests/store/test_cli_capabilities.py +374 -0
  302. pyqmd_mlx-0.7.0/tests/store/test_collection_stats.py +50 -0
  303. pyqmd_mlx-0.7.0/tests/store/test_collections.py +208 -0
  304. pyqmd_mlx-0.7.0/tests/store/test_concurrency.py +127 -0
  305. pyqmd_mlx-0.7.0/tests/store/test_context.py +201 -0
  306. pyqmd_mlx-0.7.0/tests/store/test_documents.py +136 -0
  307. pyqmd_mlx-0.7.0/tests/store/test_expansion.py +77 -0
  308. pyqmd_mlx-0.7.0/tests/store/test_fts_query.py +57 -0
  309. pyqmd_mlx-0.7.0/tests/store/test_indexing.py +245 -0
  310. pyqmd_mlx-0.7.0/tests/store/test_indexing_scan.py +319 -0
  311. pyqmd_mlx-0.7.0/tests/store/test_integration.py +28 -0
  312. pyqmd_mlx-0.7.0/tests/store/test_intent.py +29 -0
  313. pyqmd_mlx-0.7.0/tests/store/test_llm_wrapping.py +114 -0
  314. pyqmd_mlx-0.7.0/tests/store/test_metadata_extraction.py +208 -0
  315. pyqmd_mlx-0.7.0/tests/store/test_metadata_filter_compile.py +200 -0
  316. pyqmd_mlx-0.7.0/tests/store/test_metadata_filter_parse.py +160 -0
  317. pyqmd_mlx-0.7.0/tests/store/test_metadata_persistence.py +167 -0
  318. pyqmd_mlx-0.7.0/tests/store/test_metadata_queries.py +105 -0
  319. pyqmd_mlx-0.7.0/tests/store/test_metadata_schema.py +101 -0
  320. pyqmd_mlx-0.7.0/tests/store/test_multi_collection.py +125 -0
  321. pyqmd_mlx-0.7.0/tests/store/test_orphan_cleanup.py +62 -0
  322. pyqmd_mlx-0.7.0/tests/store/test_query.py +386 -0
  323. pyqmd_mlx-0.7.0/tests/store/test_query_retrieval.py +106 -0
  324. pyqmd_mlx-0.7.0/tests/store/test_rrf.py +53 -0
  325. pyqmd_mlx-0.7.0/tests/store/test_schema.py +69 -0
  326. pyqmd_mlx-0.7.0/tests/store/test_search_fts.py +170 -0
  327. pyqmd_mlx-0.7.0/tests/store/test_search_vec.py +284 -0
  328. pyqmd_mlx-0.7.0/tests/store/test_types.py +48 -0
  329. pyqmd_mlx-0.7.0/tests/test_cache.py +31 -0
  330. pyqmd_mlx-0.7.0/tests/test_compare_rerank_fixtures.py +170 -0
  331. pyqmd_mlx-0.7.0/tests/test_convert_expand_gguf.py +97 -0
  332. pyqmd_mlx-0.7.0/tests/test_expand_grammar.py +160 -0
  333. pyqmd_mlx-0.7.0/tests/test_expand_model.py +188 -0
  334. pyqmd_mlx-0.7.0/tests/test_expand_sampling.py +106 -0
  335. pyqmd_mlx-0.7.0/tests/test_expand_seed.py +41 -0
  336. pyqmd_mlx-0.7.0/tests/test_hub.py +81 -0
  337. pyqmd_mlx-0.7.0/tests/test_integration.py +128 -0
  338. pyqmd_mlx-0.7.0/tests/test_packaging.py +41 -0
  339. pyqmd_mlx-0.7.0/tests/test_prepare_scifact_corpus.py +37 -0
  340. pyqmd_mlx-0.7.0/tests/test_prompts.py +66 -0
  341. pyqmd_mlx-0.7.0/tests/test_rerank.py +82 -0
  342. pyqmd_mlx-0.7.0/tests/test_score_rerank_fixture.py +31 -0
  343. pyqmd_mlx-0.7.0/uv.lock +2191 -0
@@ -0,0 +1,50 @@
1
+ set shell := ["bash", "-uc"]
2
+
3
+ # Just runs the first target if no arguments are provided, so we set this to list all targets for safety.
4
+ _default:
5
+ @just --list
6
+
7
+ # Install/upgrade dev dependencies and activate pre-commit hooks.
8
+ [group('development')]
9
+ develop:
10
+ uv sync --dev
11
+ uv tool install pre-commit
12
+ pre-commit install
13
+
14
+ [group('quality')]
15
+ test *args:
16
+ uv run pytest {{args}} -v
17
+
18
+ [group('quality')]
19
+ test-fast:
20
+ uv run pytest -v -m "not slow"
21
+
22
+ [group('quality')]
23
+ test-slow:
24
+ uv run pytest -v -m slow
25
+
26
+ [group('quality')]
27
+ test-parity *args:
28
+ uv run pytest parity/ {{args}}
29
+
30
+ # Performance comparison against a Node qmd checkout at ../qmd (override with e.g. `just bench-scifact --qmd-repo-root /path/to/qmd`).
31
+ # Uses the built-in SciFact profile by default (override with `--dataset-config path/to/profile.yaml`,
32
+ # same as `test-parity`) -- its corpus lives in data/scifact/, gitignored and not shipped with the repo;
33
+ # generate it first with `uv run scripts/prepare_scifact_corpus.py`.
34
+ [group('quality')]
35
+ bench-scifact *args:
36
+ uv run python -m parity.benchmark --qmd-repo-root ../qmd {{args}}
37
+
38
+ [group('quality')]
39
+ lint:
40
+ uv run ruff check .
41
+ uv run ruff format --check .
42
+
43
+ # Install pyqmd as a real `pyqmd` command on PATH, editable (source changes apply without reinstalling).
44
+ [group('install')]
45
+ install:
46
+ uv tool install --editable .
47
+
48
+ [group('install')]
49
+ uninstall:
50
+ uv tool uninstall pyqmd-mlx
@@ -0,0 +1,47 @@
1
+ export default {
2
+ extends: ["@commitlint/config-conventional"],
3
+ rules: {
4
+ // 0 = off, 1 = warn, 2 = error | "always" / "never"
5
+ "scope-enum": [
6
+ 2,
7
+ "always",
8
+ [
9
+ "store", // src/pyqmd_mlx/store/ -- schema, Store class, search/query
10
+ "cli", // src/pyqmd_mlx/cli/ -- Typer commands, output formatting
11
+ "mcp", // src/pyqmd_mlx/mcp/ -- MCP server (stdio/HTTP)
12
+ "llm", // src/pyqmd_mlx/llm/ -- MLX embed/rerank/query-expansion layer
13
+ "bench", // src/pyqmd_mlx/bench/ and the bench command
14
+ "skills", // src/pyqmd_mlx/skills/ and the skill/skills commands
15
+ "parity", // parity/ -- Node-vs-pyqmd golden-snapshot suite
16
+ "scripts", // scripts/ -- dev utility scripts
17
+ "config", // pyproject.toml, .pre-commit-config.yaml, Justfile, .gitignore
18
+ "docs", // README/CLAUDE.md/COMMAND_STATUS.md and any docs/ that aren't specs
19
+ "specs", // docs/specs/ -- published design/spec docs
20
+ "tests", // test-only changes
21
+ ],
22
+ ],
23
+ "scope-empty": [0, "never"], // off - some commits legitimately have no scope
24
+ "type-enum": [
25
+ 2,
26
+ "always",
27
+ [
28
+ // conventional commits standard types
29
+ "feat",
30
+ "fix",
31
+ "docs",
32
+ "style",
33
+ "refactor",
34
+ "perf",
35
+ "test",
36
+ "build",
37
+ "ci",
38
+ "chore",
39
+ "revert",
40
+ // escape hatch — never bumps version, never appears in changelog
41
+ "doh",
42
+ // changes a reviewer asked for on an open PR — like doh, never released or logged
43
+ "review",
44
+ ],
45
+ ],
46
+ },
47
+ };
@@ -0,0 +1,61 @@
1
+ name: Build
2
+
3
+ # Reusable: ci.yml runs it on every PR/push, release.yml on the new tag.
4
+ # No credentials: release.yml's publish job only downloads this artifact.
5
+ on:
6
+ workflow_call:
7
+ inputs:
8
+ ref:
9
+ description: Commit or tag to build
10
+ required: true
11
+ type: string
12
+ expected-version:
13
+ description: If set, the wheel's `pyqmd --version` must print exactly this
14
+ required: false
15
+ type: string
16
+ default: ""
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ build:
23
+ # Apple Silicon, the only platform pyqmd supports. GitHub's macOS
24
+ # runners have no Metal access: this proves install + CLI startup,
25
+ # never that the MLX models run (those are `just test-slow`, locally).
26
+ runs-on: macos-latest
27
+ steps:
28
+ - uses: actions/checkout@v7
29
+ with:
30
+ ref: ${{ inputs.ref }}
31
+ persist-credentials: false
32
+ - uses: astral-sh/setup-uv@v8.2.0
33
+ with:
34
+ python-version: "3.12"
35
+ # Same reason as ci.yml's macOS test leg: the runner's preinstalled
36
+ # Python lacks sqlite3 loadable-extension support.
37
+ - name: Force managed Python
38
+ run: echo "UV_PYTHON_PREFERENCE=only-managed" >> "$GITHUB_ENV"
39
+ - run: uv build
40
+ - run: uvx twine check --strict dist/*
41
+ # Installs the wheel with the *latest* dependencies (no uv.lock), like
42
+ # a user's `uv tool install pyqmd-mlx` -- the one check that catches a
43
+ # new dependency release breaking pyqmd.
44
+ - name: Smoke-test the wheel
45
+ env:
46
+ EXPECTED_VERSION: ${{ inputs.expected-version }}
47
+ run: |
48
+ export UV_TOOL_DIR="$RUNNER_TEMP/uv-tools" UV_TOOL_BIN_DIR="$RUNNER_TEMP/uv-bin"
49
+ uv tool install dist/*.whl
50
+ "$UV_TOOL_BIN_DIR/pyqmd" --help > /dev/null
51
+ version=$("$UV_TOOL_BIN_DIR/pyqmd" --version)
52
+ echo "pyqmd --version: $version"
53
+ if [ -n "$EXPECTED_VERSION" ] && [ "$version" != "$EXPECTED_VERSION" ]; then
54
+ echo "::error::expected pyqmd --version $EXPECTED_VERSION, got $version"
55
+ exit 1
56
+ fi
57
+ - uses: actions/upload-artifact@v7
58
+ with:
59
+ name: dist
60
+ path: dist/
61
+ if-no-files-found: error
@@ -0,0 +1,60 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ lint:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v7
16
+ - uses: astral-sh/setup-uv@v8.2.0
17
+ with:
18
+ python-version: "3.12"
19
+ - run: uv sync --dev
20
+ - run: uv run ruff check .
21
+ - run: uv run ruff format --check .
22
+
23
+ test:
24
+ needs: [lint]
25
+ strategy:
26
+ # Pinned, not floating: mlx ships manylinux_2_35+ wheels only, so
27
+ # ubuntu-24.04 (glibc 2.39) is the floor -- an older ubuntu image
28
+ # cannot even resolve uv.lock. macos-latest is ARM, covering the
29
+ # Apple Silicon import path.
30
+ matrix:
31
+ os: [ubuntu-24.04, macos-latest]
32
+ runs-on: ${{ matrix.os }}
33
+ steps:
34
+ - uses: actions/checkout@v7
35
+ - uses: astral-sh/setup-uv@v8.2.0
36
+ with:
37
+ python-version: "3.12"
38
+ # macOS only: uv's discovery prefers the runner-preinstalled
39
+ # python-build-standalone (higher patch version wins), whose macOS
40
+ # builds lack sqlite3 loadable extension support -- every Store()
41
+ # construction then dies in load_sqlite_vec with AttributeError.
42
+ # only-managed forces the astral build setup-uv just installed
43
+ # (verified to have enable_load_extension). Ubuntu is untouched
44
+ # (green as-is). Done as a conditional step rather than job-level
45
+ # env so the ubuntu leg keeps default discovery byte-for-byte.
46
+ - name: Force managed Python on macOS
47
+ if: matrix.os == 'macos-latest'
48
+ run: echo "UV_PYTHON_PREFERENCE=only-managed" >> "$GITHUB_ENV"
49
+ - run: uv sync --dev
50
+ # No data/ or models/ on a fresh checkout (both gitignored): the
51
+ # scifact corpus (self-generatable but 33MB + slow) and the
52
+ # self-converted expansion weights (not fetchable anywhere) are
53
+ # absent, so requires_scifact_corpus / requires_expansion_weights
54
+ # tests skip with a clear reason (see tests/conftest.py).
55
+ - run: uv run pytest -m "not slow" -q
56
+
57
+ build:
58
+ uses: ./.github/workflows/build.yml
59
+ with:
60
+ ref: ${{ github.event.pull_request.head.sha || github.sha }}
@@ -0,0 +1,24 @@
1
+ name: PR title
2
+
3
+ # A squash merge of a multi-commit PR takes the PR title as its commit
4
+ # subject, and semantic-release reads that subject to decide the release.
5
+ # The commit-msg hook never sees it, so lint it here.
6
+ on:
7
+ pull_request:
8
+ types: [opened, edited, reopened, synchronize]
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ pr-title:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v7
18
+ - uses: actions/setup-node@v7
19
+ with:
20
+ node-version: lts/*
21
+ - run: npm install --no-save --no-package-lock @commitlint/cli@21.2.3 @commitlint/config-conventional@21.2.3
22
+ - run: printf '%s\n' "$PR_TITLE" | npx --no-install commitlint --config .commitlintrc.mjs
23
+ env:
24
+ PR_TITLE: ${{ github.event.pull_request.title }}
@@ -0,0 +1,87 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_run:
5
+ workflows: ["CI"]
6
+ types: [completed]
7
+ branches: [main]
8
+
9
+ # Each job declares its own permissions.
10
+ permissions: {}
11
+
12
+ jobs:
13
+ release:
14
+ if: ${{ github.event.workflow_run.conclusion == 'success' }}
15
+ runs-on: ubuntu-latest
16
+ concurrency: release
17
+ permissions:
18
+ contents: write
19
+ outputs:
20
+ released: ${{ steps.result.outputs.released }}
21
+ tag: ${{ steps.result.outputs.tag }}
22
+ version: ${{ steps.result.outputs.version }}
23
+ steps:
24
+ - uses: actions/checkout@v7
25
+ with:
26
+ fetch-depth: 0
27
+ fetch-tags: true
28
+ token: ${{ secrets.RELEASE_PAT }}
29
+ - id: before
30
+ run: echo "head=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
31
+ - uses: astral-sh/setup-uv@v8.2.0
32
+ with:
33
+ python-version: "3.12"
34
+ - run: uv tool install python-semantic-release==10.6.1
35
+ - run: semantic-release version --skip-build --no-commit --no-tag --no-changelog
36
+ env:
37
+ GH_TOKEN: ${{ secrets.RELEASE_PAT }}
38
+ - run: |
39
+ uv lock --upgrade-package pyqmd-mlx
40
+ git add uv.lock
41
+ - run: semantic-release version
42
+ env:
43
+ GH_TOKEN: ${{ secrets.RELEASE_PAT }}
44
+ # A release moves HEAD to PSR's release commit; no release leaves it.
45
+ - id: result
46
+ env:
47
+ BEFORE: ${{ steps.before.outputs.head }}
48
+ run: |
49
+ if [ "$(git rev-parse HEAD)" != "$BEFORE" ]; then
50
+ tag=$(git tag --points-at HEAD --list 'v*' | head -1)
51
+ {
52
+ echo "released=true"
53
+ echo "tag=$tag"
54
+ echo "version=${tag#v}"
55
+ } >> "$GITHUB_OUTPUT"
56
+ else
57
+ echo "released=false" >> "$GITHUB_OUTPUT"
58
+ fi
59
+
60
+ build:
61
+ needs: release
62
+ if: ${{ needs.release.outputs.released == 'true' }}
63
+ permissions:
64
+ contents: read
65
+ uses: ./.github/workflows/build.yml
66
+ with:
67
+ # The tag, not main: another merge may land after `release` checked out.
68
+ ref: ${{ needs.release.outputs.tag }}
69
+ expected-version: ${{ needs.release.outputs.version }}
70
+
71
+ publish:
72
+ needs: [release, build]
73
+ runs-on: ubuntu-latest # the PyPA action is a Docker action
74
+ # PyPI's trusted publisher matches workflow release.yml + environment pypi,
75
+ # so only this job can get a PyPI token. No checkout, no repo code.
76
+ environment:
77
+ name: pypi
78
+ url: https://pypi.org/project/pyqmd-mlx/${{ needs.release.outputs.version }}/
79
+ permissions:
80
+ id-token: write
81
+ contents: read
82
+ steps:
83
+ - uses: actions/download-artifact@v8
84
+ with:
85
+ name: dist
86
+ path: dist/
87
+ - uses: pypa/gh-action-pypi-publish@v1.14.2
@@ -0,0 +1,60 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+
8
+ # uv / venv
9
+ .venv/
10
+
11
+ # tooling caches
12
+ .pytest_cache/
13
+ .ruff_cache/
14
+
15
+ # env / secrets
16
+ .env
17
+
18
+ # editor / OS
19
+ .DS_Store
20
+ .idea/
21
+ .vscode/
22
+
23
+ # generated data and models (large, re-fetchable)
24
+ data/
25
+ models/
26
+
27
+ # A user's own dataset profile + private data for the parity suite --
28
+ # never committed. .gitkeep above keeps the directory itself tracked.
29
+ parity/datasets/local/*
30
+ !parity/datasets/local/.gitkeep
31
+
32
+ # A user's own captured Node baseline lands in parity/node_ref/<profile>/
33
+ # regardless of where their profile YAML lives -- ignore every profile's
34
+ # captured data there except the built-in scifact one (the project's own
35
+ # tracked golden-reference data). Without this, README's "your data and
36
+ # captured baseline never get committed" claim was false for anything
37
+ # outside parity/datasets/local/ itself.
38
+ parity/node_ref/*
39
+ !parity/node_ref/scifact/
40
+
41
+ # Scratch Node collection-registry/index-DB state the capture script
42
+ # creates as isolation artifacts, not intended captured output --
43
+ # baked-in absolute paths make these non-portable across machines.
44
+ parity/node_ref/*/config/
45
+ parity/node_ref/*/_capture*.sqlite*
46
+ parity/node_ref/*/_structural_capture/
47
+ parity/node_ref/*/_quality_capture/
48
+ parity/node_ref/*/_mcp_capture/
49
+ parity/node_ref/*/_flow_*_capture/
50
+
51
+ # benchmark.py's generated report -- machine- and moment-dependent timing
52
+ # numbers, not something to track in git.
53
+ parity/BENCHMARK_RESULTS.md
54
+
55
+ # isolated git worktrees (per using-git-worktrees skill)
56
+ .worktrees/
57
+
58
+ # Private specs, plans, notes, leak-check tooling and history archive --
59
+ # see CLAUDE.md "Workflow". Public specs live in docs/specs/.
60
+ docs/superpowers/
@@ -0,0 +1,71 @@
1
+ ---
2
+ # Run 'just develop' to install pre-commit and activate these hooks.
3
+ default_install_hook_types: [pre-commit, commit-msg, pre-push]
4
+ default_stages: [pre-commit]
5
+
6
+ repos:
7
+ # --- General hygiene ---
8
+ - repo: https://github.com/pre-commit/pre-commit-hooks
9
+ rev: v5.0.0
10
+ hooks:
11
+ - id: trailing-whitespace
12
+ - id: end-of-file-fixer
13
+ - id: check-merge-conflict
14
+ - id: check-added-large-files
15
+ - id: detect-private-key
16
+ - id: mixed-line-ending
17
+ - id: check-yaml
18
+ - id: check-json
19
+ - id: check-toml
20
+
21
+ # --- Python lint/format ---
22
+ - repo: https://github.com/astral-sh/ruff-pre-commit
23
+ rev: v0.15.16
24
+ hooks:
25
+ - id: ruff-check
26
+ args: [--fix, --exit-non-zero-on-fix]
27
+ types_or: [python, pyi]
28
+ - id: ruff-format
29
+
30
+ # --- Commit message linting (Conventional Commits) ---
31
+ # Uses `npx --yes commitlint` directly (already available on PATH) rather than
32
+ # a pre-commit-managed hook repo. This mirrors the system/local hook pattern
33
+ # used for prettier below.
34
+ # Requires @commitlint/cli and @commitlint/config-conventional installed
35
+ # globally (npm i -g @commitlint/cli @commitlint/config-conventional) --
36
+ # language: system means pre-commit can't manage this dependency itself.
37
+ - repo: local
38
+ hooks:
39
+ - id: commitlint
40
+ name: commitlint
41
+ language: system
42
+ entry: npx --yes commitlint --edit --config .commitlintrc.mjs
43
+ stages: [commit-msg]
44
+ pass_filenames: false
45
+ always_run: true
46
+
47
+ # --- Prettier, for markdown/yaml/json only ---
48
+ # Uses whatever `prettier` is on PATH rather than a pre-commit-managed
49
+ # mirror repo.
50
+ - repo: local
51
+ hooks:
52
+ - id: prettier
53
+ name: prettier
54
+ language: system
55
+ entry: prettier --write --ignore-unknown
56
+ types_or: [markdown, yaml, json]
57
+ stages: [pre-commit]
58
+
59
+ # --- Block direct pushes to main (client-side backstop) ---
60
+ # Local safety net only -- bypassable with `git push --no-verify` and only
61
+ # active for whoever has run `just develop` in their own checkout. The
62
+ # actual enforcement point is GitHub branch protection on the upstream repo.
63
+ - repo: local
64
+ hooks:
65
+ - id: block-main-push
66
+ name: block direct pushes to main
67
+ language: system
68
+ entry: scripts/block-main-push.sh
69
+ pass_filenames: false
70
+ always_run: true
71
+ stages: [pre-push]
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,9 @@
1
+ # CHANGELOG
2
+
3
+ {% if ctx.changelog_mode == "update"
4
+ %}{# # IMPORTANT: add insertion flag for next version update
5
+ #}{{
6
+ insertion_flag ~ "\n"
7
+
8
+ }}{% endif
9
+ %}
@@ -0,0 +1,29 @@
1
+ {#
2
+ This changelog template initializes a full changelog for the project,
3
+ it follows the following logic:
4
+ 1. Header
5
+ 2. Any Unreleased Details (uncommon)
6
+ 3. all previous releases except the very first release
7
+ 4. the first release
8
+
9
+ #}{#
10
+ # Header
11
+ #}{% include "changelog_header.md.j2"
12
+ -%}{#
13
+ # Any Unreleased Details (uncommon)
14
+ #}{% include "unreleased_changes.md.j2"
15
+ -%}{#
16
+ # Since this is initialization, we are generating all the previous
17
+ # release notes per version. The very first release notes is specialized
18
+ #}{% if releases | length > 0
19
+ %}{% for release in releases
20
+ %}{{ "\n"
21
+ }}{% if loop.last and ctx.mask_initial_release
22
+ %}{%- include "first_release.md.j2"
23
+ -%}{% else
24
+ %}{%- include "versioned_changes.md.j2"
25
+ -%}{% endif
26
+ %}{{ "\n"
27
+ }}{% endfor
28
+ %}{% endif
29
+ %}
@@ -0,0 +1,71 @@
1
+ {#
2
+ This Update changelog template uses the following logic:
3
+
4
+ 1. Read previous changelog file (ex. project_root/CHANGELOG.md)
5
+ 2. Split on insertion flag (ex. <!-- version list -->)
6
+ 3. Print top half of previous changelog
7
+ 3. New Changes (unreleased commits & newly released)
8
+ 4. Print bottom half of previous changelog
9
+
10
+ Note: if a previous file was not found, it does not write anything at the bottom
11
+ but render does NOT fail
12
+
13
+ #}{% set prev_changelog_contents = prev_changelog_file | read_file | safe
14
+ %}{% set changelog_parts = prev_changelog_contents.split(insertion_flag, maxsplit=1)
15
+ %}{#
16
+ #}{% if changelog_parts | length < 2
17
+ %}{# # insertion flag was not found, check if the file was empty or did not exist
18
+ #}{% if prev_changelog_contents | length > 0
19
+ %}{# # File has content but no insertion flag, therefore, file will not be updated
20
+ #}{{ changelog_parts[0]
21
+ }}{% else
22
+ %}{# # File was empty or did not exist, therefore, it will be created from scratch
23
+ #}{% include "changelog_init.md.j2"
24
+ %}{% endif
25
+ %}{% else
26
+ %}{#
27
+ # Previous Changelog Header
28
+ # - Depending if there is header content, then it will separate the insertion flag
29
+ # with a newline from header content, otherwise it will just print the insertion flag
30
+ #}{% set prev_changelog_top = changelog_parts[0] | trim
31
+ %}{% if prev_changelog_top | length > 0
32
+ %}{{
33
+ "%s\n\n%s\n" | format(prev_changelog_top, insertion_flag | trim)
34
+
35
+ }}{% else
36
+ %}{{
37
+ "%s\n" | format(insertion_flag | trim)
38
+
39
+ }}{% endif
40
+ %}{#
41
+ # Any Unreleased Details (uncommon)
42
+ #}{% include "unreleased_changes.md.j2"
43
+ -%}{#
44
+ #}{% if releases | length > 0
45
+ %}{# # Latest Release Details
46
+ #}{% set release = releases[0]
47
+ %}{#
48
+ #}{% if releases | length == 1 and ctx.mask_initial_release
49
+ %}{# # First Release detected
50
+ #}{{ "\n"
51
+ }}{%- include "first_release.md.j2"
52
+ -%}{{ "\n"
53
+ }}{#
54
+ #}{% elif "# " ~ release.version.as_semver_tag() ~ " " not in changelog_parts[1]
55
+ %}{# # The release version is not already in the changelog so we add it
56
+ #}{{ "\n"
57
+ }}{%- include "versioned_changes.md.j2"
58
+ -%}{{ "\n"
59
+ }}{#
60
+ #}{% endif
61
+ %}{% endif
62
+ %}{#
63
+ # Previous Changelog Footer
64
+ # - skips printing footer if empty, which happens when the insertion_flag
65
+ # was at the end of the file (ignoring whitespace)
66
+ #}{% set previous_changelog_bottom = changelog_parts[1] | trim
67
+ %}{% if previous_changelog_bottom | length > 0
68
+ %}{{ "\n%s\n" | format(previous_changelog_bottom)
69
+ }}{% endif
70
+ %}{% endif
71
+ %}